From 7f8683464c7925023e89cfc8a79179d384ca5abc Mon Sep 17 00:00:00 2001 From: Nick Partridge Date: Tue, 10 Jun 2025 14:46:25 -0500 Subject: [PATCH 01/14] feat: add internal lens api routes --- .../dashboard/server/api/register_routes.ts | 20 ++-- .../common/content_management/v1/types.ts | 10 +- .../shared/lens/server/api/constants.ts | 11 ++ .../shared/lens/server/api/routes/index.ts | 13 ++ .../api/routes/visualizations/create.ts | 95 +++++++++++++++ .../api/routes/visualizations/delete.ts | 80 +++++++++++++ .../server/api/routes/visualizations/get.ts | 90 ++++++++++++++ .../server/api/routes/visualizations/index.ts | 23 ++++ .../api/routes/visualizations/search.ts | 113 ++++++++++++++++++ .../api/routes/visualizations/update.ts | 96 +++++++++++++++ .../plugins/shared/lens/server/api/types.ts | 21 ++++ .../server/content_management/lens_storage.ts | 3 + .../content_management/v1/cm_services.ts | 66 ++++++---- .../server/content_management/v1/index.ts | 8 ++ .../plugins/shared/lens/server/plugin.tsx | 15 ++- 15 files changed, 618 insertions(+), 46 deletions(-) create mode 100644 x-pack/platform/plugins/shared/lens/server/api/constants.ts create mode 100644 x-pack/platform/plugins/shared/lens/server/api/routes/index.ts create mode 100644 x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/create.ts create mode 100644 x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/delete.ts create mode 100644 x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/get.ts create mode 100644 x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/index.ts create mode 100644 x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/search.ts create mode 100644 x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/update.ts create mode 100644 x-pack/platform/plugins/shared/lens/server/api/types.ts create mode 100644 x-pack/platform/plugins/shared/lens/server/content_management/v1/index.ts diff --git a/src/platform/plugins/shared/dashboard/server/api/register_routes.ts b/src/platform/plugins/shared/dashboard/server/api/register_routes.ts index ea22de76f9525..dabf4e153f3f0 100644 --- a/src/platform/plugins/shared/dashboard/server/api/register_routes.ts +++ b/src/platform/plugins/shared/dashboard/server/api/register_routes.ts @@ -222,17 +222,15 @@ export function registerAPIRoutes({ min: 1, defaultValue: 1, }), - perPage: schema.maybe( - schema.number({ - meta: { - description: - 'The number of dashboards to display on each page (max 1000). Default is "20".', - }, - defaultValue: 20, - min: 1, - max: 1000, - }) - ), + perPage: schema.number({ + meta: { + description: + 'The number of dashboards to display on each page (max 1000). Default is "20".', + }, + defaultValue: 20, + min: 1, + max: 1000, + }), }), }, response: { diff --git a/x-pack/platform/plugins/shared/lens/common/content_management/v1/types.ts b/x-pack/platform/plugins/shared/lens/common/content_management/v1/types.ts index d722936cdbfa6..57264e3a4c5ba 100644 --- a/x-pack/platform/plugins/shared/lens/common/content_management/v1/types.ts +++ b/x-pack/platform/plugins/shared/lens/common/content_management/v1/types.ts @@ -56,25 +56,21 @@ export type LensSavedObject = LensCrudTypes['Item']; export type PartialLensSavedObject = LensCrudTypes['PartialItem']; // ----------- GET -------------- - export type LensGetIn = LensCrudTypes['GetIn']; - export type LensGetOut = LensCrudTypes['GetOut']; // ----------- CREATE -------------- - export type LensCreateIn = LensCrudTypes['CreateIn']; - export type LensCreateOut = LensCrudTypes['CreateOut']; -// ----------- UPDATE -------------- +// ----------- UPDATE -------------- export type LensUpdateIn = LensCrudTypes['UpdateIn']; export type LensUpdateOut = LensCrudTypes['UpdateOut']; -// ----------- DELETE -------------- +// ----------- DELETE -------------- export type LensDeleteIn = LensCrudTypes['DeleteIn']; export type LensDeleteOut = LensCrudTypes['DeleteOut']; -// ----------- SEARCH -------------- +// ----------- SEARCH -------------- export type LensSearchIn = LensCrudTypes['SearchIn']; export type LensSearchOut = LensCrudTypes['SearchOut']; diff --git a/x-pack/platform/plugins/shared/lens/server/api/constants.ts b/x-pack/platform/plugins/shared/lens/server/api/constants.ts new file mode 100644 index 0000000000000..ef40c7044882e --- /dev/null +++ b/x-pack/platform/plugins/shared/lens/server/api/constants.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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export const PUBLIC_API_VERSION = '1'; +export const PUBLIC_API_CONTENT_MANAGEMENT_VERSION = 1; +export const PUBLIC_API_PATH = '/api/lens'; +export const PUBLIC_API_ACCESS = 'internal'; diff --git a/x-pack/platform/plugins/shared/lens/server/api/routes/index.ts b/x-pack/platform/plugins/shared/lens/server/api/routes/index.ts new file mode 100644 index 0000000000000..9515f4da9df0b --- /dev/null +++ b/x-pack/platform/plugins/shared/lens/server/api/routes/index.ts @@ -0,0 +1,13 @@ +/* + * 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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { RegisterAPIRoutesArgs } from '../types'; +import { registerLensVisualizationsAPIRoutes } from './visualizations'; + +export function registerLensAPIRoutes(args: RegisterAPIRoutesArgs) { + registerLensVisualizationsAPIRoutes(args); +} diff --git a/x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/create.ts b/x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/create.ts new file mode 100644 index 0000000000000..a727191df62ab --- /dev/null +++ b/x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/create.ts @@ -0,0 +1,95 @@ +/* + * 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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { schema } from '@kbn/config-schema'; + +import { CONTENT_ID } from '../../../../common/content_management'; +import { + PUBLIC_API_PATH, + PUBLIC_API_VERSION, + PUBLIC_API_CONTENT_MANAGEMENT_VERSION, + PUBLIC_API_ACCESS, +} from '../../constants'; +import { + lensAttributesSchema, + lensCreateOptionsSchema, + lensCreateResultSchema, +} from '../../../content_management/v1'; +import { RegisterAPIRouteFn } from '../../types'; + +export const registerLensVisualizationsCreateAPIRoute: RegisterAPIRouteFn = ( + router, + { contentManagement } +) => { + const createRoute = router.post({ + path: `${PUBLIC_API_PATH}/visualizations`, + access: PUBLIC_API_ACCESS, + enableQueryVersion: true, + summary: 'Create a Lens visualization', + options: { + tags: ['oas-tag:Lens'], + availability: { + stability: 'experimental', + }, + }, + security: { + authz: { + enabled: false, + reason: 'Relies on Content Client for authorization', + }, + }, + }); + + createRoute.addVersion( + { + version: PUBLIC_API_VERSION, + validate: { + request: { + params: schema.object({ + // should we allow custom ids? + id: schema.maybe( + schema.string({ + meta: { + description: 'The saved object ID of the Lens visualization.', + }, + }) + ), + }), + body: schema.object({ + options: lensCreateOptionsSchema, + data: lensAttributesSchema, + }), + }, + response: { + 200: { + body: () => lensCreateResultSchema, + }, + }, + }, + }, + async (ctx, req, res) => { + const { data, options } = req.body; + const client = contentManagement.contentClient + .getForRequest({ request: req, requestHandlerContext: ctx }) + .for(CONTENT_ID, PUBLIC_API_CONTENT_MANAGEMENT_VERSION); + let result; + try { + ({ result } = await client.create(data, options)); + } catch (e) { + // TODO prevent duplicate titles? + + if (e.isBoom && e.output.statusCode === 403) { + return res.forbidden(); + } + + return res.badRequest(); + } + + return res.ok({ body: result }); + } + ); +}; diff --git a/x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/delete.ts b/x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/delete.ts new file mode 100644 index 0000000000000..401cdc850d423 --- /dev/null +++ b/x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/delete.ts @@ -0,0 +1,80 @@ +/* + * 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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { schema } from '@kbn/config-schema'; + +import { CONTENT_ID } from '../../../../common/content_management'; +import { + PUBLIC_API_PATH, + PUBLIC_API_VERSION, + PUBLIC_API_CONTENT_MANAGEMENT_VERSION, + PUBLIC_API_ACCESS, +} from '../../constants'; +import { RegisterAPIRouteFn } from '../../types'; + +export const registerLensVisualizationsDeleteAPIRoute: RegisterAPIRouteFn = ( + router, + { contentManagement } +) => { + const deleteRoute = router.delete({ + path: `${PUBLIC_API_PATH}/visualizations/{id}`, + access: PUBLIC_API_ACCESS, + enableQueryVersion: true, + summary: `Delete a Lens visualization`, + options: { + tags: ['oas-tag:Lens'], + availability: { + stability: 'experimental', + }, + }, + security: { + authz: { + enabled: false, + reason: 'Relies on Content Client for authorization', + }, + }, + }); + + deleteRoute.addVersion( + { + version: PUBLIC_API_VERSION, + validate: { + request: { + params: schema.object({ + id: schema.string({ + meta: { + description: 'The saved object ID of the Lens visualization.', + }, + }), + }), + }, + }, + }, + async (ctx, req, res) => { + const client = contentManagement.contentClient + .getForRequest({ request: req, requestHandlerContext: ctx }) + .for(CONTENT_ID, PUBLIC_API_CONTENT_MANAGEMENT_VERSION); + try { + await client.delete(req.params.id); + } catch (e) { + if (e.isBoom && e.output.statusCode === 404) { + return res.notFound({ + body: { + message: `A Lens visualization with saved object ID ${req.params.id} was not found.`, + }, + }); + } + if (e.isBoom && e.output.statusCode === 403) { + return res.forbidden(); + } + return res.badRequest(); + } + + return res.ok(); + } + ); +}; diff --git a/x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/get.ts b/x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/get.ts new file mode 100644 index 0000000000000..e97f4fd1b40f1 --- /dev/null +++ b/x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/get.ts @@ -0,0 +1,90 @@ +/* + * 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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { schema } from '@kbn/config-schema'; + +import { CONTENT_ID } from '../../../../common/content_management'; +import { + PUBLIC_API_PATH, + PUBLIC_API_VERSION, + PUBLIC_API_CONTENT_MANAGEMENT_VERSION, + PUBLIC_API_ACCESS, +} from '../../constants'; +import { lensGetResultSchema } from '../../../content_management/v1'; +import { RegisterAPIRouteFn } from '../../types'; + +export const registerLensVisualizationsGetAPIRoute: RegisterAPIRouteFn = ( + router, + { contentManagement } +) => { + const getRoute = router.get({ + path: `${PUBLIC_API_PATH}/visualizations/{id}`, + access: PUBLIC_API_ACCESS, + enableQueryVersion: true, + summary: `Get a Lens visualization`, + options: { + tags: ['oas-tag:Lens'], + availability: { + stability: 'experimental', + }, + }, + security: { + authz: { + enabled: false, + reason: 'Relies on Content Client for authorization', + }, + }, + }); + + getRoute.addVersion( + { + version: PUBLIC_API_VERSION, + validate: { + request: { + params: schema.object({ + id: schema.string({ + meta: { + description: 'The saved object ID of the Lens visualization.', + }, + }), + }), + }, + response: { + 200: { + body: () => lensGetResultSchema, + }, + }, + }, + }, + async (ctx, req, res) => { + let result; + const client = contentManagement.contentClient + .getForRequest({ request: req, requestHandlerContext: ctx }) + .for(CONTENT_ID, PUBLIC_API_CONTENT_MANAGEMENT_VERSION); + + try { + ({ result } = await client.get(req.params.id)); + } catch (e) { + if (e.isBoom && e.output.statusCode === 404) { + return res.notFound({ + body: { + message: `A Lens visualization with saved object ID ${req.params.id}] was not found.`, + }, + }); + } + + if (e.isBoom && e.output.statusCode === 403) { + return res.forbidden(); + } + + return res.badRequest(e.message); + } + + return res.ok({ body: result }); + } + ); +}; diff --git a/x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/index.ts b/x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/index.ts new file mode 100644 index 0000000000000..dd820226e4073 --- /dev/null +++ b/x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/index.ts @@ -0,0 +1,23 @@ +/* + * 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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { RegisterAPIRoutesArgs } from '../../types'; +import { registerLensVisualizationsCreateAPIRoute } from './create'; +import { registerLensVisualizationsGetAPIRoute } from './get'; +import { registerLensVisualizationsUpdateAPIRoute } from './update'; +import { registerLensVisualizationsDeleteAPIRoute } from './delete'; +import { registerLensVisualizationsSearchAPIRoute } from './search'; + +export function registerLensVisualizationsAPIRoutes({ http, ...rest }: RegisterAPIRoutesArgs) { + const { versioned: versionedRouter } = http.createRouter(); + + registerLensVisualizationsCreateAPIRoute(versionedRouter, rest); + registerLensVisualizationsGetAPIRoute(versionedRouter, rest); + registerLensVisualizationsUpdateAPIRoute(versionedRouter, rest); + registerLensVisualizationsDeleteAPIRoute(versionedRouter, rest); + registerLensVisualizationsSearchAPIRoute(versionedRouter, rest); +} diff --git a/x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/search.ts b/x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/search.ts new file mode 100644 index 0000000000000..e4957ae669332 --- /dev/null +++ b/x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/search.ts @@ -0,0 +1,113 @@ +/* + * 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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { schema } from '@kbn/config-schema'; + +import { CONTENT_ID } from '../../../../common/content_management'; +import { + PUBLIC_API_PATH, + PUBLIC_API_VERSION, + PUBLIC_API_CONTENT_MANAGEMENT_VERSION, + PUBLIC_API_ACCESS, +} from '../../constants'; +import { lensSearchResultSchema } from '../../../content_management/v1'; +import { RegisterAPIRouteFn } from '../../types'; + +export const registerLensVisualizationsSearchAPIRoute: RegisterAPIRouteFn = ( + router, + { contentManagement } +) => { + const searchRoute = router.get({ + path: `${PUBLIC_API_PATH}/visualizations`, + access: PUBLIC_API_ACCESS, + enableQueryVersion: true, + summary: `Get a list of Lens visualizations`, + options: { + tags: ['oas-tag:Lens'], + availability: { + stability: 'experimental', + }, + }, + security: { + authz: { + enabled: false, + reason: 'Relies on Content Client for authorization', + }, + }, + }); + + searchRoute.addVersion( + { + version: PUBLIC_API_VERSION, + validate: { + request: { + query: schema.object({ + query: schema.maybe( + schema.string({ + meta: { + description: 'The text to search for Lens visualizations', + }, + }) + ), + page: schema.number({ + meta: { + description: 'The page number to return. Default is "1".', + }, + min: 1, + defaultValue: 1, + }), + perPage: schema.number({ + meta: { + description: + 'The number of dashboards to display on each page (max 1000). Default is "20".', + }, + defaultValue: 20, + min: 1, + max: 1000, + }), + }), + }, + response: { + 200: { + body: () => lensSearchResultSchema, + }, + }, + }, + }, + async (ctx, req, res) => { + const { query, page, perPage: limit } = req.query; + const client = contentManagement.contentClient + .getForRequest({ request: req, requestHandlerContext: ctx }) + .for(CONTENT_ID, PUBLIC_API_CONTENT_MANAGEMENT_VERSION); + let result; + try { + ({ result } = await client.search( + { + text: query, + cursor: page.toString(), + limit, + }, + { + searchFields: ['title', 'description'], + } + )); + } catch (e) { + if (e.isBoom && e.output.statusCode === 403) { + return res.forbidden(); + } + + return res.badRequest(); + } + + const body = { + items: result.hits, + total: result.pagination.total, + }; + return res.ok({ body }); + } + ); +}; diff --git a/x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/update.ts b/x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/update.ts new file mode 100644 index 0000000000000..1a20636eb6fa4 --- /dev/null +++ b/x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/update.ts @@ -0,0 +1,96 @@ +/* + * 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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { schema } from '@kbn/config-schema'; + +import { CONTENT_ID } from '../../../../common/content_management'; +import { + PUBLIC_API_PATH, + PUBLIC_API_VERSION, + PUBLIC_API_CONTENT_MANAGEMENT_VERSION, + PUBLIC_API_ACCESS, +} from '../../constants'; +import { + lensAttributesSchema, + lensCreateOptionsSchema, + lensCreateResultSchema, +} from '../../../content_management/v1'; +import { RegisterAPIRouteFn } from '../../types'; + +export const registerLensVisualizationsUpdateAPIRoute: RegisterAPIRouteFn = ( + router, + { contentManagement } +) => { + const updateRoute = router.put({ + path: `${PUBLIC_API_PATH}/visualizations/{id}`, + access: PUBLIC_API_ACCESS, + enableQueryVersion: true, + summary: 'Update an existing Lens visualization', + options: { + tags: ['oas-tag:Lens'], + availability: { + stability: 'experimental', + }, + }, + security: { + authz: { + enabled: false, + reason: 'Relies on Content Client for authorization', + }, + }, + }); + + updateRoute.addVersion( + { + version: PUBLIC_API_VERSION, + validate: { + request: { + params: schema.object({ + id: schema.string({ + meta: { + description: 'The saved object ID of the Lens visualization.', + }, + }), + }), + body: schema.object({ + options: lensCreateOptionsSchema, + data: lensAttributesSchema, + }), + }, + response: { + 200: { + body: () => lensCreateResultSchema, + }, + }, + }, + }, + async (ctx, req, res) => { + const { data, options } = req.body; + let result; + const client = contentManagement.contentClient + .getForRequest({ request: req, requestHandlerContext: ctx }) + .for(CONTENT_ID, PUBLIC_API_CONTENT_MANAGEMENT_VERSION); + try { + // This does not check on the existing SO id and will instead create a new one + ({ result } = await client.update(req.params.id, data, options)); + } catch (e) { + if (e.isBoom && e.output.statusCode === 404) { + return res.notFound({ + body: { + message: `A Lens visualization with saved object ID ${req.params.id} was not found.`, + }, + }); + } + if (e.isBoom && e.output.statusCode === 403) { + return res.forbidden(); + } + return res.badRequest(e.message); + } + return res.ok({ body: result }); + } + ); +}; diff --git a/x-pack/platform/plugins/shared/lens/server/api/types.ts b/x-pack/platform/plugins/shared/lens/server/api/types.ts new file mode 100644 index 0000000000000..68ff2865183b6 --- /dev/null +++ b/x-pack/platform/plugins/shared/lens/server/api/types.ts @@ -0,0 +1,21 @@ +/* + * 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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { HttpServiceSetup, Logger, RequestHandlerContext } from '@kbn/core/server'; +import { ContentManagementServerSetup } from '@kbn/content-management-plugin/server'; +import { VersionedRouter } from '@kbn/core-http-server'; + +export interface RegisterAPIRoutesArgs { + http: HttpServiceSetup; + contentManagement: ContentManagementServerSetup; + logger: Logger; +} + +export type RegisterAPIRouteFn = ( + router: VersionedRouter, + args: Omit +) => void; diff --git a/x-pack/platform/plugins/shared/lens/server/content_management/lens_storage.ts b/x-pack/platform/plugins/shared/lens/server/content_management/lens_storage.ts index e17ea543b8bd7..41a0b0953a779 100644 --- a/x-pack/platform/plugins/shared/lens/server/content_management/lens_storage.ts +++ b/x-pack/platform/plugins/shared/lens/server/content_management/lens_storage.ts @@ -136,6 +136,9 @@ export class LensStorage extends SOContentStorage { // Save data in DB const soClient = await savedObjectClientFromRequest(ctx); + // since we use create below this is to throw if SO id not found + await soClient.get(CONTENT_ID, id); + const savedObject = await soClient.create(CONTENT_ID, dataToLatest, { id, overwrite: true, diff --git a/x-pack/platform/plugins/shared/lens/server/content_management/v1/cm_services.ts b/x-pack/platform/plugins/shared/lens/server/content_management/v1/cm_services.ts index 22e1af6272978..cecc7cfc94ba7 100644 --- a/x-pack/platform/plugins/shared/lens/server/content_management/v1/cm_services.ts +++ b/x-pack/platform/plugins/shared/lens/server/content_management/v1/cm_services.ts @@ -25,7 +25,7 @@ const referenceSchema = schema.object( const referencesSchema = schema.arrayOf(referenceSchema); -const lensAttributesSchema = schema.object( +export const lensAttributesSchema = schema.object( { title: schema.string(), description: schema.maybe(schema.nullable(schema.string())), @@ -38,7 +38,7 @@ const lensAttributesSchema = schema.object( { unknowns: 'forbid' } ); -const lensSavedObjectSchema = schema.object( +export const lensSavedObjectSchema = schema.object( { id: schema.string(), type: schema.string(), @@ -54,7 +54,7 @@ const lensSavedObjectSchema = schema.object( { unknowns: 'allow' } ); -const getResultSchema = schema.object( +export const lensGetResultSchema = schema.object( { item: lensSavedObjectSchema, meta: schema.object( @@ -78,63 +78,77 @@ const getResultSchema = schema.object( { unknowns: 'forbid' } ); -const createOptionsSchema = schema.object({ +export const lensCreateOptionsSchema = schema.object({ overwrite: schema.maybe(schema.boolean()), references: schema.maybe(referencesSchema), }); +export const lensSearchOptionsSchema = schema.maybe( + schema.object( + { + searchFields: schema.maybe(schema.arrayOf(schema.string())), + types: schema.maybe(schema.arrayOf(schema.string())), + }, + { unknowns: 'forbid' } + ) +); + +export const lensCreateResultSchema = schema.object( + { + item: lensSavedObjectSchema, + }, + { unknowns: 'forbid' } +); + +export const lensSearchResultSchema = schema.object({ + items: schema.arrayOf(lensSavedObjectSchema), + total: schema.number(), +}); + // Content management service definition. // We need it for BWC support between different versions of the content export const serviceDefinition: ServicesDefinition = { get: { out: { result: { - schema: getResultSchema, + schema: lensGetResultSchema, }, }, }, create: { in: { - options: { - schema: createOptionsSchema, - }, data: { schema: lensAttributesSchema, }, + options: { + schema: lensCreateOptionsSchema, + }, }, out: { result: { - schema: schema.object( - { - item: lensSavedObjectSchema, - }, - { unknowns: 'forbid' } - ), + schema: lensCreateResultSchema, }, }, }, update: { in: { - options: { - schema: createOptionsSchema, // same schema as "create" - }, data: { schema: lensAttributesSchema, }, + options: { + schema: lensCreateOptionsSchema, + }, + }, + out: { + result: { + schema: lensCreateResultSchema, + }, }, }, search: { in: { options: { - schema: schema.maybe( - schema.object( - { - searchFields: schema.maybe(schema.arrayOf(schema.string())), - types: schema.maybe(schema.arrayOf(schema.string())), - }, - { unknowns: 'forbid' } - ) - ), + schema: lensSearchOptionsSchema, }, }, }, diff --git a/x-pack/platform/plugins/shared/lens/server/content_management/v1/index.ts b/x-pack/platform/plugins/shared/lens/server/content_management/v1/index.ts new file mode 100644 index 0000000000000..e0be3d04393f7 --- /dev/null +++ b/x-pack/platform/plugins/shared/lens/server/content_management/v1/index.ts @@ -0,0 +1,8 @@ +/* + * 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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +export * from './cm_services'; diff --git a/x-pack/platform/plugins/shared/lens/server/plugin.tsx b/x-pack/platform/plugins/shared/lens/server/plugin.tsx index ab683555d70c2..b3c41328fc853 100644 --- a/x-pack/platform/plugins/shared/lens/server/plugin.tsx +++ b/x-pack/platform/plugins/shared/lens/server/plugin.tsx @@ -5,7 +5,7 @@ * 2.0. */ -import { Plugin, CoreSetup, CoreStart, PluginInitializerContext } from '@kbn/core/server'; +import { Plugin, CoreSetup, CoreStart, PluginInitializerContext, Logger } from '@kbn/core/server'; import { PluginStart as DataViewsServerPluginStart } from '@kbn/data-views-plugin/server'; import { PluginStart as DataPluginStart, @@ -30,6 +30,7 @@ import type { CustomVisualizationMigrations } from './migrations/types'; import { LensAppLocatorDefinition } from '../common/locator/locator'; import { CONTENT_ID, LATEST_VERSION } from '../common/content_management'; import { LensStorage } from './content_management'; +import { registerLensAPIRoutes } from './api/routes'; export interface PluginSetupContract { taskManager?: TaskManagerSetupContract; @@ -65,8 +66,11 @@ export class LensServerPlugin implements Plugin { private customVisualizationMigrations: CustomVisualizationMigrations = {}; + private readonly logger: Logger; - constructor(private initializerContext: PluginInitializerContext) {} + constructor(private initializerContext: PluginInitializerContext) { + this.logger = initializerContext.logger.get(); + } setup(core: CoreSetup, plugins: PluginSetupContract) { const getFilterMigrations = plugins.data.query.filterManager.getAllMigrations.bind( @@ -96,6 +100,13 @@ export class LensServerPlugin this.customVisualizationMigrations ); plugins.embeddable.registerEmbeddableFactory(lensEmbeddableFactory()); + + registerLensAPIRoutes({ + http: core.http, + contentManagement: plugins.contentManagement, + logger: this.logger, + }); + return { lensEmbeddableFactory, registerVisualizationMigration: ( From 9c9754db861406d9d6652bfc0ea9e6fee2a5a0cd Mon Sep 17 00:00:00 2001 From: Nick Partridge Date: Tue, 17 Jun 2025 11:30:32 -0500 Subject: [PATCH 02/14] chore: update api specs and error handling --- .../api/routes/visualizations/create.ts | 50 ++++++++------- .../api/routes/visualizations/delete.ts | 58 ++++++++++++----- .../server/api/routes/visualizations/get.ts | 57 +++++++++++------ .../api/routes/visualizations/search.ts | 45 +++++++++----- .../api/routes/visualizations/update.ts | 62 +++++++++++++------ .../content_management/v1/cm_services.ts | 9 +-- 6 files changed, 179 insertions(+), 102 deletions(-) diff --git a/x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/create.ts b/x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/create.ts index a727191df62ab..e1fc00bf06bab 100644 --- a/x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/create.ts +++ b/x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/create.ts @@ -7,7 +7,8 @@ import { schema } from '@kbn/config-schema'; -import { CONTENT_ID } from '../../../../common/content_management'; +import { boomify, isBoom } from '@hapi/boom'; +import { CONTENT_ID, type LensSavedObject } from '../../../../common/content_management'; import { PUBLIC_API_PATH, PUBLIC_API_VERSION, @@ -17,7 +18,7 @@ import { import { lensAttributesSchema, lensCreateOptionsSchema, - lensCreateResultSchema, + lensSavedObjectSchema, } from '../../../content_management/v1'; import { RegisterAPIRouteFn } from '../../types'; @@ -29,7 +30,8 @@ export const registerLensVisualizationsCreateAPIRoute: RegisterAPIRouteFn = ( path: `${PUBLIC_API_PATH}/visualizations`, access: PUBLIC_API_ACCESS, enableQueryVersion: true, - summary: 'Create a Lens visualization', + summary: 'Create Lens visualization', + description: 'Create a new Lens visualization.', options: { tags: ['oas-tag:Lens'], availability: { @@ -49,47 +51,49 @@ export const registerLensVisualizationsCreateAPIRoute: RegisterAPIRouteFn = ( version: PUBLIC_API_VERSION, validate: { request: { - params: schema.object({ - // should we allow custom ids? - id: schema.maybe( - schema.string({ - meta: { - description: 'The saved object ID of the Lens visualization.', - }, - }) - ), - }), body: schema.object({ options: lensCreateOptionsSchema, data: lensAttributesSchema, }), }, response: { - 200: { - body: () => lensCreateResultSchema, + 201: { + body: () => lensSavedObjectSchema, + description: 'Created', + }, + 400: { + description: 'Malformed request', + }, + 401: { + description: 'Unauthorized', + }, + 403: { + description: 'Forbidden', + }, + 500: { + description: 'Internal Server Error', }, }, }, }, async (ctx, req, res) => { + let result; const { data, options } = req.body; const client = contentManagement.contentClient .getForRequest({ request: req, requestHandlerContext: ctx }) - .for(CONTENT_ID, PUBLIC_API_CONTENT_MANAGEMENT_VERSION); - let result; + .for(CONTENT_ID, PUBLIC_API_CONTENT_MANAGEMENT_VERSION); + try { ({ result } = await client.create(data, options)); - } catch (e) { - // TODO prevent duplicate titles? - - if (e.isBoom && e.output.statusCode === 403) { + } catch (error) { + if (isBoom(error) && error.output.statusCode === 403) { return res.forbidden(); } - return res.badRequest(); + return boomify(error); // forward unknown error } - return res.ok({ body: result }); + return res.created({ body: result.item }); } ); }; diff --git a/x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/delete.ts b/x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/delete.ts index 401cdc850d423..b8a596fac0255 100644 --- a/x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/delete.ts +++ b/x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/delete.ts @@ -7,7 +7,8 @@ import { schema } from '@kbn/config-schema'; -import { CONTENT_ID } from '../../../../common/content_management'; +import { boomify, isBoom } from '@hapi/boom'; +import { CONTENT_ID, type LensSavedObject } from '../../../../common/content_management'; import { PUBLIC_API_PATH, PUBLIC_API_VERSION, @@ -24,7 +25,8 @@ export const registerLensVisualizationsDeleteAPIRoute: RegisterAPIRouteFn = ( path: `${PUBLIC_API_PATH}/visualizations/{id}`, access: PUBLIC_API_ACCESS, enableQueryVersion: true, - summary: `Delete a Lens visualization`, + summary: 'Delete Lens visualization', + description: 'Delete a Lens visualization by id.', options: { tags: ['oas-tag:Lens'], availability: { @@ -47,34 +49,58 @@ export const registerLensVisualizationsDeleteAPIRoute: RegisterAPIRouteFn = ( params: schema.object({ id: schema.string({ meta: { - description: 'The saved object ID of the Lens visualization.', + description: 'The saved object id of a Lens visualization.', }, }), }), }, + response: { + 204: { + description: 'No Content', + }, + 400: { + description: 'Malformed request', + }, + 401: { + description: 'Unauthorized', + }, + 403: { + description: 'Forbidden', + }, + 404: { + description: 'Resource not found', + }, + 500: { + description: 'Internal Server Error', + }, + }, }, }, async (ctx, req, res) => { const client = contentManagement.contentClient .getForRequest({ request: req, requestHandlerContext: ctx }) - .for(CONTENT_ID, PUBLIC_API_CONTENT_MANAGEMENT_VERSION); + .for(CONTENT_ID, PUBLIC_API_CONTENT_MANAGEMENT_VERSION); + try { await client.delete(req.params.id); - } catch (e) { - if (e.isBoom && e.output.statusCode === 404) { - return res.notFound({ - body: { - message: `A Lens visualization with saved object ID ${req.params.id} was not found.`, - }, - }); - } - if (e.isBoom && e.output.statusCode === 403) { - return res.forbidden(); + } catch (error) { + if (isBoom(error)) { + if (error.output.statusCode === 404) { + return res.notFound({ + body: { + message: `A Lens visualization with saved object id [${req.params.id}] was not found.`, + }, + }); + } + if (error.output.statusCode === 403) { + return res.forbidden(); + } } - return res.badRequest(); + + return boomify(error); // forward unknown error } - return res.ok(); + return res.noContent(); } ); }; diff --git a/x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/get.ts b/x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/get.ts index e97f4fd1b40f1..185a897bf398d 100644 --- a/x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/get.ts +++ b/x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/get.ts @@ -7,14 +7,15 @@ import { schema } from '@kbn/config-schema'; -import { CONTENT_ID } from '../../../../common/content_management'; +import { boomify, isBoom } from '@hapi/boom'; +import { CONTENT_ID, type LensSavedObject } from '../../../../common/content_management'; import { PUBLIC_API_PATH, PUBLIC_API_VERSION, PUBLIC_API_CONTENT_MANAGEMENT_VERSION, PUBLIC_API_ACCESS, } from '../../constants'; -import { lensGetResultSchema } from '../../../content_management/v1'; +import { lensSavedObjectSchema } from '../../../content_management/v1'; import { RegisterAPIRouteFn } from '../../types'; export const registerLensVisualizationsGetAPIRoute: RegisterAPIRouteFn = ( @@ -25,7 +26,8 @@ export const registerLensVisualizationsGetAPIRoute: RegisterAPIRouteFn = ( path: `${PUBLIC_API_PATH}/visualizations/{id}`, access: PUBLIC_API_ACCESS, enableQueryVersion: true, - summary: `Get a Lens visualization`, + summary: 'Get Lens visualization', + description: 'Get a Lens visualization from id.', options: { tags: ['oas-tag:Lens'], availability: { @@ -48,14 +50,30 @@ export const registerLensVisualizationsGetAPIRoute: RegisterAPIRouteFn = ( params: schema.object({ id: schema.string({ meta: { - description: 'The saved object ID of the Lens visualization.', + description: 'The saved object id of a Lens visualization.', }, }), }), }, response: { 200: { - body: () => lensGetResultSchema, + body: () => lensSavedObjectSchema, + description: 'Ok', + }, + 400: { + description: 'Malformed request', + }, + 401: { + description: 'Unauthorized', + }, + 403: { + description: 'Forbidden', + }, + 404: { + description: 'Resource not found', + }, + 500: { + description: 'Internal Server Error', }, }, }, @@ -64,27 +82,28 @@ export const registerLensVisualizationsGetAPIRoute: RegisterAPIRouteFn = ( let result; const client = contentManagement.contentClient .getForRequest({ request: req, requestHandlerContext: ctx }) - .for(CONTENT_ID, PUBLIC_API_CONTENT_MANAGEMENT_VERSION); + .for(CONTENT_ID, PUBLIC_API_CONTENT_MANAGEMENT_VERSION); try { ({ result } = await client.get(req.params.id)); - } catch (e) { - if (e.isBoom && e.output.statusCode === 404) { - return res.notFound({ - body: { - message: `A Lens visualization with saved object ID ${req.params.id}] was not found.`, - }, - }); - } - - if (e.isBoom && e.output.statusCode === 403) { - return res.forbidden(); + } catch (error) { + if (isBoom(error)) { + if (error.output.statusCode === 404) { + return res.notFound({ + body: { + message: `A Lens visualization with saved object id [${req.params.id}] was not found.`, + }, + }); + } + if (error.output.statusCode === 403) { + return res.forbidden(); + } } - return res.badRequest(e.message); + return boomify(error); // forward unknown error } - return res.ok({ body: result }); + return res.ok({ body: result.item }); } ); }; diff --git a/x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/search.ts b/x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/search.ts index e4957ae669332..3ab47a50824c0 100644 --- a/x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/search.ts +++ b/x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/search.ts @@ -7,14 +7,15 @@ import { schema } from '@kbn/config-schema'; -import { CONTENT_ID } from '../../../../common/content_management'; +import { isBoom, boomify } from '@hapi/boom'; +import { CONTENT_ID, type LensSavedObject } from '../../../../common/content_management'; import { PUBLIC_API_PATH, PUBLIC_API_VERSION, PUBLIC_API_CONTENT_MANAGEMENT_VERSION, PUBLIC_API_ACCESS, } from '../../constants'; -import { lensSearchResultSchema } from '../../../content_management/v1'; +import { lensSavedObjectSchema } from '../../../content_management/v1'; import { RegisterAPIRouteFn } from '../../types'; export const registerLensVisualizationsSearchAPIRoute: RegisterAPIRouteFn = ( @@ -25,7 +26,8 @@ export const registerLensVisualizationsSearchAPIRoute: RegisterAPIRouteFn = ( path: `${PUBLIC_API_PATH}/visualizations`, access: PUBLIC_API_ACCESS, enableQueryVersion: true, - summary: `Get a list of Lens visualizations`, + summary: 'Search Lens visualizations', + description: 'Get list of Lens visualizations.', options: { tags: ['oas-tag:Lens'], availability: { @@ -55,15 +57,14 @@ export const registerLensVisualizationsSearchAPIRoute: RegisterAPIRouteFn = ( ), page: schema.number({ meta: { - description: 'The page number to return. Default is "1".', + description: 'Specifies the current page number of the paginated result.', }, min: 1, defaultValue: 1, }), perPage: schema.number({ meta: { - description: - 'The number of dashboards to display on each page (max 1000). Default is "20".', + description: 'Maximum number of Lens visualizations included in a single response', }, defaultValue: 20, min: 1, @@ -73,17 +74,31 @@ export const registerLensVisualizationsSearchAPIRoute: RegisterAPIRouteFn = ( }, response: { 200: { - body: () => lensSearchResultSchema, + body: () => schema.arrayOf(lensSavedObjectSchema), + description: 'Ok', + }, + 400: { + description: 'Malformed request', + }, + 401: { + description: 'Unauthorized', + }, + 403: { + description: 'Forbidden', + }, + 500: { + description: 'Internal Server Error', }, }, }, }, async (ctx, req, res) => { + let result; const { query, page, perPage: limit } = req.query; const client = contentManagement.contentClient .getForRequest({ request: req, requestHandlerContext: ctx }) - .for(CONTENT_ID, PUBLIC_API_CONTENT_MANAGEMENT_VERSION); - let result; + .for(CONTENT_ID, PUBLIC_API_CONTENT_MANAGEMENT_VERSION); + try { ({ result } = await client.search( { @@ -95,19 +110,15 @@ export const registerLensVisualizationsSearchAPIRoute: RegisterAPIRouteFn = ( searchFields: ['title', 'description'], } )); - } catch (e) { - if (e.isBoom && e.output.statusCode === 403) { + } catch (error) { + if (isBoom(error) && error.output.statusCode === 403) { return res.forbidden(); } - return res.badRequest(); + return boomify(error); // forward unknown error } - const body = { - items: result.hits, - total: result.pagination.total, - }; - return res.ok({ body }); + return res.ok({ body: result.hits }); } ); }; diff --git a/x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/update.ts b/x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/update.ts index 1a20636eb6fa4..1f3279a5976dd 100644 --- a/x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/update.ts +++ b/x-pack/platform/plugins/shared/lens/server/api/routes/visualizations/update.ts @@ -6,8 +6,9 @@ */ import { schema } from '@kbn/config-schema'; +import { boomify, isBoom } from '@hapi/boom'; -import { CONTENT_ID } from '../../../../common/content_management'; +import { CONTENT_ID, type LensSavedObject } from '../../../../common/content_management'; import { PUBLIC_API_PATH, PUBLIC_API_VERSION, @@ -17,7 +18,7 @@ import { import { lensAttributesSchema, lensCreateOptionsSchema, - lensCreateResultSchema, + lensSavedObjectSchema, } from '../../../content_management/v1'; import { RegisterAPIRouteFn } from '../../types'; @@ -29,7 +30,8 @@ export const registerLensVisualizationsUpdateAPIRoute: RegisterAPIRouteFn = ( path: `${PUBLIC_API_PATH}/visualizations/{id}`, access: PUBLIC_API_ACCESS, enableQueryVersion: true, - summary: 'Update an existing Lens visualization', + summary: 'Update Lens visualization', + description: 'Update an existing Lens visualization.', options: { tags: ['oas-tag:Lens'], availability: { @@ -52,7 +54,7 @@ export const registerLensVisualizationsUpdateAPIRoute: RegisterAPIRouteFn = ( params: schema.object({ id: schema.string({ meta: { - description: 'The saved object ID of the Lens visualization.', + description: 'The saved object id of a Lens visualization.', }, }), }), @@ -63,34 +65,54 @@ export const registerLensVisualizationsUpdateAPIRoute: RegisterAPIRouteFn = ( }, response: { 200: { - body: () => lensCreateResultSchema, + body: () => lensSavedObjectSchema, + description: 'Ok', + }, + 400: { + description: 'Malformed request', + }, + 401: { + description: 'Unauthorized', + }, + 403: { + description: 'Forbidden', + }, + 404: { + description: 'Resource not found', + }, + 500: { + description: 'Internal Server Error', }, }, }, }, async (ctx, req, res) => { - const { data, options } = req.body; let result; + const { data, options } = req.body; const client = contentManagement.contentClient .getForRequest({ request: req, requestHandlerContext: ctx }) - .for(CONTENT_ID, PUBLIC_API_CONTENT_MANAGEMENT_VERSION); + .for(CONTENT_ID, PUBLIC_API_CONTENT_MANAGEMENT_VERSION); + try { - // This does not check on the existing SO id and will instead create a new one ({ result } = await client.update(req.params.id, data, options)); - } catch (e) { - if (e.isBoom && e.output.statusCode === 404) { - return res.notFound({ - body: { - message: `A Lens visualization with saved object ID ${req.params.id} was not found.`, - }, - }); - } - if (e.isBoom && e.output.statusCode === 403) { - return res.forbidden(); + } catch (error) { + if (isBoom(error)) { + if (error.output.statusCode === 404) { + return res.notFound({ + body: { + message: `A Lens visualization with saved object id [${req.params.id}] was not found.`, + }, + }); + } + if (error.output.statusCode === 403) { + return res.forbidden(); + } } - return res.badRequest(e.message); + + return boomify(error); // forward unknown error } - return res.ok({ body: result }); + + return res.ok({ body: result.item }); } ); }; diff --git a/x-pack/platform/plugins/shared/lens/server/content_management/v1/cm_services.ts b/x-pack/platform/plugins/shared/lens/server/content_management/v1/cm_services.ts index cecc7cfc94ba7..afbd000805f82 100644 --- a/x-pack/platform/plugins/shared/lens/server/content_management/v1/cm_services.ts +++ b/x-pack/platform/plugins/shared/lens/server/content_management/v1/cm_services.ts @@ -54,7 +54,7 @@ export const lensSavedObjectSchema = schema.object( { unknowns: 'allow' } ); -export const lensGetResultSchema = schema.object( +const lensGetResultSchema = schema.object( { item: lensSavedObjectSchema, meta: schema.object( @@ -93,18 +93,13 @@ export const lensSearchOptionsSchema = schema.maybe( ) ); -export const lensCreateResultSchema = schema.object( +const lensCreateResultSchema = schema.object( { item: lensSavedObjectSchema, }, { unknowns: 'forbid' } ); -export const lensSearchResultSchema = schema.object({ - items: schema.arrayOf(lensSavedObjectSchema), - total: schema.number(), -}); - // Content management service definition. // We need it for BWC support between different versions of the content export const serviceDefinition: ServicesDefinition = { From 058f4b269fdd31217c053231c196057f1181954c Mon Sep 17 00:00:00 2001 From: Nick Partridge Date: Tue, 17 Jun 2025 11:32:44 -0500 Subject: [PATCH 03/14] test: add basic lens api integration tests --- .../test/api_integration/apis/index.ts | 1 + .../api_integration/apis/lens/examples.ts | 76 +++++ .../test/api_integration/apis/lens/index.ts | 20 ++ .../apis/lens/visualizations/create/index.ts | 30 ++ .../apis/lens/visualizations/create/main.ts | 31 ++ .../lens/visualizations/create/validation.ts | 31 ++ .../apis/lens/visualizations/delete/index.ts | 35 ++ .../apis/lens/visualizations/delete/main.ts | 45 +++ .../apis/lens/visualizations/get/index.ts | 35 ++ .../apis/lens/visualizations/get/main.ts | 44 +++ .../apis/lens/visualizations/search/index.ts | 36 ++ .../apis/lens/visualizations/search/main.ts | 41 +++ .../lens/visualizations/search/validation.ts | 31 ++ .../apis/lens/visualizations/update/index.ts | 36 ++ .../apis/lens/visualizations/update/main.ts | 47 +++ .../lens/visualizations/update/validation.ts | 32 ++ .../kbn_archiver/saved_objects/lens.json | 315 ++++++++++++++++++ .../plugins/shared/lens/server/index.ts | 2 + 18 files changed, 888 insertions(+) create mode 100644 src/platform/test/api_integration/apis/lens/examples.ts create mode 100644 src/platform/test/api_integration/apis/lens/index.ts create mode 100644 src/platform/test/api_integration/apis/lens/visualizations/create/index.ts create mode 100644 src/platform/test/api_integration/apis/lens/visualizations/create/main.ts create mode 100644 src/platform/test/api_integration/apis/lens/visualizations/create/validation.ts create mode 100644 src/platform/test/api_integration/apis/lens/visualizations/delete/index.ts create mode 100644 src/platform/test/api_integration/apis/lens/visualizations/delete/main.ts create mode 100644 src/platform/test/api_integration/apis/lens/visualizations/get/index.ts create mode 100644 src/platform/test/api_integration/apis/lens/visualizations/get/main.ts create mode 100644 src/platform/test/api_integration/apis/lens/visualizations/search/index.ts create mode 100644 src/platform/test/api_integration/apis/lens/visualizations/search/main.ts create mode 100644 src/platform/test/api_integration/apis/lens/visualizations/search/validation.ts create mode 100644 src/platform/test/api_integration/apis/lens/visualizations/update/index.ts create mode 100644 src/platform/test/api_integration/apis/lens/visualizations/update/main.ts create mode 100644 src/platform/test/api_integration/apis/lens/visualizations/update/validation.ts create mode 100644 src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/lens.json diff --git a/src/platform/test/api_integration/apis/index.ts b/src/platform/test/api_integration/apis/index.ts index af1cbf2464fa9..0a1633f82f6c3 100644 --- a/src/platform/test/api_integration/apis/index.ts +++ b/src/platform/test/api_integration/apis/index.ts @@ -35,5 +35,6 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./telemetry')); loadTestFile(require.resolve('./guided_onboarding')); loadTestFile(require.resolve('./esql')); + loadTestFile(require.resolve('./lens')); }); } diff --git a/src/platform/test/api_integration/apis/lens/examples.ts b/src/platform/test/api_integration/apis/lens/examples.ts new file mode 100644 index 0000000000000..1083902ca5d28 --- /dev/null +++ b/src/platform/test/api_integration/apis/lens/examples.ts @@ -0,0 +1,76 @@ +/* + * 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 const getExampleLensBody = (title = `Lens vis - ${Date.now()} - ${Math.random()}`) => ({ + data: { + title, + description: '', + visualizationType: 'lnsMetric', + state: { + visualization: { + layerId: '32e889c6-89f9-4873-b1f7-d5bea381c582', + layerType: 'data', + metricAccessor: '1c6729bc-ec92-4000-8dcc-0fdd7b56d5b8', + secondaryTrend: { + type: 'none', + }, + }, + query: { + query: '', + language: 'kuery', + }, + filters: [], + datasourceStates: { + formBased: { + layers: { + '32e889c6-89f9-4873-b1f7-d5bea381c582': { + columns: { + '1c6729bc-ec92-4000-8dcc-0fdd7b56d5b8': { + label: 'Count of records', + dataType: 'number', + operationType: 'count', + isBucketed: false, + scale: 'ratio', + sourceField: '___records___', + params: { + emptyAsNull: true, + }, + }, + }, + columnOrder: ['1c6729bc-ec92-4000-8dcc-0fdd7b56d5b8'], + incompleteColumns: { + 'd0b92889-f74c-4194-b738-76eb5d268524': { + operationType: 'date_histogram', + }, + }, + sampling: 1, + }, + }, + }, + indexpattern: { + layers: {}, + }, + textBased: { + layers: {}, + }, + }, + internalReferences: [], + adHocDataViews: {}, + }, + }, + options: { + references: [ + { + type: 'index-pattern', + id: '91200a00-9efd-11e7-acb3-3dab96693fab', + name: 'indexpattern-datasource-layer-32e889c6-89f9-4873-b1f7-d5bea381c582', + }, + ], + }, +}); diff --git a/src/platform/test/api_integration/apis/lens/index.ts b/src/platform/test/api_integration/apis/lens/index.ts new file mode 100644 index 0000000000000..4624e4b6786e7 --- /dev/null +++ b/src/platform/test/api_integration/apis/lens/index.ts @@ -0,0 +1,20 @@ +/* + * 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 { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ loadTestFile }: FtrProviderContext) { + describe('lens - nick', () => { + loadTestFile(require.resolve('./visualizations/create')); + loadTestFile(require.resolve('./visualizations/get')); + loadTestFile(require.resolve('./visualizations/update')); + loadTestFile(require.resolve('./visualizations/delete')); + loadTestFile(require.resolve('./visualizations/search')); + }); +} diff --git a/src/platform/test/api_integration/apis/lens/visualizations/create/index.ts b/src/platform/test/api_integration/apis/lens/visualizations/create/index.ts new file mode 100644 index 0000000000000..3190b9f7e0391 --- /dev/null +++ b/src/platform/test/api_integration/apis/lens/visualizations/create/index.ts @@ -0,0 +1,30 @@ +/* + * 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 { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ getService, loadTestFile }: FtrProviderContext) { + const kibanaServer = getService('kibanaServer'); + describe('visualizations - create', () => { + before(async () => { + await kibanaServer.importExport.load( + 'src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/basic.json' + ); + }); + + after(async () => { + await kibanaServer.savedObjects.cleanStandardList(); + await kibanaServer.importExport.unload( + 'src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/basic.json' + ); + }); + loadTestFile(require.resolve('./main')); + loadTestFile(require.resolve('./validation')); + }); +} diff --git a/src/platform/test/api_integration/apis/lens/visualizations/create/main.ts b/src/platform/test/api_integration/apis/lens/visualizations/create/main.ts new file mode 100644 index 0000000000000..b85f4578ccfe3 --- /dev/null +++ b/src/platform/test/api_integration/apis/lens/visualizations/create/main.ts @@ -0,0 +1,31 @@ +/* + * 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 expect from '@kbn/expect'; +import { PUBLIC_API_PATH, PUBLIC_API_VERSION } from '@kbn/lens-plugin/server'; +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; + +import { FtrProviderContext } from '../../../../ftr_provider_context'; +import { getExampleLensBody } from '../../examples'; + +export default function ({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + + describe('main', () => { + it('should create a lens visualization', async () => { + const response = await supertest + .post(`${PUBLIC_API_PATH}/visualizations`) + .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, PUBLIC_API_VERSION) + .send(getExampleLensBody()); + + expect(response.status).to.be(201); + }); + }); +} diff --git a/src/platform/test/api_integration/apis/lens/visualizations/create/validation.ts b/src/platform/test/api_integration/apis/lens/visualizations/create/validation.ts new file mode 100644 index 0000000000000..f8a7c679da3f9 --- /dev/null +++ b/src/platform/test/api_integration/apis/lens/visualizations/create/validation.ts @@ -0,0 +1,31 @@ +/* + * 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 expect from '@kbn/expect'; +import { PUBLIC_API_PATH, PUBLIC_API_VERSION } from '@kbn/lens-plugin/server'; +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + describe('validation', () => { + it('should return error if body is empty', async () => { + const response = await supertest + .post(`${PUBLIC_API_PATH}/visualizations`) + .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, PUBLIC_API_VERSION) + .send({}); + + expect(response.status).to.be(400); + expect(response.body.message).to.be( + '[request body.data.title]: expected value of type [string] but got [undefined]' + ); + }); + }); +} diff --git a/src/platform/test/api_integration/apis/lens/visualizations/delete/index.ts b/src/platform/test/api_integration/apis/lens/visualizations/delete/index.ts new file mode 100644 index 0000000000000..0cbc46743894e --- /dev/null +++ b/src/platform/test/api_integration/apis/lens/visualizations/delete/index.ts @@ -0,0 +1,35 @@ +/* + * 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 { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ getService, loadTestFile }: FtrProviderContext) { + const kibanaServer = getService('kibanaServer'); + describe('visualizations - create', () => { + before(async () => { + await kibanaServer.importExport.load( + 'src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/basic.json' + ); + await kibanaServer.importExport.load( + 'src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/lens.json' + ); + }); + + after(async () => { + await kibanaServer.savedObjects.cleanStandardList(); + await kibanaServer.importExport.unload( + 'src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/basic.json' + ); + await kibanaServer.importExport.unload( + 'src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/lens.json' + ); + }); + loadTestFile(require.resolve('./main')); + }); +} diff --git a/src/platform/test/api_integration/apis/lens/visualizations/delete/main.ts b/src/platform/test/api_integration/apis/lens/visualizations/delete/main.ts new file mode 100644 index 0000000000000..309a3d2495a25 --- /dev/null +++ b/src/platform/test/api_integration/apis/lens/visualizations/delete/main.ts @@ -0,0 +1,45 @@ +/* + * 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 expect from '@kbn/expect'; +import { PUBLIC_API_PATH, PUBLIC_API_VERSION } from '@kbn/lens-plugin/server'; +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; + +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + + describe('main', () => { + it('should delete a lens visualization', async () => { + const id = '71c9c185-3e6d-49d0-b7e5-f966eaf51625'; // known id + const response = await supertest + .delete(`${PUBLIC_API_PATH}/visualizations/${id}`) + .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, PUBLIC_API_VERSION) + .send(); + + expect(response.status).to.be(204); + }); + + it('should error when deleting an unknown lens visualization', async () => { + const id = '123'; // unknown id + const response = await supertest + .delete(`${PUBLIC_API_PATH}/visualizations/${id}`) + .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, PUBLIC_API_VERSION) + .send(); + + expect(response.status).to.be(404); + expect(response.body.message).to.be( + 'A Lens visualization with saved object id [123] was not found.' + ); + }); + }); +} diff --git a/src/platform/test/api_integration/apis/lens/visualizations/get/index.ts b/src/platform/test/api_integration/apis/lens/visualizations/get/index.ts new file mode 100644 index 0000000000000..0cbc46743894e --- /dev/null +++ b/src/platform/test/api_integration/apis/lens/visualizations/get/index.ts @@ -0,0 +1,35 @@ +/* + * 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 { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ getService, loadTestFile }: FtrProviderContext) { + const kibanaServer = getService('kibanaServer'); + describe('visualizations - create', () => { + before(async () => { + await kibanaServer.importExport.load( + 'src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/basic.json' + ); + await kibanaServer.importExport.load( + 'src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/lens.json' + ); + }); + + after(async () => { + await kibanaServer.savedObjects.cleanStandardList(); + await kibanaServer.importExport.unload( + 'src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/basic.json' + ); + await kibanaServer.importExport.unload( + 'src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/lens.json' + ); + }); + loadTestFile(require.resolve('./main')); + }); +} diff --git a/src/platform/test/api_integration/apis/lens/visualizations/get/main.ts b/src/platform/test/api_integration/apis/lens/visualizations/get/main.ts new file mode 100644 index 0000000000000..20b85d2331966 --- /dev/null +++ b/src/platform/test/api_integration/apis/lens/visualizations/get/main.ts @@ -0,0 +1,44 @@ +/* + * 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 expect from '@kbn/expect'; +import { PUBLIC_API_PATH, PUBLIC_API_VERSION } from '@kbn/lens-plugin/server'; +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; + +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + + describe('main', () => { + it('should get a lens visualization', async () => { + const id = '71c9c185-3e6d-49d0-b7e5-f966eaf51625'; // known id + const response = await supertest + .get(`${PUBLIC_API_PATH}/visualizations/${id}`) + .set(ELASTIC_HTTP_VERSION_HEADER, PUBLIC_API_VERSION) + .send(); + + expect(response.status).to.be(200); + expect(response.body.attributes.title).to.be('Lens example - 1'); + }); + + it('should error when fetching an unknown lens visualization', async () => { + const id = '123'; // unknown id + const response = await supertest + .get(`${PUBLIC_API_PATH}/visualizations/${id}`) + .set(ELASTIC_HTTP_VERSION_HEADER, PUBLIC_API_VERSION) + .send(); + + expect(response.status).to.be(404); + expect(response.body.message).to.be( + 'A Lens visualization with saved object id [123] was not found.' + ); + }); + }); +} diff --git a/src/platform/test/api_integration/apis/lens/visualizations/search/index.ts b/src/platform/test/api_integration/apis/lens/visualizations/search/index.ts new file mode 100644 index 0000000000000..e5705ac4e065e --- /dev/null +++ b/src/platform/test/api_integration/apis/lens/visualizations/search/index.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 { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ getService, loadTestFile }: FtrProviderContext) { + const kibanaServer = getService('kibanaServer'); + describe('visualizations - update', () => { + before(async () => { + await kibanaServer.importExport.load( + 'src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/basic.json' + ); + await kibanaServer.importExport.load( + 'src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/lens.json' + ); + }); + + after(async () => { + await kibanaServer.savedObjects.cleanStandardList(); + await kibanaServer.importExport.unload( + 'src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/basic.json' + ); + await kibanaServer.importExport.unload( + 'src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/lens.json' + ); + }); + loadTestFile(require.resolve('./main')); + loadTestFile(require.resolve('./validation')); + }); +} diff --git a/src/platform/test/api_integration/apis/lens/visualizations/search/main.ts b/src/platform/test/api_integration/apis/lens/visualizations/search/main.ts new file mode 100644 index 0000000000000..ea3fca4ff54b9 --- /dev/null +++ b/src/platform/test/api_integration/apis/lens/visualizations/search/main.ts @@ -0,0 +1,41 @@ +/* + * 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 expect from '@kbn/expect'; +import { PUBLIC_API_PATH, PUBLIC_API_VERSION } from '@kbn/lens-plugin/server'; +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; + +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + + describe('main', () => { + it('should get list of lens visualizations', async () => { + const response = await supertest + .get(`${PUBLIC_API_PATH}/visualizations`) + .set(ELASTIC_HTTP_VERSION_HEADER, PUBLIC_API_VERSION) + .send(); + + expect(response.status).to.be(200); + expect(response.body.length).to.be(4); + }); + + it('should filter lens visualizations by title and description', async () => { + const response = await supertest + .get(`${PUBLIC_API_PATH}/visualizations`) + .query({ query: '1' }) + .set(ELASTIC_HTTP_VERSION_HEADER, PUBLIC_API_VERSION) + .send(); + + expect(response.status).to.be(200); + expect(response.body.length).to.be(2); + }); + }); +} diff --git a/src/platform/test/api_integration/apis/lens/visualizations/search/validation.ts b/src/platform/test/api_integration/apis/lens/visualizations/search/validation.ts new file mode 100644 index 0000000000000..eb4fce368cc65 --- /dev/null +++ b/src/platform/test/api_integration/apis/lens/visualizations/search/validation.ts @@ -0,0 +1,31 @@ +/* + * 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 expect from '@kbn/expect'; +import { PUBLIC_API_PATH, PUBLIC_API_VERSION } from '@kbn/lens-plugin/server'; +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + describe('validation', () => { + it('should return error if using unknown params', async () => { + const response = await supertest + .get(`${PUBLIC_API_PATH}/visualizations`) + .query({ xyz: 'unknown param' }) + .set(ELASTIC_HTTP_VERSION_HEADER, PUBLIC_API_VERSION) + .send({}); + + expect(response.status).to.be(400); + expect(response.body.message).to.be( + '[request query.xyz]: definition for this key is missing' + ); + }); + }); +} diff --git a/src/platform/test/api_integration/apis/lens/visualizations/update/index.ts b/src/platform/test/api_integration/apis/lens/visualizations/update/index.ts new file mode 100644 index 0000000000000..e5705ac4e065e --- /dev/null +++ b/src/platform/test/api_integration/apis/lens/visualizations/update/index.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 { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ getService, loadTestFile }: FtrProviderContext) { + const kibanaServer = getService('kibanaServer'); + describe('visualizations - update', () => { + before(async () => { + await kibanaServer.importExport.load( + 'src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/basic.json' + ); + await kibanaServer.importExport.load( + 'src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/lens.json' + ); + }); + + after(async () => { + await kibanaServer.savedObjects.cleanStandardList(); + await kibanaServer.importExport.unload( + 'src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/basic.json' + ); + await kibanaServer.importExport.unload( + 'src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/lens.json' + ); + }); + loadTestFile(require.resolve('./main')); + loadTestFile(require.resolve('./validation')); + }); +} diff --git a/src/platform/test/api_integration/apis/lens/visualizations/update/main.ts b/src/platform/test/api_integration/apis/lens/visualizations/update/main.ts new file mode 100644 index 0000000000000..4a76d92cc545a --- /dev/null +++ b/src/platform/test/api_integration/apis/lens/visualizations/update/main.ts @@ -0,0 +1,47 @@ +/* + * 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 expect from '@kbn/expect'; +import { PUBLIC_API_PATH, PUBLIC_API_VERSION } from '@kbn/lens-plugin/server'; +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; + +import { FtrProviderContext } from '../../../../ftr_provider_context'; +import { getExampleLensBody } from '../../examples'; + +export default function ({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + + describe('main', () => { + it('should update a lens visualization', async () => { + const id = '71c9c185-3e6d-49d0-b7e5-f966eaf51625'; // known id + const response = await supertest + .put(`${PUBLIC_API_PATH}/visualizations/${id}`) + .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, PUBLIC_API_VERSION) + .send(getExampleLensBody('Custom title')); + + expect(response.status).to.be(200); + expect(response.body.attributes.title).to.be('Custom title'); + }); + + it('should error when updating an unknown lens visualization', async () => { + const id = '123'; // unknown id + const response = await supertest + .put(`${PUBLIC_API_PATH}/visualizations/${id}`) + .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, PUBLIC_API_VERSION) + .send(getExampleLensBody('Custom title')); + + expect(response.status).to.be(404); + expect(response.body.message).to.be( + 'A Lens visualization with saved object id [123] was not found.' + ); + }); + }); +} diff --git a/src/platform/test/api_integration/apis/lens/visualizations/update/validation.ts b/src/platform/test/api_integration/apis/lens/visualizations/update/validation.ts new file mode 100644 index 0000000000000..09f10073dd55d --- /dev/null +++ b/src/platform/test/api_integration/apis/lens/visualizations/update/validation.ts @@ -0,0 +1,32 @@ +/* + * 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 expect from '@kbn/expect'; +import { PUBLIC_API_PATH, PUBLIC_API_VERSION } from '@kbn/lens-plugin/server'; +import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; +import { FtrProviderContext } from '../../../../ftr_provider_context'; + +export default function ({ getService }: FtrProviderContext) { + const supertest = getService('supertest'); + describe('validation', () => { + it('should return error if body is empty', async () => { + const id = '71c9c185-3e6d-49d0-b7e5-f966eaf51625'; // known id + const response = await supertest + .put(`${PUBLIC_API_PATH}/visualizations/${id}`) + .set('kbn-xsrf', 'true') + .set(ELASTIC_HTTP_VERSION_HEADER, PUBLIC_API_VERSION) + .send({}); + + expect(response.status).to.be(400); + expect(response.body.message).to.be( + '[request body.data.title]: expected value of type [string] but got [undefined]' + ); + }); + }); +} diff --git a/src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/lens.json b/src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/lens.json new file mode 100644 index 0000000000000..1adcdea2ecab9 --- /dev/null +++ b/src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/lens.json @@ -0,0 +1,315 @@ +{ + "id": "71c9c185-3e6d-49d0-b7e5-f966eaf51625", + "type": "lens", + "namespaces": [ + "default" + ], + "updated_at": "2025-06-17T15:47:13.313Z", + "created_at": "2025-06-17T15:47:13.313Z", + "version": "WzU5LDFd", + "attributes": { + "title": "Lens example - 1", + "description": "", + "visualizationType": "lnsMetric", + "state": { + "visualization": { + "layerId": "7aa8fd7f-f664-48fe-8232-3a26054f9cdc", + "layerType": "data", + "metricAccessor": "89a69d8d-a6bc-47a8-80c6-94272762e785", + "secondaryTrend": { + "type": "none" + } + }, + "query": { + "query": "", + "language": "kuery" + }, + "filters": [], + "datasourceStates": { + "formBased": { + "layers": { + "7aa8fd7f-f664-48fe-8232-3a26054f9cdc": { + "columns": { + "89a69d8d-a6bc-47a8-80c6-94272762e785": { + "label": "Count of records", + "dataType": "number", + "operationType": "count", + "isBucketed": false, + "scale": "ratio", + "sourceField": "___records___", + "params": { + "emptyAsNull": true + } + } + }, + "columnOrder": [ + "89a69d8d-a6bc-47a8-80c6-94272762e785" + ], + "incompleteColumns": { + "806819b9-b606-4383-9337-e6a40b8602ad": { + "operationType": "date_histogram" + } + }, + "sampling": 1 + } + } + }, + "indexpattern": { + "layers": {} + }, + "textBased": { + "layers": {} + } + }, + "internalReferences": [], + "adHocDataViews": {} + } + }, + "references": [ + { + "type": "index-pattern", + "id": "91200a00-9efd-11e7-acb3-3dab96693fab", + "name": "indexpattern-datasource-layer-7aa8fd7f-f664-48fe-8232-3a26054f9cdc" + } + ], + "managed": false, + "coreMigrationVersion": "8.8.0", + "typeMigrationVersion": "8.9.0" +} + +{ + "id": "4fad4960-5be9-408c-854b-3b53ac80df81", + "type": "lens", + "namespaces": [ + "default" + ], + "updated_at": "2025-06-17T15:48:59.917Z", + "created_at": "2025-06-17T15:48:59.917Z", + "version": "WzYyLDFd", + "attributes": { + "title": "Lens example - 2", + "description": "", + "visualizationType": "lnsMetric", + "state": { + "visualization": { + "layerId": "7aa8fd7f-f664-48fe-8232-3a26054f9cdc", + "layerType": "data", + "metricAccessor": "89a69d8d-a6bc-47a8-80c6-94272762e785", + "secondaryTrend": { + "type": "none" + } + }, + "query": { + "query": "", + "language": "kuery" + }, + "filters": [], + "datasourceStates": { + "formBased": { + "layers": { + "7aa8fd7f-f664-48fe-8232-3a26054f9cdc": { + "columns": { + "89a69d8d-a6bc-47a8-80c6-94272762e785": { + "label": "Count of records", + "dataType": "number", + "operationType": "count", + "isBucketed": false, + "scale": "ratio", + "sourceField": "___records___", + "params": { + "emptyAsNull": true + } + } + }, + "columnOrder": [ + "89a69d8d-a6bc-47a8-80c6-94272762e785" + ], + "incompleteColumns": { + "806819b9-b606-4383-9337-e6a40b8602ad": { + "operationType": "date_histogram" + } + }, + "sampling": 1 + } + } + }, + "indexpattern": { + "layers": {} + }, + "textBased": { + "layers": {} + } + }, + "internalReferences": [], + "adHocDataViews": {} + } + }, + "references": [ + { + "type": "index-pattern", + "id": "91200a00-9efd-11e7-acb3-3dab96693fab", + "name": "indexpattern-datasource-layer-7aa8fd7f-f664-48fe-8232-3a26054f9cdc" + } + ], + "managed": false, + "coreMigrationVersion": "8.8.0", + "typeMigrationVersion": "8.9.0" +} + +{ + "id": "af239293-933a-4f35-969f-9dcccfefa8e4", + "type": "lens", + "namespaces": [ + "default" + ], + "updated_at": "2025-06-17T15:50:00.097Z", + "created_at": "2025-06-17T15:50:00.097Z", + "version": "WzY0LDFd", + "attributes": { + "title": "Lens example - 3", + "description": "Some description - 1", + "visualizationType": "lnsMetric", + "state": { + "visualization": { + "layerId": "7aa8fd7f-f664-48fe-8232-3a26054f9cdc", + "layerType": "data", + "metricAccessor": "89a69d8d-a6bc-47a8-80c6-94272762e785", + "secondaryTrend": { + "type": "none" + } + }, + "query": { + "query": "", + "language": "kuery" + }, + "filters": [], + "datasourceStates": { + "formBased": { + "layers": { + "7aa8fd7f-f664-48fe-8232-3a26054f9cdc": { + "columns": { + "89a69d8d-a6bc-47a8-80c6-94272762e785": { + "label": "Count of records", + "dataType": "number", + "operationType": "count", + "isBucketed": false, + "scale": "ratio", + "sourceField": "___records___", + "params": { + "emptyAsNull": true + } + } + }, + "columnOrder": [ + "89a69d8d-a6bc-47a8-80c6-94272762e785" + ], + "incompleteColumns": { + "806819b9-b606-4383-9337-e6a40b8602ad": { + "operationType": "date_histogram" + } + }, + "sampling": 1 + } + } + }, + "indexpattern": { + "layers": {} + }, + "textBased": { + "layers": {} + } + }, + "internalReferences": [], + "adHocDataViews": {} + } + }, + "references": [ + { + "type": "index-pattern", + "id": "91200a00-9efd-11e7-acb3-3dab96693fab", + "name": "indexpattern-datasource-layer-7aa8fd7f-f664-48fe-8232-3a26054f9cdc" + } + ], + "managed": false, + "coreMigrationVersion": "8.8.0", + "typeMigrationVersion": "8.9.0" +} + +{ + "id": "f708d303-2418-4313-aa28-c2830f7cf4cd", + "type": "lens", + "namespaces": [ + "default" + ], + "updated_at": "2025-06-17T15:50:05.680Z", + "created_at": "2025-06-17T15:50:05.680Z", + "version": "WzY2LDFd", + "attributes": { + "title": "Lens example - 4", + "description": "", + "visualizationType": "lnsMetric", + "state": { + "visualization": { + "layerId": "7aa8fd7f-f664-48fe-8232-3a26054f9cdc", + "layerType": "data", + "metricAccessor": "89a69d8d-a6bc-47a8-80c6-94272762e785", + "secondaryTrend": { + "type": "none" + } + }, + "query": { + "query": "", + "language": "kuery" + }, + "filters": [], + "datasourceStates": { + "formBased": { + "layers": { + "7aa8fd7f-f664-48fe-8232-3a26054f9cdc": { + "columns": { + "89a69d8d-a6bc-47a8-80c6-94272762e785": { + "label": "Count of records", + "dataType": "number", + "operationType": "count", + "isBucketed": false, + "scale": "ratio", + "sourceField": "___records___", + "params": { + "emptyAsNull": true + } + } + }, + "columnOrder": [ + "89a69d8d-a6bc-47a8-80c6-94272762e785" + ], + "incompleteColumns": { + "806819b9-b606-4383-9337-e6a40b8602ad": { + "operationType": "date_histogram" + } + }, + "sampling": 1 + } + } + }, + "indexpattern": { + "layers": {} + }, + "textBased": { + "layers": {} + } + }, + "internalReferences": [], + "adHocDataViews": {} + } + }, + "references": [ + { + "type": "index-pattern", + "id": "91200a00-9efd-11e7-acb3-3dab96693fab", + "name": "indexpattern-datasource-layer-7aa8fd7f-f664-48fe-8232-3a26054f9cdc" + } + ], + "managed": false, + "coreMigrationVersion": "8.8.0", + "typeMigrationVersion": "8.9.0" +} \ No newline at end of file diff --git a/x-pack/platform/plugins/shared/lens/server/index.ts b/x-pack/platform/plugins/shared/lens/server/index.ts index 80a61445b9cdb..d3f3eeb83c6c6 100644 --- a/x-pack/platform/plugins/shared/lens/server/index.ts +++ b/x-pack/platform/plugins/shared/lens/server/index.ts @@ -13,4 +13,6 @@ export const plugin = async (initContext: PluginInitializerContext) => { return new LensServerPlugin(initContext); }; +export { PUBLIC_API_PATH, PUBLIC_API_VERSION } from './api/constants'; + export type { LensDocShape715 } from './migrations/types'; From 30a61d27aa0bc79e2456f89d6dd2a603feb2cc0a Mon Sep 17 00:00:00 2001 From: Nick Partridge Date: Tue, 17 Jun 2025 20:26:44 -0500 Subject: [PATCH 04/14] chore: fix test title --- src/platform/test/api_integration/apis/lens/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform/test/api_integration/apis/lens/index.ts b/src/platform/test/api_integration/apis/lens/index.ts index 4624e4b6786e7..aeb7fd5be82b6 100644 --- a/src/platform/test/api_integration/apis/lens/index.ts +++ b/src/platform/test/api_integration/apis/lens/index.ts @@ -10,7 +10,7 @@ import { FtrProviderContext } from '../../ftr_provider_context'; export default function ({ loadTestFile }: FtrProviderContext) { - describe('lens - nick', () => { + describe('lens', () => { loadTestFile(require.resolve('./visualizations/create')); loadTestFile(require.resolve('./visualizations/get')); loadTestFile(require.resolve('./visualizations/update')); From baef217487a2f00f140eb8495b9ef18a3103f7c9 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Wed, 18 Jun 2025 01:39:13 +0000 Subject: [PATCH 05/14] [CI] Auto-commit changed files from 'node scripts/yarn_deduplicate' --- src/platform/test/tsconfig.json | 1 + x-pack/platform/plugins/shared/lens/tsconfig.json | 1 + 2 files changed, 2 insertions(+) diff --git a/src/platform/test/tsconfig.json b/src/platform/test/tsconfig.json index 375cde3b3ec1b..0b4d03b038d50 100644 --- a/src/platform/test/tsconfig.json +++ b/src/platform/test/tsconfig.json @@ -80,5 +80,6 @@ "@kbn/esql-utils", "@kbn/apm-synthtrace-client", "@kbn/apm-synthtrace", + "@kbn/lens-plugin", ] } diff --git a/x-pack/platform/plugins/shared/lens/tsconfig.json b/x-pack/platform/plugins/shared/lens/tsconfig.json index cac53597bd08f..e1380dfd4cd6b 100644 --- a/x-pack/platform/plugins/shared/lens/tsconfig.json +++ b/x-pack/platform/plugins/shared/lens/tsconfig.json @@ -124,6 +124,7 @@ "@kbn/fields-metadata-plugin", "@kbn/alerts-ui-shared", "@kbn/deeplinks-analytics", + "@kbn/core-http-server", ], "exclude": ["target/**/*"] } From fb73fc25f282f76f6345fa850edd4fd034471ffd Mon Sep 17 00:00:00 2001 From: Marco Vettorello Date: Wed, 18 Jun 2025 10:37:58 +0200 Subject: [PATCH 06/14] update codeowners file --- .github/CODEOWNERS | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 5b93f7141f4d9..f22a2dc70a135 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1240,7 +1240,6 @@ src/platform/plugins/shared/discover/public/context_awareness/profile_providers/ /x-pack/test/functional/es_archives/visualize @elastic/kibana-visualizations /src/platform/test/functional/fixtures/kbn_archiver/visualize.json @elastic/kibana-visualizations /src/platform/test/functional/fixtures/kbn_archiver/managed_content.json @elastic/kibana-visualizations # Assigned per only use: https://github.com/elastic/kibana/blob/main/x-pack/test/functional/apps/managed_content/managed_content.ts#L38 -/src/platform/test/api_integration/fixtures/kbn_archiver/event_annotations/event_annotations.json @elastic/kibana-visualizations /src/platform/test/functional/apps/getting_started/*.ts @elastic/kibana-visualizations # Assigned per https://github.com/elastic/kibana/pull/199767#discussion_r1840485031 /x-pack/test/upgrade/apps/graph @elastic/kibana-visualizations /x-pack/test/functional/page_objects/log_wrapper.ts @elastic/kibana-visualizations # Assigned per https://github.com/elastic/kibana/pull/36437 @@ -1275,9 +1274,11 @@ src/platform/plugins/shared/discover/public/context_awareness/profile_providers/ /x-pack/test/api_integration/apis/lens/ @elastic/kibana-visualizations /src/platform/test/functional/apps/visualize/ @elastic/kibana-visualizations /x-pack/test/functional/apps/graph @elastic/kibana-visualizations -/src/platform/test/api_integration/apis/event_annotations @elastic/kibana-visualizations /x-pack/test_serverless/functional/test_suites/common/visualizations/ @elastic/kibana-visualizations /x-pack/test_serverless/functional/fixtures/kbn_archiver/lens/ @elastic/kibana-visualizations +/src/platform/test/api_integration/apis/event_annotations @elastic/kibana-visualizations +/src/platform/test/api_integration/apis/lens @elastic/kibana-visualizations +/src/platform/test/api_integration/fixtures/kbn_archiver/event_annotations/event_annotations.json @elastic/kibana-visualizations # ES|QL /src/platform/test/api_integration/apis/esql/*.ts @elastic/kibana-esql From fe1b2d4842f6380bc891176191233666336ab967 Mon Sep 17 00:00:00 2001 From: Nick Partridge Date: Mon, 23 Jun 2025 19:49:39 -0500 Subject: [PATCH 07/14] chore: assign vis team as fixture CO --- .github/CODEOWNERS | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 5b93f7141f4d9..9308c1ebe5113 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1241,6 +1241,7 @@ src/platform/plugins/shared/discover/public/context_awareness/profile_providers/ /src/platform/test/functional/fixtures/kbn_archiver/visualize.json @elastic/kibana-visualizations /src/platform/test/functional/fixtures/kbn_archiver/managed_content.json @elastic/kibana-visualizations # Assigned per only use: https://github.com/elastic/kibana/blob/main/x-pack/test/functional/apps/managed_content/managed_content.ts#L38 /src/platform/test/api_integration/fixtures/kbn_archiver/event_annotations/event_annotations.json @elastic/kibana-visualizations +/src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/lens.json @elastic/kibana-visualizations /src/platform/test/functional/apps/getting_started/*.ts @elastic/kibana-visualizations # Assigned per https://github.com/elastic/kibana/pull/199767#discussion_r1840485031 /x-pack/test/upgrade/apps/graph @elastic/kibana-visualizations /x-pack/test/functional/page_objects/log_wrapper.ts @elastic/kibana-visualizations # Assigned per https://github.com/elastic/kibana/pull/36437 @@ -1279,6 +1280,7 @@ src/platform/plugins/shared/discover/public/context_awareness/profile_providers/ /x-pack/test_serverless/functional/test_suites/common/visualizations/ @elastic/kibana-visualizations /x-pack/test_serverless/functional/fixtures/kbn_archiver/lens/ @elastic/kibana-visualizations + # ES|QL /src/platform/test/api_integration/apis/esql/*.ts @elastic/kibana-esql /src/platform/test/functional/services/esql.ts @elastic/kibana-esql @@ -2739,6 +2741,8 @@ x-pack/solutions/security/plugins/security_solution/public/security_integrations x-pack/solutions/security/plugins/security_solution/server/security_integrations @elastic/security-service-integrations x-pack/solutions/security/plugins/security_solution/server/lib/security_integrations @elastic/security-service-integrations +# Visualizations overrides +/src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/lens.json @elastic/kibana-visualizations # Kibana design # scss overrides should be below this line for specificity From 4cab9836b3f6fe37088b70cd2e5862f6b23e1951 Mon Sep 17 00:00:00 2001 From: Nick Partridge Date: Mon, 23 Jun 2025 19:54:30 -0500 Subject: [PATCH 08/14] chore: fix bad CO merge --- .github/CODEOWNERS | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index aae0a44f6c2fe..212e8349343e3 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1278,12 +1278,9 @@ src/platform/plugins/shared/discover/public/context_awareness/profile_providers/ /x-pack/test/api_integration/apis/lens/ @elastic/kibana-visualizations /src/platform/test/functional/apps/visualize/ @elastic/kibana-visualizations /x-pack/test/functional/apps/graph @elastic/kibana-visualizations +/src/platform/test/api_integration/apis/event_annotations @elastic/kibana-visualizations /x-pack/test_serverless/functional/test_suites/common/visualizations/ @elastic/kibana-visualizations /x-pack/test_serverless/functional/fixtures/kbn_archiver/lens/ @elastic/kibana-visualizations -/src/platform/test/api_integration/apis/event_annotations @elastic/kibana-visualizations -/src/platform/test/api_integration/apis/lens @elastic/kibana-visualizations -/src/platform/test/api_integration/fixtures/kbn_archiver/event_annotations/event_annotations.json @elastic/kibana-visualizations - # ES|QL /src/platform/test/api_integration/apis/esql/*.ts @elastic/kibana-esql @@ -2740,8 +2737,6 @@ x-pack/solutions/security/plugins/security_solution/public/security_integrations x-pack/solutions/security/plugins/security_solution/server/security_integrations @elastic/security-service-integrations x-pack/solutions/security/plugins/security_solution/server/lib/security_integrations @elastic/security-service-integrations -# Visualizations overrides -/src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/lens.json @elastic/kibana-visualizations # Kibana design # scss overrides should be below this line for specificity @@ -2840,11 +2835,11 @@ src/platform/testfunctional/page_objects/solution_navigation.ts @elastic/appex-s /x-pack/test/api_integration/deployment_agnostic/apis/intercepts/*.ts @elastic/appex-sharedux # OpenAPI spec files -oas_docs/linters @elastic/core-docs @elastic/experience-docs -oas_docs/overlays @elastic/core-docs @elastic/experience-docs -oas_docs/kibana.info.serverless.yaml @elastic/core-docs @elastic/experience-docs -oas_docs/kibana.info.yaml @elastic/core-docs @elastic/experience-docs -oas_docs/output @elastic/core-docs @elastic/experience-docs +oas_docs/linters @elastic/core-docs @elastic/experience-docs +oas_docs/overlays @elastic/core-docs @elastic/experience-docs +oas_docs/kibana.info.serverless.yaml @elastic/core-docs @elastic/experience-docs +oas_docs/kibana.info.yaml @elastic/core-docs @elastic/experience-docs +oas_docs/output @elastic/core-docs @elastic/experience-docs # Documentation settings files docs/settings-gen @elastic/platform-docs @elastic/experience-docs From 38a5438b58ba3e70c34a8b6bcc10ccc24afd8c6c Mon Sep 17 00:00:00 2001 From: Nick Partridge Date: Mon, 23 Jun 2025 19:54:48 -0500 Subject: [PATCH 09/14] chore: fix bad CO merge --- .github/CODEOWNERS | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 212e8349343e3..1f84ccf32831b 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -2737,6 +2737,8 @@ x-pack/solutions/security/plugins/security_solution/public/security_integrations x-pack/solutions/security/plugins/security_solution/server/security_integrations @elastic/security-service-integrations x-pack/solutions/security/plugins/security_solution/server/lib/security_integrations @elastic/security-service-integrations +# Visualizations overrides +/src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/lens.json @elastic/kibana-visualizations # Kibana design # scss overrides should be below this line for specificity @@ -2835,11 +2837,11 @@ src/platform/testfunctional/page_objects/solution_navigation.ts @elastic/appex-s /x-pack/test/api_integration/deployment_agnostic/apis/intercepts/*.ts @elastic/appex-sharedux # OpenAPI spec files -oas_docs/linters @elastic/core-docs @elastic/experience-docs -oas_docs/overlays @elastic/core-docs @elastic/experience-docs -oas_docs/kibana.info.serverless.yaml @elastic/core-docs @elastic/experience-docs -oas_docs/kibana.info.yaml @elastic/core-docs @elastic/experience-docs -oas_docs/output @elastic/core-docs @elastic/experience-docs +oas_docs/linters @elastic/core-docs @elastic/experience-docs +oas_docs/overlays @elastic/core-docs @elastic/experience-docs +oas_docs/kibana.info.serverless.yaml @elastic/core-docs @elastic/experience-docs +oas_docs/kibana.info.yaml @elastic/core-docs @elastic/experience-docs +oas_docs/output @elastic/core-docs @elastic/experience-docs # Documentation settings files docs/settings-gen @elastic/platform-docs @elastic/experience-docs From 6cefe3923fca2aed43b25a199f3f382ec1f0e977 Mon Sep 17 00:00:00 2001 From: Nick Partridge Date: Mon, 23 Jun 2025 20:46:29 -0500 Subject: [PATCH 10/14] chore: move lens api tests under x-pack - fix paths - update files after move - move fixtures - add lens test config - update CO file with move --- .buildkite/ftr_platform_stateful_configs.yml | 1 + .github/CODEOWNERS | 5 +---- .../test/api_integration/apis/index.ts | 1 - .../test/api_integration/apis/lens/index.ts | 20 ------------------- .../test/api_integration/apis/lens/config.ts | 17 ++++++++++++++++ .../api_integration/apis/lens/examples.ts | 8 +++----- .../test/api_integration/apis/lens/index.ts | 14 +++++++++++++ .../apis/lens/visualizations/create/index.ts | 10 ++++------ .../apis/lens/visualizations/create/main.ts | 10 ++++------ .../lens/visualizations/create/validation.ts | 11 +++++----- .../apis/lens/visualizations/delete/index.ts | 14 ++++++------- .../apis/lens/visualizations/delete/main.ts | 10 ++++------ .../apis/lens/visualizations/get/index.ts | 14 ++++++------- .../apis/lens/visualizations/get/main.ts | 10 ++++------ .../apis/lens/visualizations/index.ts | 18 +++++++++++++++++ .../apis/lens/visualizations/search}/index.ts | 14 ++++++------- .../apis/lens/visualizations/search/main.ts | 10 ++++------ .../lens/visualizations/search/validation.ts | 11 +++++----- .../apis/lens/visualizations/update}/index.ts | 14 ++++++------- .../apis/lens/visualizations/update/main.ts | 10 ++++------ .../lens/visualizations/update/validation.ts | 11 +++++----- .../kbn_archiver/lens/example_docs.json | 0 22 files changed, 117 insertions(+), 116 deletions(-) delete mode 100644 src/platform/test/api_integration/apis/lens/index.ts create mode 100644 x-pack/platform/test/api_integration/apis/lens/config.ts rename {src => x-pack}/platform/test/api_integration/apis/lens/examples.ts (83%) create mode 100644 x-pack/platform/test/api_integration/apis/lens/index.ts rename {src => x-pack}/platform/test/api_integration/apis/lens/visualizations/create/index.ts (63%) rename {src => x-pack}/platform/test/api_integration/apis/lens/visualizations/create/main.ts (63%) rename {src => x-pack}/platform/test/api_integration/apis/lens/visualizations/create/validation.ts (66%) rename {src => x-pack}/platform/test/api_integration/apis/lens/visualizations/delete/index.ts (57%) rename {src => x-pack}/platform/test/api_integration/apis/lens/visualizations/delete/main.ts (74%) rename {src => x-pack}/platform/test/api_integration/apis/lens/visualizations/get/index.ts (57%) rename {src => x-pack}/platform/test/api_integration/apis/lens/visualizations/get/main.ts (74%) create mode 100644 x-pack/platform/test/api_integration/apis/lens/visualizations/index.ts rename {src/platform/test/api_integration/apis/lens/visualizations/update => x-pack/platform/test/api_integration/apis/lens/visualizations/search}/index.ts (58%) rename {src => x-pack}/platform/test/api_integration/apis/lens/visualizations/search/main.ts (71%) rename {src => x-pack}/platform/test/api_integration/apis/lens/visualizations/search/validation.ts (65%) rename {src/platform/test/api_integration/apis/lens/visualizations/search => x-pack/platform/test/api_integration/apis/lens/visualizations/update}/index.ts (58%) rename {src => x-pack}/platform/test/api_integration/apis/lens/visualizations/update/main.ts (76%) rename {src => x-pack}/platform/test/api_integration/apis/lens/visualizations/update/validation.ts (67%) rename src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/lens.json => x-pack/test/api_integration/fixtures/kbn_archiver/lens/example_docs.json (100%) diff --git a/.buildkite/ftr_platform_stateful_configs.yml b/.buildkite/ftr_platform_stateful_configs.yml index afd448fa92450..53d96e0c13ac7 100644 --- a/.buildkite/ftr_platform_stateful_configs.yml +++ b/.buildkite/ftr_platform_stateful_configs.yml @@ -378,6 +378,7 @@ enabled: - x-pack/platform/test/api_integration/apis/management/config.ts - x-pack/platform/test/api_integration/apis/management/index_management/disabled_data_enrichers/config.ts - x-pack/platform/test/api_integration/apis/maps/config.ts + - x-pack/platform/test/api_integration/apis/lens/config.ts - x-pack/platform/test/api_integration/apis/ml/config.ts - x-pack/platform/test/api_integration/apis/monitoring/config.ts - x-pack/platform/test/api_integration/apis/monitoring_collection/config.ts diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 1f84ccf32831b..d47c49ffb172a 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1260,7 +1260,7 @@ src/platform/plugins/shared/discover/public/context_awareness/profile_providers/ /x-pack/test/functional/page_objects/lens_page.ts @elastic/kibana-visualizations /x-pack/test/functional/es_archives/lens @elastic/kibana-visualizations /x-pack/test/examples/embedded_lens @elastic/kibana-visualizations -/x-pack/test/api_integration/fixtures/kbn_archiver/lens/constant_keyword.json @elastic/kibana-visualizations +/x-pack/test/api_integration/fixtures/kbn_archiver/lens/ @elastic/kibana-visualizations /src/platform/test/plugin_functional/test_suites/custom_visualizations @elastic/kibana-visualizations /src/platform/test/plugin_functional/plugins/kbn_tp_custom_visualizations @elastic/kibana-visualizations /x-pack/test/functional/fixtures/kbn_archiver/visualize @elastic/kibana-visualizations @@ -2737,9 +2737,6 @@ x-pack/solutions/security/plugins/security_solution/public/security_integrations x-pack/solutions/security/plugins/security_solution/server/security_integrations @elastic/security-service-integrations x-pack/solutions/security/plugins/security_solution/server/lib/security_integrations @elastic/security-service-integrations -# Visualizations overrides -/src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/lens.json @elastic/kibana-visualizations - # Kibana design # scss overrides should be below this line for specificity **/*.scss @elastic/kibana-design diff --git a/src/platform/test/api_integration/apis/index.ts b/src/platform/test/api_integration/apis/index.ts index 0a1633f82f6c3..af1cbf2464fa9 100644 --- a/src/platform/test/api_integration/apis/index.ts +++ b/src/platform/test/api_integration/apis/index.ts @@ -35,6 +35,5 @@ export default function ({ loadTestFile }: FtrProviderContext) { loadTestFile(require.resolve('./telemetry')); loadTestFile(require.resolve('./guided_onboarding')); loadTestFile(require.resolve('./esql')); - loadTestFile(require.resolve('./lens')); }); } diff --git a/src/platform/test/api_integration/apis/lens/index.ts b/src/platform/test/api_integration/apis/lens/index.ts deleted file mode 100644 index aeb7fd5be82b6..0000000000000 --- a/src/platform/test/api_integration/apis/lens/index.ts +++ /dev/null @@ -1,20 +0,0 @@ -/* - * 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 { FtrProviderContext } from '../../ftr_provider_context'; - -export default function ({ loadTestFile }: FtrProviderContext) { - describe('lens', () => { - loadTestFile(require.resolve('./visualizations/create')); - loadTestFile(require.resolve('./visualizations/get')); - loadTestFile(require.resolve('./visualizations/update')); - loadTestFile(require.resolve('./visualizations/delete')); - loadTestFile(require.resolve('./visualizations/search')); - }); -} diff --git a/x-pack/platform/test/api_integration/apis/lens/config.ts b/x-pack/platform/test/api_integration/apis/lens/config.ts new file mode 100644 index 0000000000000..5f335f116fefe --- /dev/null +++ b/x-pack/platform/test/api_integration/apis/lens/config.ts @@ -0,0 +1,17 @@ +/* + * 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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrConfigProviderContext } from '@kbn/test'; + +export default async function ({ readConfigFile }: FtrConfigProviderContext) { + const baseIntegrationTestsConfig = await readConfigFile(require.resolve('../../config.ts')); + + return { + ...baseIntegrationTestsConfig.getAll(), + testFiles: [require.resolve('.')], + }; +} diff --git a/src/platform/test/api_integration/apis/lens/examples.ts b/x-pack/platform/test/api_integration/apis/lens/examples.ts similarity index 83% rename from src/platform/test/api_integration/apis/lens/examples.ts rename to x-pack/platform/test/api_integration/apis/lens/examples.ts index 1083902ca5d28..a4da3167673f2 100644 --- a/src/platform/test/api_integration/apis/lens/examples.ts +++ b/x-pack/platform/test/api_integration/apis/lens/examples.ts @@ -1,10 +1,8 @@ /* * 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". + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. */ export const getExampleLensBody = (title = `Lens vis - ${Date.now()} - ${Math.random()}`) => ({ diff --git a/x-pack/platform/test/api_integration/apis/lens/index.ts b/x-pack/platform/test/api_integration/apis/lens/index.ts new file mode 100644 index 0000000000000..42fd587c9884a --- /dev/null +++ b/x-pack/platform/test/api_integration/apis/lens/index.ts @@ -0,0 +1,14 @@ +/* + * 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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../ftr_provider_context'; + +export default function ({ loadTestFile }: FtrProviderContext) { + describe('lens', () => { + loadTestFile(require.resolve('./visualizations')); + }); +} diff --git a/src/platform/test/api_integration/apis/lens/visualizations/create/index.ts b/x-pack/platform/test/api_integration/apis/lens/visualizations/create/index.ts similarity index 63% rename from src/platform/test/api_integration/apis/lens/visualizations/create/index.ts rename to x-pack/platform/test/api_integration/apis/lens/visualizations/create/index.ts index 3190b9f7e0391..929a6bff04995 100644 --- a/src/platform/test/api_integration/apis/lens/visualizations/create/index.ts +++ b/x-pack/platform/test/api_integration/apis/lens/visualizations/create/index.ts @@ -1,13 +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". + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. */ -import { FtrProviderContext } from '../../../../ftr_provider_context'; +import type { FtrProviderContext } from '../../../../ftr_provider_context'; export default function ({ getService, loadTestFile }: FtrProviderContext) { const kibanaServer = getService('kibanaServer'); diff --git a/src/platform/test/api_integration/apis/lens/visualizations/create/main.ts b/x-pack/platform/test/api_integration/apis/lens/visualizations/create/main.ts similarity index 63% rename from src/platform/test/api_integration/apis/lens/visualizations/create/main.ts rename to x-pack/platform/test/api_integration/apis/lens/visualizations/create/main.ts index b85f4578ccfe3..e390eb2f51bbe 100644 --- a/src/platform/test/api_integration/apis/lens/visualizations/create/main.ts +++ b/x-pack/platform/test/api_integration/apis/lens/visualizations/create/main.ts @@ -1,17 +1,15 @@ /* * 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". + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. */ import expect from '@kbn/expect'; import { PUBLIC_API_PATH, PUBLIC_API_VERSION } from '@kbn/lens-plugin/server'; import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; -import { FtrProviderContext } from '../../../../ftr_provider_context'; +import type { FtrProviderContext } from '../../../../ftr_provider_context'; import { getExampleLensBody } from '../../examples'; export default function ({ getService }: FtrProviderContext) { diff --git a/src/platform/test/api_integration/apis/lens/visualizations/create/validation.ts b/x-pack/platform/test/api_integration/apis/lens/visualizations/create/validation.ts similarity index 66% rename from src/platform/test/api_integration/apis/lens/visualizations/create/validation.ts rename to x-pack/platform/test/api_integration/apis/lens/visualizations/create/validation.ts index f8a7c679da3f9..07992cbd74818 100644 --- a/src/platform/test/api_integration/apis/lens/visualizations/create/validation.ts +++ b/x-pack/platform/test/api_integration/apis/lens/visualizations/create/validation.ts @@ -1,16 +1,15 @@ /* * 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". + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. */ import expect from '@kbn/expect'; import { PUBLIC_API_PATH, PUBLIC_API_VERSION } from '@kbn/lens-plugin/server'; import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; -import { FtrProviderContext } from '../../../../ftr_provider_context'; + +import type { FtrProviderContext } from '../../../../ftr_provider_context'; export default function ({ getService }: FtrProviderContext) { const supertest = getService('supertest'); diff --git a/src/platform/test/api_integration/apis/lens/visualizations/delete/index.ts b/x-pack/platform/test/api_integration/apis/lens/visualizations/delete/index.ts similarity index 57% rename from src/platform/test/api_integration/apis/lens/visualizations/delete/index.ts rename to x-pack/platform/test/api_integration/apis/lens/visualizations/delete/index.ts index 0cbc46743894e..008870b281c18 100644 --- a/src/platform/test/api_integration/apis/lens/visualizations/delete/index.ts +++ b/x-pack/platform/test/api_integration/apis/lens/visualizations/delete/index.ts @@ -1,13 +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". + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. */ -import { FtrProviderContext } from '../../../../ftr_provider_context'; +import type { FtrProviderContext } from '../../../../ftr_provider_context'; export default function ({ getService, loadTestFile }: FtrProviderContext) { const kibanaServer = getService('kibanaServer'); @@ -17,7 +15,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { 'src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/basic.json' ); await kibanaServer.importExport.load( - 'src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/lens.json' + 'x-pack/test/api_integration/fixtures/kbn_archiver/lens/example_docs.json' ); }); @@ -27,7 +25,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { 'src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/basic.json' ); await kibanaServer.importExport.unload( - 'src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/lens.json' + 'x-pack/test/api_integration/fixtures/kbn_archiver/lens/example_docs.json' ); }); loadTestFile(require.resolve('./main')); diff --git a/src/platform/test/api_integration/apis/lens/visualizations/delete/main.ts b/x-pack/platform/test/api_integration/apis/lens/visualizations/delete/main.ts similarity index 74% rename from src/platform/test/api_integration/apis/lens/visualizations/delete/main.ts rename to x-pack/platform/test/api_integration/apis/lens/visualizations/delete/main.ts index 309a3d2495a25..b954b0e312363 100644 --- a/src/platform/test/api_integration/apis/lens/visualizations/delete/main.ts +++ b/x-pack/platform/test/api_integration/apis/lens/visualizations/delete/main.ts @@ -1,17 +1,15 @@ /* * 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". + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. */ import expect from '@kbn/expect'; import { PUBLIC_API_PATH, PUBLIC_API_VERSION } from '@kbn/lens-plugin/server'; import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; -import { FtrProviderContext } from '../../../../ftr_provider_context'; +import type { FtrProviderContext } from '../../../../ftr_provider_context'; export default function ({ getService }: FtrProviderContext) { const supertest = getService('supertest'); diff --git a/src/platform/test/api_integration/apis/lens/visualizations/get/index.ts b/x-pack/platform/test/api_integration/apis/lens/visualizations/get/index.ts similarity index 57% rename from src/platform/test/api_integration/apis/lens/visualizations/get/index.ts rename to x-pack/platform/test/api_integration/apis/lens/visualizations/get/index.ts index 0cbc46743894e..008870b281c18 100644 --- a/src/platform/test/api_integration/apis/lens/visualizations/get/index.ts +++ b/x-pack/platform/test/api_integration/apis/lens/visualizations/get/index.ts @@ -1,13 +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". + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. */ -import { FtrProviderContext } from '../../../../ftr_provider_context'; +import type { FtrProviderContext } from '../../../../ftr_provider_context'; export default function ({ getService, loadTestFile }: FtrProviderContext) { const kibanaServer = getService('kibanaServer'); @@ -17,7 +15,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { 'src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/basic.json' ); await kibanaServer.importExport.load( - 'src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/lens.json' + 'x-pack/test/api_integration/fixtures/kbn_archiver/lens/example_docs.json' ); }); @@ -27,7 +25,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { 'src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/basic.json' ); await kibanaServer.importExport.unload( - 'src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/lens.json' + 'x-pack/test/api_integration/fixtures/kbn_archiver/lens/example_docs.json' ); }); loadTestFile(require.resolve('./main')); diff --git a/src/platform/test/api_integration/apis/lens/visualizations/get/main.ts b/x-pack/platform/test/api_integration/apis/lens/visualizations/get/main.ts similarity index 74% rename from src/platform/test/api_integration/apis/lens/visualizations/get/main.ts rename to x-pack/platform/test/api_integration/apis/lens/visualizations/get/main.ts index 20b85d2331966..f30684a456c87 100644 --- a/src/platform/test/api_integration/apis/lens/visualizations/get/main.ts +++ b/x-pack/platform/test/api_integration/apis/lens/visualizations/get/main.ts @@ -1,17 +1,15 @@ /* * 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". + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. */ import expect from '@kbn/expect'; import { PUBLIC_API_PATH, PUBLIC_API_VERSION } from '@kbn/lens-plugin/server'; import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; -import { FtrProviderContext } from '../../../../ftr_provider_context'; +import type { FtrProviderContext } from '../../../../ftr_provider_context'; export default function ({ getService }: FtrProviderContext) { const supertest = getService('supertest'); diff --git a/x-pack/platform/test/api_integration/apis/lens/visualizations/index.ts b/x-pack/platform/test/api_integration/apis/lens/visualizations/index.ts new file mode 100644 index 0000000000000..47f4688d74bd1 --- /dev/null +++ b/x-pack/platform/test/api_integration/apis/lens/visualizations/index.ts @@ -0,0 +1,18 @@ +/* + * 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; you may not use this file except in compliance with the Elastic License + * 2.0. + */ + +import { FtrProviderContext } from '../../../../functional/ftr_provider_context'; + +export default function ({ loadTestFile }: FtrProviderContext) { + describe('visualizations', () => { + loadTestFile(require.resolve('./create')); + loadTestFile(require.resolve('./get')); + loadTestFile(require.resolve('./update')); + loadTestFile(require.resolve('./delete')); + loadTestFile(require.resolve('./search')); + }); +} diff --git a/src/platform/test/api_integration/apis/lens/visualizations/update/index.ts b/x-pack/platform/test/api_integration/apis/lens/visualizations/search/index.ts similarity index 58% rename from src/platform/test/api_integration/apis/lens/visualizations/update/index.ts rename to x-pack/platform/test/api_integration/apis/lens/visualizations/search/index.ts index e5705ac4e065e..0e449474750f1 100644 --- a/src/platform/test/api_integration/apis/lens/visualizations/update/index.ts +++ b/x-pack/platform/test/api_integration/apis/lens/visualizations/search/index.ts @@ -1,13 +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". + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. */ -import { FtrProviderContext } from '../../../../ftr_provider_context'; +import type { FtrProviderContext } from '../../../../ftr_provider_context'; export default function ({ getService, loadTestFile }: FtrProviderContext) { const kibanaServer = getService('kibanaServer'); @@ -17,7 +15,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { 'src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/basic.json' ); await kibanaServer.importExport.load( - 'src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/lens.json' + 'x-pack/test/api_integration/fixtures/kbn_archiver/lens/example_docs.json' ); }); @@ -27,7 +25,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { 'src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/basic.json' ); await kibanaServer.importExport.unload( - 'src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/lens.json' + 'x-pack/test/api_integration/fixtures/kbn_archiver/lens/example_docs.json' ); }); loadTestFile(require.resolve('./main')); diff --git a/src/platform/test/api_integration/apis/lens/visualizations/search/main.ts b/x-pack/platform/test/api_integration/apis/lens/visualizations/search/main.ts similarity index 71% rename from src/platform/test/api_integration/apis/lens/visualizations/search/main.ts rename to x-pack/platform/test/api_integration/apis/lens/visualizations/search/main.ts index ea3fca4ff54b9..f0a86f93ce854 100644 --- a/src/platform/test/api_integration/apis/lens/visualizations/search/main.ts +++ b/x-pack/platform/test/api_integration/apis/lens/visualizations/search/main.ts @@ -1,17 +1,15 @@ /* * 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". + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. */ import expect from '@kbn/expect'; import { PUBLIC_API_PATH, PUBLIC_API_VERSION } from '@kbn/lens-plugin/server'; import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; -import { FtrProviderContext } from '../../../../ftr_provider_context'; +import type { FtrProviderContext } from '../../../../ftr_provider_context'; export default function ({ getService }: FtrProviderContext) { const supertest = getService('supertest'); diff --git a/src/platform/test/api_integration/apis/lens/visualizations/search/validation.ts b/x-pack/platform/test/api_integration/apis/lens/visualizations/search/validation.ts similarity index 65% rename from src/platform/test/api_integration/apis/lens/visualizations/search/validation.ts rename to x-pack/platform/test/api_integration/apis/lens/visualizations/search/validation.ts index eb4fce368cc65..3cc8eeff85a00 100644 --- a/src/platform/test/api_integration/apis/lens/visualizations/search/validation.ts +++ b/x-pack/platform/test/api_integration/apis/lens/visualizations/search/validation.ts @@ -1,16 +1,15 @@ /* * 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". + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. */ import expect from '@kbn/expect'; import { PUBLIC_API_PATH, PUBLIC_API_VERSION } from '@kbn/lens-plugin/server'; import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; -import { FtrProviderContext } from '../../../../ftr_provider_context'; + +import type { FtrProviderContext } from '../../../../ftr_provider_context'; export default function ({ getService }: FtrProviderContext) { const supertest = getService('supertest'); diff --git a/src/platform/test/api_integration/apis/lens/visualizations/search/index.ts b/x-pack/platform/test/api_integration/apis/lens/visualizations/update/index.ts similarity index 58% rename from src/platform/test/api_integration/apis/lens/visualizations/search/index.ts rename to x-pack/platform/test/api_integration/apis/lens/visualizations/update/index.ts index e5705ac4e065e..0e449474750f1 100644 --- a/src/platform/test/api_integration/apis/lens/visualizations/search/index.ts +++ b/x-pack/platform/test/api_integration/apis/lens/visualizations/update/index.ts @@ -1,13 +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". + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. */ -import { FtrProviderContext } from '../../../../ftr_provider_context'; +import type { FtrProviderContext } from '../../../../ftr_provider_context'; export default function ({ getService, loadTestFile }: FtrProviderContext) { const kibanaServer = getService('kibanaServer'); @@ -17,7 +15,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { 'src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/basic.json' ); await kibanaServer.importExport.load( - 'src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/lens.json' + 'x-pack/test/api_integration/fixtures/kbn_archiver/lens/example_docs.json' ); }); @@ -27,7 +25,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) { 'src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/basic.json' ); await kibanaServer.importExport.unload( - 'src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/lens.json' + 'x-pack/test/api_integration/fixtures/kbn_archiver/lens/example_docs.json' ); }); loadTestFile(require.resolve('./main')); diff --git a/src/platform/test/api_integration/apis/lens/visualizations/update/main.ts b/x-pack/platform/test/api_integration/apis/lens/visualizations/update/main.ts similarity index 76% rename from src/platform/test/api_integration/apis/lens/visualizations/update/main.ts rename to x-pack/platform/test/api_integration/apis/lens/visualizations/update/main.ts index 4a76d92cc545a..c5e38106a6ab1 100644 --- a/src/platform/test/api_integration/apis/lens/visualizations/update/main.ts +++ b/x-pack/platform/test/api_integration/apis/lens/visualizations/update/main.ts @@ -1,17 +1,15 @@ /* * 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". + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. */ import expect from '@kbn/expect'; import { PUBLIC_API_PATH, PUBLIC_API_VERSION } from '@kbn/lens-plugin/server'; import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; -import { FtrProviderContext } from '../../../../ftr_provider_context'; +import type { FtrProviderContext } from '../../../../ftr_provider_context'; import { getExampleLensBody } from '../../examples'; export default function ({ getService }: FtrProviderContext) { diff --git a/src/platform/test/api_integration/apis/lens/visualizations/update/validation.ts b/x-pack/platform/test/api_integration/apis/lens/visualizations/update/validation.ts similarity index 67% rename from src/platform/test/api_integration/apis/lens/visualizations/update/validation.ts rename to x-pack/platform/test/api_integration/apis/lens/visualizations/update/validation.ts index 09f10073dd55d..777cc9cc82c2b 100644 --- a/src/platform/test/api_integration/apis/lens/visualizations/update/validation.ts +++ b/x-pack/platform/test/api_integration/apis/lens/visualizations/update/validation.ts @@ -1,16 +1,15 @@ /* * 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". + * or more contributor license agreements. Licensed under the Elastic License + * 2.0; you may not use this file except in compliance with the Elastic License + * 2.0. */ import expect from '@kbn/expect'; import { PUBLIC_API_PATH, PUBLIC_API_VERSION } from '@kbn/lens-plugin/server'; import { ELASTIC_HTTP_VERSION_HEADER } from '@kbn/core-http-common'; -import { FtrProviderContext } from '../../../../ftr_provider_context'; + +import type { FtrProviderContext } from '../../../../ftr_provider_context'; export default function ({ getService }: FtrProviderContext) { const supertest = getService('supertest'); diff --git a/src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/lens.json b/x-pack/test/api_integration/fixtures/kbn_archiver/lens/example_docs.json similarity index 100% rename from src/platform/test/api_integration/fixtures/kbn_archiver/saved_objects/lens.json rename to x-pack/test/api_integration/fixtures/kbn_archiver/lens/example_docs.json From 8ce00c888ec484440e6083e2e37d14b0268eec08 Mon Sep 17 00:00:00 2001 From: Nick Partridge Date: Mon, 23 Jun 2025 20:49:30 -0500 Subject: [PATCH 11/14] chore: update COs again --- .github/CODEOWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index d47c49ffb172a..343098d378203 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -1261,6 +1261,7 @@ src/platform/plugins/shared/discover/public/context_awareness/profile_providers/ /x-pack/test/functional/es_archives/lens @elastic/kibana-visualizations /x-pack/test/examples/embedded_lens @elastic/kibana-visualizations /x-pack/test/api_integration/fixtures/kbn_archiver/lens/ @elastic/kibana-visualizations +/x-pack/platform/test/api_integration/apis/lens @elastic/kibana-visualizations /src/platform/test/plugin_functional/test_suites/custom_visualizations @elastic/kibana-visualizations /src/platform/test/plugin_functional/plugins/kbn_tp_custom_visualizations @elastic/kibana-visualizations /x-pack/test/functional/fixtures/kbn_archiver/visualize @elastic/kibana-visualizations From 06a6a19202a8d75b87d9c53ca1771ca06a212ae6 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Tue, 24 Jun 2025 02:02:30 +0000 Subject: [PATCH 12/14] [CI] Auto-commit changed files from 'node scripts/yarn_deduplicate' --- src/platform/test/tsconfig.json | 1 - 1 file changed, 1 deletion(-) diff --git a/src/platform/test/tsconfig.json b/src/platform/test/tsconfig.json index b359d7477c4d0..e2595c8550821 100644 --- a/src/platform/test/tsconfig.json +++ b/src/platform/test/tsconfig.json @@ -79,6 +79,5 @@ "@kbn/esql-utils", "@kbn/apm-synthtrace-client", "@kbn/apm-synthtrace", - "@kbn/lens-plugin", ] } From 2cac74cc750ad195853441607867847f093d9be1 Mon Sep 17 00:00:00 2001 From: kibanamachine <42973632+kibanamachine@users.noreply.github.com> Date: Tue, 24 Jun 2025 02:13:11 +0000 Subject: [PATCH 13/14] [CI] Auto-commit changed files from 'node scripts/styled_components_mapping' --- x-pack/platform/test/tsconfig.json | 1 + 1 file changed, 1 insertion(+) diff --git a/x-pack/platform/test/tsconfig.json b/x-pack/platform/test/tsconfig.json index 837aa6b044733..1820b9af8b404 100644 --- a/x-pack/platform/test/tsconfig.json +++ b/x-pack/platform/test/tsconfig.json @@ -95,5 +95,6 @@ "@kbn/stack-alerts-plugin", "@kbn/triggers-actions-ui-plugin", "@kbn/alerts-as-data-utils", + "@kbn/lens-plugin", ] } From af410d9e9f9cd34d6090c79c02fcbf2ec7d06e06 Mon Sep 17 00:00:00 2001 From: Nick Partridge Date: Wed, 25 Jun 2025 12:24:07 -0500 Subject: [PATCH 14/14] chore: remove co presentation review changes --- .../dashboard/server/api/register_routes.ts | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/src/platform/plugins/shared/dashboard/server/api/register_routes.ts b/src/platform/plugins/shared/dashboard/server/api/register_routes.ts index 4075ce9e17fac..fe218528e7943 100644 --- a/src/platform/plugins/shared/dashboard/server/api/register_routes.ts +++ b/src/platform/plugins/shared/dashboard/server/api/register_routes.ts @@ -206,15 +206,17 @@ export function registerAPIRoutes({ min: 1, defaultValue: 1, }), - perPage: schema.number({ - meta: { - description: - 'The number of dashboards to display on each page (max 1000). Default is "20".', - }, - defaultValue: 20, - min: 1, - max: 1000, - }), + perPage: schema.maybe( + schema.number({ + meta: { + description: + 'The number of dashboards to display on each page (max 1000). Default is "20".', + }, + defaultValue: 20, + min: 1, + max: 1000, + }) + ), }), }, response: {