@nocobase/plugin-flow-engine 2.2.0-beta.1 → 2.2.0-beta.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (72) hide show
  1. package/dist/client/index.js +1 -1
  2. package/dist/externalVersion.js +9 -9
  3. package/dist/locale/en-US.json +1 -0
  4. package/dist/locale/index.d.ts +2 -0
  5. package/dist/locale/zh-CN.json +1 -0
  6. package/dist/node_modules/@ant-design/icons-svg/package.json +1 -1
  7. package/dist/node_modules/acorn/package.json +1 -1
  8. package/dist/node_modules/acorn-jsx/package.json +1 -1
  9. package/dist/node_modules/acorn-walk/package.json +1 -1
  10. package/dist/node_modules/ses/package.json +1 -1
  11. package/dist/node_modules/zod/package.json +1 -1
  12. package/dist/server/flow-surfaces/{runjs-authoring/blocked-global-stop/index.d.ts → approval/authoring-validation.d.ts} +1 -2
  13. package/dist/server/flow-surfaces/approval/authoring-validation.js +1151 -0
  14. package/dist/server/flow-surfaces/approval/blueprint-service.js +2 -0
  15. package/dist/server/flow-surfaces/authoring-validation.d.ts +2 -1
  16. package/dist/server/flow-surfaces/authoring-validation.js +639 -59
  17. package/dist/server/flow-surfaces/blueprint/compile-blocks.js +7 -3
  18. package/dist/server/flow-surfaces/blueprint/compile-plan.js +19 -15
  19. package/dist/server/flow-surfaces/blueprint/export-document.d.ts +50 -0
  20. package/dist/server/flow-surfaces/blueprint/export-document.js +2510 -0
  21. package/dist/server/flow-surfaces/blueprint/normalize-document.js +2 -1
  22. package/dist/server/flow-surfaces/blueprint/public-types.d.ts +1 -0
  23. package/dist/server/flow-surfaces/builder.js +43 -5
  24. package/dist/server/flow-surfaces/catalog.js +13 -2
  25. package/dist/server/flow-surfaces/configure-options.js +5 -3
  26. package/dist/server/flow-surfaces/constants.d.ts +9 -2
  27. package/dist/server/flow-surfaces/constants.js +1 -0
  28. package/dist/server/flow-surfaces/contract-guard.js +37 -5
  29. package/dist/server/flow-surfaces/default-action-popup.d.ts +2 -0
  30. package/dist/server/flow-surfaces/default-action-popup.js +27 -13
  31. package/dist/server/flow-surfaces/filter-group.d.ts +19 -2
  32. package/dist/server/flow-surfaces/filter-group.js +232 -3
  33. package/dist/server/flow-surfaces/planning/compiler.d.ts +1 -0
  34. package/dist/server/flow-surfaces/planning/compiler.js +205 -82
  35. package/dist/server/flow-surfaces/planning/key-registry.d.ts +1 -1
  36. package/dist/server/flow-surfaces/planning/runtime.js +1 -0
  37. package/dist/server/flow-surfaces/planning/step-link.d.ts +1 -1
  38. package/dist/server/flow-surfaces/planning/step-link.js +22 -3
  39. package/dist/server/flow-surfaces/public-data-surface-default-filter.js +0 -9
  40. package/dist/server/flow-surfaces/reaction/field-value.d.ts +9 -0
  41. package/dist/server/flow-surfaces/reaction/field-value.js +51 -2
  42. package/dist/server/flow-surfaces/reaction/linkage.d.ts +6 -1
  43. package/dist/server/flow-surfaces/reaction/linkage.js +18 -3
  44. package/dist/server/flow-surfaces/reaction/meta.js +19 -1
  45. package/dist/server/flow-surfaces/reaction/types.d.ts +19 -0
  46. package/dist/server/flow-surfaces/relation-backing-foreign-key.d.ts +10 -0
  47. package/dist/server/flow-surfaces/relation-backing-foreign-key.js +79 -0
  48. package/dist/server/flow-surfaces/runjs-authoring/ast/source.d.ts +1 -0
  49. package/dist/server/flow-surfaces/runjs-authoring/ast/source.js +20 -0
  50. package/dist/server/flow-surfaces/runjs-authoring/rules.js +0 -2
  51. package/dist/server/flow-surfaces/runjs-authoring/runtime/constants.d.ts +0 -1
  52. package/dist/server/flow-surfaces/runjs-authoring/runtime/constants.js +11 -19
  53. package/dist/server/flow-surfaces/runjs-authoring/runtime/types.d.ts +0 -12
  54. package/dist/server/flow-surfaces/runjs-authoring/scan/filter.js +12 -2
  55. package/dist/server/flow-surfaces/runjs-authoring/scan/index.d.ts +0 -14
  56. package/dist/server/flow-surfaces/runjs-authoring/scan/index.js +10 -8
  57. package/dist/server/flow-surfaces/runjs-authoring/scan/source-patterns.d.ts +0 -14
  58. package/dist/server/flow-surfaces/runjs-authoring/scan/source-patterns.js +18 -73
  59. package/dist/server/flow-surfaces/runjs-authoring/types.d.ts +1 -1
  60. package/dist/server/flow-surfaces/runjs-authoring/validators/index.js +9 -53
  61. package/dist/server/flow-surfaces/service.d.ts +53 -0
  62. package/dist/server/flow-surfaces/service.js +997 -127
  63. package/dist/server/flow-surfaces/types.d.ts +2 -1
  64. package/dist/server/variables/records.js +7 -2
  65. package/dist/server/variables/registry.js +3 -0
  66. package/dist/swagger/flow-surfaces.d.ts +193 -0
  67. package/dist/swagger/flow-surfaces.examples.d.ts +11 -0
  68. package/dist/swagger/flow-surfaces.examples.js +11 -0
  69. package/dist/swagger/flow-surfaces.js +179 -10
  70. package/dist/swagger/index.d.ts +193 -0
  71. package/package.json +2 -2
  72. package/dist/server/flow-surfaces/runjs-authoring/blocked-global-stop/index.js +0 -40
@@ -45,7 +45,8 @@ export type FlowSurfaceConfigureOption = {
45
45
  type: FlowSurfaceConfigureOptionValueType;
46
46
  description?: string;
47
47
  enum?: Array<string | number | boolean>;
48
- example?: any;
48
+ example?: unknown;
49
+ default?: unknown;
49
50
  supportsFlowContext?: boolean;
50
51
  };
51
52
  export type FlowSurfaceConfigureOptions = Record<string, FlowSurfaceConfigureOption>;
@@ -63,9 +63,14 @@ function mergeFieldsWithExtras(fields, extras = []) {
63
63
  if (!Array.isArray(fields) || fields.length === 0 || extras.length === 0) return fields;
64
64
  return uniqStrings([...fields, ...extras]);
65
65
  }
66
+ function toJsonRecord(record) {
67
+ if (!record || typeof record !== "object") return record;
68
+ const toJSON = record.toJSON;
69
+ return typeof toJSON === "function" ? toJSON.call(record) : record;
70
+ }
66
71
  function toJsonArray(rows) {
67
72
  if (!Array.isArray(rows)) return [];
68
- return rows.map((r) => (r == null ? void 0 : r.toJSON) ? r.toJSON() : r);
73
+ return rows.map(toJsonRecord);
69
74
  }
70
75
  function reorderRecordsByFilterByTk(records, filterByTk, options) {
71
76
  if (!Array.isArray(filterByTk) || filterByTk.length === 0) return records;
@@ -110,7 +115,7 @@ async function fetchRecordOrRecordsJson(repo, params) {
110
115
  const rec = await repo.findOne(
111
116
  preferFullRecord ? { filterByTk } : { filterByTk, fields, appends }
112
117
  );
113
- return rec ? rec.toJSON() : void 0;
118
+ return rec ? toJsonRecord(rec) : void 0;
114
119
  }
115
120
  // Annotate the CommonJS export names for ESM import in node:
116
121
  0 && (module.exports = {
@@ -89,6 +89,9 @@ class VariableRegistry {
89
89
  }
90
90
  const GLOBAL_KEY = "__ncbVarRegistry__";
91
91
  const g = typeof globalThis !== "undefined" ? globalThis : global;
92
+ if (g[GLOBAL_KEY] && typeof g[GLOBAL_KEY] === "object") {
93
+ Object.setPrototypeOf(g[GLOBAL_KEY], VariableRegistry.prototype);
94
+ }
92
95
  if (!g[GLOBAL_KEY]) {
93
96
  g[GLOBAL_KEY] = new VariableRegistry();
94
97
  }
@@ -2635,6 +2635,10 @@ declare const _default: {
2635
2635
  FlowSurfaceApplyBlueprintNavigation: {
2636
2636
  type: string;
2637
2637
  properties: {
2638
+ layoutUid: {
2639
+ type: string;
2640
+ description: string;
2641
+ };
2638
2642
  group: {
2639
2643
  $ref: string;
2640
2644
  };
@@ -3148,6 +3152,10 @@ declare const _default: {
3148
3152
  type: string;
3149
3153
  required: string[];
3150
3154
  properties: {
3155
+ layoutUid: {
3156
+ type: string;
3157
+ description: string;
3158
+ };
3151
3159
  title: {
3152
3160
  type: string;
3153
3161
  };
@@ -3270,6 +3278,10 @@ declare const _default: {
3270
3278
  FlowSurfaceCreatePageRequest: {
3271
3279
  type: string;
3272
3280
  properties: {
3281
+ layoutUid: {
3282
+ type: string;
3283
+ description: string;
3284
+ };
3273
3285
  menuRouteId: {
3274
3286
  oneOf: {
3275
3287
  type: string;
@@ -5763,6 +5775,186 @@ declare const _default: {
5763
5775
  };
5764
5776
  additionalProperties: boolean;
5765
5777
  };
5778
+ FlowSurfaceExportBlueprintUnsupportedPolicy: {
5779
+ type: string;
5780
+ enum: string[];
5781
+ description: string;
5782
+ };
5783
+ FlowSurfaceExportBlueprintUnsupportedItem: {
5784
+ type: string;
5785
+ required: string[];
5786
+ properties: {
5787
+ kind: {
5788
+ type: string;
5789
+ enum: string[];
5790
+ };
5791
+ use: {
5792
+ type: string;
5793
+ example: string;
5794
+ };
5795
+ type: {
5796
+ type: string;
5797
+ example: string;
5798
+ };
5799
+ path: {
5800
+ type: string;
5801
+ example: string;
5802
+ };
5803
+ reasonCode: {
5804
+ type: string;
5805
+ example: string;
5806
+ };
5807
+ manualAction: {
5808
+ type: string;
5809
+ example: string;
5810
+ };
5811
+ };
5812
+ additionalProperties: boolean;
5813
+ };
5814
+ FlowSurfaceExportBlueprintTarget: {
5815
+ oneOf: ({
5816
+ type: string;
5817
+ required: string[];
5818
+ properties: {
5819
+ uid: {
5820
+ type: string;
5821
+ };
5822
+ pageSchemaUid?: undefined;
5823
+ tabSchemaUid?: undefined;
5824
+ routeId?: undefined;
5825
+ };
5826
+ additionalProperties: boolean;
5827
+ } | {
5828
+ type: string;
5829
+ required: string[];
5830
+ properties: {
5831
+ pageSchemaUid: {
5832
+ type: string;
5833
+ };
5834
+ uid?: undefined;
5835
+ tabSchemaUid?: undefined;
5836
+ routeId?: undefined;
5837
+ };
5838
+ additionalProperties: boolean;
5839
+ } | {
5840
+ type: string;
5841
+ required: string[];
5842
+ properties: {
5843
+ tabSchemaUid: {
5844
+ type: string;
5845
+ };
5846
+ uid?: undefined;
5847
+ pageSchemaUid?: undefined;
5848
+ routeId?: undefined;
5849
+ };
5850
+ additionalProperties: boolean;
5851
+ } | {
5852
+ type: string;
5853
+ required: string[];
5854
+ properties: {
5855
+ routeId: {
5856
+ type: string;
5857
+ };
5858
+ uid?: undefined;
5859
+ pageSchemaUid?: undefined;
5860
+ tabSchemaUid?: undefined;
5861
+ };
5862
+ additionalProperties: boolean;
5863
+ })[];
5864
+ description: string;
5865
+ };
5866
+ FlowSurfaceExportBlueprintRequest: {
5867
+ type: string;
5868
+ required: string[];
5869
+ properties: {
5870
+ target: {
5871
+ $ref: string;
5872
+ };
5873
+ options: {
5874
+ type: string;
5875
+ properties: {
5876
+ unsupported: {
5877
+ $ref: string;
5878
+ };
5879
+ };
5880
+ additionalProperties: boolean;
5881
+ };
5882
+ };
5883
+ additionalProperties: boolean;
5884
+ };
5885
+ FlowSurfaceExportBlueprintSource: {
5886
+ type: string;
5887
+ required: string[];
5888
+ properties: {
5889
+ target: {
5890
+ $ref: string;
5891
+ };
5892
+ pageTitle: {
5893
+ type: string;
5894
+ };
5895
+ };
5896
+ additionalProperties: boolean;
5897
+ };
5898
+ FlowSurfaceExportBlueprintDocument: {
5899
+ type: string;
5900
+ required: string[];
5901
+ description: string;
5902
+ properties: {
5903
+ version: {
5904
+ type: string;
5905
+ enum: string[];
5906
+ };
5907
+ mode: {
5908
+ type: string;
5909
+ enum: string[];
5910
+ };
5911
+ target: {
5912
+ $ref: string;
5913
+ };
5914
+ page: {
5915
+ $ref: string;
5916
+ };
5917
+ tabs: {
5918
+ type: string;
5919
+ minItems: number;
5920
+ items: {
5921
+ $ref: string;
5922
+ };
5923
+ };
5924
+ assets: {
5925
+ $ref: string;
5926
+ };
5927
+ reaction: {
5928
+ $ref: string;
5929
+ };
5930
+ };
5931
+ additionalProperties: boolean;
5932
+ };
5933
+ FlowSurfaceExportBlueprintResponse: {
5934
+ type: string;
5935
+ required: string[];
5936
+ properties: {
5937
+ document: {
5938
+ $ref: string;
5939
+ };
5940
+ source: {
5941
+ $ref: string;
5942
+ };
5943
+ warnings: {
5944
+ type: string;
5945
+ items: {
5946
+ type: string;
5947
+ };
5948
+ };
5949
+ unsupported: {
5950
+ type: string;
5951
+ items: {
5952
+ $ref: string;
5953
+ };
5954
+ };
5955
+ };
5956
+ additionalProperties: boolean;
5957
+ };
5766
5958
  FlowSurfaceMutateWriteTarget: {
5767
5959
  type: string;
5768
5960
  required: string[];
@@ -5922,6 +6114,7 @@ declare const _default: {
5922
6114
  };
5923
6115
  };
5924
6116
  example: {};
6117
+ default: {};
5925
6118
  supportsFlowContext: {
5926
6119
  type: string;
5927
6120
  };
@@ -28,6 +28,14 @@ export declare const flowSurfaceExamples: {
28
28
  expectedKind: string;
29
29
  }[];
30
30
  };
31
+ exportBlueprint: {
32
+ target: {
33
+ pageSchemaUid: string;
34
+ };
35
+ options: {
36
+ unsupported: string;
37
+ };
38
+ };
31
39
  applyBlueprint: {
32
40
  version: string;
33
41
  mode: string;
@@ -660,6 +668,7 @@ export declare const flowSurfaceExamples: {
660
668
  title: string;
661
669
  description: string;
662
670
  className: string;
671
+ showBlockCard: boolean;
663
672
  version: string;
664
673
  code: string;
665
674
  };
@@ -756,6 +765,7 @@ export declare const flowSurfaceExamples: {
756
765
  title: string;
757
766
  description: string;
758
767
  className: string;
768
+ showBlockCard: boolean;
759
769
  version: string;
760
770
  code: string;
761
771
  };
@@ -1060,6 +1070,7 @@ export declare const flowSurfaceExamples: {
1060
1070
  settings: {
1061
1071
  title: string;
1062
1072
  description: string;
1073
+ showBlockCard: boolean;
1063
1074
  version: string;
1064
1075
  code: string;
1065
1076
  };
@@ -106,6 +106,14 @@ const flowSurfaceExamples = {
106
106
  }
107
107
  ]
108
108
  },
109
+ exportBlueprint: {
110
+ target: {
111
+ pageSchemaUid: "employees-page-schema"
112
+ },
113
+ options: {
114
+ unsupported: "error"
115
+ }
116
+ },
109
117
  applyBlueprint: {
110
118
  version: "1",
111
119
  mode: "create",
@@ -885,6 +893,7 @@ const flowSurfaceExamples = {
885
893
  title: "Custom hero",
886
894
  description: "Rendered by JS block runtime",
887
895
  className: "hero-shell",
896
+ showBlockCard: true,
888
897
  version: "1.0.0",
889
898
  code: "ctx.render('<div>Hello from JS block</div>');"
890
899
  }
@@ -988,6 +997,7 @@ const flowSurfaceExamples = {
988
997
  title: "Users hero",
989
998
  description: "Rendered from FlowSurfaces configure",
990
999
  className: "users-hero",
1000
+ showBlockCard: true,
991
1001
  version: "1.0.1",
992
1002
  code: "ctx.render('<div>Users hero</div>');"
993
1003
  }
@@ -1333,6 +1343,7 @@ const flowSurfaceExamples = {
1333
1343
  settings: {
1334
1344
  title: "Users banner",
1335
1345
  description: "Custom JS rendered banner",
1346
+ showBlockCard: true,
1336
1347
  version: "1.0.0",
1337
1348
  code: "ctx.render('<div>Users banner</div>');"
1338
1349
  }
@@ -141,7 +141,11 @@ const APPLY_BLUEPRINT_BLOCK_TYPE_ENUM = [
141
141
  "jsBlock",
142
142
  "tree"
143
143
  ];
144
- const APPROVAL_BLUEPRINT_BLOCK_TYPE_ENUM = [...import_catalog_specs.APPROVAL_BLOCK_PUBLIC_KEYS];
144
+ const APPROVAL_BLUEPRINT_GENERIC_BLOCK_TYPE_ENUM = ["markdown", "jsBlock"];
145
+ const APPROVAL_BLUEPRINT_BLOCK_TYPE_ENUM = [
146
+ ...import_catalog_specs.APPROVAL_BLOCK_PUBLIC_KEYS,
147
+ ...APPROVAL_BLUEPRINT_GENERIC_BLOCK_TYPE_ENUM
148
+ ];
145
149
  const COMPOSE_BLOCK_TYPE_ENUM = [...APPLY_BLUEPRINT_BLOCK_TYPE_ENUM, ...import_catalog_specs.APPROVAL_BLOCK_PUBLIC_KEYS];
146
150
  const RELATION_FIELD_TYPE_ENUM = [
147
151
  "text",
@@ -496,7 +500,7 @@ function buildReactionCapabilitySchema(kind, ruleSchemaName, extraProperties = {
496
500
  additionalProperties: false
497
501
  };
498
502
  }
499
- const FLOW_SURFACES_READ_ACL_NOTE = "Read actions (`get` / `describeSurface` / `catalog` / `context` / `getReactionMeta` / `getEventFlowMeta` / `listTemplates` / `getTemplate`) are open to `loggedIn` by default. Write actions still require the `ui.flowSurfaces` snippet.";
503
+ const FLOW_SURFACES_READ_ACL_NOTE = "Read actions (`get` / `describeSurface` / `exportBlueprint` / `catalog` / `context` / `getReactionMeta` / `getEventFlowMeta` / `listTemplates` / `getTemplate`) are open to `loggedIn` by default. Write actions still require the `ui.flowSurfaces` snippet.";
500
504
  const templateActionDocs = (0, import_flow_surfaces2.createFlowSurfaceTemplateActionDocs)({
501
505
  tag: FLOW_SURFACES_TAG,
502
506
  readAclNote: FLOW_SURFACES_READ_ACL_NOTE,
@@ -606,11 +610,20 @@ const actionDocs = {
606
610
  requestBody: requestBody("FlowSurfaceDescribeSurfaceRequest", import_flow_surfaces.flowSurfaceExamples.describeSurface),
607
611
  responses: responses("FlowSurfaceDescribeSurfaceResponse")
608
612
  },
613
+ exportBlueprint: {
614
+ tags: [FLOW_SURFACES_TAG],
615
+ summary: "Export one root Modern page as an applyBlueprint replace document",
616
+ description: valuesCompatibilityNote(
617
+ `Exports an existing root flow page into a v1 \`FlowSurfaceApplyBlueprintDocument\` that can be sent back to \`flowSurfaces:applyBlueprint\` for same-instance \`replace\`. The request body uses \`{ target, options }\` and does not change the \`flowSurfaces:get\` GET query-locator contract. v1 only supports root page export; block, field, action, tab, and \`tabSchemaUid\` subtree targets return HTTP 400. The exported document intentionally omits \`navigation\` and does not expose raw \`tree\`, \`nodeMap\`, node uid, internal refs, or internal metadata. \`document.target.pageSchemaUid\` is retained for same-instance replace. ${FLOW_SURFACES_READ_ACL_NOTE}`
618
+ ),
619
+ requestBody: requestBody("FlowSurfaceExportBlueprintRequest", import_flow_surfaces.flowSurfaceExamples.exportBlueprint),
620
+ responses: responses("FlowSurfaceExportBlueprintResponse")
621
+ },
609
622
  applyBlueprint: {
610
623
  tags: [FLOW_SURFACES_TAG],
611
624
  summary: "Apply a page blueprint to create or replace one Modern page",
612
625
  description: valuesCompatibilityNote(
613
- `Accepts one simplified JSON page blueprint and compiles it to internal flow-surface operations. The public blueprint describes page structure (\`create\` or \`replace\`, page metadata, ordered tabs, blocks, fields, actions, inline popups, optional reusable assets) and optional top-level \`reaction.items[]\` for whole-page interaction authoring. Each reaction item targets an explicit local key / bind key produced by the same blueprint run. Only explicitly listed reaction items are written. \`rules: []\` clears the targeted slot. Repeating the same \`(type, target)\` reaction slot in one blueprint is invalid. In \`replace\`, reaction targets always bind to the newly produced blueprint result, not historical nodes from the previous page version; if a slot must exist in the resulting surface, include it explicitly instead of relying on omission. Localized reaction edits on an existing surface should use \`getReactionMeta\` + \`set*Rules\` instead of applying a whole page blueprint again. The request body is that page-document JSON object itself and must not be JSON-stringified. Wrong: \`{ "requestBody": "{\\"version\\":\\"1\\"}" }\`. Internal planning details stay hidden. In \`create\`, \`navigation.group.routeId\` has the highest priority when targeting an existing menu group. If \`routeId\` is present, applyBlueprint ignores \`title\`, \`icon\`, \`tooltip\`, and \`hideInMenu\` on \`navigation.group\`; applyBlueprint create mode does not mutate existing group metadata, so callers should use \`updateMenu\` separately when that is required. When \`routeId\` is omitted and \`navigation.group.title\` is provided, applyBlueprint reuses one existing same-title group when it is unique, creates a new group when none exists, and rejects ambiguous multi-match cases. Metadata such as \`icon\`, \`tooltip\`, and \`hideInMenu\` is used only when a new group is created and is ignored when an existing group is reused. \`replace\` uses \`target.pageSchemaUid\`, updates only the explicit page-level fields provided in \`page\`, maps blueprint tabs to existing route-backed tab slots by index, rewrites each slot in order, removes trailing old tabs, and appends extra new tabs when needed. Tab and block keys are optional in the public blueprint; omit them unless custom layout or cross-block targeting needs a stable in-document identifier. \`layout\` is only allowed on tabs and inline popup documents; blocks themselves do not accept a \`layout\` property. Public applyBlueprint blocks do not support generic \`form\`; use \`editForm\` or \`createForm\`. AI employee actions use \`type: "aiEmployee"\` plus public \`settings.username\`, \`workContext\`, \`tasks\`, \`auto\`, and \`style\`; work context may target \`self\` or a same-blueprint block key and is persisted as real Flow Model \`uid\` values. For JS blocks/fields/actions, \`script\` is a non-empty string asset key into \`assets.scripts\`; put inline JS in \`settings.code\` and \`settings.version\`. Direct \`table\` / \`list\` / \`gridCard\` / \`calendar\` / \`kanban\` blocks may omit \`defaultFilter\`; the backend generates one from live metadata with up to 4 scalar/filterable fields. Explicit values must contain at least the smaller of 3 and the collection eligible-field count, and values with more than 4 fields are truncated before persistence. A valid explicit or generated block-level value backfills the default \`filter\` action \`settings.defaultFilter\`; explicit filter-action \`settings.defaultFilter\` still wins. ${TREE_TABLE_RECORD_ACTION_DEFAULTS_NOTE} ${APPLY_BLUEPRINT_TREE_TABLE_TITLE_FIELD_NOTE} Inline popup documents may set \`popup.tryTemplate=true\` to ask the backend for the best compatible popup template before falling back to local popup content. Inline popup documents may also combine \`popup.tryTemplate\` with \`popup.saveAsTemplate={ name, description, local? }\`: a hit binds the matched template immediately and lets later inline popups in the same blueprint reuse that final bound template through \`popup.template={ local, mode }\`, while a miss requires explicit local \`popup.blocks\` so the fallback popup can be saved and reused. Custom \`edit\` popups that provide \`popup.blocks\` must include exactly one \`editForm\` block; that \`editForm\` may omit \`resource\` and then inherits the opener's current-record context. When layout is omitted, applyBlueprint auto-generates a simple top-to-bottom layout. When a \`replace\` run expands a page to multiple tabs while the current page still has \`enableTabs=false\`, callers must set \`page.enableTabs=true\` explicitly. The response hides execution internals and returns only the resolved page target and final surface readback.`
626
+ `Accepts one simplified JSON page blueprint and compiles it to internal flow-surface operations. The public blueprint describes page structure (\`create\` or \`replace\`, page metadata, ordered tabs, blocks, fields, actions, inline popups, optional reusable assets) and optional top-level \`reaction.items[]\` for whole-page interaction authoring. Each reaction item targets an explicit local key / bind key produced by the same blueprint run. Only explicitly listed reaction items are written. \`rules: []\` clears the targeted slot. Repeating the same \`(type, target)\` reaction slot in one blueprint is invalid. In \`replace\`, reaction targets always bind to the newly produced blueprint result, not historical nodes from the previous page version; if a slot must exist in the resulting surface, include it explicitly instead of relying on omission. Localized reaction edits on an existing surface should use \`getReactionMeta\` + \`set*Rules\` instead of applying a whole page blueprint again. The request body is that page-document JSON object itself and must not be JSON-stringified. Wrong: \`{ "requestBody": "{\\"version\\":\\"1\\"}" }\`. Internal planning details stay hidden. In \`create\`, \`navigation.layoutUid\` optionally scopes menu group reuse, duplicate page identity checks, and newly created routes to an enabled UI layout such as \`admin-layout-model\` or \`mobile-layout-model\`; when the target layout type is mobile, applyBlueprint ignores \`navigation.group\` and creates a root-level mobile tab page. When \`layoutUid\` is omitted, routes keep the existing admin/default inheritance behavior. In non-mobile \`create\`, \`navigation.group.routeId\` has the highest priority when targeting an existing menu group. If \`routeId\` is present, applyBlueprint ignores \`title\`, \`icon\`, \`tooltip\`, and \`hideInMenu\` on \`navigation.group\`; applyBlueprint create mode does not mutate existing group metadata, so callers should use \`updateMenu\` separately when that is required. When \`routeId\` is omitted and \`navigation.group.title\` is provided, applyBlueprint reuses one existing same-title group in the target layout when it is unique, creates a new group when none exists, and rejects ambiguous multi-match cases. Metadata such as \`icon\`, \`tooltip\`, and \`hideInMenu\` is used only when a new group is created and is ignored when an existing group is reused. \`replace\` uses \`target.pageSchemaUid\`, updates only the explicit page-level fields provided in \`page\`, maps blueprint tabs to existing route-backed tab slots by index, rewrites each slot in order, removes trailing old tabs, and appends extra new tabs when needed. Tab and block keys are optional in the public blueprint; omit them unless custom layout or cross-block targeting needs a stable in-document identifier. \`layout\` is only allowed on tabs and inline popup documents; blocks themselves do not accept a \`layout\` property. Public applyBlueprint blocks do not support generic \`form\`; use \`editForm\` or \`createForm\`. AI employee actions use \`type: "aiEmployee"\` plus public \`settings.username\`, \`workContext\`, \`tasks\`, \`auto\`, and \`style\`; work context may target \`self\` or a same-blueprint block key and is persisted as real Flow Model \`uid\` values. For JS blocks/fields/actions, \`script\` is a non-empty string asset key into \`assets.scripts\`; put inline JS in \`settings.code\` and \`settings.version\`. Direct \`table\` / \`list\` / \`gridCard\` / \`calendar\` / \`kanban\` blocks may omit \`defaultFilter\`; the backend generates one from live metadata with up to 4 scalar/filterable fields. Explicit values must contain at least the smaller of 3 and the collection eligible-field count, and values with more than 4 fields are truncated before persistence. A valid explicit or generated block-level value backfills the default \`filter\` action \`settings.defaultFilter\`; explicit filter-action \`settings.defaultFilter\` still wins. ${TREE_TABLE_RECORD_ACTION_DEFAULTS_NOTE} ${APPLY_BLUEPRINT_TREE_TABLE_TITLE_FIELD_NOTE} Inline popup documents may set \`popup.tryTemplate=true\` to ask the backend for the best compatible popup template before falling back to local popup content. Inline popup documents may also combine \`popup.tryTemplate\` with \`popup.saveAsTemplate={ name, description, local? }\`: a hit binds the matched template immediately and lets later inline popups in the same blueprint reuse that final bound template through \`popup.template={ local, mode }\`, while a miss requires explicit local \`popup.blocks\` so the fallback popup can be saved and reused. Custom \`edit\` popups that provide \`popup.blocks\` must include exactly one \`editForm\` block; that \`editForm\` may omit \`resource\` and then inherits the opener's current-record context. When layout is omitted, applyBlueprint auto-generates a simple top-to-bottom layout. When a \`replace\` run expands a page to multiple tabs while the current page still has \`enableTabs=false\`, callers must set \`page.enableTabs=true\` explicitly. The response hides execution internals and returns only the resolved page target and final surface readback.`
614
627
  ),
615
628
  requestBody: {
616
629
  required: true,
@@ -641,7 +654,7 @@ const actionDocs = {
641
654
  tags: [FLOW_SURFACES_TAG],
642
655
  summary: "Apply an approval blueprint to initiator, approver, or task-card surfaces",
643
656
  description: valuesCompatibilityNote(
644
- "Builds workflow-approval configuration surfaces through the existing flowSurfaces orchestration layer instead of a separate approval resource. This is the preferred whole-surface bootstrap / replace entry for approval initiator, approver, and task-card UIs. Unlike route-backed `applyBlueprint`, this action targets approval-bound FlowModel roots stored on approval workflow trigger config (`workflow.config.approvalUid` / `workflow.config.taskCardUid`) or approval node config (`node.config.approvalUid` / `node.config.taskCardUid`). The backend creates or reuses the correct approval root automatically, rewrites the binding uid, applies a `replace` blueprint to that root, and reconciles approval runtime config derived from approval actions such as withdraw / approve / reject / return / delegate / add-assignee. `surface='initiator'` requires `workflowId` and writes page-like `blocks + layout` into `TriggerChildPageModel -> TriggerChildPageTabModel -> TriggerBlockGridModel`. `surface='approver'` requires `nodeId` and writes page-like `blocks + layout` into `ApprovalChildPageModel -> ApprovalChildPageTabModel -> ApprovalBlockGridModel`. Page-like `blocks[]` may either declare a concrete `type` or reuse a saved block template through `template: { uid, mode }`. `surface='taskCard'` requires exactly one of `workflowId` or `nodeId` and writes `fields + layout` into `ApplyTaskCardDetailsModel` or `ApprovalTaskCardDetailsModel`. This v1 action does not cover legacy schema-config wiring; it focuses on approval FlowModel construction, binding persistence, and approval runtime-config synchronization. When `layout` is omitted, the backend generates a simple top-to-bottom layout for the resulting blocks or fields."
657
+ "Builds workflow-approval configuration surfaces through the existing flowSurfaces orchestration layer instead of a separate approval resource. This is the preferred whole-surface bootstrap / replace entry for approval initiator, approver, and task-card UIs. Unlike route-backed `applyBlueprint`, this action targets approval-bound FlowModel roots stored on approval workflow trigger config (`workflow.config.approvalUid` / `workflow.config.taskCardUid`) or approval node config (`node.config.approvalUid` / `node.config.taskCardUid`). The backend creates or reuses the correct approval root automatically, rewrites the binding uid, applies a `replace` blueprint to that root, and reconciles approval runtime config derived from approval actions such as withdraw / approve / reject / return / delegate / add-assignee. `surface='initiator'` requires `workflowId` and writes page-like `blocks + layout` into `TriggerChildPageModel -> TriggerChildPageTabModel -> TriggerBlockGridModel`. `approvalInitiator` creates `approvalSubmit` by default; do not include `approvalSubmit` in `blocks[].actions`, otherwise authoring validation returns aggregate `errors[]` and the same write must be retried after removing it. `surface='approver'` requires `nodeId` and writes page-like `blocks + layout` into `ApprovalChildPageModel -> ApprovalChildPageTabModel -> ApprovalBlockGridModel`. Page-like `blocks[]` may declare approval-specific block types, fixed generic block types (`markdown`, `jsBlock`), or reuse a saved block template through `template: { uid, mode }`. `surface='taskCard'` requires exactly one of `workflowId` or `nodeId` and writes `fields + layout` into `ApplyTaskCardDetailsModel` or `ApprovalTaskCardDetailsModel`. This v1 action does not cover legacy schema-config wiring; it focuses on approval FlowModel construction, binding persistence, and approval runtime-config synchronization. When `layout` is omitted, the backend generates a simple top-to-bottom layout for the resulting blocks or fields."
645
658
  ),
646
659
  requestBody: {
647
660
  required: true,
@@ -796,7 +809,7 @@ const actionDocs = {
796
809
  tags: [FLOW_SURFACES_TAG],
797
810
  summary: "Create a group menu or a bindable V2 menu item",
798
811
  description: valuesCompatibilityNote(
799
- 'Creates a FlowSurfaces menu node. `type="group"` creates a menu group. `type="item"` creates a menu item that can be bound to a modern page (v2), and automatically fills in the flowPage route, the default hidden tab route, and the RootPageModel anchor.'
812
+ 'Creates a FlowSurfaces menu node. `type="group"` creates a menu group. `type="item"` creates a menu item that can be bound to a modern page (v2), and automatically fills in the flowPage route, the default hidden tab route, and the RootPageModel anchor. Optional `layoutUid` scopes the route to an enabled UI layout; omitted values keep the existing parent/default admin layout inheritance.'
800
813
  ),
801
814
  requestBody: requestBody("FlowSurfaceCreateMenuRequest", import_flow_surfaces.flowSurfaceExamples.createMenu),
802
815
  responses: responses("FlowSurfaceCreateMenuResult")
@@ -814,7 +827,7 @@ const actionDocs = {
814
827
  tags: [FLOW_SURFACES_TAG],
815
828
  summary: "Initialize a modern page for an existing bindable menu item",
816
829
  description: valuesCompatibilityNote(
817
- "Initializes a modern page (v2) for an existing bindable menu item through `menuRouteId` first, and fills in the default BlockGridModel. In compatibility mode, if `menuRouteId` is omitted, the old behavior still applies and a top-level menu plus page will be created automatically. Before initialization, do not call page/tab lifecycle actions such as `addTab`, `updateTab`, `moveTab`, `removeTab`, or `destroyPage`."
830
+ "Initializes a modern page (v2) for an existing bindable menu item through `menuRouteId` first, and fills in the default BlockGridModel. Optional `layoutUid` asserts that the existing menu route belongs to the target UI layout; omitted values keep the existing parent/default admin layout inheritance. In compatibility mode, if `menuRouteId` is omitted, the old behavior still applies and a top-level menu plus page will be created automatically. Before initialization, do not call page/tab lifecycle actions such as `addTab`, `updateTab`, `moveTab`, `removeTab`, or `destroyPage`."
818
831
  ),
819
832
  requestBody: requestBody("FlowSurfaceCreatePageRequest", import_flow_surfaces.flowSurfaceExamples.createPage),
820
833
  responses: responses("FlowSurfaceCreatePageResult")
@@ -1345,6 +1358,149 @@ const schemas = {
1345
1358
  },
1346
1359
  additionalProperties: false
1347
1360
  },
1361
+ FlowSurfaceExportBlueprintUnsupportedPolicy: {
1362
+ type: "string",
1363
+ enum: ["error", "warn"],
1364
+ description: "`error` rejects visible nodes the v1 mapper cannot express. `warn` skips them and reports warnings/unsupported items."
1365
+ },
1366
+ FlowSurfaceExportBlueprintUnsupportedItem: {
1367
+ type: "object",
1368
+ required: ["kind", "path", "reasonCode", "manualAction"],
1369
+ properties: {
1370
+ kind: {
1371
+ type: "string",
1372
+ enum: ["page", "tab", "block", "field", "action", "recordAction", "reaction", "layout", "popup"]
1373
+ },
1374
+ use: {
1375
+ type: "string",
1376
+ example: "UnknownModel"
1377
+ },
1378
+ type: {
1379
+ type: "string",
1380
+ example: "unknown"
1381
+ },
1382
+ path: {
1383
+ type: "string",
1384
+ example: "$.tabs[0].blocks[2]"
1385
+ },
1386
+ reasonCode: {
1387
+ type: "string",
1388
+ example: "unsupported-node"
1389
+ },
1390
+ manualAction: {
1391
+ type: "string",
1392
+ example: "Recreate this block manually or add mapper support."
1393
+ }
1394
+ },
1395
+ additionalProperties: false
1396
+ },
1397
+ FlowSurfaceExportBlueprintTarget: {
1398
+ oneOf: [
1399
+ {
1400
+ type: "object",
1401
+ required: ["uid"],
1402
+ properties: {
1403
+ uid: { type: "string" }
1404
+ },
1405
+ additionalProperties: false
1406
+ },
1407
+ {
1408
+ type: "object",
1409
+ required: ["pageSchemaUid"],
1410
+ properties: {
1411
+ pageSchemaUid: { type: "string" }
1412
+ },
1413
+ additionalProperties: false
1414
+ },
1415
+ {
1416
+ type: "object",
1417
+ required: ["tabSchemaUid"],
1418
+ properties: {
1419
+ tabSchemaUid: { type: "string" }
1420
+ },
1421
+ additionalProperties: false
1422
+ },
1423
+ {
1424
+ type: "object",
1425
+ required: ["routeId"],
1426
+ properties: {
1427
+ routeId: { type: "string" }
1428
+ },
1429
+ additionalProperties: false
1430
+ }
1431
+ ],
1432
+ description: "Exactly one root locator. v1 accepts pageSchemaUid, routeId, or a uid that resolves to the root page. tabSchemaUid and non-root uid targets return HTTP 400."
1433
+ },
1434
+ FlowSurfaceExportBlueprintRequest: {
1435
+ type: "object",
1436
+ required: ["target"],
1437
+ properties: {
1438
+ target: ref("FlowSurfaceExportBlueprintTarget"),
1439
+ options: {
1440
+ type: "object",
1441
+ properties: {
1442
+ unsupported: ref("FlowSurfaceExportBlueprintUnsupportedPolicy")
1443
+ },
1444
+ additionalProperties: false
1445
+ }
1446
+ },
1447
+ additionalProperties: false
1448
+ },
1449
+ FlowSurfaceExportBlueprintSource: {
1450
+ type: "object",
1451
+ required: ["target"],
1452
+ properties: {
1453
+ target: ref("FlowSurfaceApplyBlueprintTarget"),
1454
+ pageTitle: {
1455
+ type: "string"
1456
+ }
1457
+ },
1458
+ additionalProperties: false
1459
+ },
1460
+ FlowSurfaceExportBlueprintDocument: {
1461
+ type: "object",
1462
+ required: ["version", "mode", "target", "tabs", "assets"],
1463
+ description: "Prepared v1 applyBlueprint document in replace mode. It intentionally omits navigation and retains target.pageSchemaUid for same-instance replace.",
1464
+ properties: {
1465
+ version: {
1466
+ type: "string",
1467
+ enum: ["1"]
1468
+ },
1469
+ mode: {
1470
+ type: "string",
1471
+ enum: ["replace"]
1472
+ },
1473
+ target: ref("FlowSurfaceApplyBlueprintTarget"),
1474
+ page: ref("FlowSurfaceApplyBlueprintPage"),
1475
+ tabs: {
1476
+ type: "array",
1477
+ minItems: 1,
1478
+ items: ref("FlowSurfaceApplyBlueprintTab")
1479
+ },
1480
+ assets: ref("FlowSurfaceApplyBlueprintAssets"),
1481
+ reaction: ref("FlowSurfaceApplyBlueprintReaction")
1482
+ },
1483
+ additionalProperties: false
1484
+ },
1485
+ FlowSurfaceExportBlueprintResponse: {
1486
+ type: "object",
1487
+ required: ["document", "source", "warnings", "unsupported"],
1488
+ properties: {
1489
+ document: ref("FlowSurfaceExportBlueprintDocument"),
1490
+ source: ref("FlowSurfaceExportBlueprintSource"),
1491
+ warnings: {
1492
+ type: "array",
1493
+ items: {
1494
+ type: "string"
1495
+ }
1496
+ },
1497
+ unsupported: {
1498
+ type: "array",
1499
+ items: ref("FlowSurfaceExportBlueprintUnsupportedItem")
1500
+ }
1501
+ },
1502
+ additionalProperties: false
1503
+ },
1348
1504
  FlowSurfaceMutateWriteTarget: {
1349
1505
  type: "object",
1350
1506
  required: ["uid"],
@@ -1486,6 +1642,7 @@ const schemas = {
1486
1642
  }
1487
1643
  },
1488
1644
  example: {},
1645
+ default: {},
1489
1646
  supportsFlowContext: {
1490
1647
  type: "boolean"
1491
1648
  }
@@ -4010,11 +4167,11 @@ const schemas = {
4010
4167
  properties: {
4011
4168
  routeId: {
4012
4169
  ...STRING_OR_INTEGER_SCHEMA,
4013
- description: "Preferred existing menu-group route id. When present, routeId has the highest priority and title/icon/tooltip/hideInMenu are ignored. applyBlueprint create mode does not mutate existing group metadata; use low-level updateMenu separately when needed."
4170
+ description: "Preferred existing menu-group route id for non-mobile create mode. When present, routeId has the highest priority and title/icon/tooltip/hideInMenu are ignored. Ignored when navigation.layoutUid targets a mobile layout because mobile pages are created as root tabs. applyBlueprint create mode does not mutate existing group metadata; use low-level updateMenu separately when needed."
4014
4171
  },
4015
4172
  title: {
4016
4173
  type: "string",
4017
- description: "Group title for create mode. When `routeId` is omitted, applyBlueprint reuses a same-title group if the match is unique, creates one when no group exists, and rejects ambiguous multi-match cases. If an existing group is reused, group metadata is ignored; use low-level updateMenu to change existing group metadata."
4174
+ description: "Group title for non-mobile create mode. When `routeId` is omitted, applyBlueprint reuses a same-title group if the match is unique, creates one when no group exists, and rejects ambiguous multi-match cases. Ignored when navigation.layoutUid targets a mobile layout because mobile pages are created as root tabs. If an existing group is reused, group metadata is ignored; use low-level updateMenu to change existing group metadata."
4018
4175
  },
4019
4176
  icon: {
4020
4177
  type: "string",
@@ -4034,6 +4191,10 @@ const schemas = {
4034
4191
  FlowSurfaceApplyBlueprintNavigation: {
4035
4192
  type: "object",
4036
4193
  properties: {
4194
+ layoutUid: {
4195
+ type: "string",
4196
+ description: "Optional enabled UI layout uid that scopes create-mode route lookup and newly created routes. Use `mobile-layout-model` for mobile pages; mobile layouts ignore navigation.group and create a root-level tab page. When omitted, the server preserves the existing parent/default admin layout behavior."
4197
+ },
4037
4198
  group: ref("FlowSurfaceApplyBlueprintNavigationGroup"),
4038
4199
  item: {
4039
4200
  type: "object",
@@ -4249,7 +4410,7 @@ const schemas = {
4249
4410
  FlowSurfaceApplyBlueprintRequest: {
4250
4411
  type: "object",
4251
4412
  required: ["mode", "tabs"],
4252
- description: `Simplified page-structure request object for applyBlueprint. \`version\` may be omitted and defaults to '1'. Runtime validation enforces mode-specific rules: create does not accept target, while replace requires target.pageSchemaUid and does not use navigation. For JS blocks/fields/actions, \`script\` is a non-empty string asset key into \`assets.scripts\`, and referenced script assets must provide non-empty \`code\`; put inline JS in \`settings.code\` and \`settings.version\`. ${TREE_TABLE_RECORD_ACTION_DEFAULTS_NOTE} ${APPLY_BLUEPRINT_TREE_TABLE_TITLE_FIELD_NOTE} \`defaults.collections\` may provide main data-source collection-level fieldGroups, popup metadata with required \`name\` and \`description\`, and formBehavior for generated default add/edit popup forms; use \`defaults.dataSources.<dataSourceKey>.collections\` for external data sources. v1 does not support \`defaults.blocks\`.`,
4413
+ description: `Simplified page-structure request object for applyBlueprint. \`version\` may be omitted and defaults to '1'. Runtime validation enforces mode-specific rules: create does not accept target, while replace requires target.pageSchemaUid and does not use navigation. In create mode, \`navigation.layoutUid\` scopes menu group reuse, duplicate page identity, and newly created routes to the target layout; use \`mobile-layout-model\` for mobile pages, where \`navigation.group\` is ignored and the page is created as a root tab, and omit it for default admin behavior. For JS blocks/fields/actions, \`script\` is a non-empty string asset key into \`assets.scripts\`, and referenced script assets must provide non-empty \`code\`; put inline JS in \`settings.code\` and \`settings.version\`. ${TREE_TABLE_RECORD_ACTION_DEFAULTS_NOTE} ${APPLY_BLUEPRINT_TREE_TABLE_TITLE_FIELD_NOTE} \`defaults.collections\` may provide main data-source collection-level fieldGroups, popup metadata with required \`name\` and \`description\`, and formBehavior for generated default add/edit popup forms; use \`defaults.dataSources.<dataSourceKey>.collections\` for external data sources. v1 does not support \`defaults.blocks\`.`,
4253
4414
  properties: {
4254
4415
  version: {
4255
4416
  type: "string",
@@ -4336,7 +4497,7 @@ const schemas = {
4336
4497
  FlowSurfaceApplyApprovalBlueprintRequest: {
4337
4498
  type: "object",
4338
4499
  required: ["surface"],
4339
- description: "Simplified approval-surface blueprint request for workflow approval UIs. This is the preferred bootstrap / replace route for approval initiator, approver, and task-card surfaces. `version` may be omitted and defaults to '1'. `mode` may be omitted and defaults to `replace`; v1 only supports `replace`. Runtime validation enforces binding rules: `initiator` requires `workflowId`, `approver` requires `nodeId`, and `taskCard` requires exactly one of `workflowId` or `nodeId`. Page-like surfaces (`initiator`, `approver`) accept `blocks + layout`; each block may declare `type` directly or reuse `template: { uid, mode }`. `taskCard` accepts `fields + layout`. This route does not perform schema wiring, but it does persist binding fields and reconcile approval runtime config from approval actions.",
4500
+ description: "Simplified approval-surface blueprint request for workflow approval UIs. This is the preferred bootstrap / replace route for approval initiator, approver, and task-card surfaces. `version` may be omitted and defaults to '1'. `mode` may be omitted and defaults to `replace`; v1 only supports `replace`. Runtime validation enforces binding rules: `initiator` requires `workflowId`, `approver` requires `nodeId`, and `taskCard` requires exactly one of `workflowId` or `nodeId`. Page-like surfaces (`initiator`, `approver`) accept `blocks + layout`; each block may declare approval-specific types, fixed generic types (`markdown`, `jsBlock`), or reuse `template: { uid, mode }`. `approvalInitiator` creates `approvalSubmit` by default, so callers should only add optional initiator actions such as `approvalSaveDraft` or `approvalWithdraw`. `taskCard` accepts `fields + layout`. This route does not perform schema wiring, but it does persist binding fields and reconcile approval runtime config from approval actions. Authoring validation failures use the same aggregate `errors[]` retry contract as `applyBlueprint`.",
4340
4501
  properties: {
4341
4502
  version: {
4342
4503
  type: "string",
@@ -4421,6 +4582,10 @@ const schemas = {
4421
4582
  type: "object",
4422
4583
  required: ["title"],
4423
4584
  properties: {
4585
+ layoutUid: {
4586
+ type: "string",
4587
+ description: "Optional enabled UI layout uid for the created menu route, for example `mobile-layout-model`. When omitted, the route inherits its parent layout or the default admin layout."
4588
+ },
4424
4589
  title: {
4425
4590
  type: "string"
4426
4591
  },
@@ -4517,6 +4682,10 @@ const schemas = {
4517
4682
  FlowSurfaceCreatePageRequest: {
4518
4683
  type: "object",
4519
4684
  properties: {
4685
+ layoutUid: {
4686
+ type: "string",
4687
+ description: "Optional enabled UI layout uid. With `menuRouteId`, the existing route must already belong to this layout. Without `menuRouteId`, the compatibility create-menu fallback creates the route in this layout."
4688
+ },
4520
4689
  menuRouteId: STRING_OR_INTEGER_SCHEMA,
4521
4690
  pageSchemaUid: {
4522
4691
  type: "string"