import { cloneDeep , assign , defaults , forOwn } from 'lodash' ; import { i18n } from '@kbn/i18n' ; import { IBasePath , OverlayStart , SavedObjectsClientContract , SavedObjectAttributes , } from 'kibana/public' ; import { SavedObjectSaveOpts , checkForDuplicateTitle , saveWithConfirmation , isErrorNonFatal , } from '../../../../../src/plugins/saved_objects/public' ; import { injectReferences , extractReferences , } from '../services/persistence/saved_workspace_references' ; import { SavedObjectNotFound } from '../../../../../src/plugins/kibana_utils/public' ; import { GraphWorkspaceSavedObject } from '../types' ; const savedWorkspaceType = 'graph-workspace' ; const mapping = { title : 'text' , description : 'text' , numLinks : 'integer' , numVertices : 'integer' , version : 'integer' , wsState : 'json' , } ; const defaultsProps = { title : i18n . translate ( 'xpack.graph.savedWorkspace.workspaceNameTitle' , { defaultMessage : 'New Graph Workspace' , } ) , numLinks : 0 , numVertices : 0 , wsState : '{}' , version : 1 , } ; const urlFor = ( basePath , id ) => basePath . prepend ( `/app/graph#/workspace/${ encodeURIComponent ( id ) }` ) ; function mapHits ( hit , url ) { const source = hit . attributes ; source . id = hit . id ; source . url = url ; source . icon = 'fa-share-alt' ; return source ; } interface SavedWorkspaceServices { basePath : IBasePath ; savedObjectsClient : SavedObjectsClientContract ; } export function findSavedWorkspace ( { savedObjectsClient , basePath } , searchString , size = 100 ) { return savedObjectsClient . find < Record < string , unknown > > ( { type : savedWorkspaceType , search : searchString ? `${ searchString }*` : undefined , perPage : size , searchFields : [ 'title^3' , 'description' ] , } ) . then ( ( resp ) => { return { total : resp . total , hits : resp . savedObjects . map ( ( hit ) => mapHits ( hit , urlFor ( basePath , hit . id ) ) ) , } ; } ) ; } export function getEmptyWorkspace ( ) { return { savedObject : { displayName : 'graph workspace' , getEsType : ( ) => savedWorkspaceType , ... defaultsProps , } as GraphWorkspaceSavedObject , } ; } export async function getSavedWorkspace ( savedObjectsClient , id ) { const resolveResult = await savedObjectsClient . resolve < Record < string , unknown > > ( savedWorkspaceType , id ) ; const resp = resolveResult . saved_object ; if ( ! resp . _version ) { throw new SavedObjectNotFound ( savedWorkspaceType , id || '' ) ; } const savedObject = { id , displayName : 'graph workspace' , getEsType : ( ) => savedWorkspaceType , _source : cloneDeep ( resp . attributes ) , } as GraphWorkspaceSavedObject ; defaults ( savedObject . _source , defaultsProps ) ; if ( savedObject . _source . wsState ) { savedObject . _source . wsState = JSON . parse ( savedObject . _source . wsState as string ) ; } assign ( savedObject , savedObject . _source ) ; savedObject . lastSavedTitle = savedObject . title ; if ( resp . references && resp . references . length > 0 ) { injectReferences ( savedObject , resp . references ) ; } const sharingSavedObjectProps = { outcome : resolveResult . outcome , aliasTargetId : resolveResult . alias_target_id , } ; return { savedObject , sharingSavedObjectProps , } ; } export function deleteSavedWorkspace ( savedObjectsClient , ids ) { return Promise . all ( ids . map ( ( id ) => savedObjectsClient . delete ( savedWorkspaceType , id ) ) ) ; } export async function saveSavedWorkspace ( savedObject , { confirmOverwrite = false , isTitleDuplicateConfirmed = false , onTitleDuplicate , } = { } , services ) { const originalId = savedObject . id ; if ( savedObject . copyOnSave ) { delete savedObject . id ; } let attributes = { } ; forOwn ( mapping , ( fieldType , fieldName ) => { const savedObjectFieldVal = savedObject [ fieldName as keyof GraphWorkspaceSavedObject ] as string ; if ( savedObjectFieldVal != null ) { attributes [ fieldName as keyof GraphWorkspaceSavedObject ] = fieldName === 'wsState' ? JSON . stringify ( savedObjectFieldVal ) : savedObjectFieldVal ; } } ) ; const extractedRefs = extractReferences ( { attributes , references : [ ] } ) ; const references = extractedRefs . references ; attributes = extractedRefs . attributes ; if ( ! references ) { throw new Error ( 'References not returned from extractReferences' ) ; } try { await checkForDuplicateTitle ( savedObject as any , isTitleDuplicateConfirmed , onTitleDuplicate , services ) ; savedObject . isSaving = true ; const createOpt = { id : savedObject . id , migrationVersion : savedObject . migrationVersion , references , } ; const resp = confirmOverwrite ? await saveWithConfirmation ( attributes , savedObject , createOpt , services ) : await services . savedObjectsClient . create ( savedObject . getEsType ( ) , attributes , { ... createOpt , overwrite : true , } ) ; savedObject . id = resp . id ; savedObject . isSaving = false ; savedObject . lastSavedTitle = savedObject . title ; return savedObject . id ; } catch ( err ) { savedObject . isSaving = false ; savedObject . id = originalId ; if ( isErrorNonFatal ( err ) ) { return '' ; } return Promise . reject ( err ) ; } }