Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,7 @@ describe('checking migration metadata changes on all registered SO types', () =>
"links": "5fb928a940af4360d4e84f55121aeebfd089c372896073875de8a9fb5b0d1e02",
"maintenance-window": "666d3ec4bb27f84efe14aa17e9257f4c0eeee315b500de6b3b0b3b4ffeb71d04",
"map": "7660b8b519a9a56f0f48af65d7a6fa103c1eb00009c1eb8827c6997c98791001",
"markdown": "e5f35bb7f64f1666a02919f95e22a7620cccc01933413c3a2986a16fcb42b9a2",
"markdown": "4942b33287c8a084d2b298a3d0ee23246fad29d37e354ea6cecd0d281e0f8eaf",
"metrics-data-source": "26cff6bfde01fe7e798ae716d3786f5c165f6342050ca436d3b122cb010815d9",
"metrics-explorer-view": "c75ae4b97007820e62cffc0a37b407bbb4f9222e1857cfac8fba1575889f5b2a",
"ml-job": "c76b6c50ff95a890cd0991777f51ef98bae140a699d58ac2a64ead6c157cd914",
Expand Down Expand Up @@ -1000,7 +1000,7 @@ describe('checking migration metadata changes on all registered SO types', () =>
"markdown|global: 02a5c250e23734d356cd7fd36b1d8bb44a97030f",
"markdown|mappings: 16e53f65d58da76131a981a0f1bc10e7ead10ee9",
"markdown|schemas: da39a3ee5e6b4b0d3255bfef95601890afd80709",
"markdown|10.1.0: 9edd32ab95c52a31924622c5a13a42f9ed4355bb0780b9c3b024bd57ff9445d4",
"markdown|10.1.0: 6a24188816fe1b9caf37fd4ab5337a8e62e5ab64219898dcf072842109692eb7",
"=================================================================================",
"metrics-data-source|global: 356d897223d1b613dbcc230d73ef4d4399f29ede",
"metrics-data-source|mappings: e1b10e5bec060a176469a5e9a4f80c94e23abcd7",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,3 @@ const result = idSchema.validate('dashboard_abc123'); // throws if invalid
## Exported Schemas

- `asCodeIdSchema` — Validates As Code identifiers according to platform requirements.

## Exported Types

- `AsCodeId` - ID type
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,3 @@
*/

export { asCodeIdSchema } from './src/schemas';

export type { AsCodeId } from './src/schemas/types';
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,19 @@
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import type { TypeOf } from '@kbn/config-schema';
import { schema } from '@kbn/config-schema';
import { isValidId } from './is_valid_id';

export const asCodeIdSchema = schema.maybe(
schema.string({
meta: {
description:
'A unique identifier. Must contain only lowercase letters, numbers, hyphens, and underscores.',
},
validate: (value) => {
if (!isValidId(value)) {
return 'ID must contain only lowercase letters, numbers, hyphens, and underscores.';
}
},
minLength: 1,
maxLength: 250,
})
);

export type AsCodeId = TypeOf<typeof asCodeIdSchema>;
export const asCodeIdSchema = schema.string({
meta: {
description:
'A unique identifier. Must contain only lowercase letters, numbers, hyphens, and underscores.',
},
validate: (value) => {
if (!isValidId(value)) {
return 'ID must contain only lowercase letters, numbers, hyphens, and underscores.';
}
},
minLength: 1,
maxLength: 250,
});
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,3 @@
*/

export { asCodeIdSchema } from './id';
export type { AsCodeId } from './id';

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import Boom from '@hapi/boom';
import type { RequestHandlerContext } from '@kbn/core/server';
import type { DashboardSavedObjectAttributes } from '../../dashboard_saved_object';
import { DASHBOARD_SAVED_OBJECT_TYPE } from '../../../common/constants';
import type { DashboardCreateRequestBody, DashboardCreateRequestParams } from './types';
import type { DashboardCreateRequestBody } from './types';
import { transformDashboardIn } from '../transforms';
import { getDashboardCRUResponseBody } from '../saved_object_utils';
import type { DashboardCreateResponseBody } from './types';
Expand All @@ -21,7 +21,6 @@ export async function create(
requestCtx: RequestHandlerContext,
dashboardStateSchema: ReturnType<typeof getDashboardStateSchema>,
createBody: DashboardCreateRequestBody,
createParams?: DashboardCreateRequestParams,
isDashboardAppRequest: boolean = false
): Promise<DashboardCreateResponseBody> {
const { core } = await requestCtx.resolve(['core']);
Expand All @@ -45,7 +44,6 @@ export async function create(
soAttributes,
{
references: soReferences,
...(createParams?.id && { id: createParams.id }),
...(accessControl?.access_mode &&
supportsAccessControl && {
accessControl: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,7 @@ import type { VersionedRouter } from '@kbn/core-http-server';
import type { RequestHandlerContext } from '@kbn/core/server';
import { once } from 'lodash';
import { getRouteConfig } from '../get_route_config';
import {
createRequestParamsSchema,
getCreateRequestBodySchema,
getCreateResponseBodySchema,
} from './schemas';
import { getCreateRequestBodySchema, getCreateResponseBodySchema } from './schemas';
import { create } from './create';
import { getDashboardStateSchema } from '../dashboard_state_schemas';

Expand All @@ -25,7 +21,7 @@ export function registerCreateRoute(
) {
const { basePath, routeConfig, routeVersion } = getRouteConfig(isDashboardAppRequest);
const createRoute = router.post({
path: `${basePath}/{id?}`,
path: basePath,
summary: 'Create a dashboard with an auto-generated ID or a specified ID',
...routeConfig,
});
Expand All @@ -42,22 +38,18 @@ export function registerCreateRoute(
version: routeVersion,
validate: () => ({
request: {
params: createRequestParamsSchema,
body: getCreateRequestBodySchema(isDashboardAppRequest),
},
response: {
201: {
body: () => getCreateResponseBodySchema(isDashboardAppRequest),
description: 'Indicates the dashboard is created successfully',
description: 'created',
},
400: {
description: 'Indicates an invalid schema or parameters.',
description: 'invalid request',
},
403: {
description: 'Indicates that this call is forbidden.',
},
409: {
description: 'Indicates that a dashboard with the given ID already exists.',
description: 'forbidden',
},
},
}),
Expand All @@ -68,19 +60,10 @@ export function registerCreateRoute(
ctx,
getCachedDashboardStateSchema(),
req.body,
req.params,
isDashboardAppRequest
);
return res.created({ body: result });
} catch (e) {
if (e.isBoom && e.output.statusCode === 409) {
return res.conflict({
body: {
message: `A dashboard with ID ${req?.params?.id} already exists.`,
},
});
}

if (e.isBoom && e.output.statusCode === 403) {
return res.forbidden({ body: { message: e.message } });
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,9 @@
*/

import { schema } from '@kbn/config-schema';
import { asCodeIdSchema } from '@kbn/as-code-shared-schemas';
import { getDashboardStateSchema } from '../dashboard_state_schemas';
import { baseMetaSchema, createdMetaSchema, updatedMetaSchema } from '../meta_schemas';

export const createRequestParamsSchema = schema.maybe(
schema.object(
{
id: asCodeIdSchema,
},
{ unknowns: 'forbid' }
)
);

export function getCreateRequestBodySchema(isDashboardAppRequest: boolean) {
return getDashboardStateSchema(isDashboardAppRequest);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,8 @@
*/

import type { TypeOf } from '@kbn/config-schema';
import type {
createRequestParamsSchema,
getCreateRequestBodySchema,
getCreateResponseBodySchema,
} from './schemas';
import type { getCreateRequestBodySchema, getCreateResponseBodySchema } from './schemas';

/** The request params type for creating a dashboard. */
export type DashboardCreateRequestParams = TypeOf<typeof createRequestParamsSchema>;
/** The request body type for creating a dashboard. */
export type DashboardCreateRequestBody = TypeOf<ReturnType<typeof getCreateRequestBodySchema>>;
/** The response body type for creating a dashboard. */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,6 @@ import {

const MAX_PANELS = 100;

export const allowUnmappedKeysSchema = schema.boolean({
defaultValue: false,
meta: {
deprecated: true,
description:
'When enabled, dashboard REST endpoints support unmapped keys. Unmapped key schemas can be changed or removed without notice and are not supported.',
},
});

export const panelGridSchema = schema.object({
x: schema.number({ meta: { description: 'The x coordinate of the panel in grid units' } }),
y: schema.number({ meta: { description: 'The y coordinate of the panel in grid units' } }),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,13 +36,13 @@ export function registerDeleteRoute(router: VersionedRouter<RequestHandlerContex
},
response: {
200: {
description: 'Indicates the dashboard is deleted successfully',
description: 'deleted',
},
403: {
description: 'Indicates that this call is forbidden.',
description: 'forbidden',
},
404: {
description: 'Indicates that the dashboard with the given ID is not found.',
description: 'not found',
},
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,13 @@ export function registerReadRoute(
response: {
200: {
body: () => getReadResponseBodySchema(isDashboardAppRequest),
description: 'Indicates the dashboard with the given ID is retrieved successfully',
description: 'success',
},
403: {
description: 'Indicates that this call is forbidden.',
description: 'forbidden',
},
404: {
description: 'Indicates that the dashboard with the given ID is not found.',
description: 'not found',
},
},
}),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,17 @@ import type { Warnings } from './types';
export function getDashboardMeta(
savedObject:
| SavedObject<DashboardSavedObjectAttributes>
| SavedObjectsUpdateResponse<DashboardSavedObjectAttributes>,
operation: 'create' | 'read' | 'update' | 'search'
| SavedObjectsUpdateResponse<DashboardSavedObjectAttributes>
) {
return {
error: savedObject.error,
...(savedObject.created_at && { created_at: savedObject.created_at }),
...(savedObject.created_by && { created_by: savedObject.created_by }),
managed: savedObject.managed,
owner: savedObject.accessControl?.owner,
updated_at: savedObject.updated_at,
updated_by: savedObject.updated_by,
Comment thread
macroscopeapp[bot] marked this conversation as resolved.
version: savedObject.version ?? '',
...(['create', 'read', 'search'].includes(operation) && {
created_at: savedObject.created_at,
created_by: savedObject.created_by,
}),
};
}

Expand Down Expand Up @@ -80,7 +77,7 @@ export function getDashboardCRUResponseBody(
},
}),
},
meta: getDashboardMeta(savedObject, operation),
meta: getDashboardMeta(savedObject),
...(operation === 'read' && warnings?.length && { warnings }),
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ export function registerSearchRoute(router: VersionedRouter<RequestHandlerContex
response: {
200: {
body: () => searchResponseBodySchema,
description: 'Indicates the search is successful and the dashboards are retrieved',
description: 'success',
},
403: {
description: 'Indicates that this call is forbidden.',
description: 'forbidden',
},
},
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ export async function search(
}),
title: title ?? '',
},
meta: getDashboardMeta(so, 'search'),
meta: getDashboardMeta(so),
};
}),
page: soResponse.page,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@ import type { VersionedRouter } from '@kbn/core-http-server';
import type { RequestHandlerContext } from '@kbn/core/server';
import { schema } from '@kbn/config-schema';
import { once } from 'lodash';
import { asCodeIdSchema } from '@kbn/as-code-shared-schemas';
import { getRouteConfig } from '../get_route_config';
import { getUpdateRequestBodySchema, getUpdateResponseBodySchema } from './schemas';
import { update } from './update';
import { allowUnmappedKeysSchema, getDashboardStateSchema } from '../dashboard_state_schemas';
import { getDashboardStateSchema } from '../dashboard_state_schemas';

export function registerUpdateRoute(
router: VersionedRouter<RequestHandlerContext>,
Expand All @@ -23,7 +24,7 @@ export function registerUpdateRoute(
const { basePath, routeConfig, routeVersion } = getRouteConfig(isDashboardAppRequest);
const updateRoute = router.put({
path: `${basePath}/{id}`,
summary: `Replace current dashboard state with the dashboard state from request body.`,
summary: `Upsert dashboard`,
...routeConfig,
});

Expand All @@ -40,27 +41,21 @@ export function registerUpdateRoute(
validate: () => ({
request: {
params: schema.object({
id: schema.string({
meta: { description: 'A unique identifier for the dashboard.' },
}),
id: asCodeIdSchema,
}),
query: schema.maybe(
schema.object({
allowUnmappedKeys: schema.maybe(allowUnmappedKeysSchema),
})
),
body: getUpdateRequestBodySchema(isDashboardAppRequest),
},
response: {
200: {
body: () => getUpdateResponseBodySchema(isDashboardAppRequest),
description: 'Indicates the dashboard is updated successfully',
description: 'updated',
},
403: {
description: 'Indicates that this call is forbidden.',
201: {
body: () => getUpdateResponseBodySchema(isDashboardAppRequest),
description: 'created',
},
Comment thread
nickofthyme marked this conversation as resolved.
404: {
description: 'Indicates that the dashboard with the given ID is not found.',
403: {
description: 'forbidden',
},
},
}),
Expand All @@ -74,15 +69,10 @@ export function registerUpdateRoute(
req.body,
isDashboardAppRequest
);
return res.ok({ body: result });
return result.meta.updated_at === result.meta.created_at
? res.created({ body: result })
: res.ok({ body: result });
} catch (e) {
if (e.isBoom && e.output.statusCode === 404) {
return res.notFound({
body: {
message: `A dashboard with ID [${req.params.id}] was not found.`,
},
});
}
if (e.isBoom && e.output.statusCode === 403) {
return res.forbidden({ body: { message: e.message } });
}
Expand Down
Loading
Loading