diff --git a/examples/embeddable_examples/server/book/content_management/schema/schema.ts b/examples/embeddable_examples/common/book/content_management/schema/constants.ts similarity index 63% rename from examples/embeddable_examples/server/book/content_management/schema/schema.ts rename to examples/embeddable_examples/common/book/content_management/schema/constants.ts index 77f2461f8c7b8..fd8ab66fa5dde 100644 --- a/examples/embeddable_examples/server/book/content_management/schema/schema.ts +++ b/examples/embeddable_examples/common/book/content_management/schema/constants.ts @@ -7,12 +7,6 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { schema } from '@kbn/config-schema'; +export const BOOK_LATEST_VERSION = 1; -export const bookAttributesSchema = schema.object({ - bookTitle: schema.string(), - author: schema.string(), - pages: schema.number(), - synopsis: schema.maybe(schema.string()), - published: schema.nullable(schema.number()), -}); +export const BOOK_CONTENT_ID = 'book'; diff --git a/examples/embeddable_examples/common/book/content_management/schema/index.ts b/examples/embeddable_examples/common/book/content_management/schema/index.ts index f3191341faa6a..967b96b441b48 100644 --- a/examples/embeddable_examples/common/book/content_management/schema/index.ts +++ b/examples/embeddable_examples/common/book/content_management/schema/index.ts @@ -8,3 +8,5 @@ */ export { bookAttributesDefinition } from './schema'; +export { BOOK_CONTENT_ID, BOOK_LATEST_VERSION } from './constants'; +export { itemToSavedObject, savedObjectToItem } from './transforms'; diff --git a/examples/embeddable_examples/common/book/content_management/schema/schema.ts b/examples/embeddable_examples/common/book/content_management/schema/schema.ts index c6730da9f78dc..564ace712643d 100644 --- a/examples/embeddable_examples/common/book/content_management/schema/schema.ts +++ b/examples/embeddable_examples/common/book/content_management/schema/schema.ts @@ -9,38 +9,13 @@ import type { VersionableEmbeddableObject } from '@kbn/embeddable-plugin/common'; import type { SavedBookAttributes } from '../../../../server/types'; -import type { BookAttributes } from '../../../../server/book/content_management/schema'; +import type { BookAttributes } from '../../../../server/book/content_management/v1'; +import { itemToSavedObject, savedObjectToItem } from './transforms'; export const bookAttributesDefinition: VersionableEmbeddableObject< SavedBookAttributes, BookAttributes > = { - itemToSavedObject: ({ attributes, references }) => ({ - attributes: { - bookTitleAsArray: [...attributes.bookTitle], - metadata: { - numbers: { - numberOfPages: attributes.pages, - publicationYear: attributes.published ?? undefined, - }, - text: { - authorName: attributes.author, - bookSynopsis: attributes.synopsis, - }, - }, - // Generate a string of random letters and numbers to demonstrate simplifying a savedObject - uselessGarbage: Array.from(Array(10), () => Math.random().toString(36).substring(2)).join(''), - }, - references, - }), - savedObjectToItem: ({ attributes, references }) => ({ - attributes: { - bookTitle: attributes.bookTitleAsArray.join(''), - author: attributes.metadata.text.authorName, - pages: attributes.metadata.numbers.numberOfPages, - synopsis: attributes.metadata.text.bookSynopsis, - published: attributes.metadata.numbers.publicationYear ?? null, - }, - references, - }), + itemToSavedObject, + savedObjectToItem, }; diff --git a/examples/embeddable_examples/common/book/content_management/schema/transforms/index.ts b/examples/embeddable_examples/common/book/content_management/schema/transforms/index.ts new file mode 100644 index 0000000000000..d0cdd7ef7534a --- /dev/null +++ b/examples/embeddable_examples/common/book/content_management/schema/transforms/index.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +export { itemToSavedObject } from './item_to_saved_object'; +export { savedObjectToItem } from './saved_object_to_item'; diff --git a/examples/embeddable_examples/common/book/content_management/schema/transforms/item_to_saved_object.ts b/examples/embeddable_examples/common/book/content_management/schema/transforms/item_to_saved_object.ts new file mode 100644 index 0000000000000..514e09b8f9e17 --- /dev/null +++ b/examples/embeddable_examples/common/book/content_management/schema/transforms/item_to_saved_object.ts @@ -0,0 +1,37 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import type { + ItemAttributesWithReferences, + SavedObjectAttributesWithReferences, +} from '@kbn/embeddable-plugin/common/types'; +import type { BookAttributes } from '../../../../../server/book/content_management/latest'; +import type { SavedBookAttributes } from '../../../../../server/book/saved_object'; + +export const itemToSavedObject = ({ + attributes, + references, +}: ItemAttributesWithReferences): SavedObjectAttributesWithReferences => ({ + attributes: { + bookTitleAsArray: [...attributes.bookTitle], + metadata: { + numbers: { + numberOfPages: attributes.pages, + publicationYear: attributes.published ?? undefined, + }, + text: { + authorName: attributes.author, + bookSynopsis: attributes.synopsis, + }, + }, + // Generate a string of random letters and numbers to demonstrate simplifying a savedObject + uselessGarbage: Array.from(Array(10), () => Math.random().toString(36).substring(2)).join(''), + }, + references, +}); diff --git a/examples/embeddable_examples/common/book/content_management/schema/transforms/saved_object_to_item.ts b/examples/embeddable_examples/common/book/content_management/schema/transforms/saved_object_to_item.ts new file mode 100644 index 0000000000000..175bacd97f40c --- /dev/null +++ b/examples/embeddable_examples/common/book/content_management/schema/transforms/saved_object_to_item.ts @@ -0,0 +1,29 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import type { + ItemAttributesWithReferences, + SavedObjectAttributesWithReferences, +} from '@kbn/embeddable-plugin/common/types'; +import type { SavedBookAttributes } from '../../../../../server/book/saved_object'; +import type { BookAttributes } from '../../../../../server/book/content_management/latest'; + +export const savedObjectToItem = ({ + attributes, + references, +}: SavedObjectAttributesWithReferences): ItemAttributesWithReferences => ({ + attributes: { + bookTitle: attributes.bookTitleAsArray.join(''), + author: attributes.metadata.text.authorName, + pages: attributes.metadata.numbers.numberOfPages, + synopsis: attributes.metadata.text.bookSynopsis, + published: attributes.metadata.numbers.publicationYear ?? null, + }, + references, +}); diff --git a/examples/embeddable_examples/kibana.jsonc b/examples/embeddable_examples/kibana.jsonc index 740ec762e94d5..b92634af9725d 100644 --- a/examples/embeddable_examples/kibana.jsonc +++ b/examples/embeddable_examples/kibana.jsonc @@ -8,6 +8,7 @@ "server": true, "browser": true, "requiredPlugins": [ + "contentManagement", "dataViews", "embeddable", "uiActions", diff --git a/examples/embeddable_examples/public/kibana_services.ts b/examples/embeddable_examples/public/kibana_services.ts new file mode 100644 index 0000000000000..39cb3e7368e63 --- /dev/null +++ b/examples/embeddable_examples/public/kibana_services.ts @@ -0,0 +1,36 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { BehaviorSubject } from 'rxjs'; + +import type { CoreStart } from '@kbn/core/public'; +import type { StartDeps } from './plugin'; + +export let core: CoreStart; +export let contentManagement: StartDeps['contentManagement']; + +const servicesReady$ = new BehaviorSubject(false); +export const untilPluginStartServicesReady = () => { + if (servicesReady$.value) return Promise.resolve(); + return new Promise((resolve) => { + const subscription = servicesReady$.subscribe((isInitialized) => { + if (isInitialized) { + subscription.unsubscribe(); + resolve(); + } + }); + }); +}; + +export const setKibanaServices = (kibanaCore: CoreStart, deps: StartDeps) => { + core = kibanaCore; + contentManagement = deps.contentManagement; + + servicesReady$.next(true); +}; diff --git a/examples/embeddable_examples/public/plugin.ts b/examples/embeddable_examples/public/plugin.ts index 6efa9a569212d..fa69c4fe30d3e 100644 --- a/examples/embeddable_examples/public/plugin.ts +++ b/examples/embeddable_examples/public/plugin.ts @@ -17,6 +17,10 @@ import { DeveloperExamplesSetup } from '@kbn/developer-examples-plugin/public'; import { EmbeddableSetup, EmbeddableStart } from '@kbn/embeddable-plugin/public'; import { FieldFormatsStart } from '@kbn/field-formats-plugin/public'; import { UiActionsStart } from '@kbn/ui-actions-plugin/public'; +import { + ContentManagementPublicSetup, + ContentManagementPublicStart, +} from '@kbn/content-management-plugin/public'; import { setupApp } from './app/setup_app'; import { DATA_TABLE_ID } from './react_embeddables/data_table/constants'; import { registerCreateDataTableAction } from './react_embeddables/data_table/create_data_table_action'; @@ -31,14 +35,18 @@ import { registerAddSearchPanelAction } from './react_embeddables/search/registe import { registerSearchEmbeddable } from './react_embeddables/search/register_search_embeddable'; import { bookCmDefinitions } from '../common/book/content_management/cm_services'; import { fieldListCmDefinitions } from '../common/field_list/content_management/cm_services'; +import { BOOK_CONTENT_ID, BOOK_LATEST_VERSION } from '../common/book/content_management/schema'; +import { setKibanaServices } from './kibana_services'; export interface SetupDeps { + contentManagement: ContentManagementPublicSetup; developerExamples: DeveloperExamplesSetup; embeddable: EmbeddableSetup; uiActions: UiActionsStart; } export interface StartDeps { + contentManagement: ContentManagementPublicStart; dataViews: DataViewsPublicPluginStart; dataViewFieldEditor: DataViewFieldEditorStart; embeddable: EmbeddableStart; @@ -50,7 +58,10 @@ export interface StartDeps { } export class EmbeddableExamplesPlugin implements Plugin { - public setup(core: CoreSetup, { embeddable, developerExamples }: SetupDeps) { + public setup( + core: CoreSetup, + { contentManagement, embeddable, developerExamples }: SetupDeps + ) { setupApp(core, developerExamples); const startServicesPromise = core.getStartServices(); @@ -93,9 +104,17 @@ export class EmbeddableExamplesPlugin implements Plugin { + return { + type: BOOK_SAVED_OBJECT_TYPE, + searchFields: options?.onlyTitle ? ['title'] : ['title^3', 'description'], + fields: options?.fields, + search: query.text, + perPage: query.limit, + page: query.cursor ? +query.cursor : undefined, + defaultSearchOperator: 'AND', + namespaces: options?.spaces, + ...tagsToFindOptions(query.tags), + }; +}; + +const savedObjectClientFromRequest = async (ctx: StorageContext) => { + if (!ctx.requestHandlerContext) { + throw new Error('Storage context.requestHandlerContext missing.'); + } + + const { savedObjects } = await ctx.requestHandlerContext.core; + return savedObjects.client; +}; + +export class SavedBookStorage implements ContentStorage { + constructor({ logger }: { logger: Logger }) { + this.logger = logger; + } + + private readonly logger: Logger; + + async get(ctx: StorageContext, id: string) { + const transforms = ctx.utils.getTransforms(cmServicesDefinition); + const soClient = await savedObjectClientFromRequest(ctx); + + const { saved_object: savedObject } = await soClient.resolve( + BOOK_SAVED_OBJECT_TYPE, + id + ); + + let item; + + try { + item = savedObjectToItem(savedObject); + } catch (error) { + this.logger.error(`Error transforming saved book attributes: ${error.message}`); + throw Boom.badRequest(`Invalid response. ${error.message}`); + } + + const response = item; + + const { value, error: resultError } = transforms.get.out.result.down(response, undefined, { + validate: false, + }); + + if (resultError) { + this.logger.error(`Error transforming saved book attributes: ${resultError.message}`); + throw Boom.badRequest(`Invalid response. ${resultError.message}`); + } + return value; + } + + async bulkGet(): Promise { + // Not implemented + throw new Error(`[bulkGet] has not been implemented. See DashboardStorage class.`); + } + + async create(ctx: StorageContext, data: BookAttributes, options?: object | undefined) { + const transforms = ctx.utils.getTransforms(cmServicesDefinition); + const soClient = await savedObjectClientFromRequest(ctx); + + // Validate input (data & options) & UP transform them to the latest version + const { value: dataToLatest, error: dataError } = transforms.create.in.data.up< + BookAttributes, + BookAttributes + >(data); + if (dataError) { + throw Boom.badRequest(`Invalid data. ${dataError.message}`); + } + + let soAttributes: SavedBookAttributes; + let soReferences: SavedObjectReference[]; + try { + ({ attributes: soAttributes, references: soReferences } = itemToSavedObject({ + attributes: dataToLatest, + references: [], + })); + } catch (error) { + throw Boom.badRequest(`Invalid data. ${error.message}`); + } + + const savedObject = await soClient.create( + BOOK_SAVED_OBJECT_TYPE, + soAttributes, + { + ...options, + references: soReferences, + } + ); + + let item: ItemAttributesWithReferences; + + try { + item = savedObjectToItem(savedObject); + } catch (error) { + throw Boom.badRequest(`Invalid response. ${error.message}`); + } + + // Validate DB response and DOWN transform to the request version + const { value, error: resultError } = transforms.create.out.result.down( + { item }, + undefined, // do not override version + { validate: false } // validation is done above + ); + + if (resultError) { + throw Boom.badRequest(`Invalid response. ${resultError.message}`); + } + + return value; + } + + async update( + ctx: StorageContext, + id: string, + data: BookAttributes, + options?: object | undefined + ) { + const transforms = ctx.utils.getTransforms(cmServicesDefinition); + const soClient = await savedObjectClientFromRequest(ctx); + + // Validate input (data & options) & UP transform them to the latest version + const { value: dataToLatest, error: dataError } = transforms.update.in.data.up< + BookAttributes, + BookAttributes + >(data); + if (dataError) { + throw Boom.badRequest(`Invalid data. ${dataError.message}`); + } + + let soAttributes: SavedBookAttributes; + let soReferences: SavedObjectReference[]; + + try { + ({ attributes: soAttributes, references: soReferences } = itemToSavedObject({ + attributes: dataToLatest, + references: [], + })); + } catch (error) { + throw Boom.badRequest(`Invalid data. ${error.message}`); + } + + const savedObject = await soClient.update( + BOOK_SAVED_OBJECT_TYPE, + id, + soAttributes, + { + ...options, + references: soReferences, + } + ); + + let item: ItemAttributesWithReferences; + + try { + // TODO fix partial types + item = savedObjectToItem( + savedObject as SavedObjectAttributesWithReferences + ); + } catch (error) { + throw Boom.badRequest(`Invalid response. ${error.message}`); + } + + // Validate DB response and DOWN transform to the request version + const { value, error: resultError } = transforms.create.out.result.down( + { item }, + undefined, // do not override version + { validate: false } // validation is done above + ); + + if (resultError) { + throw Boom.badRequest(`Invalid response. ${resultError.message}`); + } + + return value; + } + + async delete(ctx: StorageContext, id: string, options?: object | undefined) { + const soClient = await savedObjectClientFromRequest(ctx); + await soClient.delete(BOOK_SAVED_OBJECT_TYPE, id, options); + return { success: true }; + } + + async search(ctx: StorageContext, query: object, options?: object | undefined) { + const transforms = ctx.utils.getTransforms(cmServicesDefinition); + const soClient = await savedObjectClientFromRequest(ctx); + + const soQuery = searchArgsToSOFindOptions(query, options); + + const soResponse = await soClient.find(soQuery); + const hits = await Promise.all( + soResponse.saved_objects + .map(async (so) => { + const item = savedObjectToItem(so); + return item; + }) + // Ignore any saved objects that failed to convert to items. + .filter((item) => item !== null) + ); + const response = { + hits, + pagination: { + total: soResponse.total, + }, + }; + + // Validate the response and DOWN transform to the request version + const { value, error: resultError } = transforms.search.out.result.down( + response, + undefined, // do not override version + { validate: false } // validation is done above + ); + + if (resultError) { + throw Boom.badRequest(`Invalid response. ${resultError.message}`); + } + + return value; + } +} diff --git a/examples/embeddable_examples/server/book/content_management/v1/index.ts b/examples/embeddable_examples/server/book/content_management/v1/index.ts new file mode 100644 index 0000000000000..ca3f63f691920 --- /dev/null +++ b/examples/embeddable_examples/server/book/content_management/v1/index.ts @@ -0,0 +1,11 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +export type { BookAttributes, BookSearchOptions } from './types'; +export { bookAttributesSchema, serviceDefinition } from './v1'; diff --git a/examples/embeddable_examples/server/book/content_management/schema/types.ts b/examples/embeddable_examples/server/book/content_management/v1/types.ts similarity index 80% rename from examples/embeddable_examples/server/book/content_management/schema/types.ts rename to examples/embeddable_examples/server/book/content_management/v1/types.ts index 38be5b3884fa7..127958a2b11ce 100644 --- a/examples/embeddable_examples/server/book/content_management/schema/types.ts +++ b/examples/embeddable_examples/server/book/content_management/v1/types.ts @@ -8,6 +8,7 @@ */ import { TypeOf } from '@kbn/config-schema'; -import { bookAttributesSchema } from './schema'; +import { bookAttributesSchema, bookSearchOptionsSchema } from './v1'; export type BookAttributes = TypeOf; +export type BookSearchOptions = TypeOf; diff --git a/examples/embeddable_examples/server/book/content_management/v1/v1.ts b/examples/embeddable_examples/server/book/content_management/v1/v1.ts new file mode 100644 index 0000000000000..7b6a07f995939 --- /dev/null +++ b/examples/embeddable_examples/server/book/content_management/v1/v1.ts @@ -0,0 +1,121 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { schema } from '@kbn/config-schema'; +import { createOptionsSchemas, updateOptionsSchema } from '@kbn/content-management-utils'; +import type { ContentManagementServicesDefinition as ServicesDefinition } from '@kbn/object-versioning'; + +export const referenceSchema = schema.object( + { + name: schema.string(), + type: schema.string(), + id: schema.string(), + }, + { unknowns: 'forbid' } +); + +export const bookAttributesSchema = schema.object({ + bookTitle: schema.string(), + author: schema.string(), + pages: schema.number(), + synopsis: schema.maybe(schema.string()), + published: schema.nullable(schema.number()), +}); + +export const bookSearchOptionsSchema = schema.maybe( + schema.object( + { + onlyTitle: schema.maybe(schema.boolean()), + fields: schema.maybe(schema.arrayOf(schema.string())), + includeReferences: schema.maybe(schema.arrayOf(schema.oneOf([schema.literal('tag')]))), + kuery: schema.maybe(schema.string()), + cursor: schema.maybe(schema.number()), + limit: schema.maybe(schema.number()), + spaces: schema.maybe( + schema.arrayOf(schema.string(), { + meta: { + description: + 'An array of spaces to search or "*" to search all spaces. Defaults to the current space if not specified.', + }, + }) + ), + }, + { unknowns: 'forbid' } + ) +); + +export const bookResponseSchema = schema.object({ + data: bookAttributesSchema, + meta: schema.object({ + type: schema.string(), + version: schema.maybe(schema.string()), + createdAt: schema.maybe(schema.string()), + updatedAt: schema.maybe(schema.string()), + createdBy: schema.maybe(schema.string()), + updatedBy: schema.maybe(schema.string()), + managed: schema.maybe(schema.boolean()), + references: schema.arrayOf(referenceSchema), + namespaces: schema.maybe(schema.arrayOf(schema.string())), + originId: schema.maybe(schema.string()), + }), +}); + +export const bookCreateOptionsSchema = schema.object({ + id: schema.maybe(createOptionsSchemas.id), + overwrite: schema.maybe(createOptionsSchemas.overwrite), + references: schema.maybe(schema.arrayOf(referenceSchema)), + initialNamespaces: schema.maybe(createOptionsSchemas.initialNamespaces), +}); + +export const bookUpdateOptionsSchema = schema.object({ + references: schema.maybe(schema.arrayOf(referenceSchema)), + mergeAttributes: schema.maybe(updateOptionsSchema.mergeAttributes), +}); + +export const serviceDefinition: ServicesDefinition = { + get: { + out: { + result: { + schema: bookResponseSchema, + }, + }, + }, + create: { + in: { + options: { + schema: bookCreateOptionsSchema, + }, + data: { + schema: bookAttributesSchema, + }, + }, + out: { + result: { + schema: bookResponseSchema, + }, + }, + }, + update: { + in: { + options: { + schema: bookUpdateOptionsSchema, + }, + data: { + schema: bookAttributesSchema, + }, + }, + }, + search: { + in: { + options: { + schema: bookSearchOptionsSchema, + }, + }, + }, +}; diff --git a/examples/embeddable_examples/server/book/saved_object/book_saved_object.ts b/examples/embeddable_examples/server/book/saved_object/book_saved_object.ts new file mode 100644 index 0000000000000..6ffd171ff1fc6 --- /dev/null +++ b/examples/embeddable_examples/server/book/saved_object/book_saved_object.ts @@ -0,0 +1,52 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the "Elastic License + * 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side + * Public License v 1"; you may not use this file except in compliance with, at + * your election, the "Elastic License 2.0", the "GNU Affero General Public + * License v3.0 only", or the "Server Side Public License, v 1". + */ + +import { SavedObjectsType } from '@kbn/core/server'; + +import { savedBookAttributesSchema } from './schema'; + +export const BOOK_SAVED_OBJECT_TYPE = 'devExample_book'; + +export const createBookSavedObjectType = (): SavedObjectsType => ({ + name: BOOK_SAVED_OBJECT_TYPE, + getTitle: (obj) => obj.attributes.title, + hidden: false, + namespaceType: 'multiple-isolated', + modelVersions: { + 1: { + changes: [], + schemas: { + forwardCompatibility: savedBookAttributesSchema.extends({}, { unknowns: 'ignore' }), + create: savedBookAttributesSchema, + }, + }, + }, + mappings: { + properties: { + bookTitleAsArray: { type: 'text', index: false }, + metadata: { + properties: { + text: { + properties: { + authorName: { type: 'text', index: false }, + bookSynopsis: { type: 'text', index: false }, + }, + }, + numbers: { + properties: { + numberOfPages: { type: 'integer' }, + publicationYear: { type: 'integer' }, + }, + }, + }, + }, + uselessGarbage: { type: 'text', index: false }, + }, + }, +}); diff --git a/examples/embeddable_examples/server/book/saved_object/schema/index.ts b/examples/embeddable_examples/server/book/saved_object/index.ts similarity index 86% rename from examples/embeddable_examples/server/book/saved_object/schema/index.ts rename to examples/embeddable_examples/server/book/saved_object/index.ts index 74a3aa1560b26..599a283a8a97a 100644 --- a/examples/embeddable_examples/server/book/saved_object/schema/index.ts +++ b/examples/embeddable_examples/server/book/saved_object/index.ts @@ -9,3 +9,4 @@ export type { SavedBookAttributes } from './types'; export { savedBookAttributesSchema } from './schema'; +export { BOOK_SAVED_OBJECT_TYPE, createBookSavedObjectType } from './book_saved_object'; diff --git a/examples/embeddable_examples/server/book/saved_object/schema/schema.ts b/examples/embeddable_examples/server/book/saved_object/schema.ts similarity index 100% rename from examples/embeddable_examples/server/book/saved_object/schema/schema.ts rename to examples/embeddable_examples/server/book/saved_object/schema.ts diff --git a/examples/embeddable_examples/server/book/saved_object/schema/types.ts b/examples/embeddable_examples/server/book/saved_object/types.ts similarity index 100% rename from examples/embeddable_examples/server/book/saved_object/schema/types.ts rename to examples/embeddable_examples/server/book/saved_object/types.ts diff --git a/examples/embeddable_examples/server/plugin.ts b/examples/embeddable_examples/server/plugin.ts index 65e328dab4dca..97bd34c674382 100644 --- a/examples/embeddable_examples/server/plugin.ts +++ b/examples/embeddable_examples/server/plugin.ts @@ -7,16 +7,23 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ -import { CoreSetup, CoreStart, Plugin, PluginInitializerContext } from '@kbn/core/server'; +import { CoreSetup, CoreStart, Logger, Plugin, PluginInitializerContext } from '@kbn/core/server'; import type { EmbeddableContentManagementDefinition } from '@kbn/embeddable-plugin/common'; import type { SetupDeps, StartDeps } from './types'; import { bookCmDefinitions } from '../common/book/content_management/cm_services'; -import { bookAttributesSchema } from './book/content_management/schema'; +import { bookAttributesSchema } from './book/content_management/v1'; +import { SavedBookAttributes, createBookSavedObjectType } from './book/saved_object'; +import { SavedBookStorage } from './book/content_management'; +import { BOOK_CONTENT_ID, BOOK_LATEST_VERSION } from '../common/book/content_management/schema'; export class EmbeddableExamplesPlugin implements Plugin { - constructor(initializerContext: PluginInitializerContext) {} + private readonly logger: Logger; - public setup(core: CoreSetup, { embeddable }: SetupDeps) { + constructor(initializerContext: PluginInitializerContext) { + this.logger = initializerContext.logger.get(); + } + + public setup(core: CoreSetup, { contentManagement, embeddable }: SetupDeps) { const bookCmDefinitionsWithSchemas: EmbeddableContentManagementDefinition = { id: 'book', versions: { @@ -25,6 +32,18 @@ export class EmbeddableExamplesPlugin implements Plugin(createBookSavedObjectType()); + + contentManagement.register({ + id: BOOK_CONTENT_ID, + storage: new SavedBookStorage({ + logger: this.logger.get('storage'), + }), + version: { + latest: BOOK_LATEST_VERSION, + }, + }); + embeddable.registerEmbeddableContentManagementDefinition(bookCmDefinitionsWithSchemas); return {}; diff --git a/examples/embeddable_examples/server/types.ts b/examples/embeddable_examples/server/types.ts index 10bf78eafa259..d75cb69ece71c 100644 --- a/examples/embeddable_examples/server/types.ts +++ b/examples/embeddable_examples/server/types.ts @@ -7,13 +7,15 @@ * License v3.0 only", or the "Server Side Public License, v 1". */ +import type { ContentManagementServerSetup } from '@kbn/content-management-plugin/server'; import type { EmbeddableSetup, EmbeddableStart } from '@kbn/embeddable-plugin/server'; -export type { SavedBookAttributes } from './book/saved_object/schema'; +export type { SavedBookAttributes } from './book/saved_object'; export type { SavedFieldListAttributes } from './field_list/saved_object/schema'; export interface SetupDeps { + contentManagement: ContentManagementServerSetup; embeddable: EmbeddableSetup; }