@nocobase/plugin-flow-engine 2.1.0-alpha.20 → 2.1.0-alpha.21

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 (50) hide show
  1. package/dist/externalVersion.js +11 -10
  2. package/dist/node_modules/ses/dist/ses.cjs +1 -1
  3. package/dist/node_modules/ses/package.json +1 -1
  4. package/dist/node_modules/zod/index.cjs +1 -1
  5. package/dist/node_modules/zod/package.json +1 -1
  6. package/dist/server/flow-surfaces/action-scope.d.ts +1 -0
  7. package/dist/server/flow-surfaces/action-scope.js +4 -0
  8. package/dist/server/flow-surfaces/apply/compiler.js +1 -1
  9. package/dist/server/flow-surfaces/approval/builder.js +8 -8
  10. package/dist/server/flow-surfaces/blueprint/compile-blocks.js +192 -29
  11. package/dist/server/flow-surfaces/blueprint/defaults.d.ts +26 -0
  12. package/dist/server/flow-surfaces/blueprint/defaults.js +133 -0
  13. package/dist/server/flow-surfaces/blueprint/index.d.ts +1 -1
  14. package/dist/server/flow-surfaces/blueprint/normalize-document.js +121 -1
  15. package/dist/server/flow-surfaces/blueprint/public-types.d.ts +32 -0
  16. package/dist/server/flow-surfaces/builder.d.ts +2 -2
  17. package/dist/server/flow-surfaces/builder.js +148 -50
  18. package/dist/server/flow-surfaces/catalog.js +276 -34
  19. package/dist/server/flow-surfaces/compose-compiler.d.ts +2 -0
  20. package/dist/server/flow-surfaces/compose-compiler.js +5 -1
  21. package/dist/server/flow-surfaces/configure-options.js +88 -12
  22. package/dist/server/flow-surfaces/contract-guard.js +60 -69
  23. package/dist/server/flow-surfaces/default-action-popup.d.ts +11 -1
  24. package/dist/server/flow-surfaces/default-action-popup.js +72 -12
  25. package/dist/server/flow-surfaces/default-block-actions.js +8 -1
  26. package/dist/server/flow-surfaces/filter-group.d.ts +15 -0
  27. package/dist/server/flow-surfaces/filter-group.js +94 -0
  28. package/dist/server/flow-surfaces/index.js +70 -2
  29. package/dist/server/flow-surfaces/node-use-sets.js +6 -1
  30. package/dist/server/flow-surfaces/placement.js +3 -0
  31. package/dist/server/flow-surfaces/public-data-surface-default-filter.d.ts +20 -0
  32. package/dist/server/flow-surfaces/public-data-surface-default-filter.js +111 -0
  33. package/dist/server/flow-surfaces/reaction/registry.d.ts +7 -0
  34. package/dist/server/flow-surfaces/reaction/registry.js +7 -0
  35. package/dist/server/flow-surfaces/service-utils.d.ts +7 -0
  36. package/dist/server/flow-surfaces/service-utils.js +58 -9
  37. package/dist/server/flow-surfaces/service.d.ts +73 -3
  38. package/dist/server/flow-surfaces/service.js +1794 -162
  39. package/dist/server/flow-surfaces/support-matrix.d.ts +5 -2
  40. package/dist/server/flow-surfaces/support-matrix.js +16 -3
  41. package/dist/server/flow-surfaces/surface-context.js +2 -1
  42. package/dist/server/flow-surfaces/template-display.d.ts +20 -0
  43. package/dist/server/flow-surfaces/template-display.js +289 -0
  44. package/dist/server/flow-surfaces/types.d.ts +1 -0
  45. package/dist/swagger/flow-surfaces.d.ts +160 -0
  46. package/dist/swagger/flow-surfaces.examples.d.ts +117 -11
  47. package/dist/swagger/flow-surfaces.examples.js +152 -1
  48. package/dist/swagger/flow-surfaces.js +141 -21
  49. package/dist/swagger/index.d.ts +160 -0
  50. package/package.json +2 -2
@@ -106,8 +106,12 @@ const JS_CODE = stringOption("JS code", {
106
106
  const JS_VERSION = stringOption("JS code version", {
107
107
  example: "v2"
108
108
  });
109
- const COMMON_BLOCK_TITLE_OPTIONS = {
109
+ const COMMON_BLOCK_HEADER_OPTIONS = {
110
110
  title: stringOption("Title", { example: "User Table" }),
111
+ description: stringOption("Description", { example: "Team directory and summary" })
112
+ };
113
+ const FILTER_FORM_HEADER_OPTIONS = {
114
+ title: stringOption("Title", { example: "User filters" }),
111
115
  displayTitle: booleanOption("Whether to display the title", { example: true })
112
116
  };
113
117
  const COMMON_HEIGHT_OPTIONS = {
@@ -131,7 +135,7 @@ const TAB_OPTIONS = {
131
135
  documentTitle: stringOption("Browser document title", { example: "User Overview" })
132
136
  };
133
137
  const TABLE_OPTIONS = {
134
- ...COMMON_BLOCK_TITLE_OPTIONS,
138
+ ...COMMON_BLOCK_HEADER_OPTIONS,
135
139
  ...COMMON_HEIGHT_OPTIONS,
136
140
  resource: COMMON_RESOURCE,
137
141
  pageSize: numberOption("Page size", { example: 20 }),
@@ -146,7 +150,7 @@ const TABLE_OPTIONS = {
146
150
  dragSortBy: stringOption("Drag-sort field", { example: "sort" })
147
151
  };
148
152
  const FORM_COMMON_OPTIONS = {
149
- ...COMMON_BLOCK_TITLE_OPTIONS,
153
+ ...COMMON_BLOCK_HEADER_OPTIONS,
150
154
  resource: COMMON_RESOURCE,
151
155
  layout: stringOption("Layout key", { example: "vertical" }),
152
156
  labelAlign: stringOption("Label alignment", { example: "left" }),
@@ -163,7 +167,7 @@ const EDIT_FORM_OPTIONS = {
163
167
  dataScope: FILTER_GROUP
164
168
  };
165
169
  const DETAILS_OPTIONS = {
166
- ...COMMON_BLOCK_TITLE_OPTIONS,
170
+ ...COMMON_BLOCK_HEADER_OPTIONS,
167
171
  resource: COMMON_RESOURCE,
168
172
  layout: stringOption("Layout key", { example: "vertical" }),
169
173
  labelAlign: stringOption("Label alignment", { example: "left" }),
@@ -178,7 +182,7 @@ const DETAILS_OPTIONS = {
178
182
  )
179
183
  };
180
184
  const FILTER_FORM_OPTIONS = {
181
- ...COMMON_BLOCK_TITLE_OPTIONS,
185
+ ...FILTER_FORM_HEADER_OPTIONS,
182
186
  resource: COMMON_RESOURCE,
183
187
  layout: stringOption("Layout key", { example: "vertical" }),
184
188
  labelAlign: stringOption("Label alignment", { example: "left" }),
@@ -187,7 +191,7 @@ const FILTER_FORM_OPTIONS = {
187
191
  defaultValues: objectOption("Default filter values", { example: { status: "draft" } })
188
192
  };
189
193
  const LIST_OPTIONS = {
190
- ...COMMON_BLOCK_TITLE_OPTIONS,
194
+ ...COMMON_BLOCK_HEADER_OPTIONS,
191
195
  ...COMMON_HEIGHT_OPTIONS,
192
196
  resource: COMMON_RESOURCE,
193
197
  pageSize: numberOption("Page size", { example: 20 }),
@@ -195,8 +199,28 @@ const LIST_OPTIONS = {
195
199
  sorting: SORTING,
196
200
  layout: stringOption("List layout", { example: "vertical" })
197
201
  };
202
+ const CALENDAR_OPTIONS = {
203
+ ...COMMON_BLOCK_HEADER_OPTIONS,
204
+ ...COMMON_HEIGHT_OPTIONS,
205
+ resource: COMMON_RESOURCE,
206
+ titleField: stringOption("Calendar event title field", { example: "title" }),
207
+ colorField: stringOption("Calendar event color field", { example: "status" }),
208
+ startField: stringOption("Calendar event start field", { example: "startAt" }),
209
+ endField: stringOption("Calendar event end field", { example: "endAt" }),
210
+ defaultView: stringOption("Default calendar view", { enum: ["month", "week", "day"], example: "month" }),
211
+ quickCreateEvent: booleanOption("Whether slot quick-create is enabled", { example: true }),
212
+ showLunar: booleanOption("Whether lunar labels are displayed", { example: false }),
213
+ weekStart: numberOption("Week start day. Use 1 for Monday or 0 for Sunday.", { example: 1 }),
214
+ dataScope: FILTER_GROUP,
215
+ linkageRules: arrayOption(
216
+ "Raw linkage-rules payload. For AI/CLI authoring, prefer `getReactionMeta` + `setBlockLinkageRules` instead of guessing this configure key directly.",
217
+ { example: [] }
218
+ ),
219
+ quickCreatePopup: OPEN_VIEW,
220
+ eventPopup: OPEN_VIEW
221
+ };
198
222
  const GRID_CARD_OPTIONS = {
199
- ...COMMON_BLOCK_TITLE_OPTIONS,
223
+ ...COMMON_BLOCK_HEADER_OPTIONS,
200
224
  ...COMMON_HEIGHT_OPTIONS,
201
225
  resource: COMMON_RESOURCE,
202
226
  columns: objectOption("Column count. Pass a number or a full responsive object that includes xs/sm/md/lg/xl/xxl.", {
@@ -215,11 +239,11 @@ const GRID_CARD_OPTIONS = {
215
239
  layout: stringOption("Card layout", { example: "vertical" })
216
240
  };
217
241
  const MARKDOWN_OPTIONS = {
218
- ...COMMON_BLOCK_TITLE_OPTIONS,
242
+ ...COMMON_BLOCK_HEADER_OPTIONS,
219
243
  content: stringOption("Markdown content", { example: "# Team handbook" })
220
244
  };
221
245
  const IFRAME_OPTIONS = {
222
- ...COMMON_BLOCK_TITLE_OPTIONS,
246
+ ...COMMON_BLOCK_HEADER_OPTIONS,
223
247
  ...COMMON_HEIGHT_OPTIONS,
224
248
  mode: stringOption("iframe mode", { example: "url" }),
225
249
  url: stringOption("URL", { example: "https://example.com/embed" }),
@@ -229,7 +253,7 @@ const IFRAME_OPTIONS = {
229
253
  htmlId: stringOption("Embedded HTML node ID")
230
254
  };
231
255
  const CHART_OPTIONS = {
232
- ...COMMON_BLOCK_TITLE_OPTIONS,
256
+ ...COMMON_BLOCK_HEADER_OPTIONS,
233
257
  ...COMMON_HEIGHT_OPTIONS,
234
258
  query: objectOption("Chart query DSL. Builder mode is recommended by default.", {
235
259
  example: {
@@ -287,10 +311,26 @@ const CHART_OPTIONS = {
287
311
  )
288
312
  };
289
313
  const ACTION_PANEL_OPTIONS = {
290
- ...COMMON_BLOCK_TITLE_OPTIONS,
314
+ ...COMMON_BLOCK_HEADER_OPTIONS,
291
315
  layout: stringOption("Layout key", { example: "list" }),
292
316
  ellipsis: booleanOption("Whether to collapse overly long buttons", { example: false })
293
317
  };
318
+ const MAP_OPTIONS = {
319
+ ...COMMON_BLOCK_HEADER_OPTIONS,
320
+ ...COMMON_HEIGHT_OPTIONS,
321
+ resource: COMMON_RESOURCE,
322
+ mapField: arrayOption("Map field path", { example: ["location"] }),
323
+ marker: stringOption("Marker field", { example: "name" }),
324
+ dataScope: FILTER_GROUP,
325
+ sorting: SORTING,
326
+ zoom: numberOption("Default zoom level", { example: 13 })
327
+ };
328
+ const COMMENTS_OPTIONS = {
329
+ ...COMMON_BLOCK_HEADER_OPTIONS,
330
+ resource: COMMON_RESOURCE,
331
+ pageSize: numberOption("Page size", { example: 20 }),
332
+ dataScope: FILTER_GROUP
333
+ };
294
334
  const JS_BLOCK_OPTIONS = {
295
335
  title: stringOption("Title", { example: "Runtime Banner" }),
296
336
  description: stringOption("Description", { example: "Custom JS block" }),
@@ -423,6 +463,13 @@ const JS_ITEM_OPTIONS = {
423
463
  code: JS_CODE,
424
464
  version: JS_VERSION
425
465
  };
466
+ const DIVIDER_ITEM_OPTIONS = {
467
+ label: stringOption("Divider label", { example: "Basic information" }),
468
+ orientation: stringOption("Label position", { example: "left" }),
469
+ dashed: booleanOption("Whether the divider is dashed", { example: false }),
470
+ color: stringOption("Label color"),
471
+ borderColor: stringOption("Divider line color")
472
+ };
426
473
  const ACTION_COMMON_OPTIONS = {
427
474
  title: stringOption("Button title", { example: "Run" }),
428
475
  tooltip: stringOption("Tooltip"),
@@ -454,6 +501,12 @@ const ACTION_LINKAGE_OPTIONS = {
454
501
  { example: [] }
455
502
  )
456
503
  };
504
+ const FILTER_ACTION_OPTIONS = {
505
+ filterableFieldNames: arrayOption("Allowed filter field name list", {
506
+ example: ["username", "email", "roles"]
507
+ }),
508
+ defaultFilter: FILTER_GROUP
509
+ };
457
510
  const ACTION_JS_OPTIONS = {
458
511
  code: JS_CODE,
459
512
  version: JS_VERSION
@@ -493,10 +546,14 @@ const ACTION_EMAIL_OPTIONS = {
493
546
  emailFieldNames: arrayOption("Email field name list", { example: ["email"] }),
494
547
  defaultSelectAllRecords: booleanOption("Whether all records are selected by default", { example: false })
495
548
  };
549
+ const CALENDAR_ACTION_POSITION_OPTIONS = {
550
+ position: stringOption("Position", { enum: ["left", "right"], example: "left" })
551
+ };
496
552
  const GLOBAL_FLOW_CONTEXT_OPTION_KEYS = /* @__PURE__ */ new Set([
497
553
  "assignRules",
498
554
  "confirm",
499
555
  "dataScope",
556
+ "defaultFilter",
500
557
  "defaultValues",
501
558
  "initialValue",
502
559
  "linkageRules",
@@ -544,6 +601,12 @@ function getActionConfigureOptionsByUse(use) {
544
601
  const base = [ACTION_COMMON_OPTIONS];
545
602
  const merged = (...extra) => mergeOptions(...base, ...extra);
546
603
  switch (normalized) {
604
+ case "CalendarTodayActionModel":
605
+ return merged(CALENDAR_ACTION_POSITION_OPTIONS, ACTION_LINKAGE_OPTIONS);
606
+ case "CalendarNavActionModel":
607
+ case "CalendarTitleActionModel":
608
+ case "CalendarViewSelectActionModel":
609
+ return mergeOptions(CALENDAR_ACTION_POSITION_OPTIONS, ACTION_LINKAGE_OPTIONS);
547
610
  case "AddNewActionModel":
548
611
  case "ViewActionModel":
549
612
  case "EditActionModel":
@@ -586,11 +649,12 @@ function getActionConfigureOptionsByUse(use) {
586
649
  case "FormTriggerWorkflowActionModel":
587
650
  case "WorkbenchTriggerWorkflowActionModel":
588
651
  case "RefreshActionModel":
589
- case "FilterActionModel":
590
652
  case "ExpandCollapseActionModel":
591
653
  case "FilterFormSubmitActionModel":
592
654
  case "FilterFormResetActionModel":
593
655
  return merged(ACTION_LINKAGE_OPTIONS);
656
+ case "FilterActionModel":
657
+ return merged(FILTER_ACTION_OPTIONS, ACTION_LINKAGE_OPTIONS);
594
658
  case "ApplyFormSubmitModel":
595
659
  case "ApplyFormSaveDraftModel":
596
660
  return merged(ACTION_CONFIRM_OPTIONS, APPROVAL_ASSIGN_ACTION_OPTIONS, ACTION_LINKAGE_OPTIONS);
@@ -647,6 +711,9 @@ function getConfigureOptionsForUse(use) {
647
711
  case "TableBlockModel":
648
712
  options = cloneOptions(TABLE_OPTIONS);
649
713
  break;
714
+ case "CalendarBlockModel":
715
+ options = cloneOptions(CALENDAR_OPTIONS);
716
+ break;
650
717
  case "FormBlockModel":
651
718
  case "CreateFormModel":
652
719
  options = cloneOptions(FORM_COMMON_OPTIONS);
@@ -678,6 +745,12 @@ function getConfigureOptionsForUse(use) {
678
745
  case "ActionPanelBlockModel":
679
746
  options = cloneOptions(ACTION_PANEL_OPTIONS);
680
747
  break;
748
+ case "MapBlockModel":
749
+ options = cloneOptions(MAP_OPTIONS);
750
+ break;
751
+ case "CommentsBlockModel":
752
+ options = cloneOptions(COMMENTS_OPTIONS);
753
+ break;
681
754
  case "JSBlockModel":
682
755
  options = cloneOptions(JS_BLOCK_OPTIONS);
683
756
  break;
@@ -710,6 +783,9 @@ function getConfigureOptionsForUse(use) {
710
783
  case "FormJSFieldItemModel":
711
784
  options = cloneOptions(JS_ITEM_OPTIONS);
712
785
  break;
786
+ case "DividerItemModel":
787
+ options = cloneOptions(DIVIDER_ITEM_OPTIONS);
788
+ break;
713
789
  default:
714
790
  if (isGenericFieldNodeUse(normalized) || isGenericFieldNodeUse(semanticUse)) {
715
791
  options = cloneOptions(FIELD_NODE_OPTIONS);
@@ -40,15 +40,10 @@ __export(contract_guard_exports, {
40
40
  });
41
41
  module.exports = __toCommonJS(contract_guard_exports);
42
42
  var import_lodash = __toESM(require("lodash"));
43
- var import_utils = require("@nocobase/utils");
44
43
  var import_catalog = require("./catalog");
45
44
  var import_errors = require("./errors");
45
+ var import_filter_group = require("./filter-group");
46
46
  const EMPTY_GRID_ITEM_UID = "__EMPTY__";
47
- const EMPTY_FILTER_GROUP = {
48
- logic: "$and",
49
- items: []
50
- };
51
- const FILTER_GROUP_EXAMPLE = JSON.stringify(EMPTY_FILTER_GROUP);
52
47
  class FlowSurfaceContractGuard {
53
48
  mergeDomainValue(domain, currentValue, nextValue, contract, use) {
54
49
  if (!import_lodash.default.isPlainObject(nextValue)) {
@@ -90,12 +85,12 @@ class FlowSurfaceContractGuard {
90
85
  `flowSurfaces updateSettings domain '${domain}.${groupKey}' on '${use}' requires an object payload`
91
86
  );
92
87
  }
93
- const normalizedValue = normalizeGroupValue(value, groupContract, {
88
+ const normalizedValue2 = normalizeGroupValue(value, groupContract, {
94
89
  domain,
95
90
  groupKey,
96
91
  use
97
92
  });
98
- const invalidPaths = collectLeafPaths(normalizedValue).filter(
93
+ const invalidPaths = collectLeafPaths(normalizedValue2).filter(
99
94
  (path) => !isAllowedGroupPath(groupContract, path)
100
95
  );
101
96
  if (invalidPaths.length) {
@@ -105,15 +100,15 @@ class FlowSurfaceContractGuard {
105
100
  )}`
106
101
  );
107
102
  }
108
- const invalidValueTypes = collectTypedValueErrors(normalizedValue, groupContract.pathSchemas || {});
109
- if (invalidValueTypes.length) {
103
+ const invalidValueTypes2 = collectTypedValueErrors(normalizedValue2, groupContract.pathSchemas || {});
104
+ if (invalidValueTypes2.length) {
110
105
  (0, import_errors.throwBadRequest)(
111
- `flowSurfaces updateSettings domain '${domain}.${groupKey}' on '${use}' has invalid values: ${invalidValueTypes.join(
106
+ `flowSurfaces updateSettings domain '${domain}.${groupKey}' on '${use}' has invalid values: ${invalidValueTypes2.join(
112
107
  ", "
113
108
  )}`
114
109
  );
115
110
  }
116
- next2[groupKey] = groupContract.mergeStrategy === "replace" ? import_lodash.default.cloneDeep(normalizedValue) : import_lodash.default.merge({}, (currentValue == null ? void 0 : currentValue[groupKey]) || {}, normalizedValue);
111
+ next2[groupKey] = groupContract.mergeStrategy === "replace" ? import_lodash.default.cloneDeep(normalizedValue2) : import_lodash.default.merge({}, (currentValue == null ? void 0 : currentValue[groupKey]) || {}, normalizedValue2);
117
112
  });
118
113
  return next2;
119
114
  }
@@ -123,11 +118,23 @@ class FlowSurfaceContractGuard {
123
118
  `flowSurfaces updateSettings domain '${domain}' on '${use}' does not allow keys: ${unknownKeys.join(", ")}`
124
119
  );
125
120
  }
126
- if (!Object.keys(nextValue).length) {
121
+ const normalizedValue = normalizeDomainValue(nextValue, contract, {
122
+ domain,
123
+ use
124
+ });
125
+ if (!Object.keys(normalizedValue).length) {
127
126
  return {};
128
127
  }
128
+ const invalidValueTypes = collectTypedValueErrors(normalizedValue, contract.pathSchemas || {});
129
+ if (invalidValueTypes.length) {
130
+ (0, import_errors.throwBadRequest)(
131
+ `flowSurfaces updateSettings domain '${domain}' on '${use}' has invalid values: ${invalidValueTypes.join(
132
+ ", "
133
+ )}`
134
+ );
135
+ }
129
136
  const next = import_lodash.default.cloneDeep(currentValue || {});
130
- Object.entries(nextValue).forEach(([key, value]) => {
137
+ Object.entries(normalizedValue).forEach(([key, value]) => {
131
138
  next[key] = contract.mergeStrategy === "replace" || !import_lodash.default.isPlainObject(value) || !Object.keys(value).length ? import_lodash.default.cloneDeep(value) : import_lodash.default.merge({}, (currentValue == null ? void 0 : currentValue[key]) || {}, value);
132
139
  });
133
140
  return next;
@@ -303,79 +310,63 @@ function collectTypedValueErrors(value, pathSchemas) {
303
310
  return [];
304
311
  }
305
312
  const candidate = import_lodash.default.get(value, path);
306
- return matchesValueSchema(candidate, schema) ? [] : [`${path} expected ${schema.type}`];
307
- });
308
- }
309
- function normalizeGroupValue(value, groupContract, context) {
310
- const normalized = import_lodash.default.cloneDeep(value);
311
- Object.entries(groupContract.pathSchemas || {}).forEach(([path, schema]) => {
312
- if (!import_lodash.default.has(normalized, path) || !isFilterGroupSchema(schema)) {
313
- return;
314
- }
315
- import_lodash.default.set(normalized, path, normalizeFilterGroupValue(import_lodash.default.get(normalized, path), context, path));
313
+ return collectSchemaValueErrors(candidate, schema, path);
316
314
  });
317
- return normalized;
318
315
  }
319
- function matchesValueSchema(value, schema) {
316
+ function collectSchemaValueErrors(value, schema, path) {
320
317
  if (value === null) {
321
- return (schema == null ? void 0 : schema.nullable) === true;
318
+ return (schema == null ? void 0 : schema.nullable) === true ? [] : [`${path} expected ${(schema == null ? void 0 : schema.type) || "value"}`];
322
319
  }
323
320
  switch (schema == null ? void 0 : schema.type) {
324
321
  case "string":
325
- return typeof value === "string";
322
+ return typeof value === "string" ? [] : [`${path} expected string`];
326
323
  case "boolean":
327
- return typeof value === "boolean";
324
+ return typeof value === "boolean" ? [] : [`${path} expected boolean`];
328
325
  case "number":
329
- return typeof value === "number" && Number.isFinite(value);
326
+ return typeof value === "number" && Number.isFinite(value) ? [] : [`${path} expected number`];
330
327
  case "object":
331
- return import_lodash.default.isPlainObject(value);
328
+ return import_lodash.default.isPlainObject(value) ? [] : [`${path} expected object`];
332
329
  case "array":
333
- return Array.isArray(value);
330
+ if (!Array.isArray(value)) {
331
+ return [`${path} expected array`];
332
+ }
333
+ if (!schema.items) {
334
+ return [];
335
+ }
336
+ return value.flatMap((item, index) => collectSchemaValueErrors(item, schema.items, `${path}[${index}]`));
334
337
  default:
335
- return true;
336
- }
337
- }
338
- function isFilterGroupSchema(schema) {
339
- return (schema == null ? void 0 : schema["x-flowSurfaceFormat"]) === "filter-group";
340
- }
341
- function normalizeFilterGroupValue(value, context, path) {
342
- if (value === null || import_lodash.default.isPlainObject(value) && !Object.keys(value).length) {
343
- return import_lodash.default.cloneDeep(EMPTY_FILTER_GROUP);
344
- }
345
- try {
346
- assertFilterGroupShape(value);
347
- (0, import_utils.transformFilter)(value);
348
- return import_lodash.default.cloneDeep(value);
349
- } catch (error) {
350
- const reason = error instanceof Error ? error.message : String(error);
351
- (0, import_errors.throwBadRequest)(
352
- `flowSurfaces updateSettings domain '${context.domain}.${context.groupKey}.${path}' on '${context.use}' expects FilterGroup like ${FILTER_GROUP_EXAMPLE}: ${reason}`
353
- );
338
+ return [];
354
339
  }
355
340
  }
356
- function assertFilterGroupShape(filter) {
357
- if (!import_lodash.default.isPlainObject(filter)) {
358
- (0, import_errors.throwBadRequest)("Invalid filter: filter must be an object");
359
- }
360
- if (!("logic" in filter) || !("items" in filter)) {
361
- (0, import_errors.throwBadRequest)("Invalid filter: filter must have logic and items properties");
362
- }
363
- if (filter.logic !== "$and" && filter.logic !== "$or") {
364
- (0, import_errors.throwBadRequest)("Invalid filter: logic must be '$and' or '$or'");
365
- }
366
- if (!Array.isArray(filter.items)) {
367
- (0, import_errors.throwBadRequest)("Invalid filter: items must be an array");
368
- }
369
- filter.items.forEach((item) => {
370
- if (import_lodash.default.isPlainObject(item) && "logic" in item && "items" in item) {
371
- assertFilterGroupShape(item);
341
+ function normalizeDomainValue(value, contract, context) {
342
+ const normalized = import_lodash.default.cloneDeep(value);
343
+ Object.entries(contract.pathSchemas || {}).forEach(([path, schema]) => {
344
+ if (!import_lodash.default.has(normalized, path) || !isFilterGroupSchema(schema)) {
372
345
  return;
373
346
  }
374
- if (import_lodash.default.isPlainObject(item) && typeof item.path === "string" && typeof item.operator === "string") {
347
+ import_lodash.default.set(normalized, path, normalizeFilterGroupValue(import_lodash.default.get(normalized, path), context, path));
348
+ });
349
+ return normalized;
350
+ }
351
+ function normalizeGroupValue(value, groupContract, context) {
352
+ const normalized = import_lodash.default.cloneDeep(value);
353
+ Object.entries(groupContract.pathSchemas || {}).forEach(([path, schema]) => {
354
+ if (!import_lodash.default.has(normalized, path) || !isFilterGroupSchema(schema)) {
375
355
  return;
376
356
  }
377
- (0, import_errors.throwBadRequest)("Invalid filter item type");
357
+ import_lodash.default.set(normalized, path, normalizeFilterGroupValue(import_lodash.default.get(normalized, path), context, path));
378
358
  });
359
+ return normalized;
360
+ }
361
+ function isFilterGroupSchema(schema) {
362
+ return (schema == null ? void 0 : schema["x-flowSurfaceFormat"]) === "filter-group";
363
+ }
364
+ function normalizeFilterGroupValue(value, context, path) {
365
+ const domainPath = context.groupKey ? `${context.domain}.${context.groupKey}.${path}` : `${context.domain}.${path}`;
366
+ return (0, import_filter_group.normalizeFlowSurfaceFilterGroupValue)(
367
+ value,
368
+ `flowSurfaces updateSettings domain '${domainPath}' on '${context.use}' expects FilterGroup like ${import_filter_group.FLOW_SURFACE_FILTER_GROUP_EXAMPLE}`
369
+ );
379
370
  }
380
371
  function isContractDefinedFlowGroup(groupContract) {
381
372
  if (!groupContract) {
@@ -34,10 +34,19 @@ export type FlowSurfaceDefaultActionPopupFieldCandidate = {
34
34
  field?: any;
35
35
  fieldPath?: string;
36
36
  };
37
+ export type FlowSurfaceDefaultActionPopupFieldGroupCandidate = {
38
+ key?: string;
39
+ title: string;
40
+ fields: string[];
41
+ };
37
42
  type FlowSurfaceDefaultActionPopupFieldFilterOptions = {
38
43
  excludeAuditTimestampFields?: boolean;
39
44
  excludeAssociationFields?: boolean;
40
45
  };
46
+ type FlowSurfaceDefaultActionPopupFieldsInput = string[] | {
47
+ fieldPaths?: string[];
48
+ fieldGroups?: FlowSurfaceDefaultActionPopupFieldGroupCandidate[];
49
+ };
41
50
  export declare const FLOW_SURFACE_DEFAULT_ACTION_POPUP_TYPES: Set<FlowSurfaceDefaultActionPopupType>;
42
51
  export declare const FLOW_SURFACE_DEFAULT_ACTION_POPUP_USES: Set<FlowSurfaceDefaultActionPopupUse>;
43
52
  export declare function isFlowSurfaceDefaultActionPopupType(type?: string): type is FlowSurfaceDefaultActionPopupType;
@@ -45,7 +54,8 @@ export declare function isFlowSurfaceDefaultActionPopupUse(use?: string): use is
45
54
  export declare function getFlowSurfaceDefaultActionPopupConfigByUse(use?: string): FlowSurfaceDefaultActionPopupConfig;
46
55
  export declare function resolveFlowSurfaceDefaultActionPopupTabTitle(use?: string, currentTitle?: string | null): string;
47
56
  export declare function pickFlowSurfaceDefaultActionPopupFieldPaths(candidates: FlowSurfaceDefaultActionPopupFieldCandidate[], options?: FlowSurfaceDefaultActionPopupFieldFilterOptions): string[];
48
- export declare function buildFlowSurfaceDefaultActionPopupBlocks(use: string | undefined, fieldPaths: string[]): _.Dictionary<string | string[] | Record<string, any> | FlowSurfaceDefaultActionPopupSubmitAction[] | {
57
+ export declare function pickFlowSurfaceDefaultActionPopupFieldGroups(candidates: FlowSurfaceDefaultActionPopupFieldCandidate[], fieldGroups: FlowSurfaceDefaultActionPopupFieldGroupCandidate[] | undefined, options?: FlowSurfaceDefaultActionPopupFieldFilterOptions): FlowSurfaceDefaultActionPopupFieldGroupCandidate[];
58
+ export declare function buildFlowSurfaceDefaultActionPopupBlocks(use: string | undefined, fieldsInput: FlowSurfaceDefaultActionPopupFieldsInput): _.Dictionary<string | string[] | Record<string, any> | FlowSurfaceDefaultActionPopupFieldGroupCandidate[] | FlowSurfaceDefaultActionPopupSubmitAction[] | {
49
59
  binding: "currentCollection" | "currentRecord";
50
60
  }>[];
51
61
  export declare function hasFlowSurfaceInlinePopupTemplate(popup?: Record<string, any>): boolean;
@@ -44,6 +44,7 @@ __export(default_action_popup_exports, {
44
44
  hasFlowSurfaceInlinePopupTemplate: () => hasFlowSurfaceInlinePopupTemplate,
45
45
  isFlowSurfaceDefaultActionPopupType: () => isFlowSurfaceDefaultActionPopupType,
46
46
  isFlowSurfaceDefaultActionPopupUse: () => isFlowSurfaceDefaultActionPopupUse,
47
+ pickFlowSurfaceDefaultActionPopupFieldGroups: () => pickFlowSurfaceDefaultActionPopupFieldGroups,
47
48
  pickFlowSurfaceDefaultActionPopupFieldPaths: () => pickFlowSurfaceDefaultActionPopupFieldPaths,
48
49
  resolveFlowSurfaceDefaultActionPopupTabTitle: () => resolveFlowSurfaceDefaultActionPopupTabTitle
49
50
  });
@@ -66,8 +67,8 @@ const FLOW_SURFACE_DEFAULT_ACTION_POPUP_CONFIGS = [
66
67
  {
67
68
  type: "addNew",
68
69
  use: "AddNewActionModel",
69
- defaultButtonTitle: "Add new",
70
- defaultPopupTabTitle: "Add new",
70
+ defaultButtonTitle: '{{t("Add new")}}',
71
+ defaultPopupTabTitle: '{{t("Add new")}}',
71
72
  blockKey: "defaultCreateForm",
72
73
  blockType: "createForm",
73
74
  blockUse: "CreateFormModel",
@@ -81,7 +82,7 @@ const FLOW_SURFACE_DEFAULT_ACTION_POPUP_CONFIGS = [
81
82
  key: "defaultSubmit",
82
83
  type: "submit",
83
84
  settings: {
84
- title: "Submit",
85
+ title: '{{t("Submit")}}',
85
86
  type: "primary",
86
87
  confirm: false
87
88
  }
@@ -90,8 +91,8 @@ const FLOW_SURFACE_DEFAULT_ACTION_POPUP_CONFIGS = [
90
91
  {
91
92
  type: "view",
92
93
  use: "ViewActionModel",
93
- defaultButtonTitle: "View",
94
- defaultPopupTabTitle: "Details",
94
+ defaultButtonTitle: '{{t("View")}}',
95
+ defaultPopupTabTitle: '{{t("Details")}}',
95
96
  blockKey: "defaultDetails",
96
97
  blockType: "details",
97
98
  blockUse: "DetailsBlockModel",
@@ -109,8 +110,8 @@ const FLOW_SURFACE_DEFAULT_ACTION_POPUP_CONFIGS = [
109
110
  {
110
111
  type: "edit",
111
112
  use: "EditActionModel",
112
- defaultButtonTitle: "Edit",
113
- defaultPopupTabTitle: "Edit",
113
+ defaultButtonTitle: '{{t("Edit")}}',
114
+ defaultPopupTabTitle: '{{t("Edit")}}',
114
115
  blockKey: "defaultEditForm",
115
116
  blockType: "editForm",
116
117
  blockUse: "EditFormModel",
@@ -128,7 +129,7 @@ const FLOW_SURFACE_DEFAULT_ACTION_POPUP_CONFIGS = [
128
129
  key: "defaultSubmit",
129
130
  type: "submit",
130
131
  settings: {
131
- title: "Submit",
132
+ title: '{{t("Submit")}}',
132
133
  type: "primary",
133
134
  confirm: false
134
135
  }
@@ -148,6 +149,11 @@ const FLOW_SURFACE_DEFAULT_ACTION_POPUP_CONFIG_BY_USE = FLOW_SURFACE_DEFAULT_ACT
148
149
  },
149
150
  {}
150
151
  );
152
+ const FLOW_SURFACE_DEFAULT_ACTION_POPUP_LEGACY_BUTTON_TITLES = {
153
+ AddNewActionModel: "Add new",
154
+ ViewActionModel: "View",
155
+ EditActionModel: "Edit"
156
+ };
151
157
  function isFlowSurfaceDefaultActionPopupType(type) {
152
158
  return FLOW_SURFACE_DEFAULT_ACTION_POPUP_TYPES.has(String(type || "").trim());
153
159
  }
@@ -167,7 +173,8 @@ function resolveFlowSurfaceDefaultActionPopupTabTitle(use, currentTitle) {
167
173
  return void 0;
168
174
  }
169
175
  const normalizedTitle = String(currentTitle || "").trim();
170
- if (normalizedTitle && normalizedTitle !== actionConfig.defaultButtonTitle) {
176
+ const legacyDefaultButtonTitle = FLOW_SURFACE_DEFAULT_ACTION_POPUP_LEGACY_BUTTON_TITLES[actionConfig.use];
177
+ if (normalizedTitle && normalizedTitle !== actionConfig.defaultButtonTitle && normalizedTitle !== legacyDefaultButtonTitle) {
171
178
  return normalizedTitle;
172
179
  }
173
180
  return actionConfig.defaultPopupTabTitle;
@@ -210,6 +217,9 @@ function isFlowSurfaceDefaultActionPopupAssociationForeignKeyField(field, associ
210
217
  return !!fieldName && associationForeignKeys.has(fieldName);
211
218
  }
212
219
  function pickFlowSurfaceDefaultActionPopupFieldPaths(candidates, options = {}) {
220
+ return filterFlowSurfaceDefaultActionPopupFieldCandidates(candidates, options).map((candidate) => String((candidate == null ? void 0 : candidate.fieldPath) || "").trim()).filter(Boolean);
221
+ }
222
+ function filterFlowSurfaceDefaultActionPopupFieldCandidates(candidates, options = {}) {
213
223
  const associationForeignKeys = collectFlowSurfaceDefaultActionPopupAssociationForeignKeys(candidates);
214
224
  const preferredCandidates = candidates.filter(
215
225
  (candidate) => !isFlowSurfaceDefaultActionPopupSystemField(candidate.field) && (!options.excludeAuditTimestampFields || !isFlowSurfaceDefaultActionPopupAuditTimestampField(candidate.field)) && (!options.excludeAssociationFields || !isFlowSurfaceDefaultActionPopupAssociationField(candidate.field)) && !isFlowSurfaceDefaultActionPopupMultiValueAssociationField(candidate.field) && !isFlowSurfaceDefaultActionPopupAssociationForeignKeyField(candidate.field, associationForeignKeys)
@@ -218,13 +228,61 @@ function pickFlowSurfaceDefaultActionPopupFieldPaths(candidates, options = {}) {
218
228
  (candidate) => !isFlowSurfaceDefaultActionPopupTechnicalIdField(candidate.field) && (!options.excludeAuditTimestampFields || !isFlowSurfaceDefaultActionPopupAuditTimestampField(candidate.field)) && (!options.excludeAssociationFields || !isFlowSurfaceDefaultActionPopupAssociationField(candidate.field)) && !isFlowSurfaceDefaultActionPopupMultiValueAssociationField(candidate.field) && !isFlowSurfaceDefaultActionPopupAssociationForeignKeyField(candidate.field, associationForeignKeys)
219
229
  );
220
230
  const baseCandidates = preferredCandidates.length ? preferredCandidates : fallbackCandidates;
221
- return baseCandidates.map((candidate) => String((candidate == null ? void 0 : candidate.fieldPath) || "").trim()).filter(Boolean);
231
+ return baseCandidates.filter((candidate) => String((candidate == null ? void 0 : candidate.fieldPath) || "").trim());
232
+ }
233
+ function pickFlowSurfaceDefaultActionPopupFieldGroups(candidates, fieldGroups, options = {}) {
234
+ const allowedFieldPaths = new Set(
235
+ filterFlowSurfaceDefaultActionPopupFieldCandidates(candidates, options).map(
236
+ (candidate) => String((candidate == null ? void 0 : candidate.fieldPath) || "").trim()
237
+ )
238
+ );
239
+ const usedFieldPaths = /* @__PURE__ */ new Set();
240
+ return import_lodash.default.castArray(fieldGroups || []).flatMap((group) => {
241
+ const title = String((group == null ? void 0 : group.title) || "").trim();
242
+ if (!title) {
243
+ return [];
244
+ }
245
+ const fields = import_lodash.default.castArray((group == null ? void 0 : group.fields) || []).map((field) => String(field || "").trim()).filter((field) => {
246
+ if (!field || !allowedFieldPaths.has(field) || usedFieldPaths.has(field)) {
247
+ return false;
248
+ }
249
+ usedFieldPaths.add(field);
250
+ return true;
251
+ });
252
+ if (!fields.length) {
253
+ return [];
254
+ }
255
+ return [
256
+ import_lodash.default.pickBy(
257
+ {
258
+ key: String((group == null ? void 0 : group.key) || "").trim() || void 0,
259
+ title,
260
+ fields
261
+ },
262
+ (value) => !import_lodash.default.isUndefined(value)
263
+ )
264
+ ];
265
+ });
266
+ }
267
+ function normalizeDefaultActionPopupFieldsInput(input) {
268
+ if (Array.isArray(input)) {
269
+ return {
270
+ fieldPaths: input,
271
+ fieldGroups: []
272
+ };
273
+ }
274
+ return {
275
+ fieldPaths: import_lodash.default.castArray((input == null ? void 0 : input.fieldPaths) || []).map((field) => String(field || "").trim()).filter(Boolean),
276
+ fieldGroups: import_lodash.default.castArray((input == null ? void 0 : input.fieldGroups) || []).filter((group) => import_lodash.default.isPlainObject(group))
277
+ };
222
278
  }
223
- function buildFlowSurfaceDefaultActionPopupBlocks(use, fieldPaths) {
279
+ function buildFlowSurfaceDefaultActionPopupBlocks(use, fieldsInput) {
224
280
  const actionConfig = getFlowSurfaceDefaultActionPopupConfigByUse(use);
225
281
  if (!actionConfig) {
226
282
  return [];
227
283
  }
284
+ const { fieldPaths, fieldGroups } = normalizeDefaultActionPopupFieldsInput(fieldsInput);
285
+ const hasFieldGroups = !!fieldGroups.length;
228
286
  return [
229
287
  import_lodash.default.pickBy(
230
288
  {
@@ -234,7 +292,8 @@ function buildFlowSurfaceDefaultActionPopupBlocks(use, fieldPaths) {
234
292
  binding: actionConfig.resourceBinding
235
293
  },
236
294
  settings: import_lodash.default.cloneDeep(actionConfig.blockSettings),
237
- fields: fieldPaths,
295
+ fields: hasFieldGroups ? void 0 : fieldPaths,
296
+ fieldGroups: hasFieldGroups ? fieldGroups : void 0,
238
297
  actions: actionConfig.submitAction ? [import_lodash.default.cloneDeep(actionConfig.submitAction)] : void 0
239
298
  },
240
299
  (value) => !import_lodash.default.isUndefined(value)
@@ -257,6 +316,7 @@ function hasFlowSurfaceInlinePopupBlocks(popup) {
257
316
  hasFlowSurfaceInlinePopupTemplate,
258
317
  isFlowSurfaceDefaultActionPopupType,
259
318
  isFlowSurfaceDefaultActionPopupUse,
319
+ pickFlowSurfaceDefaultActionPopupFieldGroups,
260
320
  pickFlowSurfaceDefaultActionPopupFieldPaths,
261
321
  resolveFlowSurfaceDefaultActionPopupTabTitle
262
322
  });
@@ -42,6 +42,7 @@ __export(default_block_actions_exports, {
42
42
  });
43
43
  module.exports = __toCommonJS(default_block_actions_exports);
44
44
  var import_lodash = __toESM(require("lodash"));
45
+ var import_defaults = require("./blueprint/defaults");
45
46
  const FLOW_SURFACE_INTERNAL_AUTO_SAVE_DEFAULT_POPUP_TEMPLATE_KEY = "__flowSurfaceAutoSaveDefaultPopupTemplate";
46
47
  const FLOW_SURFACE_DEFAULT_BLOCK_ACTIONS = {
47
48
  table: [
@@ -80,6 +81,8 @@ const FLOW_SURFACE_DEFAULT_BLOCK_ACTIONS = {
80
81
  },
81
82
  { type: "refresh", scope: "actions" }
82
83
  ],
84
+ createForm: [{ type: "submit", scope: "actions" }],
85
+ editForm: [{ type: "submit", scope: "actions" }],
83
86
  details: [
84
87
  {
85
88
  type: "edit",
@@ -116,7 +119,11 @@ function shouldMergeDefaultPopup(popup) {
116
119
  if (!keys.length) {
117
120
  return true;
118
121
  }
119
- return keys.every((key) => ["mode", "size", "title", "defaultType", "tryTemplate"].includes(key));
122
+ return keys.every(
123
+ (key) => ["mode", "size", "title", "defaultType", "tryTemplate", import_defaults.FLOW_SURFACE_APPLY_BLUEPRINT_POPUP_DEFAULTS_KEY].includes(
124
+ key
125
+ )
126
+ );
120
127
  }
121
128
  function mergeExplicitActionWithDescriptor(item, descriptor) {
122
129
  if (!descriptor.popup || !shouldMergeDefaultPopup(item == null ? void 0 : item.popup)) {