diff --git a/src/core/server/saved_objects/import/extract_errors.test.ts b/src/core/server/saved_objects/import/extract_errors.test.ts index f97cc661c0bca..ccb4daf9960ee 100644 --- a/src/core/server/saved_objects/import/extract_errors.test.ts +++ b/src/core/server/saved_objects/import/extract_errors.test.ts @@ -21,13 +21,13 @@ import { SavedObject } from '../types'; import { extractErrors } from './extract_errors'; describe('extractErrors()', () => { - test('returns empty array when no errors exist', () => { + test('returns empty array when no errors exist', async () => { const savedObjects: SavedObject[] = []; - const result = extractErrors(savedObjects, savedObjects); + const result = await extractErrors(savedObjects, savedObjects); expect(result).toMatchInlineSnapshot(`Array []`); }); - test('extracts errors from saved objects', () => { + test('extracts errors from saved objects', async () => { const savedObjects: SavedObject[] = [ { id: '1', @@ -62,7 +62,7 @@ describe('extractErrors()', () => { }, }, ]; - const result = extractErrors(savedObjects, savedObjects); + const result = await extractErrors(savedObjects, savedObjects); expect(result).toMatchInlineSnapshot(` Array [ Object { diff --git a/src/core/server/saved_objects/import/extract_errors.ts b/src/core/server/saved_objects/import/extract_errors.ts index 725e935f6e21d..3c95193ed3c1a 100644 --- a/src/core/server/saved_objects/import/extract_errors.ts +++ b/src/core/server/saved_objects/import/extract_errors.ts @@ -16,15 +16,19 @@ * specific language governing permissions and limitations * under the License. */ +import { SavedObjectsClientContract } from 'src/core/server'; import { SavedObject } from '../types'; import { SavedObjectsImportError } from './types'; -export function extractErrors( +export async function extractErrors( savedObjectResults: SavedObject[], - savedObjectsToImport: SavedObject[] + savedObjectsToImport: SavedObject[], + savedObjectsClient?: SavedObjectsClientContract, + sourceSpaceId?: string ) { const errors: SavedObjectsImportError[] = []; const originalSavedObjectsMap = new Map(); + for (const savedObject of savedObjectsToImport) { originalSavedObjectsMap.set(`${savedObject.type}:${savedObject.id}`, savedObject); } @@ -37,11 +41,31 @@ export function extractErrors( originalSavedObject && originalSavedObject.attributes && originalSavedObject.attributes.title; + if (savedObject.error.statusCode === 409) { + // find the correct title of the saved object that conflicts, in order to use it in the message box + let realTitle = title; + + if (savedObjectsClient) { + try { + if (sourceSpaceId !== undefined) { + const resp = await savedObjectsClient.get(savedObject.type, savedObject.id, { + namespace: sourceSpaceId, + }); + realTitle = resp.attributes.title; + } else { + const resp = await savedObjectsClient.get(savedObject.type, savedObject.id); + realTitle = resp.attributes.title; + } + } catch (e) { + // this shouldn't go wrong, but we re-throw the exception just in case + throw e; + } + } errors.push({ id: savedObject.id, type: savedObject.type, - title, + title: realTitle, error: { type: 'conflict', }, 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 ef3b4a214c2c2..65dc41f71cb7c 100644 --- a/src/core/server/saved_objects/import/import_saved_objects.ts +++ b/src/core/server/saved_objects/import/import_saved_objects.ts @@ -26,14 +26,17 @@ import { } from './types'; import { validateReferences } from './validate_references'; -export async function importSavedObjects({ - readStream, - objectLimit, - overwrite, - savedObjectsClient, - supportedTypes, - namespace, -}: SavedObjectsImportOptions): Promise { +export async function importSavedObjects( + { + readStream, + objectLimit, + overwrite, + savedObjectsClient, + supportedTypes, + namespace, + }: SavedObjectsImportOptions, + sourceSpaceId?: string +): Promise { let errorAccumulator: SavedObjectsImportError[] = []; // Get the objects to import @@ -65,11 +68,14 @@ export async function importSavedObjects({ overwrite, namespace, }); - errorAccumulator = [ - ...errorAccumulator, - ...extractErrors(bulkCreateResult.saved_objects, filteredObjects), - ]; + const soErrors = await extractErrors( + bulkCreateResult.saved_objects, + filteredObjects, + savedObjectsClient, + sourceSpaceId + ); + errorAccumulator = [...errorAccumulator, ...soErrors]; return { success: errorAccumulator.length === 0, successCount: bulkCreateResult.saved_objects.filter(obj => !obj.error).length, diff --git a/src/core/server/saved_objects/import/resolve_import_errors.ts b/src/core/server/saved_objects/import/resolve_import_errors.ts index 6f56f283b4aec..3d763d1c246c6 100644 --- a/src/core/server/saved_objects/import/resolve_import_errors.ts +++ b/src/core/server/saved_objects/import/resolve_import_errors.ts @@ -89,20 +89,18 @@ export async function resolveImportErrors({ overwrite: true, namespace, }); - errorAccumulator = [ - ...errorAccumulator, - ...extractErrors(bulkCreateResult.saved_objects, objectsToOverwrite), - ]; + + const extractErrs = await extractErrors(bulkCreateResult.saved_objects, objectsToOverwrite); + errorAccumulator = [...errorAccumulator, ...extractErrs]; successCount += bulkCreateResult.saved_objects.filter(obj => !obj.error).length; } if (objectsToNotOverwrite.length) { const bulkCreateResult = await savedObjectsClient.bulkCreate(objectsToNotOverwrite, { namespace, }); - errorAccumulator = [ - ...errorAccumulator, - ...extractErrors(bulkCreateResult.saved_objects, objectsToNotOverwrite), - ]; + + const extractErrs = await extractErrors(bulkCreateResult.saved_objects, objectsToNotOverwrite); + errorAccumulator = [...errorAccumulator, ...extractErrs]; successCount += bulkCreateResult.saved_objects.filter(obj => !obj.error).length; } diff --git a/src/core/server/saved_objects/service/index.ts b/src/core/server/saved_objects/service/index.ts index 386539e755d9a..e1c1997b3562f 100644 --- a/src/core/server/saved_objects/service/index.ts +++ b/src/core/server/saved_objects/service/index.ts @@ -40,7 +40,10 @@ export interface SavedObjectsService { getSavedObjectsRepository(...rest: any[]): any; importExport: { objectLimit: number; - importSavedObjects(options: SavedObjectsImportOptions): Promise; + importSavedObjects( + options: SavedObjectsImportOptions, + srcSpaceId?: string + ): Promise; resolveImportErrors( options: SavedObjectsResolveImportErrorsOptions ): Promise; diff --git a/x-pack/legacy/plugins/spaces/server/lib/copy_to_spaces/copy_to_spaces.ts b/x-pack/legacy/plugins/spaces/server/lib/copy_to_spaces/copy_to_spaces.ts index 40acf8fc32cba..600f1ac993be6 100644 --- a/x-pack/legacy/plugins/spaces/server/lib/copy_to_spaces/copy_to_spaces.ts +++ b/x-pack/legacy/plugins/spaces/server/lib/copy_to_spaces/copy_to_spaces.ts @@ -44,17 +44,21 @@ export function copySavedObjectsToSpacesFactory( const importObjectsToSpace = async ( spaceId: string, objectsStream: Readable, - options: CopyOptions + options: CopyOptions, + srcSpaceId?: string ) => { try { - const importResponse = await importExport.importSavedObjects({ - namespace: spaceIdToNamespace(spaceId), - objectLimit: importExport.objectLimit, - overwrite: options.overwrite, - savedObjectsClient, - supportedTypes: eligibleTypes, - readStream: objectsStream, - }); + const importResponse = await importExport.importSavedObjects( + { + namespace: spaceIdToNamespace(spaceId), + objectLimit: importExport.objectLimit, + overwrite: options.overwrite, + savedObjectsClient, + supportedTypes: eligibleTypes, + readStream: objectsStream, + }, + srcSpaceId + ); return { success: importResponse.success, @@ -79,7 +83,8 @@ export function copySavedObjectsToSpacesFactory( response[spaceId] = await importObjectsToSpace( spaceId, createReadableStreamFromArray(exportedSavedObjects), - options + options, + sourceSpaceId ); }