From 72f1a6700184f5ae04086841418cac54b2d31789 Mon Sep 17 00:00:00 2001 From: Vladimir Stepanenko Date: Wed, 29 Oct 2025 15:13:16 +0300 Subject: [PATCH 01/10] Add editor charts api --- src/shared/components/public-api/utils/index.ts | 11 +++++++++++ src/shared/schema/us/types/fields.ts | 1 + 2 files changed, 12 insertions(+) create mode 100644 src/shared/components/public-api/utils/index.ts diff --git a/src/shared/components/public-api/utils/index.ts b/src/shared/components/public-api/utils/index.ts new file mode 100644 index 0000000000..b4b944fbce --- /dev/null +++ b/src/shared/components/public-api/utils/index.ts @@ -0,0 +1,11 @@ +const registeredComponents = new Set(); + +export const registerComponentId = (id: string): string => { + if (registeredComponents.has(id)) { + throw new Error(`OpenAPI component ${id} is already registered`); + } + + registeredComponents.add(id); + + return id; +}; diff --git a/src/shared/schema/us/types/fields.ts b/src/shared/schema/us/types/fields.ts index be2895ca45..96e2316536 100644 --- a/src/shared/schema/us/types/fields.ts +++ b/src/shared/schema/us/types/fields.ts @@ -7,6 +7,7 @@ export type EntryFieldPublishedId = null | string; // corresponds to RETURN_COLUMNS from US export interface EntryFields { + version?: number | null; displayAlias?: string | null; createdAt: string; createdBy: string; From 4db2cce802554fc10c300de5313d9c20562b7b75 Mon Sep 17 00:00:00 2001 From: Vladimir Stepanenko Date: Fri, 31 Oct 2025 15:25:57 +0300 Subject: [PATCH 02/10] Editor actions --- src/shared/schema/gateway-utils.ts | 35 +++++++++++++++++++++++++++++- 1 file changed, 34 insertions(+), 1 deletion(-) diff --git a/src/shared/schema/gateway-utils.ts b/src/shared/schema/gateway-utils.ts index d6ae312926..8f7765d1bd 100644 --- a/src/shared/schema/gateway-utils.ts +++ b/src/shared/schema/gateway-utils.ts @@ -23,7 +23,7 @@ const VALIDATION_SCHEMA_KEY = Symbol('$schema'); const registerValidationSchema = (value: T, schema: TypedActionSchema): T => { Object.defineProperty(value, VALIDATION_SCHEMA_KEY, { value: schema, - enumerable: false, + configurable: true, }); return value; @@ -62,6 +62,39 @@ export const createTypedAction = ( return registerValidationSchema(actionConfig, schemaValidationObject); }; +export const createExtendedAction = + ( + actionConfig: ApiServiceActionConfig< + AppContext, + Request, + Response, + TConfigOutput, + TConfigParams, + TConfigTransformed + >, + ) => + (schema: { + resultSchema: z.ZodType; + paramsSchema: z.ZodType; + }) => { + const schemaValidationObject = { + paramsSchema: schema.paramsSchema, + resultSchema: schema.resultSchema, + }; + + return registerValidationSchema( + actionConfig as unknown as ApiServiceActionConfig< + AppContext, + Request, + Response, + TConfigOutput, + TParams, + TResult + >, + schemaValidationObject, + ); + }; + type AuthArgsData = { userAccessToken?: string; serviceUserAccessToken?: string; From 138084f2044882f3de574ec11fd70b4a91e7b1e8 Mon Sep 17 00:00:00 2001 From: Vladimir Stepanenko Date: Fri, 31 Oct 2025 16:20:50 +0300 Subject: [PATCH 03/10] Editor actions --- src/shared/schema/gateway-utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shared/schema/gateway-utils.ts b/src/shared/schema/gateway-utils.ts index 8f7765d1bd..4cbc8331f2 100644 --- a/src/shared/schema/gateway-utils.ts +++ b/src/shared/schema/gateway-utils.ts @@ -62,7 +62,7 @@ export const createTypedAction = ( return registerValidationSchema(actionConfig, schemaValidationObject); }; -export const createExtendedAction = +export const createExtendedTypedAction = ( actionConfig: ApiServiceActionConfig< AppContext, From 23254226549faac1300c33b2224f1d2469dd4623 Mon Sep 17 00:00:00 2001 From: Vladimir Stepanenko Date: Fri, 31 Oct 2025 18:12:00 +0300 Subject: [PATCH 04/10] Editor actions --- .../components/public-api/utils/init-public-api-swagger.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/server/components/public-api/utils/init-public-api-swagger.ts b/src/server/components/public-api/utils/init-public-api-swagger.ts index acc8160618..3a8248c61b 100644 --- a/src/server/components/public-api/utils/init-public-api-swagger.ts +++ b/src/server/components/public-api/utils/init-public-api-swagger.ts @@ -93,6 +93,8 @@ export const initPublicApiSwagger = (app: ExpressKit) => { const swaggerOptions = { url: jsonPath, validatorUrl: null, + tagsSorter: 'alpha', + operationsSorter: 'alpha', }; app.express.use( From ec559a2cea171968e15bd640d066bd587f60dabb Mon Sep 17 00:00:00 2001 From: Vladimir Stepanenko Date: Sat, 1 Nov 2025 12:52:22 +0300 Subject: [PATCH 05/10] Editor actions --- src/shared/schema/mix/schemas/ql.ts | 2 +- src/shared/schema/mix/schemas/wizard.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shared/schema/mix/schemas/ql.ts b/src/shared/schema/mix/schemas/ql.ts index 2b548def92..3a05673d54 100644 --- a/src/shared/schema/mix/schemas/ql.ts +++ b/src/shared/schema/mix/schemas/ql.ts @@ -8,7 +8,7 @@ export const deleteQLChartResultSchema = z.object({}); export const getQLChartArgsSchema = z.strictObject({ chartId: z.string(), - workbookId: z.union([z.string(), z.null()]).optional(), + workbookId: z.string().nullable().optional(), revId: z.string().optional(), includePermissions: z.boolean().optional(), includeLinks: z.boolean().optional(), diff --git a/src/shared/schema/mix/schemas/wizard.ts b/src/shared/schema/mix/schemas/wizard.ts index 8f6bbc0458..96d45cb66a 100644 --- a/src/shared/schema/mix/schemas/wizard.ts +++ b/src/shared/schema/mix/schemas/wizard.ts @@ -8,7 +8,7 @@ export const deleteWizardChartResultSchema = z.object({}); export const getWizardChartArgsSchema = z.strictObject({ chartId: z.string(), - workbookId: z.union([z.string(), z.null()]).optional(), + workbookId: z.string().nullable().optional(), revId: z.string().optional(), includePermissions: z.boolean().optional(), includeLinks: z.boolean().optional(), From 8bfdd86cab838b34b86b5210991064bde5d98bbe Mon Sep 17 00:00:00 2001 From: Vladimir Stepanenko Date: Tue, 4 Nov 2025 14:28:34 +0300 Subject: [PATCH 06/10] Fix --- src/shared/schema/us/schemas/entries/list-directory.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/shared/schema/us/schemas/entries/list-directory.ts b/src/shared/schema/us/schemas/entries/list-directory.ts index aa4da12c68..e90c856be8 100644 --- a/src/shared/schema/us/schemas/entries/list-directory.ts +++ b/src/shared/schema/us/schemas/entries/list-directory.ts @@ -19,8 +19,7 @@ export const listDirectoryArgsSchema = z.object({ page: z.number().optional(), pageSize: z.number().optional(), includePermissionsInfo: z.boolean().optional(), - // Broken in US controller - // ignoreWorkbookEntries: z.boolean().optional(), + ignoreWorkbookEntries: z.boolean().optional(), }); export const listDirectoryBreadCrumbSchema = z.object({ From 7e7fdf1fa0469bd4400dbf2a9de45d1e622af45d Mon Sep 17 00:00:00 2001 From: Vladimir Stepanenko Date: Wed, 5 Nov 2025 14:22:45 +0300 Subject: [PATCH 07/10] Fix --- src/shared/utils/array/assert-non-empty-array.ts | 5 +++++ src/shared/utils/array/index.ts | 1 + 2 files changed, 6 insertions(+) create mode 100644 src/shared/utils/array/assert-non-empty-array.ts create mode 100644 src/shared/utils/array/index.ts diff --git a/src/shared/utils/array/assert-non-empty-array.ts b/src/shared/utils/array/assert-non-empty-array.ts new file mode 100644 index 0000000000..315304b9ca --- /dev/null +++ b/src/shared/utils/array/assert-non-empty-array.ts @@ -0,0 +1,5 @@ +export function assertNonEmptyArray(arr: T[]): asserts arr is [T, ...T[]] { + if (arr.length === 0) { + throw new Error('Array for discriminated union must not be empty'); + } +} diff --git a/src/shared/utils/array/index.ts b/src/shared/utils/array/index.ts new file mode 100644 index 0000000000..7c3135d54b --- /dev/null +++ b/src/shared/utils/array/index.ts @@ -0,0 +1 @@ +export {assertNonEmptyArray} from './assert-non-empty-array'; From c44486de0eafd5687ac9649e79bb9046344320c6 Mon Sep 17 00:00:00 2001 From: Vladimir Stepanenko Date: Wed, 5 Nov 2025 14:54:14 +0300 Subject: [PATCH 08/10] Fix --- src/shared/utils/array/assert-non-empty-array.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/shared/utils/array/assert-non-empty-array.ts b/src/shared/utils/array/assert-non-empty-array.ts index 315304b9ca..f74d567762 100644 --- a/src/shared/utils/array/assert-non-empty-array.ts +++ b/src/shared/utils/array/assert-non-empty-array.ts @@ -1,5 +1,5 @@ -export function assertNonEmptyArray(arr: T[]): asserts arr is [T, ...T[]] { +export function assertNonEmptyArray(arr: T[], message?: string): asserts arr is [T, ...T[]] { if (arr.length === 0) { - throw new Error('Array for discriminated union must not be empty'); + throw new Error(message ?? 'Array must not be empty!'); } } From e1aaaef5ce53f7d4be6a2fa4b0cf2cf14afe0726 Mon Sep 17 00:00:00 2001 From: Vladimir Stepanenko Date: Wed, 5 Nov 2025 15:30:21 +0300 Subject: [PATCH 09/10] Fix --- src/shared/schema/us/schemas/entries/list-directory.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/shared/schema/us/schemas/entries/list-directory.ts b/src/shared/schema/us/schemas/entries/list-directory.ts index e90c856be8..7b9f656e9d 100644 --- a/src/shared/schema/us/schemas/entries/list-directory.ts +++ b/src/shared/schema/us/schemas/entries/list-directory.ts @@ -19,7 +19,6 @@ export const listDirectoryArgsSchema = z.object({ page: z.number().optional(), pageSize: z.number().optional(), includePermissionsInfo: z.boolean().optional(), - ignoreWorkbookEntries: z.boolean().optional(), }); export const listDirectoryBreadCrumbSchema = z.object({ From 8ec88c7551fac24a7c72a0d9299bdbfceef00ecc Mon Sep 17 00:00:00 2001 From: Vladimir Stepanenko Date: Fri, 7 Nov 2025 12:37:10 +0300 Subject: [PATCH 10/10] Fix --- src/shared/schema/us/actions/editor.ts | 8 +++++++- src/shared/schema/us/types/editor.ts | 2 ++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/shared/schema/us/actions/editor.ts b/src/shared/schema/us/actions/editor.ts index 60a3bde311..86086e6741 100644 --- a/src/shared/schema/us/actions/editor.ts +++ b/src/shared/schema/us/actions/editor.ts @@ -16,6 +16,7 @@ export const editorActions = { path: () => `${PATH_PREFIX}/entries`, params: ( { + version, type, key, data, @@ -31,6 +32,7 @@ export const editorActions = { ) => { return { body: { + version, scope: 'widget', type, key, @@ -52,9 +54,13 @@ export const editorActions = { method: 'POST', path: ({entryId}) => `${PATH_PREFIX}/entries/${filterUrlFragment(entryId)}`, - params: ({data, mode, revId, meta = {}, links, annotation, description = ''}, headers) => { + params: ( + {version, data, mode, revId, meta = {}, links, annotation, description = ''}, + headers, + ) => { return { body: { + version, mode, meta, data, diff --git a/src/shared/schema/us/types/editor.ts b/src/shared/schema/us/types/editor.ts index bbef19e1ce..192af4b2eb 100644 --- a/src/shared/schema/us/types/editor.ts +++ b/src/shared/schema/us/types/editor.ts @@ -7,6 +7,7 @@ export interface CreateEditorChartResponse extends EntryFields { } export interface CreateEditorChartArgs { + version?: number; type: string; data: EntryFieldData; key?: string; @@ -24,6 +25,7 @@ export interface UpdateEditorChartResponse extends EntryFields { } export interface UpdateEditorChartArgs { + version?: number; entryId: string; mode: 'save' | 'publish'; data: EntryFieldData;