diff --git a/src/core/public/saved_objects/saved_objects_client.ts b/src/core/public/saved_objects/saved_objects_client.ts index 5393a22f2aee..2ddc776ffdf1 100644 --- a/src/core/public/saved_objects/saved_objects_client.ts +++ b/src/core/public/saved_objects/saved_objects_client.ts @@ -61,7 +61,7 @@ export interface SavedObjectsCreateOptions { /** {@inheritDoc SavedObjectsMigrationVersion} */ migrationVersion?: SavedObjectsMigrationVersion; references?: SavedObjectReference[]; - workspace?: string; + workspaces?: string[]; } /** @@ -268,7 +268,11 @@ export class SavedObjectsClient { attributes, migrationVersion: options.migrationVersion, references: options.references, - workspace: options.workspace || currentWorkspaceId || undefined, + ...(options.workspaces || currentWorkspaceId + ? { + workspaces: options.workspaces || [currentWorkspaceId], + } + : {}), }), }); diff --git a/src/core/server/saved_objects/import/create_saved_objects.ts b/src/core/server/saved_objects/import/create_saved_objects.ts index 9076b7fd2a8d..b67cffce1e96 100644 --- a/src/core/server/saved_objects/import/create_saved_objects.ts +++ b/src/core/server/saved_objects/import/create_saved_objects.ts @@ -39,7 +39,7 @@ interface CreateSavedObjectsParams { importIdMap: Map; namespace?: string; overwrite?: boolean; - workspace?: string; + workspaces?: string[]; } interface CreateSavedObjectsResult { createdObjects: Array>; @@ -57,7 +57,7 @@ export const createSavedObjects = async ({ importIdMap, namespace, overwrite, - workspace, + workspaces, }: CreateSavedObjectsParams): Promise> => { // filter out any objects that resulted in errors const errorSet = accumulatedErrors.reduce( @@ -105,7 +105,7 @@ export const createSavedObjects = async ({ const bulkCreateResponse = await savedObjectsClient.bulkCreate(objectsToCreate, { namespace, overwrite, - workspace, + workspaces, }); expectedResults = bulkCreateResponse.saved_objects; } diff --git a/src/core/server/saved_objects/import/import_saved_objects.ts b/src/core/server/saved_objects/import/import_saved_objects.ts index 67203549cdf8..68104db85e6f 100644 --- a/src/core/server/saved_objects/import/import_saved_objects.ts +++ b/src/core/server/saved_objects/import/import_saved_objects.ts @@ -54,7 +54,7 @@ export async function importSavedObjectsFromStream({ savedObjectsClient, typeRegistry, namespace, - workspace, + workspaces, }: SavedObjectsImportOptions): Promise { let errorAccumulator: SavedObjectsImportError[] = []; const supportedTypes = typeRegistry.getImportableAndExportableTypes().map((type) => type.name); @@ -119,7 +119,7 @@ export async function importSavedObjectsFromStream({ importIdMap, overwrite, namespace, - workspace, + workspaces, }; const createSavedObjectsResult = await createSavedObjects(createSavedObjectsParams); errorAccumulator = [...errorAccumulator, ...createSavedObjectsResult.errors]; diff --git a/src/core/server/saved_objects/import/types.ts b/src/core/server/saved_objects/import/types.ts index 876d1451835a..ab13fbfe4658 100644 --- a/src/core/server/saved_objects/import/types.ts +++ b/src/core/server/saved_objects/import/types.ts @@ -187,8 +187,8 @@ export interface SavedObjectsImportOptions { namespace?: string; /** If true, will create new copies of import objects, each with a random `id` and undefined `originId`. */ createNewCopies: boolean; - /** if specified, will import in given workspace, else will import as global object */ - workspace?: string; + /** if specified, will import in given workspaces, else will import as global object */ + workspaces?: string[]; } /** diff --git a/src/core/server/saved_objects/routes/bulk_create.ts b/src/core/server/saved_objects/routes/bulk_create.ts index d117bb1d6572..a43a69464308 100644 --- a/src/core/server/saved_objects/routes/bulk_create.ts +++ b/src/core/server/saved_objects/routes/bulk_create.ts @@ -30,6 +30,7 @@ import { schema } from '@osd/config-schema'; import { IRouter } from '../../http'; +import { formatWorkspaces, workspacesValidator } from '../../workspaces'; export const registerBulkCreateRoute = (router: IRouter) => { router.post( @@ -38,7 +39,7 @@ export const registerBulkCreateRoute = (router: IRouter) => { validate: { query: schema.object({ overwrite: schema.boolean({ defaultValue: false }), - workspace: schema.maybe(schema.string()), + workspaces: workspacesValidator, }), body: schema.arrayOf( schema.object({ @@ -62,10 +63,11 @@ export const registerBulkCreateRoute = (router: IRouter) => { }, }, router.handleLegacyErrors(async (context, req, res) => { - const { overwrite, workspace } = req.query; + const { overwrite } = req.query; + const workspaces = formatWorkspaces(req.query.workspaces); const result = await context.core.savedObjects.client.bulkCreate(req.body, { overwrite, - workspace, + workspaces, }); return res.ok({ body: result }); }) diff --git a/src/core/server/saved_objects/routes/copy.ts b/src/core/server/saved_objects/routes/copy.ts index b85c4540b40d..7bace54db583 100644 --- a/src/core/server/saved_objects/routes/copy.ts +++ b/src/core/server/saved_objects/routes/copy.ts @@ -73,7 +73,7 @@ export const registerCopyRoute = (router: IRouter, config: SavedObjectConfig) => objectLimit: maxImportExportSize, overwrite: false, createNewCopies: true, - workspace: targetWorkspace, + workspaces: [targetWorkspace], }); return res.ok({ body: result }); diff --git a/src/core/server/saved_objects/routes/create.ts b/src/core/server/saved_objects/routes/create.ts index 177196a046d7..4d22bd244a03 100644 --- a/src/core/server/saved_objects/routes/create.ts +++ b/src/core/server/saved_objects/routes/create.ts @@ -56,14 +56,14 @@ export const registerCreateRoute = (router: IRouter) => { ) ), initialNamespaces: schema.maybe(schema.arrayOf(schema.string(), { minSize: 1 })), - workspace: schema.maybe(schema.string()), + workspaces: schema.maybe(schema.arrayOf(schema.string(), { minSize: 1 })), }), }, }, router.handleLegacyErrors(async (context, req, res) => { const { type, id } = req.params; const { overwrite } = req.query; - const { attributes, migrationVersion, references, initialNamespaces, workspace } = req.body; + const { attributes, migrationVersion, references, initialNamespaces, workspaces } = req.body; const options = { id, @@ -71,7 +71,7 @@ export const registerCreateRoute = (router: IRouter) => { migrationVersion, references, initialNamespaces, - workspace, + workspaces, }; const result = await context.core.savedObjects.client.create(type, attributes, options); return res.ok({ body: result }); diff --git a/src/core/server/saved_objects/routes/import.ts b/src/core/server/saved_objects/routes/import.ts index 991c3c8219bb..9675d608541c 100644 --- a/src/core/server/saved_objects/routes/import.ts +++ b/src/core/server/saved_objects/routes/import.ts @@ -35,6 +35,7 @@ import { IRouter } from '../../http'; import { importSavedObjectsFromStream } from '../import'; import { SavedObjectConfig } from '../saved_objects_config'; import { createSavedObjectsStreamFromNdJson } from './utils'; +import { formatWorkspaces, workspacesValidator } from '../../workspaces'; interface FileStream extends Readable { hapi: { @@ -60,7 +61,7 @@ export const registerImportRoute = (router: IRouter, config: SavedObjectConfig) { overwrite: schema.boolean({ defaultValue: false }), createNewCopies: schema.boolean({ defaultValue: false }), - workspace: schema.maybe(schema.string()), + workspaces: workspacesValidator, }, { validate: (object) => { @@ -76,7 +77,7 @@ export const registerImportRoute = (router: IRouter, config: SavedObjectConfig) }, }, router.handleLegacyErrors(async (context, req, res) => { - const { overwrite, createNewCopies, workspace } = req.query; + const { overwrite, createNewCopies } = req.query; const file = req.body.file as FileStream; const fileExtension = extname(file.hapi.filename).toLowerCase(); if (fileExtension !== '.ndjson') { @@ -92,6 +93,8 @@ export const registerImportRoute = (router: IRouter, config: SavedObjectConfig) }); } + const workspaces = formatWorkspaces(req.query.workspaces); + const result = await importSavedObjectsFromStream({ savedObjectsClient: context.core.savedObjects.client, typeRegistry: context.core.savedObjects.typeRegistry, @@ -99,7 +102,7 @@ export const registerImportRoute = (router: IRouter, config: SavedObjectConfig) objectLimit: maxImportExportSize, overwrite, createNewCopies, - workspace, + workspaces, }); return res.ok({ body: result }); diff --git a/src/core/server/saved_objects/service/lib/repository.ts b/src/core/server/saved_objects/service/lib/repository.ts index 291a42ee8636..482fca1b3546 100644 --- a/src/core/server/saved_objects/service/lib/repository.ts +++ b/src/core/server/saved_objects/service/lib/repository.ts @@ -256,7 +256,7 @@ export class SavedObjectsRepository { originId, initialNamespaces, version, - workspace, + workspaces, } = options; const namespace = normalizeNamespace(options.namespace); @@ -293,7 +293,7 @@ export class SavedObjectsRepository { } } - let savedObjectWorkspaces = workspace ? [workspace] : undefined; + let savedObjectWorkspaces = workspaces; if (id && overwrite) { try { diff --git a/src/core/server/saved_objects/types.ts b/src/core/server/saved_objects/types.ts index 92d348f10f46..33862cb149fb 100644 --- a/src/core/server/saved_objects/types.ts +++ b/src/core/server/saved_objects/types.ts @@ -120,7 +120,7 @@ export interface SavedObjectsFindOptions { export interface SavedObjectsBaseOptions { /** Specify the namespace for this operation */ namespace?: string; - workspace?: string; + workspaces?: string[]; } /** diff --git a/src/plugins/saved_objects_management/public/lib/import_file.ts b/src/plugins/saved_objects_management/public/lib/import_file.ts index 87fea8960725..e63241b0c3bf 100644 --- a/src/plugins/saved_objects_management/public/lib/import_file.ts +++ b/src/plugins/saved_objects_management/public/lib/import_file.ts @@ -40,11 +40,11 @@ interface ImportResponse { export async function importFile( http: HttpStart, file: File, - { createNewCopies, overwrite, workspace }: ImportMode + { createNewCopies, overwrite, workspaces }: ImportMode ) { const formData = new FormData(); formData.append('file', file); - const query = createNewCopies ? { createNewCopies, workspace } : { overwrite, workspace }; + const query = createNewCopies ? { createNewCopies, workspaces } : { overwrite, workspaces }; return await http.post('/api/saved_objects/_import', { body: formData, headers: { diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx index 179a1b4a3e73..2479772550d5 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/flyout.tsx @@ -92,7 +92,7 @@ export interface FlyoutProps { overlays: OverlayStart; http: HttpStart; search: DataPublicPluginStart['search']; - workspace?: string; + workspaces?: string[]; } export interface FlyoutState { @@ -184,7 +184,7 @@ export class Flyout extends Component { * Does the initial import of a file, resolveImportErrors then handles errors and retries */ import = async () => { - const { http, workspace } = this.props; + const { http, workspaces } = this.props; const { file, importMode } = this.state; this.setState({ status: 'loading', error: undefined }); @@ -192,7 +192,7 @@ export class Flyout extends Component { try { const response = await importFile(http, file!, { ...importMode, - workspace, + workspaces, }); this.setState(processImportResponse(response), () => { // Resolve import errors right away if there's no index patterns to match diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/components/import_mode_control.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/components/import_mode_control.tsx index 65ba93ee66f8..9953b5353b85 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/components/import_mode_control.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/components/import_mode_control.tsx @@ -51,7 +51,7 @@ export interface ImportModeControlProps { export interface ImportMode { createNewCopies: boolean; overwrite: boolean; - workspace?: string; + workspaces?: string[]; } const createNewCopiesDisabled = { diff --git a/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.tsx b/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.tsx index 08226ff63a3c..ca0aad55a0cb 100644 --- a/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.tsx +++ b/src/plugins/saved_objects_management/public/management_section/objects_table/saved_objects_table.tsx @@ -615,7 +615,7 @@ export class SavedObjectsTable extends Component