@nocobase/plugin-flow-engine 2.1.0-alpha.17 → 2.1.0-alpha.19

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 (56) hide show
  1. package/dist/externalVersion.js +11 -11
  2. package/dist/node_modules/ses/package.json +1 -1
  3. package/dist/node_modules/zod/package.json +1 -1
  4. package/dist/server/flow-surfaces/action-scope.js +3 -1
  5. package/dist/server/flow-surfaces/apply/compiler.js +84 -5
  6. package/dist/server/flow-surfaces/approval/blueprint-service.d.ts +84 -0
  7. package/dist/server/flow-surfaces/approval/blueprint-service.js +589 -0
  8. package/dist/server/flow-surfaces/approval/blueprint.d.ts +21 -0
  9. package/dist/server/flow-surfaces/approval/blueprint.js +190 -0
  10. package/dist/server/flow-surfaces/approval/builder.d.ts +225 -0
  11. package/dist/server/flow-surfaces/approval/builder.js +384 -0
  12. package/dist/server/flow-surfaces/approval/catalog-specs.d.ts +33 -0
  13. package/dist/server/flow-surfaces/approval/catalog-specs.js +156 -0
  14. package/dist/server/flow-surfaces/approval/index.d.ts +14 -0
  15. package/dist/server/flow-surfaces/approval/index.js +40 -0
  16. package/dist/server/flow-surfaces/approval/runtime-config.d.ts +44 -0
  17. package/dist/server/flow-surfaces/approval/runtime-config.js +299 -0
  18. package/dist/server/flow-surfaces/approval/semantic-use.d.ts +23 -0
  19. package/dist/server/flow-surfaces/approval/semantic-use.js +155 -0
  20. package/dist/server/flow-surfaces/blueprint/compile-blocks.js +36 -2
  21. package/dist/server/flow-surfaces/blueprint/public-types.d.ts +7 -0
  22. package/dist/server/flow-surfaces/builder.d.ts +2 -0
  23. package/dist/server/flow-surfaces/builder.js +83 -10
  24. package/dist/server/flow-surfaces/catalog.d.ts +10 -0
  25. package/dist/server/flow-surfaces/catalog.js +368 -9
  26. package/dist/server/flow-surfaces/chart-config.d.ts +1 -1
  27. package/dist/server/flow-surfaces/compose-compiler.d.ts +1 -0
  28. package/dist/server/flow-surfaces/compose-compiler.js +2 -1
  29. package/dist/server/flow-surfaces/configure-options.js +61 -3
  30. package/dist/server/flow-surfaces/constants.d.ts +342 -5
  31. package/dist/server/flow-surfaces/constants.js +59 -125
  32. package/dist/server/flow-surfaces/default-action-popup.d.ts +1 -0
  33. package/dist/server/flow-surfaces/default-action-popup.js +6 -2
  34. package/dist/server/flow-surfaces/field-semantics.js +2 -1
  35. package/dist/server/flow-surfaces/index.js +21 -273
  36. package/dist/server/flow-surfaces/locator.js +8 -6
  37. package/dist/server/flow-surfaces/node-use-sets.js +15 -3
  38. package/dist/server/flow-surfaces/placement.js +11 -7
  39. package/dist/server/flow-surfaces/planning/action-specs.d.ts +1 -1
  40. package/dist/server/flow-surfaces/planning/compiler.d.ts +1 -1
  41. package/dist/server/flow-surfaces/planning/key-kind.js +7 -5
  42. package/dist/server/flow-surfaces/reaction/registry.d.ts +13 -0
  43. package/dist/server/flow-surfaces/reaction/registry.js +13 -0
  44. package/dist/server/flow-surfaces/service-utils.d.ts +10 -14
  45. package/dist/server/flow-surfaces/service-utils.js +4 -2
  46. package/dist/server/flow-surfaces/service.d.ts +63 -1
  47. package/dist/server/flow-surfaces/service.js +1058 -109
  48. package/dist/server/flow-surfaces/surface-context.d.ts +1 -0
  49. package/dist/server/flow-surfaces/surface-context.js +99 -19
  50. package/dist/server/flow-surfaces/types.d.ts +4 -1
  51. package/dist/swagger/flow-surfaces.d.ts +406 -2
  52. package/dist/swagger/flow-surfaces.examples.d.ts +164 -0
  53. package/dist/swagger/flow-surfaces.examples.js +184 -0
  54. package/dist/swagger/flow-surfaces.js +390 -76
  55. package/dist/swagger/index.d.ts +406 -2
  56. package/package.json +2 -2
@@ -54,6 +54,7 @@ var import_executor = require("./executor");
54
54
  var import_reference_guards = require("./reference-guards");
55
55
  var import_key_registry = require("./planning/key-registry");
56
56
  var import_blueprint = require("./blueprint");
57
+ var import_compile_blocks = require("./blueprint/compile-blocks");
57
58
  var import_private_utils = require("./blueprint/private-utils");
58
59
  var import_runtime = require("./planning/runtime");
59
60
  var import_created_keys = require("./planning/created-keys");
@@ -74,6 +75,7 @@ var import_context = require("./context");
74
75
  var import_configure_options = require("./configure-options");
75
76
  var import_service_helpers = require("./service-helpers");
76
77
  var import_errors2 = require("./reaction/errors");
78
+ var import_approval = require("./approval");
77
79
  var import_field_value = require("./reaction/field-value");
78
80
  var import_fingerprint = require("./reaction/fingerprint");
79
81
  var import_linkage = require("./reaction/linkage");
@@ -84,9 +86,14 @@ var import_default_action_popup = require("./default-action-popup");
84
86
  var import_service_utils = require("./service-utils");
85
87
  var import_template_compatibility = require("./template-compatibility");
86
88
  var import_template_service_utils = require("./template-service-utils");
87
- const FORM_BLOCK_USES = /* @__PURE__ */ new Set(["FormBlockModel", "CreateFormModel", "EditFormModel"]);
88
- const DETAILS_BLOCK_USES = /* @__PURE__ */ new Set(["DetailsBlockModel"]);
89
- const SIMPLE_FORM_BLOCK_USES = /* @__PURE__ */ new Set(["FormBlockModel", "CreateFormModel", "EditFormModel"]);
89
+ const FORM_BLOCK_USES = /* @__PURE__ */ new Set(["FormBlockModel", "CreateFormModel", "EditFormModel", ...import_approval.APPROVAL_FORM_BLOCK_USES]);
90
+ const DETAILS_BLOCK_USES = /* @__PURE__ */ new Set(["DetailsBlockModel", ...import_approval.APPROVAL_DETAILS_BLOCK_USES]);
91
+ const SIMPLE_FORM_BLOCK_USES = /* @__PURE__ */ new Set([
92
+ "FormBlockModel",
93
+ "CreateFormModel",
94
+ "EditFormModel",
95
+ ...import_approval.APPROVAL_FORM_BLOCK_USES
96
+ ]);
90
97
  const LIST_BLOCK_USES = /* @__PURE__ */ new Set(["ListBlockModel"]);
91
98
  const GRID_CARD_BLOCK_USES = /* @__PURE__ */ new Set(["GridCardBlockModel"]);
92
99
  const LIST_LIKE_COMPOSE_BLOCK_TYPES = /* @__PURE__ */ new Set(["list", "gridCard"]);
@@ -106,35 +113,60 @@ const FILTER_TARGET_BLOCK_USES = /* @__PURE__ */ new Set([
106
113
  "MapBlockModel",
107
114
  "CommentsBlockModel"
108
115
  ]);
109
- const EDITABLE_FIELD_WRAPPER_USES = /* @__PURE__ */ new Set(["FormItemModel", "FilterFormItemModel"]);
110
- const DISPLAY_FIELD_WRAPPER_USES = /* @__PURE__ */ new Set(["DetailsItemModel", "TableColumnModel"]);
116
+ const EDITABLE_FIELD_WRAPPER_USES = /* @__PURE__ */ new Set(["FormItemModel", "FilterFormItemModel", "PatternFormItemModel"]);
117
+ const DISPLAY_FIELD_WRAPPER_USES = /* @__PURE__ */ new Set([
118
+ "DetailsItemModel",
119
+ "TableColumnModel",
120
+ "ApprovalDetailsItemModel",
121
+ "ApplyTaskCardDetailsItemModel",
122
+ "ApprovalTaskCardDetailsItemModel"
123
+ ]);
111
124
  const DISPLAY_COMPONENT_FIELD_WRAPPER_USES = /* @__PURE__ */ new Set([
112
125
  "DetailsItemModel",
113
126
  "FormAssociationItemModel",
114
- "TableColumnModel"
127
+ "TableColumnModel",
128
+ "ApprovalDetailsItemModel",
129
+ "ApplyTaskCardDetailsItemModel",
130
+ "ApprovalTaskCardDetailsItemModel"
115
131
  ]);
116
132
  const TITLE_FIELD_SUPPORTED_WRAPPER_USES = /* @__PURE__ */ new Set([
117
133
  "FormItemModel",
118
134
  "FormAssociationItemModel",
119
135
  "DetailsItemModel",
120
- "TableColumnModel"
136
+ "TableColumnModel",
137
+ "PatternFormItemModel",
138
+ "ApprovalDetailsItemModel",
139
+ "ApplyTaskCardDetailsItemModel",
140
+ "ApprovalTaskCardDetailsItemModel"
121
141
  ]);
122
142
  const AUTO_TITLE_FIELD_BINDING_WRAPPER_USES = /* @__PURE__ */ new Set([
123
143
  "FormItemModel",
124
144
  "FormAssociationItemModel",
125
145
  "DetailsItemModel",
126
146
  "TableColumnModel",
127
- "FilterFormItemModel"
147
+ "FilterFormItemModel",
148
+ "PatternFormItemModel",
149
+ "ApprovalDetailsItemModel",
150
+ "ApplyTaskCardDetailsItemModel",
151
+ "ApprovalTaskCardDetailsItemModel"
128
152
  ]);
129
153
  const UI_FIELD_MENU_TABLE_OWNER_USES = /* @__PURE__ */ new Set(["TableBlockModel"]);
130
- const UI_FIELD_MENU_DETAILS_OWNER_USES = /* @__PURE__ */ new Set(["DetailsBlockModel", "GridCardBlockModel", "GridCardItemModel"]);
154
+ const UI_FIELD_MENU_DETAILS_OWNER_USES = /* @__PURE__ */ new Set([
155
+ "DetailsBlockModel",
156
+ "GridCardBlockModel",
157
+ "GridCardItemModel",
158
+ ...import_approval.APPROVAL_DETAILS_BLOCK_USES,
159
+ ...import_approval.APPROVAL_DETAILS_GRID_USES
160
+ ]);
131
161
  const UI_FIELD_MENU_FORM_OWNER_USES = /* @__PURE__ */ new Set([
132
162
  "FormBlockModel",
133
163
  "CreateFormModel",
134
164
  "EditFormModel",
135
165
  "AssignFormModel",
136
166
  "FormGridModel",
137
- "AssignFormGridModel"
167
+ "AssignFormGridModel",
168
+ ...import_approval.APPROVAL_FORM_BLOCK_USES,
169
+ ...import_approval.APPROVAL_FORM_GRID_USES
138
170
  ]);
139
171
  const JS_ACTION_USES = /* @__PURE__ */ new Set([
140
172
  "JSCollectionActionModel",
@@ -169,7 +201,12 @@ const ITEM_CONTEXT_OWNER_USES = /* @__PURE__ */ new Set([
169
201
  "PopupSubTableFieldModel",
170
202
  "RecordPickerFieldModel"
171
203
  ]);
172
- const RECORD_CONTEXT_OWNER_USES = /* @__PURE__ */ new Set(["DetailsBlockModel", "QuickEditFormModel", "AssignFormModel"]);
204
+ const RECORD_CONTEXT_OWNER_USES = /* @__PURE__ */ new Set([
205
+ "DetailsBlockModel",
206
+ "QuickEditFormModel",
207
+ "AssignFormModel",
208
+ ...import_approval.APPROVAL_DETAILS_BLOCK_USES
209
+ ]);
173
210
  const POPUP_RECORD_ACTION_CONTAINER_USES = /* @__PURE__ */ new Set([
174
211
  "TableActionsColumnModel",
175
212
  "DetailsBlockModel",
@@ -181,6 +218,9 @@ const POPUP_COLLECTION_BLOCK_SCENES = {
181
218
  CreateFormModel: ["new"],
182
219
  EditFormModel: ["one", "many"],
183
220
  DetailsBlockModel: ["one", "many"],
221
+ ApplyFormModel: ["new"],
222
+ ProcessFormModel: ["one"],
223
+ ApprovalDetailsModel: ["one"],
184
224
  CommentsBlockModel: ["one", "many"],
185
225
  TableBlockModel: ["many"],
186
226
  ListBlockModel: ["many"],
@@ -260,13 +300,22 @@ const UPDATE_SETTINGS_STEP_PARAM_MIRRORS_BY_USE = {
260
300
  JSColumnModel: TABLE_COLUMN_STEP_PARAM_MIRRORS,
261
301
  TableColumnModel: TABLE_FIELD_WRAPPER_STEP_PARAM_MIRRORS,
262
302
  FormItemModel: FORM_ITEM_STEP_PARAM_MIRRORS,
303
+ PatternFormItemModel: FORM_ITEM_STEP_PARAM_MIRRORS,
263
304
  DetailsItemModel: DETAIL_ITEM_STEP_PARAM_MIRRORS,
305
+ ApprovalDetailsItemModel: DETAIL_ITEM_STEP_PARAM_MIRRORS,
306
+ ApplyTaskCardDetailsItemModel: DETAIL_ITEM_STEP_PARAM_MIRRORS,
307
+ ApprovalTaskCardDetailsItemModel: DETAIL_ITEM_STEP_PARAM_MIRRORS,
264
308
  FormAssociationItemModel: DETAIL_ITEM_STEP_PARAM_MIRRORS,
265
309
  FilterFormItemModel: FILTER_FORM_ITEM_STEP_PARAM_MIRRORS,
266
310
  FormBlockModel: FORM_BLOCK_LAYOUT_STEP_PARAM_MIRRORS,
267
311
  CreateFormModel: FORM_BLOCK_LAYOUT_STEP_PARAM_MIRRORS,
268
312
  EditFormModel: FORM_BLOCK_LAYOUT_STEP_PARAM_MIRRORS,
313
+ ApplyFormModel: FORM_BLOCK_LAYOUT_STEP_PARAM_MIRRORS,
314
+ ProcessFormModel: FORM_BLOCK_LAYOUT_STEP_PARAM_MIRRORS,
269
315
  DetailsBlockModel: DETAILS_BLOCK_LAYOUT_STEP_PARAM_MIRRORS,
316
+ ApprovalDetailsModel: DETAILS_BLOCK_LAYOUT_STEP_PARAM_MIRRORS,
317
+ ApplyTaskCardDetailsModel: DETAILS_BLOCK_LAYOUT_STEP_PARAM_MIRRORS,
318
+ ApprovalTaskCardDetailsModel: DETAILS_BLOCK_LAYOUT_STEP_PARAM_MIRRORS,
270
319
  FilterFormBlockModel: FILTER_FORM_BLOCK_LAYOUT_STEP_PARAM_MIRRORS
271
320
  };
272
321
  const FLOW_SURFACE_MENU_BINDABLE_OPTION_KEY = "flowSurfaceMenuBindable";
@@ -288,7 +337,11 @@ class FlowSurfacesService {
288
337
  }
289
338
  getFlowTemplateRepository(actionName) {
290
339
  try {
291
- return this.db.getRepository("flowModelTemplates");
340
+ const repo = this.db.getRepository("flowModelTemplates");
341
+ if (!repo) {
342
+ throw new Error("flowModelTemplates repository unavailable");
343
+ }
344
+ return repo;
292
345
  } catch (error) {
293
346
  (0, import_errors.throwBadRequest)(
294
347
  `flowSurfaces ${actionName} requires '@nocobase/plugin-ui-templates' to be enabled`,
@@ -334,6 +387,56 @@ class FlowSurfacesService {
334
387
  getCollection: (dataSourceKey, collectionName) => this.getCollection(dataSourceKey, collectionName)
335
388
  });
336
389
  }
390
+ get approvalRuntimeConfigService() {
391
+ return new import_approval.FlowSurfaceApprovalRuntimeConfigService({
392
+ db: this.db,
393
+ locator: this.locator,
394
+ repository: this.repository
395
+ });
396
+ }
397
+ get approvalBlueprintService() {
398
+ return new import_approval.FlowSurfaceApprovalBlueprintService({
399
+ contractGuard: this.contractGuard,
400
+ db: this.db,
401
+ hasDataSource: (dataSourceKey) => {
402
+ var _a, _b;
403
+ return !!((_b = (_a = this.plugin.app.dataSourceManager) == null ? void 0 : _a.get) == null ? void 0 : _b.call(_a, dataSourceKey));
404
+ },
405
+ repository: this.repository,
406
+ setNodeAsyncFlag: (uid2, asyncFlag, transaction) => this.setFlowModelNodeAsyncFlag(uid2, asyncFlag, transaction),
407
+ removeNodeTreeWithBindings: (uid2, transaction) => this.removeNodeTreeWithBindings(uid2, transaction),
408
+ surfaceContext: this.surfaceContext,
409
+ compose: (values, options) => this.compose(values, options),
410
+ addField: (values, options) => this.addField(values, options),
411
+ setLayout: (values, options) => this.setLayout(values, options),
412
+ get: (values, options) => this.get(values, options),
413
+ buildComposeLayoutPayload: (input) => this.buildComposeLayoutPayload(input),
414
+ syncApprovalRuntimeConfigForSurfaceRoot: (root, transaction) => this.approvalRuntimeConfigService.syncApprovalRuntimeConfigForSurfaceRoot(root, transaction)
415
+ });
416
+ }
417
+ async setFlowModelNodeAsyncFlag(uid2, asyncFlag, transaction) {
418
+ var _a, _b;
419
+ const sequelize = (_a = this.db) == null ? void 0 : _a.sequelize;
420
+ const queryInterface = (_b = sequelize == null ? void 0 : sequelize.getQueryInterface) == null ? void 0 : _b.call(sequelize);
421
+ const quoteIdentifier = typeof (queryInterface == null ? void 0 : queryInterface.quoteIdentifier) === "function" ? (value) => queryInterface.quoteIdentifier(value) : (value) => `"${value}"`;
422
+ if (!(sequelize == null ? void 0 : sequelize.query)) {
423
+ (0, import_errors.throwInternalError)("flowSurfaces cannot update flow model async flag because sequelize is unavailable");
424
+ }
425
+ await sequelize.query(
426
+ `UPDATE ${this.repository.flowModelTreePathTableName}
427
+ SET ${quoteIdentifier("async")} = :async
428
+ WHERE ${quoteIdentifier("ancestor")} = :uid
429
+ AND ${quoteIdentifier("descendant")} = :uid
430
+ AND ${quoteIdentifier("depth")} = 0`,
431
+ {
432
+ replacements: {
433
+ uid: uid2,
434
+ async: asyncFlag
435
+ },
436
+ transaction
437
+ }
438
+ );
439
+ }
337
440
  async loadEnabledPluginPackages(transaction) {
338
441
  if (!this.db.getCollection("applicationPlugins")) {
339
442
  return /* @__PURE__ */ new Set();
@@ -629,6 +732,19 @@ class FlowSurfacesService {
629
732
  return !!((_a2 = item.grid) == null ? void 0 : _a2.uid);
630
733
  });
631
734
  }
735
+ filterCatalogActionsForExistingApprovalSingletons(node, availableActions) {
736
+ var _a;
737
+ if (!(node == null ? void 0 : node.uid) || !availableActions.length) {
738
+ return availableActions;
739
+ }
740
+ const existingActionUses = new Set(
741
+ (0, import_service_utils.getNodeSubModelList)((_a = node == null ? void 0 : node.subModels) == null ? void 0 : _a.actions).map((item) => String((item == null ? void 0 : item.use) || "").trim()).filter((use) => import_approval.APPROVAL_SINGLETON_ACTION_USES.has(use))
742
+ );
743
+ if (!existingActionUses.size) {
744
+ return availableActions;
745
+ }
746
+ return availableActions.filter((item) => !existingActionUses.has(String((item == null ? void 0 : item.use) || "").trim()));
747
+ }
632
748
  async catalog(input, options = {}) {
633
749
  if (import_lodash.default.isUndefined(input == null ? void 0 : input.target) && (0, import_service_utils.hasLegacyLocatorFields)(input || {}, {
634
750
  allowRootUid: true
@@ -680,7 +796,9 @@ class FlowSurfacesService {
680
796
  ) : (0, import_catalog.getAvailableActionCatalogItems)(void 0, void 0, enabledPackages).filter(
681
797
  (item) => item.scope !== "record"
682
798
  );
683
- response.actions = availableActions.map((item) => this.projectCatalogItem(item, expandFlags));
799
+ response.actions = this.filterCatalogActionsForExistingApprovalSingletons(node, availableActions).map(
800
+ (item) => this.projectCatalogItem(item, expandFlags)
801
+ );
684
802
  }
685
803
  if (catalogAnalysis.selectedSections.includes("recordActions")) {
686
804
  const availableRecordActions = node ? catalogAnalysis.recordActionContainerUse ? (0, import_catalog.getAvailableActionCatalogItems)(catalogAnalysis.recordActionContainerUse, "record", enabledPackages) : [] : (0, import_catalog.getAvailableActionCatalogItems)(void 0, "record", enabledPackages);
@@ -688,7 +806,7 @@ class FlowSurfacesService {
688
806
  response.recordActions = filteredRecordActions.map((item) => this.projectCatalogItem(item, expandFlags));
689
807
  }
690
808
  if (catalogAnalysis.selectedSections.includes("node")) {
691
- response.node = this.projectCatalogNode(node, resolved, expandFlags);
809
+ response.node = this.projectCatalogNode(node, resolved, expandFlags, enabledPackages);
692
810
  }
693
811
  return response;
694
812
  }
@@ -730,13 +848,45 @@ class FlowSurfacesService {
730
848
  recordActionContainerUse
731
849
  };
732
850
  }
733
- projectCatalogNode(node, resolved, expand) {
734
- return (0, import_catalog_smart.projectCatalogNode)(node, resolved, expand, {
851
+ projectCatalogNode(node, resolved, expand, enabledPackages) {
852
+ const projected = (0, import_catalog_smart.projectCatalogNode)(node, resolved, expand, {
735
853
  getEditableDomains: this.getEditableDomains.bind(this),
736
854
  getConfigureOptionsForResolvedNode: import_configure_options.getConfigureOptionsForResolvedNode,
737
855
  getSettingsSchema: import_catalog.getSettingsSchemaForUse,
738
856
  getNodeContract: import_catalog.getNodeContract
739
857
  });
858
+ return this.patchResolvedNodeConfigureOptions(node, projected, enabledPackages);
859
+ }
860
+ patchResolvedNodeConfigureOptions(node, projected, enabledPackages) {
861
+ var _a, _b, _c;
862
+ if (!((_a = projected == null ? void 0 : projected.configureOptions) == null ? void 0 : _a.fieldComponent) || !(node == null ? void 0 : node.use)) {
863
+ return projected;
864
+ }
865
+ try {
866
+ const fieldSource = this.resolveFieldComponentFieldSource(node);
867
+ const supportedFieldUses = (0, import_catalog.getSupportedFieldComponentUseSet)({
868
+ containerUse: node.use,
869
+ field: fieldSource.field,
870
+ enabledPackages,
871
+ dataSourceKey: (_b = fieldSource.fieldSettingsInit) == null ? void 0 : _b.dataSourceKey,
872
+ getCollection: (dataSourceKey, collectionName) => this.getCollection(dataSourceKey, collectionName)
873
+ });
874
+ if (!(supportedFieldUses == null ? void 0 : supportedFieldUses.size)) {
875
+ return projected;
876
+ }
877
+ const configureOptions = import_lodash.default.cloneDeep(projected.configureOptions || {});
878
+ configureOptions.fieldComponent = {
879
+ type: ((_c = configureOptions.fieldComponent) == null ? void 0 : _c.type) || "string",
880
+ ...configureOptions.fieldComponent || {},
881
+ enum: Array.from(supportedFieldUses)
882
+ };
883
+ return {
884
+ ...projected,
885
+ configureOptions
886
+ };
887
+ } catch {
888
+ return projected;
889
+ }
740
890
  }
741
891
  projectCatalogItem(item, expand) {
742
892
  return (0, import_catalog_smart.projectCatalogItem)(item, expand, {
@@ -1079,7 +1229,7 @@ class FlowSurfacesService {
1079
1229
  resolved || { uid: uid2, target: { uid: uid2 }, kind: "node" },
1080
1230
  transaction
1081
1231
  );
1082
- const childPageIndex = ancestors.findIndex((item) => (item == null ? void 0 : item.use) === "ChildPageModel");
1232
+ const childPageIndex = ancestors.findIndex((item) => (0, import_approval.normalizeApprovalSemanticUse)(item == null ? void 0 : item.use) === "ChildPageModel");
1083
1233
  if (childPageIndex >= 0) {
1084
1234
  return ancestors[childPageIndex + 1] || null;
1085
1235
  }
@@ -1954,7 +2104,7 @@ class FlowSurfacesService {
1954
2104
  );
1955
2105
  }
1956
2106
  }
1957
- buildPlanningRuntimeDeps() {
2107
+ buildPlanningRuntimeDeps(options = {}) {
1958
2108
  return {
1959
2109
  normalizeGetTarget: (value) => this.normalizeGetTarget(value),
1960
2110
  resolveLocator: (target, resolveOptions) => this.locator.resolve(target, resolveOptions),
@@ -1966,39 +2116,45 @@ class FlowSurfacesService {
1966
2116
  buildReadTargetSummary: (target, resolved) => this.buildReadTargetSummary(target, resolved),
1967
2117
  buildSurfaceContextFingerprint: (context) => this.buildSurfaceContextFingerprint(context),
1968
2118
  buildSurfaceReadPayload: (target, resolved, node, readOptions) => this.buildSurfaceReadPayload(target, resolved, node, readOptions),
1969
- dispatchPlanOnlyAction: (action, payload, transaction) => this.dispatchPlanOnlyAction(action, payload, transaction),
2119
+ dispatchPlanOnlyAction: (action, payload, transaction) => this.dispatchPlanOnlyAction(action, payload, transaction, options),
1970
2120
  dispatchOp: (op, resolvedValues, currentCtx) => this.dispatchOp(op, resolvedValues, currentCtx)
1971
2121
  };
1972
2122
  }
1973
2123
  async describeSurface(values, options = {}) {
1974
2124
  return (0, import_runtime.describeSurface)(values, this.buildPlanningRuntimeDeps(), options);
1975
2125
  }
1976
- async dispatchPlanOnlyAction(action, payload, transaction) {
1977
- const options = { transaction };
2126
+ async dispatchPlanOnlyAction(action, payload, transaction, options = {}) {
2127
+ const actionOptions = {
2128
+ transaction,
2129
+ popupTemplateAliasSession: options.popupTemplateAliasSession
2130
+ };
1978
2131
  switch (action) {
1979
2132
  case "compose":
1980
- return this.compose(payload, options);
2133
+ return this.compose(payload, actionOptions);
1981
2134
  case "configure":
1982
- return this.configure(payload, options);
2135
+ return this.configure(payload, actionOptions);
1983
2136
  case "setFieldValueRules":
1984
- return this.setFieldValueRules(payload, options);
2137
+ return this.setFieldValueRules(
2138
+ payload,
2139
+ actionOptions
2140
+ );
1985
2141
  case "setBlockLinkageRules":
1986
2142
  return this.setBlockLinkageRules(
1987
2143
  payload,
1988
- options
2144
+ actionOptions
1989
2145
  );
1990
2146
  case "setFieldLinkageRules":
1991
2147
  return this.setFieldLinkageRules(
1992
2148
  payload,
1993
- options
2149
+ actionOptions
1994
2150
  );
1995
2151
  case "setActionLinkageRules":
1996
2152
  return this.setActionLinkageRules(
1997
2153
  payload,
1998
- options
2154
+ actionOptions
1999
2155
  );
2000
2156
  case "convertTemplateToCopy":
2001
- return this.convertTemplateToCopy(payload, options);
2157
+ return this.convertTemplateToCopy(payload, actionOptions);
2002
2158
  }
2003
2159
  const unsupportedAction = action;
2004
2160
  (0, import_errors.throwInternalError)(`flowSurfaces plan-only action '${unsupportedAction}' is not supported`);
@@ -2105,6 +2261,8 @@ class FlowSurfacesService {
2105
2261
  async applyBlueprint(values, options = {}) {
2106
2262
  var _a;
2107
2263
  const prepared = await this.prepareApplyBlueprintRequest(values, options.transaction);
2264
+ const popupTemplateAliasSession = this.createPopupTemplateAliasSession();
2265
+ this.validateApplyBlueprintPopupTemplateAliases(prepared.document, popupTemplateAliasSession);
2108
2266
  const result = await (0, import_runtime.executeInternalPlan)(
2109
2267
  {
2110
2268
  surface: prepared.surface,
@@ -2112,7 +2270,9 @@ class FlowSurfacesService {
2112
2270
  steps: prepared.steps
2113
2271
  }
2114
2272
  },
2115
- this.buildPlanningRuntimeDeps(),
2273
+ this.buildPlanningRuntimeDeps({
2274
+ popupTemplateAliasSession
2275
+ }),
2116
2276
  options
2117
2277
  );
2118
2278
  const pageLocator = (0, import_blueprint.resolveApplyBlueprintPageLocator)(prepared, result);
@@ -2127,6 +2287,21 @@ class FlowSurfacesService {
2127
2287
  surface
2128
2288
  };
2129
2289
  }
2290
+ async findApprovalSurfaceRootForNode(uid2, transaction) {
2291
+ return this.approvalRuntimeConfigService.findApprovalSurfaceRootForNode(uid2, transaction);
2292
+ }
2293
+ async syncApprovalRuntimeConfigForSurfaceRoot(root, transaction) {
2294
+ return this.approvalRuntimeConfigService.syncApprovalRuntimeConfigForSurfaceRoot(root, transaction);
2295
+ }
2296
+ async syncApprovalRuntimeConfigForNode(uid2, transaction) {
2297
+ return this.approvalRuntimeConfigService.syncApprovalRuntimeConfigForNode(uid2, transaction);
2298
+ }
2299
+ async assertApprovalActionSingleton(parentUid, actionUse, transaction) {
2300
+ return this.approvalRuntimeConfigService.assertApprovalActionSingleton(parentUid, actionUse, transaction);
2301
+ }
2302
+ async applyApprovalBlueprint(values, options = {}) {
2303
+ return this.approvalBlueprintService.applyApprovalBlueprint(values, options);
2304
+ }
2130
2305
  resolveTemplateResourceInfo(input) {
2131
2306
  return (0, import_template_compatibility.resolveTemplateResourceInfo)(input, {
2132
2307
  getCollection: (dataSourceKey, collectionName) => this.getCollection(dataSourceKey, collectionName)
@@ -2386,7 +2561,8 @@ class FlowSurfacesService {
2386
2561
  if (resourceReason2) {
2387
2562
  return resourceReason2;
2388
2563
  }
2389
- if (String(template.filterByTk || "").trim() && !popupProfile.hasCurrentRecord) {
2564
+ const hasCurrentRecord2 = (popupActionContext == null ? void 0 : popupActionContext.hasCurrentRecord) ?? popupProfile.hasCurrentRecord;
2565
+ if (String(template.filterByTk || "").trim() && !hasCurrentRecord2) {
2390
2566
  return (0, import_template_compatibility.buildTemplateMissingContextReason)("filterByTk");
2391
2567
  }
2392
2568
  return void 0;
@@ -2548,7 +2724,7 @@ class FlowSurfacesService {
2548
2724
  const pageSize = (0, import_service_helpers.normalizeTemplatePageSize)(values == null ? void 0 : values.pageSize);
2549
2725
  const [rows, count] = await repo.findAndCount({
2550
2726
  filter,
2551
- sort: values == null ? void 0 : values.sort,
2727
+ sort: this.getDefaultFlowTemplateSort(values == null ? void 0 : values.sort),
2552
2728
  limit: pageSize,
2553
2729
  offset: (page - 1) * pageSize,
2554
2730
  transaction: options.transaction
@@ -3352,12 +3528,15 @@ class FlowSurfacesService {
3352
3528
  }
3353
3529
  async compose(values, options = {}) {
3354
3530
  var _a, _b, _c;
3531
+ const popupTemplateAliasSession = options.popupTemplateAliasSession || this.createPopupTemplateAliasSession();
3355
3532
  const target = this.normalizeWriteTarget("compose", values == null ? void 0 : values.target, values);
3356
3533
  const mode = this.assertComposeMode(values == null ? void 0 : values.mode);
3357
3534
  const enabledPackages = await this.resolveEnabledPluginPackages(options);
3358
3535
  const normalizedBlocks = this.normalizeComposeBlocks(values == null ? void 0 : values.blocks, enabledPackages);
3536
+ this.validateComposePopupTemplateAliases(normalizedBlocks, popupTemplateAliasSession);
3359
3537
  const blockParent = await this.surfaceContext.resolveBlockParent(target, options.transaction);
3360
3538
  const gridUid = blockParent.parentUid;
3539
+ const approvalRoot = await this.findApprovalSurfaceRootForNode(gridUid, options.transaction);
3361
3540
  const initialGrid = await this.repository.findModelById(gridUid, {
3362
3541
  transaction: options.transaction,
3363
3542
  includeAsyncNode: true
@@ -3381,7 +3560,7 @@ class FlowSurfacesService {
3381
3560
  existingItemUids: existingItems.map((item) => item.uid),
3382
3561
  layout: values.layout
3383
3562
  });
3384
- return (0, import_compose_runtime.executeComposeRuntime)(plan, {
3563
+ const result = await (0, import_compose_runtime.executeComposeRuntime)(plan, {
3385
3564
  removeExistingItem: async (uid2) => this.removeNodeTreeWithBindings(uid2, options.transaction),
3386
3565
  createBlock: async (payload) => this.addBlock(payload, {
3387
3566
  ...options,
@@ -3394,19 +3573,27 @@ class FlowSurfacesService {
3394
3573
  }
3395
3574
  await this.applyInlineNodeSettings(actionName, targetUid, settings, options);
3396
3575
  },
3397
- createField: async (payload) => this.addField(payload, options),
3576
+ createField: async (payload) => this.addField(payload, {
3577
+ ...options,
3578
+ popupTemplateAliasSession
3579
+ }),
3398
3580
  applyFieldSettings: async (actionName, fieldResult, settings) => this.applyInlineFieldSettings(actionName, fieldResult, settings, options),
3399
3581
  createAction: async (payload) => this.addAction(payload, {
3400
3582
  ...options,
3401
3583
  enabledPackages,
3402
- autoCompleteDefaultPopup: false
3584
+ autoCompleteDefaultPopup: false,
3585
+ popupTemplateAliasSession
3403
3586
  }),
3404
3587
  createRecordAction: async (payload) => this.addRecordAction(payload, {
3405
3588
  ...options,
3406
3589
  enabledPackages,
3407
- autoCompleteDefaultPopup: false
3590
+ autoCompleteDefaultPopup: false,
3591
+ popupTemplateAliasSession
3592
+ }),
3593
+ applyActionPopup: async (actionName, actionUid, popup) => this.applyInlineActionPopup(actionName, actionUid, popup, {
3594
+ ...options,
3595
+ popupTemplateAliasSession
3408
3596
  }),
3409
- applyActionPopup: async (actionName, actionUid, popup) => this.applyInlineActionPopup(actionName, actionUid, popup, options),
3410
3597
  collectActionKeys: async (actionUid) => this.collectComposeActionKeys(actionUid, options.transaction),
3411
3598
  buildExplicitLayoutPayload: async (input) => {
3412
3599
  var _a2;
@@ -3434,6 +3621,10 @@ class FlowSurfacesService {
3434
3621
  },
3435
3622
  setLayout: async (payload) => this.setLayout(payload, options)
3436
3623
  });
3624
+ if (approvalRoot) {
3625
+ await this.syncApprovalRuntimeConfigForSurfaceRoot(approvalRoot, options.transaction);
3626
+ }
3627
+ return result;
3437
3628
  }
3438
3629
  async configure(values, options = {}) {
3439
3630
  const target = this.normalizeWriteTarget("configure", values == null ? void 0 : values.target, values);
@@ -3455,7 +3646,7 @@ class FlowSurfacesService {
3455
3646
  if (SIMPLE_FORM_BLOCK_USES.has((current == null ? void 0 : current.use) || "")) {
3456
3647
  return this.configureFormBlock(target, current.use, values.changes, options);
3457
3648
  }
3458
- if ((current == null ? void 0 : current.use) === "DetailsBlockModel") {
3649
+ if (DETAILS_BLOCK_USES.has((current == null ? void 0 : current.use) || "")) {
3459
3650
  return this.configureDetailsBlock(target, values.changes, options);
3460
3651
  }
3461
3652
  if ((current == null ? void 0 : current.use) === "FilterFormBlockModel") {
@@ -4223,7 +4414,8 @@ class FlowSurfacesService {
4223
4414
  {
4224
4415
  context: "addBlock",
4225
4416
  enabledPackages: options.enabledPackages,
4226
- requireCreateSupported: true
4417
+ requireCreateSupported: true,
4418
+ skipContainerValidation: true
4227
4419
  }
4228
4420
  );
4229
4421
  if (expectedBlock.use !== template.useModel) {
@@ -4386,17 +4578,6 @@ class FlowSurfacesService {
4386
4578
  (0, import_errors.throwBadRequest)("flowSurfaces addBlock does not allow resource and resourceInit at the same time");
4387
4579
  }
4388
4580
  const enabledPackages = await this.resolveEnabledPluginPackages(options);
4389
- const catalogItem = (0, import_catalog.resolveSupportedBlockCatalogItem)(
4390
- {
4391
- type: values.type,
4392
- use: values.use
4393
- },
4394
- {
4395
- context: "addBlock",
4396
- enabledPackages,
4397
- requireCreateSupported: true
4398
- }
4399
- );
4400
4581
  let resolvedTarget = await this.locator.resolve(target, options);
4401
4582
  let targetNode = await this.loadResolvedNode(resolvedTarget, options.transaction);
4402
4583
  const targetOpenView = this.resolvePopupHostOpenView(targetNode);
@@ -4411,6 +4592,26 @@ class FlowSurfacesService {
4411
4592
  targetNode,
4412
4593
  options.transaction
4413
4594
  );
4595
+ const { parentUid, subKey, subType, popupSurface } = await this.surfaceContext.resolveBlockParent(
4596
+ target,
4597
+ options.transaction
4598
+ );
4599
+ const parentNode = await this.repository.findModelById(parentUid, {
4600
+ transaction: options.transaction,
4601
+ includeAsyncNode: true
4602
+ });
4603
+ const catalogItem = (0, import_catalog.resolveSupportedBlockCatalogItem)(
4604
+ {
4605
+ type: values.type,
4606
+ use: values.use,
4607
+ containerUse: parentNode == null ? void 0 : parentNode.use
4608
+ },
4609
+ {
4610
+ context: "addBlock",
4611
+ enabledPackages,
4612
+ requireCreateSupported: true
4613
+ }
4614
+ );
4414
4615
  const resolvedResourceInit = await this.resolvePopupCollectionBlockResourceInit({
4415
4616
  actionName: "addBlock",
4416
4617
  blockUse: catalogItem.use,
@@ -4424,16 +4625,13 @@ class FlowSurfacesService {
4424
4625
  resourceInit: resolvedResourceInit,
4425
4626
  resourceField: rawResourceInit ? "resourceInit" : (semanticResource == null ? void 0 : semanticResource.kind) === "raw" ? "resource" : void 0
4426
4627
  });
4427
- const { parentUid, subKey, subType, popupSurface } = await this.surfaceContext.resolveBlockParent(
4428
- target,
4429
- options.transaction
4430
- );
4431
4628
  const initialGrid = options.deferAutoLayout ? null : await this.repository.findModelById(parentUid, {
4432
4629
  transaction: options.transaction,
4433
4630
  includeAsyncNode: true
4434
4631
  });
4435
4632
  const tree = (0, import_builder.buildBlockTree)({
4436
4633
  use: catalogItem.use,
4634
+ containerUse: parentNode == null ? void 0 : parentNode.use,
4437
4635
  resourceInit: resolvedResourceInit,
4438
4636
  props: values.props,
4439
4637
  decoratorProps: values.decoratorProps,
@@ -4516,11 +4714,13 @@ class FlowSurfacesService {
4516
4714
  "flowRegistry"
4517
4715
  ]);
4518
4716
  const inlineSettings = this.normalizeInlineSettings("addField", values.settings);
4519
- const inlinePopup = this.normalizeInlinePopup("addField", values.popup);
4717
+ let inlinePopup = this.normalizeInlinePopup("addField", values.popup);
4718
+ this.assertInlinePopupTemplateAliasesSupported("addField", inlinePopup, options.popupTemplateAliasSession);
4520
4719
  const resolvedTarget = await this.locator.resolve(target, options);
4521
4720
  const container = await this.surfaceContext.resolveFieldContainer(resolvedTarget.uid, options.transaction);
4522
4721
  const enabledPackages = await this.resolveEnabledPluginPackages(options);
4523
4722
  const isFilterFormItem = container.wrapperUse === "FilterFormItemModel";
4723
+ const isApprovalFormTarget = (0, import_approval.isApprovalFormContainerUse)(container.ownerUse);
4524
4724
  const requestedStandaloneType = typeof values.type === "string" && values.type.trim().length ? values.type.trim() : void 0;
4525
4725
  const fieldCapability = (0, import_catalog.resolveSupportedFieldCapability)({
4526
4726
  containerUse: container.ownerUse,
@@ -4537,6 +4737,9 @@ class FlowSurfacesService {
4537
4737
  if (isFilterFormItem) {
4538
4738
  (0, import_errors.throwBadRequest)(`flowSurfaces addField type '${values.type}' is not allowed under filter-form`);
4539
4739
  }
4740
+ if (isApprovalFormTarget && requestedStandaloneType === "jsItem") {
4741
+ (0, import_errors.throwBadRequest)(`flowSurfaces addField type 'jsItem' is not allowed under approval form`);
4742
+ }
4540
4743
  const node = (0, import_builder.buildStandaloneFieldNode)({
4541
4744
  use: fieldCapability.standaloneUse,
4542
4745
  props: values.props || values.wrapperProps,
@@ -4686,6 +4889,12 @@ class FlowSurfacesService {
4686
4889
  if (inlinePopup && !this.isPopupFieldHostUse(boundFieldCapability.fieldUse)) {
4687
4890
  (0, import_errors.throwBadRequest)(`flowSurfaces addField field '${boundFieldCapability.fieldUse}' does not support popup`);
4688
4891
  }
4892
+ if (values.__autoPopupForRelationField === true && !inlinePopup && this.isPopupFieldHostUse(boundFieldCapability.fieldUse) && ((0, import_service_helpers.isAssociationField)(resolvedField.field) || !!normalizedFieldBinding.associationPathName) && !this.peekInlineFieldSettingsOpenView(inlineSettings, boundFieldCapability.wrapperUse)) {
4893
+ inlinePopup = this.normalizeInlinePopup("addField", {
4894
+ tryTemplate: true,
4895
+ defaultType: "view"
4896
+ });
4897
+ }
4689
4898
  if (inlinePopup && this.isExternalPopupOpenView(
4690
4899
  this.peekInlineFieldSettingsOpenView(inlineSettings, boundFieldCapability.wrapperUse)
4691
4900
  )) {
@@ -4767,6 +4976,7 @@ class FlowSurfacesService {
4767
4976
  (0, import_service_utils.ensureNoRawDirectAddKeys)("addAction", values, ["props", "decoratorProps", "stepParams", "flowRegistry"]);
4768
4977
  const inlineSettings = this.normalizeInlineSettings("addAction", values.settings);
4769
4978
  const inlinePopup = this.normalizeInlinePopup("addAction", values.popup);
4979
+ this.assertInlinePopupTemplateAliasesSupported("addAction", inlinePopup, options.popupTemplateAliasSession);
4770
4980
  const enabledPackages = await this.resolveEnabledPluginPackages(options);
4771
4981
  const container = await this.surfaceContext.resolveActionContainer(target, options.transaction);
4772
4982
  if ((0, import_action_scope.getActionContainerScope)(container.ownerUse) === "record") {
@@ -4792,6 +5002,7 @@ class FlowSurfacesService {
4792
5002
  if (inlinePopup && !POPUP_ACTION_USES.has(actionCatalogItem.use)) {
4793
5003
  (0, import_errors.throwBadRequest)(`flowSurfaces addAction type '${actionCatalogItem.key}' does not support popup`);
4794
5004
  }
5005
+ await this.assertApprovalActionSingleton(container.parentUid, actionCatalogItem.use, options.transaction);
4795
5006
  (0, import_action_scope.assertRequestedActionScope)({
4796
5007
  requestedScope: void 0,
4797
5008
  resolvedScope,
@@ -4819,8 +5030,14 @@ class FlowSurfacesService {
4819
5030
  { transaction: options.transaction }
4820
5031
  );
4821
5032
  await this.applyInlineNodeSettings("addAction", created, inlineSettings, options);
4822
- await this.applyInlineActionPopup("addAction", created, inlinePopup, options);
5033
+ await this.applyInlineActionPopup("addAction", created, inlinePopup, {
5034
+ ...options,
5035
+ popupActionContext: {
5036
+ hasCurrentRecord: false
5037
+ }
5038
+ });
4823
5039
  await this.syncFlowTemplateUsagesForNodeTree(created, options.transaction);
5040
+ await this.syncApprovalRuntimeConfigForNode(created, options.transaction);
4824
5041
  const result = {
4825
5042
  uid: created,
4826
5043
  parentUid: container.parentUid,
@@ -4837,6 +5054,7 @@ class FlowSurfacesService {
4837
5054
  (0, import_service_utils.ensureNoRawDirectAddKeys)("addRecordAction", values, ["props", "decoratorProps", "stepParams", "flowRegistry"]);
4838
5055
  const inlineSettings = this.normalizeInlineSettings("addRecordAction", values.settings);
4839
5056
  const inlinePopup = this.normalizeInlinePopup("addRecordAction", values.popup);
5057
+ this.assertInlinePopupTemplateAliasesSupported("addRecordAction", inlinePopup, options.popupTemplateAliasSession);
4840
5058
  const enabledPackages = await this.resolveEnabledPluginPackages(options);
4841
5059
  const container = await this.inspectRecordActionContainer(target, options.transaction);
4842
5060
  const actionCatalogItem = this.resolveAddRecordActionCatalogItem(
@@ -4883,7 +5101,12 @@ class FlowSurfacesService {
4883
5101
  { transaction: options.transaction }
4884
5102
  );
4885
5103
  await this.applyInlineNodeSettings("addRecordAction", created, inlineSettings, options);
4886
- await this.applyInlineActionPopup("addRecordAction", created, inlinePopup, options);
5104
+ await this.applyInlineActionPopup("addRecordAction", created, inlinePopup, {
5105
+ ...options,
5106
+ popupActionContext: {
5107
+ hasCurrentRecord: true
5108
+ }
5109
+ });
4887
5110
  await this.syncFlowTemplateUsagesForNodeTree(created, options.transaction);
4888
5111
  const result = {
4889
5112
  uid: created,
@@ -4949,6 +5172,218 @@ class FlowSurfacesService {
4949
5172
  invoke: (itemValues, options) => this.addRecordAction(itemValues, options)
4950
5173
  });
4951
5174
  }
5175
+ createPopupTemplateAliasSession() {
5176
+ return /* @__PURE__ */ new Map();
5177
+ }
5178
+ normalizePopupTemplateAliasName(value, fieldName) {
5179
+ if (import_lodash.default.isUndefined(value)) {
5180
+ return void 0;
5181
+ }
5182
+ if (typeof value !== "string" || !value.trim()) {
5183
+ (0, import_errors.throwBadRequest)(`${fieldName} must be a non-empty string`);
5184
+ }
5185
+ return value.trim();
5186
+ }
5187
+ readInlinePopupTemplateLocalAlias(popup, fieldName = "popup.template.local") {
5188
+ if (!import_lodash.default.isPlainObject(popup == null ? void 0 : popup.template)) {
5189
+ return void 0;
5190
+ }
5191
+ return this.normalizePopupTemplateAliasName(popup.template.local, fieldName);
5192
+ }
5193
+ readInlinePopupSaveAsTemplateLocalAlias(popup, fieldName = "popup.saveAsTemplate.local") {
5194
+ if (!import_lodash.default.isPlainObject(popup == null ? void 0 : popup.saveAsTemplate)) {
5195
+ return void 0;
5196
+ }
5197
+ return this.normalizePopupTemplateAliasName(popup.saveAsTemplate.local, fieldName);
5198
+ }
5199
+ assertInlinePopupTemplateAliasesSupported(actionName, popup, popupTemplateAliasSession, popupPath = "popup") {
5200
+ if (!import_lodash.default.isPlainObject(popup) || popupTemplateAliasSession) {
5201
+ return;
5202
+ }
5203
+ if (this.readInlinePopupTemplateLocalAlias(popup, `${popupPath}.template.local`)) {
5204
+ (0, import_errors.throwBadRequest)(
5205
+ `flowSurfaces ${actionName} ${popupPath}.template.local is only supported in compose and applyBlueprint`
5206
+ );
5207
+ }
5208
+ if (this.readInlinePopupSaveAsTemplateLocalAlias(popup, `${popupPath}.saveAsTemplate.local`)) {
5209
+ (0, import_errors.throwBadRequest)(
5210
+ `flowSurfaces ${actionName} ${popupPath}.saveAsTemplate.local is only supported in compose and applyBlueprint`
5211
+ );
5212
+ }
5213
+ if (!(0, import_default_action_popup.hasFlowSurfaceInlinePopupBlocks)(popup)) {
5214
+ return;
5215
+ }
5216
+ this.assertInlinePopupTemplateAliasesSupportedInBlocks(
5217
+ actionName,
5218
+ import_lodash.default.castArray(popup.blocks || []),
5219
+ popupTemplateAliasSession,
5220
+ `${popupPath}.blocks`
5221
+ );
5222
+ }
5223
+ assertInlinePopupTemplateAliasesSupportedInBlocks(actionName, blocks, popupTemplateAliasSession, blocksPath = "popup.blocks") {
5224
+ if (!(blocks == null ? void 0 : blocks.length) || popupTemplateAliasSession) {
5225
+ return;
5226
+ }
5227
+ const normalizedBlocks = import_lodash.default.castArray(blocks || []);
5228
+ ["fields", "actions", "recordActions"].forEach((phase) => {
5229
+ normalizedBlocks.forEach((block, blockIndex) => {
5230
+ import_lodash.default.castArray((block == null ? void 0 : block[phase]) || []).forEach((item, itemIndex) => {
5231
+ this.assertInlinePopupTemplateAliasesSupported(
5232
+ actionName,
5233
+ import_lodash.default.isPlainObject(item == null ? void 0 : item.popup) ? item.popup : void 0,
5234
+ popupTemplateAliasSession,
5235
+ `${blocksPath}[${blockIndex}].${phase}[${itemIndex}].popup`
5236
+ );
5237
+ });
5238
+ });
5239
+ });
5240
+ }
5241
+ prepareInlinePopupTemplateAliases(actionName, popup, popupTemplateAliasSession) {
5242
+ if (!import_lodash.default.isPlainObject(popup)) {
5243
+ return popup;
5244
+ }
5245
+ const template = import_lodash.default.isPlainObject(popup.template) ? popup.template : void 0;
5246
+ const templateLocal = this.readInlinePopupTemplateLocalAlias(popup);
5247
+ if (templateLocal) {
5248
+ if (String((template == null ? void 0 : template.uid) || "").trim()) {
5249
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} popup.template cannot combine popup.template.uid and local`);
5250
+ }
5251
+ if (popup.tryTemplate === true) {
5252
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} popup.template.local cannot be combined with popup.tryTemplate`);
5253
+ }
5254
+ if (!popupTemplateAliasSession) {
5255
+ (0, import_errors.throwBadRequest)(
5256
+ `flowSurfaces ${actionName} popup.template.local is only supported in compose and applyBlueprint`
5257
+ );
5258
+ }
5259
+ const matchedTemplateUid = popupTemplateAliasSession.get(templateLocal);
5260
+ if (!matchedTemplateUid) {
5261
+ (0, import_errors.throwBadRequest)(
5262
+ `flowSurfaces ${actionName} popup.template.local '${templateLocal}' must reference an earlier popup.saveAsTemplate.local in the same request`
5263
+ );
5264
+ }
5265
+ const nextPopup = import_lodash.default.cloneDeep(popup);
5266
+ nextPopup.template = (0, import_service_utils.buildDefinedPayload)({
5267
+ ...import_lodash.default.omit(template, ["local"]),
5268
+ uid: matchedTemplateUid
5269
+ });
5270
+ return nextPopup;
5271
+ }
5272
+ const saveAsTemplateLocal = this.readInlinePopupSaveAsTemplateLocalAlias(popup);
5273
+ if (!saveAsTemplateLocal) {
5274
+ return popup;
5275
+ }
5276
+ if (!popupTemplateAliasSession) {
5277
+ (0, import_errors.throwBadRequest)(
5278
+ `flowSurfaces ${actionName} popup.saveAsTemplate.local is only supported in compose and applyBlueprint`
5279
+ );
5280
+ }
5281
+ if (popupTemplateAliasSession.has(saveAsTemplateLocal)) {
5282
+ (0, import_errors.throwBadRequest)(
5283
+ `flowSurfaces ${actionName} popup.saveAsTemplate.local '${saveAsTemplateLocal}' is duplicated in the same request`
5284
+ );
5285
+ }
5286
+ return popup;
5287
+ }
5288
+ registerInlinePopupTemplateAlias(actionName, popup, savedTemplate, popupTemplateAliasSession) {
5289
+ const local = this.readInlinePopupSaveAsTemplateLocalAlias(popup);
5290
+ if (!local) {
5291
+ return;
5292
+ }
5293
+ if (!popupTemplateAliasSession) {
5294
+ (0, import_errors.throwBadRequest)(
5295
+ `flowSurfaces ${actionName} popup.saveAsTemplate.local is only supported in compose and applyBlueprint`
5296
+ );
5297
+ }
5298
+ if (popupTemplateAliasSession.has(local)) {
5299
+ (0, import_errors.throwBadRequest)(
5300
+ `flowSurfaces ${actionName} popup.saveAsTemplate.local '${local}' is duplicated in the same request`
5301
+ );
5302
+ }
5303
+ const templateUid = String((savedTemplate == null ? void 0 : savedTemplate.uid) || "").trim();
5304
+ if (!templateUid) {
5305
+ (0, import_errors.throwConflict)(
5306
+ `flowSurfaces ${actionName} popup.saveAsTemplate.local '${local}' did not produce a saved template uid`,
5307
+ "FLOW_SURFACE_TEMPLATE_COPY_FAILED"
5308
+ );
5309
+ }
5310
+ popupTemplateAliasSession.set(local, templateUid);
5311
+ }
5312
+ validatePopupTemplateAliasesInBlocks(blocks, availableAliases, blocksPath) {
5313
+ const normalizedBlocks = import_lodash.default.castArray(blocks || []);
5314
+ ["fields", "actions", "recordActions"].forEach((phase) => {
5315
+ normalizedBlocks.forEach((block, blockIndex) => {
5316
+ import_lodash.default.castArray((block == null ? void 0 : block[phase]) || []).forEach((item, itemIndex) => {
5317
+ this.validatePopupTemplateAliasesForItemPopup(
5318
+ import_lodash.default.isPlainObject(item == null ? void 0 : item.popup) ? item.popup : void 0,
5319
+ availableAliases,
5320
+ `${blocksPath}[${blockIndex}].${phase}[${itemIndex}]`
5321
+ );
5322
+ });
5323
+ });
5324
+ });
5325
+ }
5326
+ validatePopupTemplateAliasesForItemPopup(popup, availableAliases, itemPath) {
5327
+ if (!import_lodash.default.isPlainObject(popup)) {
5328
+ return;
5329
+ }
5330
+ const template = import_lodash.default.isPlainObject(popup.template) ? popup.template : void 0;
5331
+ const templateUid = String((template == null ? void 0 : template.uid) || "").trim();
5332
+ const templateLocal = this.readInlinePopupTemplateLocalAlias(popup, `${itemPath}.popup.template.local`);
5333
+ if (templateLocal && templateUid) {
5334
+ (0, import_errors.throwBadRequest)(`${itemPath}.popup.template cannot combine uid and local`);
5335
+ }
5336
+ if (templateLocal && popup.tryTemplate === true) {
5337
+ (0, import_errors.throwBadRequest)(`${itemPath}.popup.template.local cannot be combined with ${itemPath}.popup.tryTemplate`);
5338
+ }
5339
+ if (templateLocal && !availableAliases.has(templateLocal)) {
5340
+ (0, import_errors.throwBadRequest)(
5341
+ `${itemPath}.popup.template.local '${templateLocal}' must reference an earlier popup.saveAsTemplate.local in the same request`
5342
+ );
5343
+ }
5344
+ const hasExplicitTemplate = !!(templateUid || templateLocal);
5345
+ if (!hasExplicitTemplate && (0, import_default_action_popup.hasFlowSurfaceInlinePopupBlocks)(popup)) {
5346
+ this.validatePopupTemplateAliasesInBlocks(
5347
+ import_lodash.default.castArray(popup.blocks || []),
5348
+ availableAliases,
5349
+ `${itemPath}.popup.blocks`
5350
+ );
5351
+ }
5352
+ const saveAsTemplateLocal = this.readInlinePopupSaveAsTemplateLocalAlias(
5353
+ popup,
5354
+ `${itemPath}.popup.saveAsTemplate.local`
5355
+ );
5356
+ if (!saveAsTemplateLocal) {
5357
+ return;
5358
+ }
5359
+ if (availableAliases.has(saveAsTemplateLocal)) {
5360
+ (0, import_errors.throwBadRequest)(
5361
+ `${itemPath}.popup.saveAsTemplate.local '${saveAsTemplateLocal}' is duplicated in the same request`
5362
+ );
5363
+ }
5364
+ availableAliases.add(saveAsTemplateLocal);
5365
+ }
5366
+ validateComposePopupTemplateAliases(blocks, popupTemplateAliasSession) {
5367
+ const availableAliases = new Set(popupTemplateAliasSession ? popupTemplateAliasSession.keys() : []);
5368
+ this.validatePopupTemplateAliasesInBlocks(
5369
+ blocks,
5370
+ availableAliases,
5371
+ "flowSurfaces compose.blocks"
5372
+ );
5373
+ }
5374
+ validateApplyBlueprintPopupTemplateAliases(document, popupTemplateAliasSession) {
5375
+ const availableAliases = new Set(popupTemplateAliasSession ? popupTemplateAliasSession.keys() : []);
5376
+ document.tabs.forEach((tab, tabIndex) => {
5377
+ const composeValues = (0, import_compile_blocks.compileTabComposeValues)(tab, document, tabIndex, {
5378
+ mode: document.mode === "replace" ? "replace" : "append"
5379
+ });
5380
+ this.validatePopupTemplateAliasesInBlocks(
5381
+ import_lodash.default.castArray(composeValues.blocks || []),
5382
+ availableAliases,
5383
+ `flowSurfaces applyBlueprint tabs[${tabIndex}].blocks`
5384
+ );
5385
+ });
5386
+ }
4952
5387
  normalizeInlineSettings(actionName, settings) {
4953
5388
  if (import_lodash.default.isUndefined(settings)) {
4954
5389
  return void 0;
@@ -4965,7 +5400,79 @@ class FlowSurfacesService {
4965
5400
  if (!import_lodash.default.isPlainObject(popup)) {
4966
5401
  (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} popup must be an object`);
4967
5402
  }
4968
- return popup;
5403
+ const normalizedPopup = import_lodash.default.cloneDeep(popup);
5404
+ const tryTemplate = this.normalizeOptionalPopupTryTemplate(actionName, normalizedPopup.tryTemplate);
5405
+ const defaultType = this.normalizePopupDefaultType(actionName, normalizedPopup.defaultType);
5406
+ const saveAsTemplate = this.normalizePopupSaveAsTemplate(actionName, normalizedPopup.saveAsTemplate);
5407
+ if (saveAsTemplate && !import_lodash.default.isUndefined(normalizedPopup.template)) {
5408
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} popup.saveAsTemplate cannot be combined with popup.template`);
5409
+ }
5410
+ if (saveAsTemplate && !import_lodash.default.isUndefined(tryTemplate)) {
5411
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} popup.saveAsTemplate cannot be combined with popup.tryTemplate`);
5412
+ }
5413
+ if (import_lodash.default.isUndefined(tryTemplate)) {
5414
+ delete normalizedPopup.tryTemplate;
5415
+ } else {
5416
+ normalizedPopup.tryTemplate = tryTemplate;
5417
+ }
5418
+ if (import_lodash.default.isUndefined(defaultType)) {
5419
+ delete normalizedPopup.defaultType;
5420
+ } else {
5421
+ normalizedPopup.defaultType = defaultType;
5422
+ }
5423
+ if (import_lodash.default.isUndefined(saveAsTemplate)) {
5424
+ delete normalizedPopup.saveAsTemplate;
5425
+ } else {
5426
+ normalizedPopup.saveAsTemplate = saveAsTemplate;
5427
+ }
5428
+ return normalizedPopup;
5429
+ }
5430
+ normalizePopupSaveAsTemplate(actionName, value, fieldName = "popup.saveAsTemplate") {
5431
+ if (import_lodash.default.isUndefined(value)) {
5432
+ return void 0;
5433
+ }
5434
+ if (!import_lodash.default.isPlainObject(value)) {
5435
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} ${fieldName} must be an object`);
5436
+ }
5437
+ return {
5438
+ name: (0, import_template_service_utils.normalizeRequiredTemplateString)(actionName, value.name, `${fieldName}.name`),
5439
+ description: (0, import_template_service_utils.normalizeRequiredTemplateString)(actionName, value.description, `${fieldName}.description`),
5440
+ local: this.normalizePopupTemplateAliasName(value.local, `${fieldName}.local`)
5441
+ };
5442
+ }
5443
+ hasInlinePopupSaveAsTemplateSource(popup) {
5444
+ return (0, import_default_action_popup.hasFlowSurfaceInlinePopupBlocks)(popup);
5445
+ }
5446
+ assertInlinePopupSaveAsTemplateSource(actionName, popup) {
5447
+ if (!(popup == null ? void 0 : popup.saveAsTemplate)) {
5448
+ return;
5449
+ }
5450
+ if (!this.hasInlinePopupSaveAsTemplateSource(popup)) {
5451
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} popup.saveAsTemplate requires explicit local popup.blocks`);
5452
+ }
5453
+ }
5454
+ clearPopupSurfaceKeys(result) {
5455
+ delete result.popupPageUid;
5456
+ delete result.popupTabUid;
5457
+ delete result.popupGridUid;
5458
+ }
5459
+ async savePopupAsTemplate(hostUid, popup, options) {
5460
+ const normalizedHostUid = String(hostUid || "").trim();
5461
+ const saveAsTemplate = popup == null ? void 0 : popup.saveAsTemplate;
5462
+ if (!normalizedHostUid || !saveAsTemplate) {
5463
+ return;
5464
+ }
5465
+ return this.saveTemplate(
5466
+ {
5467
+ target: {
5468
+ uid: normalizedHostUid
5469
+ },
5470
+ name: saveAsTemplate.name,
5471
+ description: saveAsTemplate.description,
5472
+ saveMode: "convert"
5473
+ },
5474
+ options
5475
+ );
4969
5476
  }
4970
5477
  buildInlinePopupTemplateOpenView(popup) {
4971
5478
  const normalizedTitle = import_lodash.default.isUndefined(popup == null ? void 0 : popup.title) || import_lodash.default.isNull(popup == null ? void 0 : popup.title) ? void 0 : String(popup.title).trim() || void 0;
@@ -5041,6 +5548,121 @@ class FlowSurfacesService {
5041
5548
  ...options.expectedType ? { expectedType: options.expectedType } : {}
5042
5549
  };
5043
5550
  }
5551
+ normalizeOptionalPopupTryTemplate(actionName, value, fieldName = "popup.tryTemplate") {
5552
+ if (import_lodash.default.isUndefined(value)) {
5553
+ return void 0;
5554
+ }
5555
+ if (typeof value !== "boolean") {
5556
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} ${fieldName} must be a boolean`);
5557
+ }
5558
+ return value;
5559
+ }
5560
+ normalizePopupDefaultType(actionName, value, fieldName = "popup.defaultType") {
5561
+ if (import_lodash.default.isUndefined(value)) {
5562
+ return void 0;
5563
+ }
5564
+ const normalized = String(value || "").trim();
5565
+ if (!(0, import_default_action_popup.isFlowSurfaceDefaultActionPopupType)(normalized) || normalized === "addNew") {
5566
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} ${fieldName} only supports 'view' or 'edit'`);
5567
+ }
5568
+ return normalized;
5569
+ }
5570
+ getDefaultFlowTemplateSort(sort) {
5571
+ const normalizedSort = import_lodash.default.castArray(sort).map((item) => String(item || "").trim()).filter(Boolean);
5572
+ if (normalizedSort.length > 0) {
5573
+ return normalizedSort;
5574
+ }
5575
+ return ["-updatedAt", "-createdAt", "uid"];
5576
+ }
5577
+ getPopupTryTemplateExpectedAssociationName(targetContext) {
5578
+ var _a, _b, _c;
5579
+ if ((_a = targetContext == null ? void 0 : targetContext.popupProfile) == null ? void 0 : _a.isPopupSurface) {
5580
+ return String(targetContext.popupProfile.associationName || "").trim() || void 0;
5581
+ }
5582
+ return String(((_c = (_b = targetContext == null ? void 0 : targetContext.resourceContext) == null ? void 0 : _b.resourceInit) == null ? void 0 : _c.associationName) || "").trim() || void 0;
5583
+ }
5584
+ getPopupTryTemplatePriority(template, expectedAssociationName) {
5585
+ const templateAssociationName = String(template.associationName || "").trim() || void 0;
5586
+ if (!expectedAssociationName) {
5587
+ return templateAssociationName ? null : 0;
5588
+ }
5589
+ if (templateAssociationName === expectedAssociationName) {
5590
+ return 0;
5591
+ }
5592
+ if (!templateAssociationName) {
5593
+ return 1;
5594
+ }
5595
+ return null;
5596
+ }
5597
+ getRequestedPopupDefaultType(popup) {
5598
+ const normalized = String((popup == null ? void 0 : popup.defaultType) || "").trim();
5599
+ if (normalized === "view" || normalized === "edit") {
5600
+ return normalized;
5601
+ }
5602
+ return void 0;
5603
+ }
5604
+ inferPopupDefaultTypeFromTemplateTree(node) {
5605
+ var _a, _b, _c, _d;
5606
+ const popupPage = (0, import_service_utils.getSingleNodeSubModel)((_a = node == null ? void 0 : node.subModels) == null ? void 0 : _a.page);
5607
+ const popupTab = import_lodash.default.castArray(((_b = popupPage == null ? void 0 : popupPage.subModels) == null ? void 0 : _b.tabs) || [])[0];
5608
+ const popupGrid = (0, import_service_utils.getSingleNodeSubModel)((_c = popupTab == null ? void 0 : popupTab.subModels) == null ? void 0 : _c.grid);
5609
+ const popupBlock = (0, import_service_utils.getNodeSubModelList)((_d = popupGrid == null ? void 0 : popupGrid.subModels) == null ? void 0 : _d.items)[0];
5610
+ if ((popupBlock == null ? void 0 : popupBlock.use) === "DetailsBlockModel") {
5611
+ return "view";
5612
+ }
5613
+ if ((popupBlock == null ? void 0 : popupBlock.use) === "EditFormModel") {
5614
+ return "edit";
5615
+ }
5616
+ return void 0;
5617
+ }
5618
+ async popupTemplateMatchesDefaultType(template, popup, options = {}) {
5619
+ const requestedDefaultType = this.getRequestedPopupDefaultType(popup);
5620
+ if (!requestedDefaultType) {
5621
+ return true;
5622
+ }
5623
+ const templateTargetUid = String((template == null ? void 0 : template.targetUid) || "").trim();
5624
+ if (!templateTargetUid) {
5625
+ return false;
5626
+ }
5627
+ const templateTree = await this.repository.findModelById(templateTargetUid, {
5628
+ transaction: options.transaction,
5629
+ includeAsyncNode: true
5630
+ });
5631
+ return this.inferPopupDefaultTypeFromTemplateTree(templateTree) === requestedDefaultType;
5632
+ }
5633
+ async tryResolvePopupTemplateForHost(actionName, popup, hostUid, options = {}) {
5634
+ const normalizedHostUid = String(hostUid || "").trim();
5635
+ if (!normalizedHostUid || !import_lodash.default.isPlainObject(popup) || !popup.tryTemplate || !import_lodash.default.isUndefined(popup.template)) {
5636
+ return null;
5637
+ }
5638
+ const repo = this.getFlowTemplateRepository(actionName);
5639
+ const targetContext = await this.loadTemplateListTargetContext({ uid: normalizedHostUid }, options.transaction);
5640
+ const templates = await repo.find({
5641
+ filter: (0, import_template_service_utils.buildTemplateListFilter)(void 0, void 0, "popup"),
5642
+ sort: this.getDefaultFlowTemplateSort(),
5643
+ transaction: options.transaction
5644
+ });
5645
+ const annotatedTemplates = await this.withTemplateAvailability(
5646
+ await this.withFlowTemplateUsageCounts(templates, actionName, options),
5647
+ {
5648
+ requestedType: "popup",
5649
+ targetContext,
5650
+ popupActionContext: options.popupActionContext
5651
+ }
5652
+ );
5653
+ const expectedAssociationName = this.getPopupTryTemplateExpectedAssociationName(targetContext);
5654
+ for (const priority of [0, 1]) {
5655
+ for (const template of annotatedTemplates) {
5656
+ if (template.available !== true || this.getPopupTryTemplatePriority(template, expectedAssociationName) !== priority) {
5657
+ continue;
5658
+ }
5659
+ if (await this.popupTemplateMatchesDefaultType(template, popup, options)) {
5660
+ return template;
5661
+ }
5662
+ }
5663
+ }
5664
+ return null;
5665
+ }
5044
5666
  async getFlowTemplateOrThrow(actionName, templateUid, options = {}) {
5045
5667
  const repo = this.getFlowTemplateRepository(actionName);
5046
5668
  const templateRecord = await repo.findOne({
@@ -5163,6 +5785,26 @@ class FlowSurfacesService {
5163
5785
  (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} openView must be an object`);
5164
5786
  }
5165
5787
  const normalizedOpenView = import_lodash.default.cloneDeep(openView);
5788
+ const tryTemplate = this.normalizeOptionalPopupTryTemplate(
5789
+ actionName,
5790
+ normalizedOpenView.tryTemplate,
5791
+ "openView.tryTemplate"
5792
+ );
5793
+ delete normalizedOpenView.tryTemplate;
5794
+ if (tryTemplate && import_lodash.default.isUndefined(normalizedOpenView.template)) {
5795
+ const matchedTemplate = await this.tryResolvePopupTemplateForHost(
5796
+ actionName,
5797
+ { tryTemplate: true },
5798
+ options.popupTemplateHostUid,
5799
+ options
5800
+ );
5801
+ if (matchedTemplate == null ? void 0 : matchedTemplate.uid) {
5802
+ normalizedOpenView.template = {
5803
+ uid: matchedTemplate.uid,
5804
+ mode: "reference"
5805
+ };
5806
+ }
5807
+ }
5166
5808
  if (!import_lodash.default.isUndefined(normalizedOpenView.template)) {
5167
5809
  const templateRef = this.normalizeFlowTemplateReference(actionName, normalizedOpenView.template, {
5168
5810
  expectedType: "popup"
@@ -5218,6 +5860,36 @@ class FlowSurfacesService {
5218
5860
  }
5219
5861
  return normalizedOpenView;
5220
5862
  }
5863
+ isTryTemplateOnlyOpenViewRequest(openView) {
5864
+ if (!import_lodash.default.isPlainObject(openView) || openView.tryTemplate !== true || !import_lodash.default.isUndefined(openView.template)) {
5865
+ return false;
5866
+ }
5867
+ return Object.keys(openView).every((key) => key === "tryTemplate");
5868
+ }
5869
+ async resolveRecordContextPopupActionContextForHost(current, transaction) {
5870
+ const currentUse = String((current == null ? void 0 : current.use) || "").trim();
5871
+ if (!currentUse || !POPUP_ACTION_USES.has(currentUse) || !POPUP_HOST_DEFAULT_RECORD_CONTEXT_ACTION_USES.has(currentUse)) {
5872
+ return void 0;
5873
+ }
5874
+ const hostContext = await this.resolvePopupHostProfileContext(current, transaction).catch(() => null);
5875
+ if (!(hostContext == null ? void 0 : hostContext.recordActionContainerUse)) {
5876
+ return void 0;
5877
+ }
5878
+ return {
5879
+ hasCurrentRecord: true
5880
+ };
5881
+ }
5882
+ unsetPayloadPathAndPruneEmptyParents(payload, path) {
5883
+ import_lodash.default.unset(payload, path);
5884
+ for (let index = path.length - 1; index > 0; index -= 1) {
5885
+ const parentPath = path.slice(0, index);
5886
+ const parentValue = import_lodash.default.get(payload, parentPath);
5887
+ if (!import_lodash.default.isPlainObject(parentValue) || Object.keys(parentValue).length > 0) {
5888
+ break;
5889
+ }
5890
+ import_lodash.default.unset(payload, parentPath);
5891
+ }
5892
+ }
5221
5893
  isExternalPopupOpenView(openView, hostUid) {
5222
5894
  if (!import_lodash.default.isPlainObject(openView)) {
5223
5895
  return false;
@@ -5364,6 +6036,7 @@ class FlowSurfacesService {
5364
6036
  }
5365
6037
  }
5366
6038
  async applyInlineFieldPopup(actionName, result, popup, options) {
6039
+ popup = this.prepareInlinePopupTemplateAliases(actionName, popup, options.popupTemplateAliasSession);
5367
6040
  const fieldHostUid = result.fieldUid || result.uid;
5368
6041
  if (!import_lodash.default.isUndefined(popup == null ? void 0 : popup.template)) {
5369
6042
  Object.assign(
@@ -5383,23 +6056,78 @@ class FlowSurfacesService {
5383
6056
  );
5384
6057
  return;
5385
6058
  }
6059
+ const matchedTemplate = await this.tryResolvePopupTemplateForHost(actionName, popup, fieldHostUid, options);
6060
+ if (matchedTemplate == null ? void 0 : matchedTemplate.uid) {
6061
+ Object.assign(
6062
+ result,
6063
+ await this.configureFieldNode(
6064
+ {
6065
+ uid: fieldHostUid
6066
+ },
6067
+ {
6068
+ openView: this.buildInlinePopupTemplateOpenView({
6069
+ ...popup,
6070
+ template: {
6071
+ uid: matchedTemplate.uid,
6072
+ mode: "reference"
6073
+ }
6074
+ })
6075
+ },
6076
+ {
6077
+ ...options,
6078
+ openViewActionName: actionName
6079
+ }
6080
+ )
6081
+ );
6082
+ return;
6083
+ }
5386
6084
  try {
5387
- Object.assign(result, await this.ensureLocalFieldPopupSurface(actionName, fieldHostUid, options, { popup }));
5388
6085
  if (!popup || !fieldHostUid) {
5389
6086
  return;
5390
6087
  }
5391
- await this.compose(
5392
- {
5393
- target: {
5394
- uid: fieldHostUid
6088
+ const { fieldNode, wrapperNode } = await this.loadFieldHostNodes(fieldHostUid, options.transaction);
6089
+ this.assertInlinePopupSaveAsTemplateSource(actionName, popup);
6090
+ const hasLocalPopupContent = (0, import_default_action_popup.hasFlowSurfaceInlinePopupBlocks)(popup) || !import_lodash.default.isUndefined(popup.layout);
6091
+ if (popup.tryTemplate && !hasLocalPopupContent && !this.shouldAutoCompleteDefaultFieldPopup(fieldNode, popup)) {
6092
+ return;
6093
+ }
6094
+ const shouldAutoCompleteDefaultPopup = this.shouldAutoCompleteDefaultFieldPopup(fieldNode, popup);
6095
+ Object.assign(result, await this.ensureLocalFieldPopupSurface(actionName, fieldHostUid, options, { popup }));
6096
+ if (shouldAutoCompleteDefaultPopup) {
6097
+ const popupContext = this.resolveFieldOpenViewContext(fieldNode, wrapperNode);
6098
+ const defaultType = this.getRequestedPopupDefaultType(popup) || "view";
6099
+ await this.compose(
6100
+ {
6101
+ target: {
6102
+ uid: fieldHostUid
6103
+ },
6104
+ mode: popup.mode || "replace",
6105
+ blocks: this.buildDefaultFieldPopupBlocks(fieldNode, popupContext, defaultType),
6106
+ layout: popup.layout
5395
6107
  },
5396
- mode: popup.mode || "replace",
5397
- blocks: popup.blocks || [],
5398
- layout: popup.layout
5399
- },
5400
- options
5401
- );
5402
- Object.assign(result, await this.collectPopupSurfaceKeys(fieldHostUid, options.transaction));
6108
+ options
6109
+ );
6110
+ await this.autoSaveDefaultFieldPopupAsTemplate(result, popup, options);
6111
+ } else {
6112
+ await this.compose(
6113
+ {
6114
+ target: {
6115
+ uid: fieldHostUid
6116
+ },
6117
+ mode: popup.mode || "replace",
6118
+ blocks: popup.blocks || [],
6119
+ layout: popup.layout
6120
+ },
6121
+ options
6122
+ );
6123
+ Object.assign(result, await this.collectPopupSurfaceKeys(fieldHostUid, options.transaction));
6124
+ }
6125
+ if (popup.saveAsTemplate) {
6126
+ const savedTemplate = await this.savePopupAsTemplate(fieldHostUid, popup, options);
6127
+ this.registerInlinePopupTemplateAlias(actionName, popup, savedTemplate, options.popupTemplateAliasSession);
6128
+ this.clearPopupSurfaceKeys(result);
6129
+ Object.assign(result, await this.collectPopupSurfaceKeys(fieldHostUid, options.transaction));
6130
+ }
5403
6131
  } catch (error) {
5404
6132
  (0, import_service_utils.rethrowInlineConfigurationError)(error, `flowSurfaces ${actionName} popup invalid`);
5405
6133
  }
@@ -5419,25 +6147,31 @@ class FlowSurfacesService {
5419
6147
  });
5420
6148
  const { wrapperChanges, fieldChanges } = (0, import_service_utils.splitComposeFieldChanges)(settings, wrapperNode == null ? void 0 : wrapperNode.use);
5421
6149
  if (Object.keys(wrapperChanges).length) {
5422
- await this.configure(
5423
- {
5424
- target: {
5425
- uid: result.wrapperUid
6150
+ Object.assign(
6151
+ result,
6152
+ await this.configure(
6153
+ {
6154
+ target: {
6155
+ uid: result.wrapperUid
6156
+ },
6157
+ changes: wrapperChanges
5426
6158
  },
5427
- changes: wrapperChanges
5428
- },
5429
- options
6159
+ options
6160
+ )
5430
6161
  );
5431
6162
  }
5432
6163
  if (Object.keys(fieldChanges).length) {
5433
- await this.configure(
5434
- {
5435
- target: {
5436
- uid: result.fieldUid
6164
+ Object.assign(
6165
+ result,
6166
+ await this.configure(
6167
+ {
6168
+ target: {
6169
+ uid: result.fieldUid
6170
+ },
6171
+ changes: fieldChanges
5437
6172
  },
5438
- changes: fieldChanges
5439
- },
5440
- options
6173
+ options
6174
+ )
5441
6175
  );
5442
6176
  }
5443
6177
  } catch (error) {
@@ -5462,6 +6196,105 @@ class FlowSurfacesService {
5462
6196
  }
5463
6197
  return !(0, import_default_action_popup.hasFlowSurfaceInlinePopupTemplate)(popup) && !(0, import_default_action_popup.hasFlowSurfaceInlinePopupBlocks)(popup);
5464
6198
  }
6199
+ shouldAutoCompleteDefaultFieldPopup(fieldNode, popup) {
6200
+ if (!import_lodash.default.isPlainObject(popup)) {
6201
+ return false;
6202
+ }
6203
+ if (!this.isPopupFieldHostUse(fieldNode == null ? void 0 : fieldNode.use)) {
6204
+ return false;
6205
+ }
6206
+ if ((0, import_default_action_popup.hasFlowSurfaceInlinePopupTemplate)(popup) || (0, import_default_action_popup.hasFlowSurfaceInlinePopupBlocks)(popup) || !import_lodash.default.isUndefined(popup.layout)) {
6207
+ return false;
6208
+ }
6209
+ const fieldContext = this.resolveFieldOpenViewContext(fieldNode, null);
6210
+ if (!String(fieldContext.associationName || "").trim()) {
6211
+ return false;
6212
+ }
6213
+ return popup.tryTemplate === true || !import_lodash.default.isUndefined(popup.defaultType) || Object.keys(popup).length === 0;
6214
+ }
6215
+ buildDefaultFieldPopupFieldPaths(input) {
6216
+ const collectionName = String(input.popupContext.collectionName || "").trim();
6217
+ if (!collectionName) {
6218
+ return [];
6219
+ }
6220
+ const mode = input.defaultType === "edit" ? "form" : "details";
6221
+ const ownerUse = input.defaultType === "edit" ? "EditFormModel" : "DetailsBlockModel";
6222
+ const directCandidates = this.buildFieldMenuDirectCandidates({
6223
+ mode,
6224
+ ownerUse,
6225
+ resourceInit: {
6226
+ dataSourceKey: input.popupContext.dataSourceKey || "main",
6227
+ collectionName
6228
+ }
6229
+ });
6230
+ return (0, import_default_action_popup.pickFlowSurfaceDefaultActionPopupFieldPaths)(directCandidates, {
6231
+ excludeAuditTimestampFields: input.defaultType === "edit",
6232
+ excludeAssociationFields: true
6233
+ });
6234
+ }
6235
+ buildDefaultFieldPopupBlocks(fieldNode, popupContext, defaultType) {
6236
+ var _a;
6237
+ const actionUse = defaultType === "edit" ? "EditActionModel" : "ViewActionModel";
6238
+ const namespace = (0, import_service_utils.normalizeFlowSurfaceComposeKey)(
6239
+ `defaultFieldPopup_${(fieldNode == null ? void 0 : fieldNode.uid) || (0, import_utils.uid)()}`,
6240
+ `flowSurfaces default popup for field '${(fieldNode == null ? void 0 : fieldNode.uid) || "unknown"}'`
6241
+ );
6242
+ const keyMap = /* @__PURE__ */ new Map();
6243
+ const actionConfig = (0, import_default_action_popup.getFlowSurfaceDefaultActionPopupConfigByUse)(actionUse);
6244
+ if (actionConfig == null ? void 0 : actionConfig.blockKey) {
6245
+ keyMap.set(actionConfig.blockKey, `${namespace}.${actionConfig.blockKey}`);
6246
+ }
6247
+ if ((_a = actionConfig == null ? void 0 : actionConfig.submitAction) == null ? void 0 : _a.key) {
6248
+ keyMap.set(actionConfig.submitAction.key, `${namespace}.${actionConfig.submitAction.key}`);
6249
+ }
6250
+ const fieldPaths = this.buildDefaultFieldPopupFieldPaths({
6251
+ defaultType,
6252
+ fieldNode,
6253
+ popupContext
6254
+ });
6255
+ return this.remapDefaultActionPopupBlocks(
6256
+ (0, import_default_action_popup.buildFlowSurfaceDefaultActionPopupBlocks)(actionUse, fieldPaths),
6257
+ keyMap,
6258
+ namespace
6259
+ );
6260
+ }
6261
+ async autoSaveDefaultFieldPopupAsTemplate(result, popup, options) {
6262
+ const fieldHostUid = result.fieldUid || result.uid;
6263
+ if (!fieldHostUid) {
6264
+ return;
6265
+ }
6266
+ const openView = this.resolvePopupHostOpenView(
6267
+ await this.repository.findModelById(fieldHostUid, {
6268
+ transaction: options.transaction,
6269
+ includeAsyncNode: true
6270
+ })
6271
+ );
6272
+ if (String((openView == null ? void 0 : openView.popupTemplateUid) || "").trim()) {
6273
+ this.clearPopupSurfaceKeys(result);
6274
+ return;
6275
+ }
6276
+ const uniqueKeySource = JSON.stringify(
6277
+ (0, import_service_utils.buildDefinedPayload)({
6278
+ dataSourceKey: openView == null ? void 0 : openView.dataSourceKey,
6279
+ collectionName: openView == null ? void 0 : openView.collectionName,
6280
+ associationName: openView == null ? void 0 : openView.associationName,
6281
+ defaultType: this.getRequestedPopupDefaultType(popup) || "view"
6282
+ })
6283
+ );
6284
+ const identity = (0, import_crypto.createHash)("sha1").update(uniqueKeySource).digest("hex").slice(0, 12);
6285
+ await this.saveTemplate(
6286
+ {
6287
+ target: {
6288
+ uid: fieldHostUid
6289
+ },
6290
+ name: `Auto popup ${identity}`,
6291
+ description: `Auto-generated popup template ${identity}`,
6292
+ saveMode: "convert"
6293
+ },
6294
+ options
6295
+ );
6296
+ this.clearPopupSurfaceKeys(result);
6297
+ }
5465
6298
  shouldAutoCompleteDefaultActionPopup(actionNode, popup, options = {}) {
5466
6299
  if (options.autoCompleteDefaultPopup === false) {
5467
6300
  return false;
@@ -5718,11 +6551,17 @@ class FlowSurfacesService {
5718
6551
  }
5719
6552
  const openView = this.resolvePopupHostOpenView(actionNode);
5720
6553
  if (this.isExternalPopupOpenView(openView, actionNode == null ? void 0 : actionNode.uid)) {
6554
+ if (popup == null ? void 0 : popup.saveAsTemplate) {
6555
+ (0, import_errors.throwBadRequest)(
6556
+ `flowSurfaces ${actionName} popup.saveAsTemplate cannot be combined with external openView.uid`
6557
+ );
6558
+ }
5721
6559
  if (import_lodash.default.isUndefined(popup) || this.isSemanticallyEmptyInlinePopup(popup)) {
5722
6560
  return;
5723
6561
  }
5724
6562
  (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} popup cannot be combined with external openView.uid`);
5725
6563
  }
6564
+ popup = this.prepareInlinePopupTemplateAliases(actionName, popup, options.popupTemplateAliasSession);
5726
6565
  if (popup && (0, import_default_action_popup.hasFlowSurfaceInlinePopupTemplate)(popup)) {
5727
6566
  await this.configureActionNode(
5728
6567
  {
@@ -5739,10 +6578,38 @@ class FlowSurfacesService {
5739
6578
  );
5740
6579
  return;
5741
6580
  }
6581
+ const matchedTemplate = await this.tryResolvePopupTemplateForHost(actionName, popup, actionUid, options);
6582
+ if (matchedTemplate == null ? void 0 : matchedTemplate.uid) {
6583
+ await this.configureActionNode(
6584
+ {
6585
+ uid: actionUid
6586
+ },
6587
+ actionNode.use,
6588
+ {
6589
+ openView: this.buildInlinePopupTemplateOpenView({
6590
+ ...popup,
6591
+ template: {
6592
+ uid: matchedTemplate.uid,
6593
+ mode: "reference"
6594
+ }
6595
+ })
6596
+ },
6597
+ {
6598
+ ...options,
6599
+ openViewActionName: actionName
6600
+ }
6601
+ );
6602
+ return;
6603
+ }
5742
6604
  const shouldAutoCompleteDefaultPopup = this.shouldAutoCompleteDefaultActionPopup(actionNode, popup, options);
6605
+ this.assertInlinePopupSaveAsTemplateSource(actionName, popup);
6606
+ const hasLocalPopupContent = (0, import_default_action_popup.hasFlowSurfaceInlinePopupBlocks)(popup) || !import_lodash.default.isUndefined(popup == null ? void 0 : popup.layout);
5743
6607
  if (import_lodash.default.isUndefined(popup) && !shouldAutoCompleteDefaultPopup) {
5744
6608
  return;
5745
6609
  }
6610
+ if ((popup == null ? void 0 : popup.tryTemplate) && !hasLocalPopupContent && !shouldAutoCompleteDefaultPopup) {
6611
+ return;
6612
+ }
5746
6613
  try {
5747
6614
  if (shouldAutoCompleteDefaultPopup) {
5748
6615
  await this.applyDefaultActionPopupContent(actionNode, popup, options);
@@ -5759,6 +6626,10 @@ class FlowSurfacesService {
5759
6626
  options
5760
6627
  );
5761
6628
  }
6629
+ if (popup == null ? void 0 : popup.saveAsTemplate) {
6630
+ const savedTemplate = await this.savePopupAsTemplate(actionUid, popup, options);
6631
+ this.registerInlinePopupTemplateAlias(actionName, popup, savedTemplate, options.popupTemplateAliasSession);
6632
+ }
5762
6633
  } catch (error) {
5763
6634
  (0, import_service_utils.rethrowInlineConfigurationError)(error, `flowSurfaces ${actionName} popup invalid`);
5764
6635
  }
@@ -5791,13 +6662,15 @@ class FlowSurfacesService {
5791
6662
  );
5792
6663
  });
5793
6664
  this.syncMirroredStepParamsForUpdateSettings(current, nextPayload);
6665
+ const popupActionContext = options.popupActionContext || await this.resolveRecordContextPopupActionContextForHost(current, options.transaction);
5794
6666
  await this.normalizeOpenViewForUpdateSettings(
5795
6667
  options.openViewActionName || "updateSettings",
5796
6668
  current,
5797
6669
  nextPayload,
5798
6670
  {
5799
6671
  transaction: options.transaction,
5800
- popupTemplateHostUid: options.popupTemplateHostUid
6672
+ popupTemplateHostUid: options.popupTemplateHostUid,
6673
+ popupActionContext
5801
6674
  }
5802
6675
  );
5803
6676
  this.syncChartConfigureForUpdateSettings(current, nextPayload);
@@ -5845,6 +6718,9 @@ class FlowSurfacesService {
5845
6718
  await this.syncChartDataBindingsForNode(effectiveNode, options.transaction);
5846
6719
  }
5847
6720
  await this.syncFlowTemplateUsagesForNodeTree(current.uid, options.transaction);
6721
+ if (import_approval.APPROVAL_SINGLETON_ACTION_USES.has(current.use || "")) {
6722
+ await this.syncApprovalRuntimeConfigForNode(current.uid, options.transaction);
6723
+ }
5848
6724
  return {
5849
6725
  uid: current.uid,
5850
6726
  updated: Object.keys(import_lodash.default.omit(nextPayload, ["uid"]))
@@ -5882,25 +6758,31 @@ class FlowSurfacesService {
5882
6758
  ];
5883
6759
  const popupTemplateHostUid = String(options.popupTemplateHostUid || (current == null ? void 0 : current.uid) || "").trim() || void 0;
5884
6760
  for (const [flowKey, stepKey] of openViewPaths) {
5885
- if (!import_lodash.default.has(nextPayload, ["stepParams", flowKey, stepKey])) {
6761
+ const openViewPath = ["stepParams", flowKey, stepKey];
6762
+ if (!import_lodash.default.has(nextPayload, openViewPath)) {
5886
6763
  continue;
5887
6764
  }
5888
- const currentOpenView = import_lodash.default.get(current, ["stepParams", flowKey, stepKey]);
5889
- const nextOpenView = await this.normalizeOpenView(
5890
- actionName,
5891
- import_lodash.default.get(nextPayload, ["stepParams", flowKey, stepKey]),
5892
- {
5893
- transaction: options.transaction,
5894
- popupTemplateHostUid
6765
+ const requestedOpenView = import_lodash.default.get(nextPayload, openViewPath);
6766
+ const currentOpenView = import_lodash.default.get(current, openViewPath);
6767
+ const nextOpenView = await this.normalizeOpenView(actionName, requestedOpenView, {
6768
+ transaction: options.transaction,
6769
+ popupTemplateHostUid,
6770
+ popupActionContext: options.popupActionContext
6771
+ });
6772
+ if (this.isTryTemplateOnlyOpenViewRequest(requestedOpenView) && import_lodash.default.isPlainObject(nextOpenView) && !Object.keys(nextOpenView).length) {
6773
+ this.unsetPayloadPathAndPruneEmptyParents(nextPayload, openViewPath);
6774
+ if (import_lodash.default.isEqual(nextPayload.stepParams, current.stepParams)) {
6775
+ delete nextPayload.stepParams;
5895
6776
  }
5896
- );
6777
+ continue;
6778
+ }
5897
6779
  await this.reconcilePopupOpenViewTransition(
5898
6780
  popupTemplateHostUid,
5899
6781
  currentOpenView,
5900
6782
  nextOpenView,
5901
6783
  options.transaction
5902
6784
  );
5903
- import_lodash.default.set(nextPayload, ["stepParams", flowKey, stepKey], nextOpenView);
6785
+ import_lodash.default.set(nextPayload, openViewPath, nextOpenView);
5904
6786
  }
5905
6787
  }
5906
6788
  syncChartConfigureForUpdateSettings(current, nextPayload) {
@@ -6256,7 +7138,11 @@ class FlowSurfacesService {
6256
7138
  if (FILTER_TARGET_BLOCK_USES.has((node == null ? void 0 : node.use) || "")) {
6257
7139
  await this.removeFilterFormTargetBindings(resolved.uid, options.transaction);
6258
7140
  }
7141
+ const approvalRoot = await this.findApprovalSurfaceRootForNode(resolved.uid, options.transaction);
6259
7142
  await this.removeNodeTreeWithBindings(resolved.uid, options.transaction);
7143
+ if ((approvalRoot == null ? void 0 : approvalRoot.uid) && approvalRoot.uid !== resolved.uid) {
7144
+ await this.syncApprovalRuntimeConfigForSurfaceRoot(approvalRoot, options.transaction);
7145
+ }
6260
7146
  return { uid: resolved.uid };
6261
7147
  }
6262
7148
  async mutate(values, options = {}) {
@@ -6473,7 +7359,7 @@ class FlowSurfacesService {
6473
7359
  });
6474
7360
  const routeSchemaUid = ((_a = route == null ? void 0 : route.get) == null ? void 0 : _a.call(route, "schemaUid")) || (route == null ? void 0 : route.schemaUid);
6475
7361
  const routeType = ((_b = route == null ? void 0 : route.get) == null ? void 0 : _b.call(route, "type")) || (route == null ? void 0 : route.type);
6476
- if (routeType !== "tabs" || !routeSchemaUid || String(routeSchemaUid) !== uid2 || (exactNode == null ? void 0 : exactNode.use) === "ChildPageTabModel") {
7362
+ if (routeType !== "tabs" || !routeSchemaUid || String(routeSchemaUid) !== uid2 || (0, import_approval.normalizeApprovalSemanticUse)(exactNode == null ? void 0 : exactNode.use) === "ChildPageTabModel") {
6477
7363
  const recommendedAction = actionName === "updateTab" ? "updatePopupTab" : actionName === "moveTab" ? "movePopupTab" : "removePopupTab";
6478
7364
  (0, import_errors.throwBadRequest)(
6479
7365
  `flowSurfaces ${actionName} only accepts a route-backed tab uid; popup child tabs use ${recommendedAction}`
@@ -6497,7 +7383,7 @@ class FlowSurfacesService {
6497
7383
  transaction,
6498
7384
  includeAsyncNode: true
6499
7385
  });
6500
- if ((popupPage == null ? void 0 : popupPage.use) !== "ChildPageModel") {
7386
+ if ((0, import_approval.normalizeApprovalSemanticUse)(popupPage == null ? void 0 : popupPage.use) !== "ChildPageModel") {
6501
7387
  (0, import_errors.throwBadRequest)(
6502
7388
  `flowSurfaces ${actionName} only accepts target.uid for popupPageUid; use get(hostUid) and read tree.subModels.page.uid first`
6503
7389
  );
@@ -6514,7 +7400,7 @@ class FlowSurfacesService {
6514
7400
  transaction,
6515
7401
  includeAsyncNode: true
6516
7402
  }) : null;
6517
- if ((popupTab == null ? void 0 : popupTab.use) !== "ChildPageTabModel" || (popupPage == null ? void 0 : popupPage.use) !== "ChildPageModel") {
7403
+ if ((0, import_approval.normalizeApprovalSemanticUse)(popupTab == null ? void 0 : popupTab.use) !== "ChildPageTabModel" || (0, import_approval.normalizeApprovalSemanticUse)(popupPage == null ? void 0 : popupPage.use) !== "ChildPageModel") {
6518
7404
  (0, import_errors.throwBadRequest)(
6519
7405
  `flowSurfaces ${actionName} only accepts popup tab uid; use get(hostUid) and read tree.subModels.page.subModels.tabs[].uid first`
6520
7406
  );
@@ -6548,10 +7434,10 @@ class FlowSurfacesService {
6548
7434
  return { uid: uid2 };
6549
7435
  }
6550
7436
  assertRemoveNodeResolvedTarget(resolved, node) {
6551
- if (resolved.kind === "page" || ["RootPageModel", "ChildPageModel"].includes((node == null ? void 0 : node.use) || "")) {
7437
+ if (resolved.kind === "page" || ["RootPageModel", "ChildPageModel"].includes((0, import_approval.normalizeApprovalSemanticUse)(node == null ? void 0 : node.use) || "")) {
6552
7438
  (0, import_errors.throwBadRequest)(`flowSurfaces removeNode does not support page surfaces; use destroyPage`);
6553
7439
  }
6554
- if (resolved.kind === "tab" || ["RootPageTabModel", "ChildPageTabModel"].includes((node == null ? void 0 : node.use) || "")) {
7440
+ if (resolved.kind === "tab" || ["RootPageTabModel", "ChildPageTabModel"].includes((0, import_approval.normalizeApprovalSemanticUse)(node == null ? void 0 : node.use) || "")) {
6555
7441
  (0, import_errors.throwBadRequest)(`flowSurfaces removeNode does not support tab surfaces; use removeTab`);
6556
7442
  }
6557
7443
  if ((node == null ? void 0 : node.use) === "RouteModel" || resolved.route && !resolved.node) {
@@ -7033,7 +7919,8 @@ class FlowSurfacesService {
7033
7919
  {
7034
7920
  context: "compose",
7035
7921
  enabledPackages,
7036
- requireCreateSupported: true
7922
+ requireCreateSupported: true,
7923
+ skipContainerValidation: true
7037
7924
  }
7038
7925
  ) : null;
7039
7926
  const actions = import_lodash.default.castArray(input.actions || []).map(
@@ -8029,6 +8916,7 @@ class FlowSurfacesService {
8029
8916
  innerField,
8030
8917
  targetFieldUse: changes.fieldComponent,
8031
8918
  normalizedBinding,
8919
+ enabledPackages,
8032
8920
  transaction: options.transaction
8033
8921
  });
8034
8922
  await this.syncFieldComponentStepParams(current, normalizedFieldComponentUse, options.transaction);
@@ -8252,6 +9140,22 @@ class FlowSurfacesService {
8252
9140
  ...(0, import_service_utils.hasOwnDefined)(changes, "linkageRules") ? { linkageRules: changes.linkageRules } : {}
8253
9141
  };
8254
9142
  }
9143
+ if ((0, import_service_utils.hasOwnDefined)(changes, "approvalReturn")) {
9144
+ if (use !== "ProcessFormReturnModel") {
9145
+ (0, import_errors.throwBadRequest)(`flowSurfaces configure action '${use}' does not support approvalReturn`);
9146
+ }
9147
+ import_lodash.default.set(
9148
+ stepParams,
9149
+ ["clickSettings", "saveResource", "approvalReturnNodeSettings"],
9150
+ import_lodash.default.cloneDeep(changes.approvalReturn || {})
9151
+ );
9152
+ }
9153
+ if ((0, import_service_utils.hasOwnDefined)(changes, "assigneesScope")) {
9154
+ if (!["ProcessFormDelegateModel", "ProcessFormAddAssigneeModel"].includes(use)) {
9155
+ (0, import_errors.throwBadRequest)(`flowSurfaces configure action '${use}' does not support assigneesScope`);
9156
+ }
9157
+ import_lodash.default.set(stepParams, ["clickSettings", "saveResource", "assigneesScope"], import_lodash.default.cloneDeep(changes.assigneesScope || {}));
9158
+ }
8255
9159
  if (!import_lodash.default.isUndefined(changes.openView)) {
8256
9160
  if (use === "UploadActionModel") {
8257
9161
  stepParams.selectExitRecordSettings = {
@@ -8667,6 +9571,7 @@ class FlowSurfacesService {
8667
9571
  }
8668
9572
  buildFieldCatalogEntriesForResource(input) {
8669
9573
  const containerKind = (0, import_field_semantics.normalizeFieldContainerKind)(input.ownerUse);
9574
+ const supportsStandaloneJsItem = containerKind === "form" && !(0, import_approval.isApprovalFormContainerUse)(input.ownerUse);
8670
9575
  const targetPrefix = input.multiTarget && input.targetLabel ? `${input.targetLabel} / ` : "";
8671
9576
  const fieldMenuEntries = this.buildFieldMenuCandidates({
8672
9577
  ownerUse: input.ownerUse,
@@ -8741,7 +9646,7 @@ class FlowSurfacesService {
8741
9646
  ...this.buildCatalogItemOptionalFields("JSColumnModel", input)
8742
9647
  });
8743
9648
  }
8744
- if (containerKind === "form") {
9649
+ if (supportsStandaloneJsItem) {
8745
9650
  semanticEntries.push({
8746
9651
  key: "jsItem",
8747
9652
  label: "JS / jsItem",
@@ -8786,6 +9691,7 @@ class FlowSurfacesService {
8786
9691
  }));
8787
9692
  });
8788
9693
  const containerKind = (0, import_field_semantics.normalizeFieldContainerKind)(input.ownerUse);
9694
+ const supportsStandaloneJsItem = containerKind === "form" && !(0, import_approval.isApprovalFormContainerUse)(input.ownerUse);
8789
9695
  const targetPrefix = input.multiTarget && input.targetLabel ? `${input.targetLabel} / ` : "";
8790
9696
  const baseEntries = [
8791
9697
  ...directFields.map((field) => ({
@@ -8852,7 +9758,7 @@ class FlowSurfacesService {
8852
9758
  ...this.buildCatalogItemOptionalFields("JSColumnModel", input)
8853
9759
  });
8854
9760
  }
8855
- if (containerKind === "form") {
9761
+ if (supportsStandaloneJsItem) {
8856
9762
  semanticEntries.push({
8857
9763
  key: "jsItem",
8858
9764
  label: "JS / jsItem",
@@ -9154,7 +10060,7 @@ class FlowSurfacesService {
9154
10060
  const rawPopupLevels = [];
9155
10061
  for (let index = 0; index < ancestors.length; index += 1) {
9156
10062
  const node = ancestors[index];
9157
- if ((node == null ? void 0 : node.use) !== "ChildPageModel") {
10063
+ if ((0, import_approval.normalizeApprovalSemanticUse)(node == null ? void 0 : node.use) !== "ChildPageModel") {
9158
10064
  continue;
9159
10065
  }
9160
10066
  const hostNode = ancestors[index + 1];
@@ -9775,11 +10681,15 @@ class FlowSurfacesService {
9775
10681
  };
9776
10682
  case "DetailsItemModel":
9777
10683
  case "FormAssociationItemModel":
10684
+ case "ApprovalDetailsItemModel":
10685
+ case "ApplyTaskCardDetailsItemModel":
10686
+ case "ApprovalTaskCardDetailsItemModel":
9778
10687
  return {
9779
10688
  flowKey: "detailItemSettings",
9780
10689
  stepKey: "model"
9781
10690
  };
9782
10691
  case "FormItemModel":
10692
+ case "PatternFormItemModel":
9783
10693
  return {
9784
10694
  flowKey: "editItemSettings",
9785
10695
  stepKey: "model"
@@ -9827,7 +10737,9 @@ class FlowSurfacesService {
9827
10737
  })
9828
10738
  };
9829
10739
  }
9830
- assertSupportedFieldComponentUse(wrapperUse, targetFieldUse) {
10740
+ assertSupportedFieldComponentUse(input) {
10741
+ const { wrapperUse, field, dataSourceKey, enabledPackages } = input;
10742
+ const targetFieldUse = input.targetFieldUse;
9831
10743
  const normalizedTargetUse = String(targetFieldUse || "").trim();
9832
10744
  if (!normalizedTargetUse) {
9833
10745
  (0, import_errors.throwBadRequest)("flowSurfaces configure fieldComponent cannot be empty");
@@ -9835,6 +10747,21 @@ class FlowSurfacesService {
9835
10747
  const normalizedWrapperUse = String(wrapperUse || "").trim();
9836
10748
  const containerUse = normalizedWrapperUse === "FormAssociationItemModel" ? "DetailsItemModel" : normalizedWrapperUse;
9837
10749
  if (DISPLAY_COMPONENT_FIELD_WRAPPER_USES.has(normalizedWrapperUse)) {
10750
+ if (field) {
10751
+ const supportedFieldUses = (0, import_catalog.getSupportedFieldComponentUseSet)({
10752
+ containerUse,
10753
+ field,
10754
+ enabledPackages,
10755
+ dataSourceKey,
10756
+ getCollection: (resolvedDataSourceKey, collectionName) => this.getCollection(resolvedDataSourceKey, collectionName)
10757
+ });
10758
+ if (!(supportedFieldUses == null ? void 0 : supportedFieldUses.has(normalizedTargetUse))) {
10759
+ (0, import_errors.throwBadRequest)(
10760
+ `flowSurfaces configure field wrapper '${normalizedWrapperUse}' does not support fieldComponent '${normalizedTargetUse}'`
10761
+ );
10762
+ }
10763
+ return normalizedTargetUse;
10764
+ }
9838
10765
  const contract = (0, import_catalog.resolveSupportedFieldCapability)({
9839
10766
  containerUse,
9840
10767
  requestedFieldUse: normalizedTargetUse
@@ -9847,6 +10774,21 @@ class FlowSurfacesService {
9847
10774
  return contract.fieldUse;
9848
10775
  }
9849
10776
  if (EDITABLE_FIELD_WRAPPER_USES.has(normalizedWrapperUse)) {
10777
+ if (field) {
10778
+ const supportedFieldUses = (0, import_catalog.getSupportedFieldComponentUseSet)({
10779
+ containerUse,
10780
+ field,
10781
+ enabledPackages,
10782
+ dataSourceKey,
10783
+ getCollection: (resolvedDataSourceKey, collectionName) => this.getCollection(resolvedDataSourceKey, collectionName)
10784
+ });
10785
+ if (!(supportedFieldUses == null ? void 0 : supportedFieldUses.has(normalizedTargetUse))) {
10786
+ (0, import_errors.throwBadRequest)(
10787
+ `flowSurfaces configure field wrapper '${normalizedWrapperUse}' does not support fieldComponent '${normalizedTargetUse}'`
10788
+ );
10789
+ }
10790
+ return normalizedTargetUse;
10791
+ }
9850
10792
  const contract = (0, import_catalog.resolveSupportedFieldCapability)({
9851
10793
  containerUse,
9852
10794
  requestedFieldUse: normalizedTargetUse
@@ -9881,7 +10823,7 @@ class FlowSurfacesService {
9881
10823
  );
9882
10824
  }
9883
10825
  async rebuildFieldSubModelOnServer(input) {
9884
- var _a, _b, _c;
10826
+ var _a, _b, _c, _d, _e;
9885
10827
  const innerField = input.innerField;
9886
10828
  if (!(innerField == null ? void 0 : innerField.uid)) {
9887
10829
  (0, import_errors.throwConflict)(
@@ -9889,12 +10831,19 @@ class FlowSurfacesService {
9889
10831
  "FLOW_SURFACE_INNER_FIELD_MISSING"
9890
10832
  );
9891
10833
  }
9892
- const normalizedTargetUse = this.assertSupportedFieldComponentUse((_b = input.wrapperNode) == null ? void 0 : _b.use, input.targetFieldUse);
9893
10834
  const fieldSource = this.resolveFieldComponentFieldSource(input.wrapperNode, input.normalizedBinding);
9894
- const defaultProps = (0, import_service_utils.getFieldBindingDefaultProps)((_c = input.wrapperNode) == null ? void 0 : _c.use, normalizedTargetUse, fieldSource.field);
10835
+ const normalizedTargetUse = this.assertSupportedFieldComponentUse({
10836
+ wrapperUse: (_b = input.wrapperNode) == null ? void 0 : _b.use,
10837
+ targetFieldUse: input.targetFieldUse,
10838
+ field: fieldSource.field,
10839
+ dataSourceKey: (_c = fieldSource.fieldSettingsInit) == null ? void 0 : _c.dataSourceKey,
10840
+ enabledPackages: input.enabledPackages
10841
+ });
10842
+ const defaultProps = (0, import_service_utils.getFieldBindingDefaultProps)((_d = input.wrapperNode) == null ? void 0 : _d.use, normalizedTargetUse, fieldSource.field);
10843
+ const shouldPreservePatternFormField = ((_e = input.wrapperNode) == null ? void 0 : _e.use) === "PatternFormItemModel";
9895
10844
  const nextFieldNode = {
9896
10845
  uid: innerField.uid,
9897
- use: normalizedTargetUse,
10846
+ use: shouldPreservePatternFormField ? "PatternFormFieldModel" : normalizedTargetUse,
9898
10847
  props: import_lodash.default.pickBy(
9899
10848
  {
9900
10849
  ...innerField.props || {},
@@ -9974,7 +10923,7 @@ class FlowSurfacesService {
9974
10923
  if (!current || typeof current !== "object") {
9975
10924
  return;
9976
10925
  }
9977
- if (current.use === "ChildPageModel") {
10926
+ if ((0, import_approval.normalizeApprovalSemanticUse)(current.use) === "ChildPageModel") {
9978
10927
  current.subModels = {
9979
10928
  ...current.subModels || {},
9980
10929
  tabs: import_lodash.default.castArray(((_a = current.subModels) == null ? void 0 : _a.tabs) || [])