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

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.
@@ -56,6 +56,7 @@ var import_key_registry = require("./planning/key-registry");
56
56
  var import_blueprint = require("./blueprint");
57
57
  var import_compile_blocks = require("./blueprint/compile-blocks");
58
58
  var import_private_utils = require("./blueprint/private-utils");
59
+ var import_default_block_actions = require("./default-block-actions");
59
60
  var import_runtime = require("./planning/runtime");
60
61
  var import_created_keys = require("./planning/created-keys");
61
62
  var import_key_persistence = require("./planning/key-persistence");
@@ -94,6 +95,7 @@ const SIMPLE_FORM_BLOCK_USES = /* @__PURE__ */ new Set([
94
95
  "EditFormModel",
95
96
  ...import_approval.APPROVAL_FORM_BLOCK_USES
96
97
  ]);
98
+ const COMPOSE_FIELD_GRID_BLOCK_TYPES = /* @__PURE__ */ new Set(["createForm", "editForm", "details", "filterForm"]);
97
99
  const LIST_BLOCK_USES = /* @__PURE__ */ new Set(["ListBlockModel"]);
98
100
  const GRID_CARD_BLOCK_USES = /* @__PURE__ */ new Set(["GridCardBlockModel"]);
99
101
  const LIST_LIKE_COMPOSE_BLOCK_TYPES = /* @__PURE__ */ new Set(["list", "gridCard"]);
@@ -194,6 +196,18 @@ const POPUP_HOST_DEFAULT_RECORD_CONTEXT_ACTION_USES = /* @__PURE__ */ new Set([
194
196
  ]);
195
197
  const DELETE_ACTION_USES = /* @__PURE__ */ new Set(["DeleteActionModel", "BulkDeleteActionModel"]);
196
198
  const CONFIRMABLE_SUBMIT_ACTION_USES = /* @__PURE__ */ new Set(["FormSubmitActionModel"]);
199
+ const APPROVAL_CONFIRM_ACTION_USES = /* @__PURE__ */ new Set([
200
+ "ApplyFormSubmitModel",
201
+ "ApplyFormSaveDraftModel",
202
+ "ApplyFormWithdrawModel"
203
+ ]);
204
+ const APPROVAL_ASSIGN_ACTION_USES = /* @__PURE__ */ new Set(["ApplyFormSubmitModel", "ApplyFormSaveDraftModel"]);
205
+ const APPROVAL_COMMENT_ACTION_USES = /* @__PURE__ */ new Set([
206
+ "ProcessFormApproveModel",
207
+ "ProcessFormRejectModel",
208
+ "ProcessFormReturnModel"
209
+ ]);
210
+ const APPROVAL_REASSIGN_ACTION_USES = /* @__PURE__ */ new Set(["ProcessFormDelegateModel", "ProcessFormAddAssigneeModel"]);
197
211
  const ITEM_CONTEXT_OWNER_USES = /* @__PURE__ */ new Set([
198
212
  "SubFormFieldModel",
199
213
  "SubFormListFieldModel",
@@ -349,6 +363,13 @@ class FlowSurfacesService {
349
363
  );
350
364
  }
351
365
  }
366
+ getFlowTemplateRepositorySafe() {
367
+ try {
368
+ return this.db.getRepository("flowModelTemplates");
369
+ } catch (error) {
370
+ return null;
371
+ }
372
+ }
352
373
  getFlowTemplateUsageRepository(actionName) {
353
374
  try {
354
375
  return this.db.getRepository("flowModelTemplateUsages");
@@ -3565,7 +3586,8 @@ class FlowSurfacesService {
3565
3586
  createBlock: async (payload) => this.addBlock(payload, {
3566
3587
  ...options,
3567
3588
  deferAutoLayout: true,
3568
- enabledPackages
3589
+ enabledPackages,
3590
+ skipDefaultBlockActions: true
3569
3591
  }),
3570
3592
  applyNodeSettings: async (actionName, targetUid, settings) => {
3571
3593
  if (!targetUid) {
@@ -3597,10 +3619,7 @@ class FlowSurfacesService {
3597
3619
  collectActionKeys: async (actionUid) => this.collectComposeActionKeys(actionUid, options.transaction),
3598
3620
  buildExplicitLayoutPayload: async (input) => {
3599
3621
  var _a2;
3600
- const finalGrid = await this.repository.findModelById(input.gridUid, {
3601
- transaction: options.transaction,
3602
- includeAsyncNode: true
3603
- });
3622
+ const finalGrid = await this.surfaceContext.resolveGridNode(input.targetUid, options.transaction);
3604
3623
  const finalItems = import_lodash.default.castArray(((_a2 = finalGrid == null ? void 0 : finalGrid.subModels) == null ? void 0 : _a2.items) || []).filter((item) => item == null ? void 0 : item.uid);
3605
3624
  return this.buildComposeLayoutPayload({
3606
3625
  layout: input.layout,
@@ -4439,7 +4458,10 @@ class FlowSurfacesService {
4439
4458
  })
4440
4459
  } : {}
4441
4460
  },
4442
- options
4461
+ {
4462
+ ...options,
4463
+ skipDefaultBlockActions: true
4464
+ }
4443
4465
  );
4444
4466
  const templateFieldsResult = await this.applyTemplateFieldsToBlock(
4445
4467
  "addBlock",
@@ -4672,6 +4694,18 @@ class FlowSurfacesService {
4672
4694
  } : {}
4673
4695
  };
4674
4696
  await this.applyInlineNodeSettings("addBlock", created, inlineSettings, options);
4697
+ if (!options.skipDefaultBlockActions) {
4698
+ await this.applyDefaultActionsForCreatedBlock(
4699
+ {
4700
+ blockUid: created,
4701
+ blockType: String(catalogItem.key || values.type || "").trim()
4702
+ },
4703
+ {
4704
+ ...options,
4705
+ enabledPackages
4706
+ }
4707
+ );
4708
+ }
4675
4709
  if (!options.deferAutoLayout && (initialGrid == null ? void 0 : initialGrid.uid)) {
4676
4710
  const finalGrid = await this.repository.findModelById(parentUid, {
4677
4711
  transaction: options.transaction,
@@ -4966,7 +5000,10 @@ class FlowSurfacesService {
4966
5000
  fieldPath: normalizedFieldBinding.fieldPath
4967
5001
  };
4968
5002
  await this.applyInlineFieldSettings("addField", result, inlineSettings, options);
4969
- await this.applyInlineFieldPopup("addField", result, inlinePopup, options);
5003
+ await this.applyInlineFieldPopup("addField", result, inlinePopup, {
5004
+ ...options,
5005
+ enabledPackages
5006
+ });
4970
5007
  await this.persistCreatedKeysForAction("addField", values, result, options.transaction);
4971
5008
  return result;
4972
5009
  }
@@ -5032,6 +5069,7 @@ class FlowSurfacesService {
5032
5069
  await this.applyInlineNodeSettings("addAction", created, inlineSettings, options);
5033
5070
  await this.applyInlineActionPopup("addAction", created, inlinePopup, {
5034
5071
  ...options,
5072
+ enabledPackages,
5035
5073
  popupActionContext: {
5036
5074
  hasCurrentRecord: false
5037
5075
  }
@@ -5103,6 +5141,7 @@ class FlowSurfacesService {
5103
5141
  await this.applyInlineNodeSettings("addRecordAction", created, inlineSettings, options);
5104
5142
  await this.applyInlineActionPopup("addRecordAction", created, inlinePopup, {
5105
5143
  ...options,
5144
+ enabledPackages,
5106
5145
  popupActionContext: {
5107
5146
  hasCurrentRecord: true
5108
5147
  }
@@ -5456,6 +5495,116 @@ class FlowSurfacesService {
5456
5495
  delete result.popupTabUid;
5457
5496
  delete result.popupGridUid;
5458
5497
  }
5498
+ buildLegacyAutoGeneratedPopupTemplateMetadata(identity) {
5499
+ return {
5500
+ name: `Auto popup ${identity}`,
5501
+ description: `Auto-generated popup template ${identity}`
5502
+ };
5503
+ }
5504
+ formatAutoGeneratedPopupTemplateMetadata(input) {
5505
+ const popupLabel = input.defaultType === "edit" ? "edit popup" : "details popup";
5506
+ return {
5507
+ name: `${input.sourceCollectionLabel} -> ${input.associationFieldLabel} ${popupLabel} (Auto generated)`,
5508
+ description: `Automatically generated ${popupLabel} template for relation field '${input.associationFieldLabel}' in collection '${input.sourceCollectionLabel}', targeting '${input.targetCollectionLabel}'.`
5509
+ };
5510
+ }
5511
+ formatAutoGeneratedActionPopupTemplateMetadata(input) {
5512
+ const popupLabel = input.popupType === "addNew" ? "create popup" : input.popupType === "edit" ? "edit popup" : "details popup";
5513
+ return {
5514
+ name: `${input.collectionLabel} ${popupLabel} (Auto generated)`,
5515
+ description: `Automatically generated ${popupLabel} template for collection '${input.collectionLabel}'.`
5516
+ };
5517
+ }
5518
+ resolveFieldBindingContext(fieldNode, wrapperNode) {
5519
+ var _a, _b, _c, _d;
5520
+ const fieldInit = ((_b = (_a = fieldNode == null ? void 0 : fieldNode.stepParams) == null ? void 0 : _a.fieldSettings) == null ? void 0 : _b.init) || ((_d = (_c = wrapperNode == null ? void 0 : wrapperNode.stepParams) == null ? void 0 : _c.fieldSettings) == null ? void 0 : _d.init) || {};
5521
+ const dataSourceKey = String(fieldInit.dataSourceKey || "main").trim() || "main";
5522
+ const collectionName = String(fieldInit.collectionName || "").trim() || void 0;
5523
+ const fieldPath = String(fieldInit.fieldPath || "").trim() || void 0;
5524
+ const associationPathName = String(fieldInit.associationPathName || "").trim() || void 0;
5525
+ const sourceCollection = collectionName ? this.getCollection(dataSourceKey, collectionName) : void 0;
5526
+ if (!sourceCollection || !fieldPath) {
5527
+ return {
5528
+ dataSourceKey,
5529
+ collectionName,
5530
+ fieldPath,
5531
+ associationPathName,
5532
+ sourceCollection
5533
+ };
5534
+ }
5535
+ const associationContext = this.resolveFieldAssociationContextFromBinding({
5536
+ collection: sourceCollection,
5537
+ fieldPath,
5538
+ associationPathName,
5539
+ dataSourceKey,
5540
+ collectionName
5541
+ });
5542
+ return {
5543
+ dataSourceKey,
5544
+ collectionName,
5545
+ fieldPath,
5546
+ associationPathName,
5547
+ sourceCollection,
5548
+ targetCollectionName: associationContext.collectionName,
5549
+ associationName: associationContext.associationName,
5550
+ associationField: associationContext.associationField,
5551
+ targetCollection: associationContext.targetCollection
5552
+ };
5553
+ }
5554
+ async resolveAutoGeneratedFieldPopupTemplateMetadata(fieldHostUid, defaultType, identity, transaction) {
5555
+ const fallback = this.buildLegacyAutoGeneratedPopupTemplateMetadata(identity);
5556
+ try {
5557
+ const { fieldNode, wrapperNode } = await this.loadFieldHostNodes(fieldHostUid, transaction);
5558
+ const bindingContext = this.resolveFieldBindingContext(fieldNode, wrapperNode);
5559
+ if (!bindingContext.collectionName || !bindingContext.fieldPath || !bindingContext.sourceCollection) {
5560
+ return fallback;
5561
+ }
5562
+ if (!bindingContext.associationField || !bindingContext.targetCollection) {
5563
+ return fallback;
5564
+ }
5565
+ const sourceCollectionLabel = String((0, import_service_helpers.getCollectionTitle)(bindingContext.sourceCollection) || "").trim() || bindingContext.collectionName;
5566
+ const associationFieldLabel = String(
5567
+ (0, import_service_helpers.getFieldTitle)(bindingContext.associationField) || (0, import_service_helpers.getFieldName)(bindingContext.associationField) || ""
5568
+ ).trim() || String((0, import_service_helpers.getFieldName)(bindingContext.associationField) || "").trim();
5569
+ const targetCollectionLabel = String((0, import_service_helpers.getCollectionTitle)(bindingContext.targetCollection) || "").trim() || String((0, import_service_helpers.getCollectionName)(bindingContext.targetCollection) || "").trim();
5570
+ if (!sourceCollectionLabel || !associationFieldLabel || !targetCollectionLabel) {
5571
+ return fallback;
5572
+ }
5573
+ return this.formatAutoGeneratedPopupTemplateMetadata({
5574
+ defaultType,
5575
+ sourceCollectionLabel,
5576
+ associationFieldLabel,
5577
+ targetCollectionLabel
5578
+ });
5579
+ } catch (error) {
5580
+ return fallback;
5581
+ }
5582
+ }
5583
+ shouldAutoSaveDefaultActionPopupTemplate(popup) {
5584
+ return (popup == null ? void 0 : popup[import_default_block_actions.FLOW_SURFACE_INTERNAL_AUTO_SAVE_DEFAULT_POPUP_TEMPLATE_KEY]) === true;
5585
+ }
5586
+ async resolveAutoGeneratedActionPopupTemplateMetadata(actionUid, identity, transaction) {
5587
+ const fallback = this.buildLegacyAutoGeneratedPopupTemplateMetadata(identity);
5588
+ try {
5589
+ const actionNode = await this.repository.findModelById(actionUid, {
5590
+ transaction,
5591
+ includeAsyncNode: true
5592
+ });
5593
+ const actionConfig = (0, import_default_action_popup.getFlowSurfaceDefaultActionPopupConfigByUse)(actionNode == null ? void 0 : actionNode.use);
5594
+ const popupProfile = (actionNode == null ? void 0 : actionNode.uid) ? await this.resolvePopupBlockProfile(actionNode.uid, null, actionNode, transaction).catch(() => null) : null;
5595
+ const popupType = actionConfig == null ? void 0 : actionConfig.type;
5596
+ const collectionLabel = String((0, import_service_helpers.getCollectionTitle)(popupProfile == null ? void 0 : popupProfile.currentCollection) || "").trim() || String((popupProfile == null ? void 0 : popupProfile.collectionName) || "").trim();
5597
+ if (!popupType || !collectionLabel) {
5598
+ return fallback;
5599
+ }
5600
+ return this.formatAutoGeneratedActionPopupTemplateMetadata({
5601
+ popupType,
5602
+ collectionLabel
5603
+ });
5604
+ } catch (error) {
5605
+ return fallback;
5606
+ }
5607
+ }
5459
5608
  async savePopupAsTemplate(hostUid, popup, options) {
5460
5609
  const normalizedHostUid = String(hostUid || "").trim();
5461
5610
  const saveAsTemplate = popup == null ? void 0 : popup.saveAsTemplate;
@@ -5601,6 +5750,28 @@ class FlowSurfacesService {
5601
5750
  }
5602
5751
  return void 0;
5603
5752
  }
5753
+ getPopupTryTemplateAllowedDefaultTypes(popup, targetContext, popupActionContext) {
5754
+ var _a;
5755
+ const requestedDefaultType = this.getRequestedPopupDefaultType(popup);
5756
+ if (requestedDefaultType) {
5757
+ return [requestedDefaultType];
5758
+ }
5759
+ const targetUse = String(((_a = targetContext == null ? void 0 : targetContext.node) == null ? void 0 : _a.use) || "").trim();
5760
+ if (!targetUse) {
5761
+ return void 0;
5762
+ }
5763
+ if (this.isPopupFieldHostUse(targetUse)) {
5764
+ return ["view", "generic"];
5765
+ }
5766
+ const actionConfig = (0, import_default_action_popup.getFlowSurfaceDefaultActionPopupConfigByUse)(targetUse);
5767
+ if (actionConfig) {
5768
+ return actionConfig.type === "view" ? ["view", "generic"] : [actionConfig.type];
5769
+ }
5770
+ if (POPUP_ACTION_USES.has(targetUse)) {
5771
+ return (popupActionContext == null ? void 0 : popupActionContext.hasCurrentRecord) ? ["view", "generic"] : ["generic"];
5772
+ }
5773
+ return void 0;
5774
+ }
5604
5775
  inferPopupDefaultTypeFromTemplateTree(node) {
5605
5776
  var _a, _b, _c, _d;
5606
5777
  const popupPage = (0, import_service_utils.getSingleNodeSubModel)((_a = node == null ? void 0 : node.subModels) == null ? void 0 : _a.page);
@@ -5613,11 +5784,15 @@ class FlowSurfacesService {
5613
5784
  if ((popupBlock == null ? void 0 : popupBlock.use) === "EditFormModel") {
5614
5785
  return "edit";
5615
5786
  }
5616
- return void 0;
5787
+ if ((popupBlock == null ? void 0 : popupBlock.use) === "CreateFormModel") {
5788
+ return "addNew";
5789
+ }
5790
+ return "generic";
5617
5791
  }
5618
5792
  async popupTemplateMatchesDefaultType(template, popup, options = {}) {
5619
- const requestedDefaultType = this.getRequestedPopupDefaultType(popup);
5620
- if (!requestedDefaultType) {
5793
+ var _a;
5794
+ const allowedDefaultTypes = ((_a = options.allowedDefaultTypes) == null ? void 0 : _a.length) ? Array.from(new Set(options.allowedDefaultTypes)) : void 0;
5795
+ if (!allowedDefaultTypes) {
5621
5796
  return true;
5622
5797
  }
5623
5798
  const templateTargetUid = String((template == null ? void 0 : template.targetUid) || "").trim();
@@ -5628,14 +5803,17 @@ class FlowSurfacesService {
5628
5803
  transaction: options.transaction,
5629
5804
  includeAsyncNode: true
5630
5805
  });
5631
- return this.inferPopupDefaultTypeFromTemplateTree(templateTree) === requestedDefaultType;
5806
+ return allowedDefaultTypes.includes(this.inferPopupDefaultTypeFromTemplateTree(templateTree));
5632
5807
  }
5633
5808
  async tryResolvePopupTemplateForHost(actionName, popup, hostUid, options = {}) {
5634
5809
  const normalizedHostUid = String(hostUid || "").trim();
5635
5810
  if (!normalizedHostUid || !import_lodash.default.isPlainObject(popup) || !popup.tryTemplate || !import_lodash.default.isUndefined(popup.template)) {
5636
5811
  return null;
5637
5812
  }
5638
- const repo = this.getFlowTemplateRepository(actionName);
5813
+ const repo = this.getFlowTemplateRepositorySafe();
5814
+ if (!repo) {
5815
+ return null;
5816
+ }
5639
5817
  const targetContext = await this.loadTemplateListTargetContext({ uid: normalizedHostUid }, options.transaction);
5640
5818
  const templates = await repo.find({
5641
5819
  filter: (0, import_template_service_utils.buildTemplateListFilter)(void 0, void 0, "popup"),
@@ -5651,12 +5829,20 @@ class FlowSurfacesService {
5651
5829
  }
5652
5830
  );
5653
5831
  const expectedAssociationName = this.getPopupTryTemplateExpectedAssociationName(targetContext);
5832
+ const allowedDefaultTypes = this.getPopupTryTemplateAllowedDefaultTypes(
5833
+ popup,
5834
+ targetContext,
5835
+ options.popupActionContext
5836
+ );
5654
5837
  for (const priority of [0, 1]) {
5655
5838
  for (const template of annotatedTemplates) {
5656
5839
  if (template.available !== true || this.getPopupTryTemplatePriority(template, expectedAssociationName) !== priority) {
5657
5840
  continue;
5658
5841
  }
5659
- if (await this.popupTemplateMatchesDefaultType(template, popup, options)) {
5842
+ if (await this.popupTemplateMatchesDefaultType(template, popup, {
5843
+ ...options,
5844
+ allowedDefaultTypes
5845
+ })) {
5660
5846
  return template;
5661
5847
  }
5662
5848
  }
@@ -6102,7 +6288,7 @@ class FlowSurfacesService {
6102
6288
  uid: fieldHostUid
6103
6289
  },
6104
6290
  mode: popup.mode || "replace",
6105
- blocks: this.buildDefaultFieldPopupBlocks(fieldNode, popupContext, defaultType),
6291
+ blocks: this.buildDefaultFieldPopupBlocks(fieldNode, popupContext, defaultType, options.enabledPackages),
6106
6292
  layout: popup.layout
6107
6293
  },
6108
6294
  options
@@ -6225,14 +6411,15 @@ class FlowSurfacesService {
6225
6411
  resourceInit: {
6226
6412
  dataSourceKey: input.popupContext.dataSourceKey || "main",
6227
6413
  collectionName
6228
- }
6414
+ },
6415
+ enabledPackages: input.enabledPackages
6229
6416
  });
6230
6417
  return (0, import_default_action_popup.pickFlowSurfaceDefaultActionPopupFieldPaths)(directCandidates, {
6231
6418
  excludeAuditTimestampFields: input.defaultType === "edit",
6232
6419
  excludeAssociationFields: true
6233
6420
  });
6234
6421
  }
6235
- buildDefaultFieldPopupBlocks(fieldNode, popupContext, defaultType) {
6422
+ buildDefaultFieldPopupBlocks(fieldNode, popupContext, defaultType, enabledPackages) {
6236
6423
  var _a;
6237
6424
  const actionUse = defaultType === "edit" ? "EditActionModel" : "ViewActionModel";
6238
6425
  const namespace = (0, import_service_utils.normalizeFlowSurfaceComposeKey)(
@@ -6250,7 +6437,8 @@ class FlowSurfacesService {
6250
6437
  const fieldPaths = this.buildDefaultFieldPopupFieldPaths({
6251
6438
  defaultType,
6252
6439
  fieldNode,
6253
- popupContext
6440
+ popupContext,
6441
+ enabledPackages
6254
6442
  });
6255
6443
  return this.remapDefaultActionPopupBlocks(
6256
6444
  (0, import_default_action_popup.buildFlowSurfaceDefaultActionPopupBlocks)(actionUse, fieldPaths),
@@ -6259,6 +6447,9 @@ class FlowSurfacesService {
6259
6447
  );
6260
6448
  }
6261
6449
  async autoSaveDefaultFieldPopupAsTemplate(result, popup, options) {
6450
+ if (!this.getFlowTemplateRepositorySafe()) {
6451
+ return;
6452
+ }
6262
6453
  const fieldHostUid = result.fieldUid || result.uid;
6263
6454
  if (!fieldHostUid) {
6264
6455
  return;
@@ -6282,19 +6473,74 @@ class FlowSurfacesService {
6282
6473
  })
6283
6474
  );
6284
6475
  const identity = (0, import_crypto.createHash)("sha1").update(uniqueKeySource).digest("hex").slice(0, 12);
6476
+ const defaultType = this.getRequestedPopupDefaultType(popup) || "view";
6477
+ const metadata = await this.resolveAutoGeneratedFieldPopupTemplateMetadata(
6478
+ fieldHostUid,
6479
+ defaultType,
6480
+ identity,
6481
+ options.transaction
6482
+ );
6285
6483
  await this.saveTemplate(
6286
6484
  {
6287
6485
  target: {
6288
6486
  uid: fieldHostUid
6289
6487
  },
6290
- name: `Auto popup ${identity}`,
6291
- description: `Auto-generated popup template ${identity}`,
6488
+ name: metadata.name,
6489
+ description: metadata.description,
6292
6490
  saveMode: "convert"
6293
6491
  },
6294
6492
  options
6295
6493
  );
6296
6494
  this.clearPopupSurfaceKeys(result);
6297
6495
  }
6496
+ async autoSaveDefaultActionPopupAsTemplate(actionUid, _popup, options) {
6497
+ if (!this.getFlowTemplateRepositorySafe()) {
6498
+ return;
6499
+ }
6500
+ const actionNode = await this.repository.findModelById(actionUid, {
6501
+ transaction: options.transaction,
6502
+ includeAsyncNode: true
6503
+ });
6504
+ if (!(actionNode == null ? void 0 : actionNode.uid)) {
6505
+ return;
6506
+ }
6507
+ const actionConfig = (0, import_default_action_popup.getFlowSurfaceDefaultActionPopupConfigByUse)(actionNode.use);
6508
+ if (!actionConfig) {
6509
+ return;
6510
+ }
6511
+ const openView = this.resolvePopupHostOpenView(actionNode);
6512
+ if (String((openView == null ? void 0 : openView.popupTemplateUid) || "").trim()) {
6513
+ return;
6514
+ }
6515
+ const uniqueKeySource = JSON.stringify(
6516
+ (0, import_service_utils.buildDefinedPayload)({
6517
+ actionUse: actionNode.use,
6518
+ dataSourceKey: openView == null ? void 0 : openView.dataSourceKey,
6519
+ collectionName: openView == null ? void 0 : openView.collectionName,
6520
+ associationName: openView == null ? void 0 : openView.associationName,
6521
+ filterByTk: openView == null ? void 0 : openView.filterByTk,
6522
+ sourceId: openView == null ? void 0 : openView.sourceId,
6523
+ popupType: actionConfig.type
6524
+ })
6525
+ );
6526
+ const identity = (0, import_crypto.createHash)("sha1").update(uniqueKeySource).digest("hex").slice(0, 12);
6527
+ const metadata = await this.resolveAutoGeneratedActionPopupTemplateMetadata(
6528
+ actionUid,
6529
+ identity,
6530
+ options.transaction
6531
+ );
6532
+ await this.saveTemplate(
6533
+ {
6534
+ target: {
6535
+ uid: actionUid
6536
+ },
6537
+ name: metadata.name,
6538
+ description: metadata.description,
6539
+ saveMode: "convert"
6540
+ },
6541
+ options
6542
+ );
6543
+ }
6298
6544
  shouldAutoCompleteDefaultActionPopup(actionNode, popup, options = {}) {
6299
6545
  if (options.autoCompleteDefaultPopup === false) {
6300
6546
  return false;
@@ -6328,7 +6574,8 @@ class FlowSurfacesService {
6328
6574
  resourceInit: {
6329
6575
  dataSourceKey: ((_b = input.popupProfile) == null ? void 0 : _b.dataSourceKey) || "main",
6330
6576
  collectionName
6331
- }
6577
+ },
6578
+ enabledPackages: input.enabledPackages
6332
6579
  });
6333
6580
  return (0, import_default_action_popup.pickFlowSurfaceDefaultActionPopupFieldPaths)(directCandidates, {
6334
6581
  excludeAuditTimestampFields: mode === "form"
@@ -6438,10 +6685,11 @@ class FlowSurfacesService {
6438
6685
  );
6439
6686
  return nextLayout;
6440
6687
  }
6441
- buildDefaultActionPopupBlocks(actionNode, popupProfile, keyMap, namespace) {
6688
+ buildDefaultActionPopupBlocks(actionNode, popupProfile, keyMap, namespace, enabledPackages) {
6442
6689
  const fieldPaths = this.buildDefaultActionPopupFieldPaths({
6443
6690
  actionUse: actionNode == null ? void 0 : actionNode.use,
6444
- popupProfile
6691
+ popupProfile,
6692
+ enabledPackages
6445
6693
  });
6446
6694
  return this.remapDefaultActionPopupBlocks(
6447
6695
  (0, import_default_action_popup.buildFlowSurfaceDefaultActionPopupBlocks)(actionNode == null ? void 0 : actionNode.use, fieldPaths),
@@ -6449,7 +6697,7 @@ class FlowSurfacesService {
6449
6697
  namespace
6450
6698
  );
6451
6699
  }
6452
- buildDefaultActionPopupComposeValues(actionNode, popupProfile, popup) {
6700
+ buildDefaultActionPopupComposeValues(actionNode, popupProfile, popup, enabledPackages) {
6453
6701
  const namespace = this.buildDefaultActionPopupNamespace(actionNode);
6454
6702
  const keyMap = this.buildDefaultActionPopupKeyMap(actionNode, namespace);
6455
6703
  return {
@@ -6457,7 +6705,7 @@ class FlowSurfacesService {
6457
6705
  uid: actionNode.uid
6458
6706
  },
6459
6707
  mode: (popup == null ? void 0 : popup.mode) || "replace",
6460
- blocks: this.buildDefaultActionPopupBlocks(actionNode, popupProfile, keyMap, namespace),
6708
+ blocks: this.buildDefaultActionPopupBlocks(actionNode, popupProfile, keyMap, namespace, enabledPackages),
6461
6709
  layout: this.remapDefaultActionPopupLayout(popup == null ? void 0 : popup.layout, keyMap)
6462
6710
  };
6463
6711
  }
@@ -6536,7 +6784,10 @@ class FlowSurfacesService {
6536
6784
  if (!(popupProfile == null ? void 0 : popupProfile.isPopupSurface)) {
6537
6785
  return;
6538
6786
  }
6539
- await this.compose(this.buildDefaultActionPopupComposeValues(actionNode, popupProfile, popup), options);
6787
+ await this.compose(
6788
+ this.buildDefaultActionPopupComposeValues(actionNode, popupProfile, popup, options.enabledPackages),
6789
+ options
6790
+ );
6540
6791
  const popupState = await this.resolveDefaultActionPopupSurfaceState(actionNode.uid, options.transaction);
6541
6792
  await this.resetDefaultActionPopupFormLinkageRules(popupState.popupBlock, options);
6542
6793
  await this.syncDefaultActionPopupTabTitle(popupState.actionNode || actionNode, popupState.popupTab, options);
@@ -6613,6 +6864,9 @@ class FlowSurfacesService {
6613
6864
  try {
6614
6865
  if (shouldAutoCompleteDefaultPopup) {
6615
6866
  await this.applyDefaultActionPopupContent(actionNode, popup, options);
6867
+ if (this.shouldAutoSaveDefaultActionPopupTemplate(popup)) {
6868
+ await this.autoSaveDefaultActionPopupAsTemplate(actionUid, popup, options);
6869
+ }
6616
6870
  } else if (!import_lodash.default.isUndefined(popup)) {
6617
6871
  await this.compose(
6618
6872
  {
@@ -7179,12 +7433,21 @@ class FlowSurfacesService {
7179
7433
  }
7180
7434
  async transaction(callback) {
7181
7435
  const transaction = await this.db.sequelize.transaction();
7436
+ const transactionState = transaction;
7182
7437
  try {
7183
7438
  const result = await callback(transaction);
7184
7439
  await transaction.commit();
7185
7440
  return result;
7186
7441
  } catch (error) {
7187
- await transaction.rollback();
7442
+ if (!transactionState.finished) {
7443
+ try {
7444
+ await transaction.rollback();
7445
+ } catch (rollbackError) {
7446
+ if (!String((rollbackError == null ? void 0 : rollbackError.message) || "").includes("Transaction cannot be rolled back")) {
7447
+ throw rollbackError;
7448
+ }
7449
+ }
7450
+ }
7188
7451
  throw error;
7189
7452
  }
7190
7453
  }
@@ -7883,6 +8146,115 @@ class FlowSurfacesService {
7883
8146
  errorCount
7884
8147
  };
7885
8148
  }
8149
+ buildInjectedComposeDefaultActionSpec(descriptor, existingKeys, context) {
8150
+ const baseKey = `${descriptor.type}Default`;
8151
+ let candidate = baseKey;
8152
+ let suffix = 2;
8153
+ while (existingKeys.has(candidate)) {
8154
+ candidate = `${baseKey}${suffix}`;
8155
+ suffix += 1;
8156
+ }
8157
+ existingKeys.add(candidate);
8158
+ return {
8159
+ key: (0, import_service_utils.normalizeFlowSurfaceComposeKey)(candidate, `${context} default ${descriptor.scope} '${descriptor.type}'`),
8160
+ type: descriptor.type,
8161
+ settings: {},
8162
+ ...descriptor.popup ? { popup: import_lodash.default.cloneDeep(descriptor.popup) } : {}
8163
+ };
8164
+ }
8165
+ normalizeComposeFieldsLayout(input, options) {
8166
+ if (import_lodash.default.isUndefined(input)) {
8167
+ return void 0;
8168
+ }
8169
+ if (!import_lodash.default.isPlainObject(input)) {
8170
+ (0, import_errors.throwBadRequest)(`${options.blockContext} fieldsLayout must be an object`);
8171
+ }
8172
+ if (!COMPOSE_FIELD_GRID_BLOCK_TYPES.has(options.blockType || "")) {
8173
+ (0, import_errors.throwBadRequest)(`flowSurfaces compose ${options.blockDescriptor} does not support fieldsLayout`);
8174
+ }
8175
+ if (!options.fields.length) {
8176
+ (0, import_errors.throwBadRequest)(`${options.blockContext} fieldsLayout requires fields[] on the same block`);
8177
+ }
8178
+ const rows = import_lodash.default.castArray(input.rows || []);
8179
+ if (!rows.length) {
8180
+ (0, import_errors.throwBadRequest)(`${options.blockContext} fieldsLayout.rows must be a non-empty array`);
8181
+ }
8182
+ const fieldKeys = new Set(options.fields.map((field) => field.key).filter(Boolean));
8183
+ const mentioned = /* @__PURE__ */ new Set();
8184
+ const normalizedRows = rows.map((row, rowIndex) => {
8185
+ if (!Array.isArray(row) || !row.length) {
8186
+ (0, import_errors.throwBadRequest)(`${options.blockContext} fieldsLayout row #${rowIndex + 1} must be a non-empty array`);
8187
+ }
8188
+ return row.map((cell, cellIndex) => {
8189
+ const cellContext = `${options.blockContext} fieldsLayout row #${rowIndex + 1} cell #${cellIndex + 1}`;
8190
+ const normalizedCell = this.normalizeComposeFieldsLayoutCell(cell, cellContext);
8191
+ if (!fieldKeys.has(normalizedCell.key)) {
8192
+ (0, import_errors.throwBadRequest)(`${cellContext} references unknown field '${normalizedCell.key}'`);
8193
+ }
8194
+ if (mentioned.has(normalizedCell.key)) {
8195
+ (0, import_errors.throwBadRequest)(`${cellContext} duplicates field '${normalizedCell.key}'`);
8196
+ }
8197
+ mentioned.add(normalizedCell.key);
8198
+ return normalizedCell.raw;
8199
+ });
8200
+ });
8201
+ const missingFieldKeys = options.fields.map((field) => field.key).filter((key) => !mentioned.has(key));
8202
+ if (missingFieldKeys.length) {
8203
+ (0, import_errors.throwBadRequest)(
8204
+ `${options.blockContext} fieldsLayout must place every field exactly once; missing: ${missingFieldKeys.join(
8205
+ ", "
8206
+ )}`
8207
+ );
8208
+ }
8209
+ return {
8210
+ rows: normalizedRows
8211
+ };
8212
+ }
8213
+ normalizeComposeFieldsLayoutCell(cell, context) {
8214
+ if (typeof cell === "string") {
8215
+ const key2 = String(cell || "").trim();
8216
+ if (!key2) {
8217
+ (0, import_errors.throwBadRequest)(`${context} cannot be empty`);
8218
+ }
8219
+ return {
8220
+ key: key2,
8221
+ raw: key2
8222
+ };
8223
+ }
8224
+ if (!import_lodash.default.isPlainObject(cell)) {
8225
+ (0, import_errors.throwBadRequest)(`${context} must be a string or object`);
8226
+ }
8227
+ const key = String(cell.key || "").trim();
8228
+ if (!key) {
8229
+ (0, import_errors.throwBadRequest)(`${context}.key cannot be empty`);
8230
+ }
8231
+ return {
8232
+ key,
8233
+ raw: (0, import_service_utils.buildDefinedPayload)({
8234
+ key,
8235
+ span: import_lodash.default.isUndefined(cell.span) ? void 0 : import_lodash.default.isNumber(cell.span) ? cell.span : (0, import_errors.throwBadRequest)(`${context}.span must be a number`)
8236
+ })
8237
+ };
8238
+ }
8239
+ async applyDefaultActionsForCreatedBlock(input, options = {}) {
8240
+ const descriptors = (0, import_default_block_actions.getFlowSurfaceDefaultBlockActions)({
8241
+ blockType: input.blockType
8242
+ });
8243
+ for (const descriptor of descriptors) {
8244
+ const actionValues = (0, import_service_utils.buildDefinedPayload)({
8245
+ target: {
8246
+ uid: input.blockUid
8247
+ },
8248
+ type: descriptor.type,
8249
+ popup: descriptor.popup ? import_lodash.default.cloneDeep(descriptor.popup) : void 0
8250
+ });
8251
+ if (descriptor.scope === "actions") {
8252
+ await this.addAction(actionValues, options);
8253
+ } else {
8254
+ await this.addRecordAction(actionValues, options);
8255
+ }
8256
+ }
8257
+ }
7886
8258
  normalizeComposeBlock(input, index, enabledPackages) {
7887
8259
  if (!import_lodash.default.isPlainObject(input)) {
7888
8260
  (0, import_errors.throwBadRequest)(`flowSurfaces compose block #${index + 1} must be an object`);
@@ -7943,6 +8315,30 @@ class FlowSurfacesService {
7943
8315
  if (blockCatalogItem) {
7944
8316
  this.validateComposeActionGroups(blockCatalogItem.use, actions, recordActions, enabledPackages);
7945
8317
  }
8318
+ const actionKeys = new Set(actions.map((item) => item.key).filter(Boolean));
8319
+ const recordActionKeys = new Set(recordActions.map((item) => item.key).filter(Boolean));
8320
+ const blockDescriptor = this.describeComposeBlock({
8321
+ index: index + 1,
8322
+ key,
8323
+ type
8324
+ });
8325
+ const fieldsLayout = this.normalizeComposeFieldsLayout(input.fieldsLayout, {
8326
+ blockContext: `flowSurfaces compose block #${index + 1}`,
8327
+ blockDescriptor,
8328
+ blockType: type,
8329
+ fields
8330
+ });
8331
+ const mergedActions = (0, import_default_block_actions.mergeFlowSurfaceDefaultBlockActions)({
8332
+ blockType: type,
8333
+ template,
8334
+ actions,
8335
+ recordActions,
8336
+ createAction: (descriptor) => this.buildInjectedComposeDefaultActionSpec(
8337
+ descriptor,
8338
+ descriptor.scope === "actions" ? actionKeys : recordActionKeys,
8339
+ `flowSurfaces compose block #${index + 1}`
8340
+ )
8341
+ });
7946
8342
  return {
7947
8343
  index: index + 1,
7948
8344
  key,
@@ -7951,8 +8347,9 @@ class FlowSurfacesService {
7951
8347
  resource: this.normalizeResourceInput(input.resource),
7952
8348
  settings: import_lodash.default.isPlainObject(input.settings) ? input.settings : {},
7953
8349
  fields,
7954
- actions,
7955
- recordActions,
8350
+ ...fieldsLayout ? { fieldsLayout } : {},
8351
+ actions: mergedActions.actions,
8352
+ recordActions: mergedActions.recordActions,
7956
8353
  template
7957
8354
  };
7958
8355
  }
@@ -9151,11 +9548,17 @@ class FlowSurfacesService {
9151
9548
  );
9152
9549
  }
9153
9550
  if ((0, import_service_utils.hasOwnDefined)(changes, "assigneesScope")) {
9154
- if (!["ProcessFormDelegateModel", "ProcessFormAddAssigneeModel"].includes(use)) {
9551
+ if (!APPROVAL_REASSIGN_ACTION_USES.has(use)) {
9155
9552
  (0, import_errors.throwBadRequest)(`flowSurfaces configure action '${use}' does not support assigneesScope`);
9156
9553
  }
9157
9554
  import_lodash.default.set(stepParams, ["clickSettings", "saveResource", "assigneesScope"], import_lodash.default.cloneDeep(changes.assigneesScope || {}));
9158
9555
  }
9556
+ if ((0, import_service_utils.hasOwnDefined)(changes, "commentFormUid")) {
9557
+ if (!APPROVAL_COMMENT_ACTION_USES.has(use)) {
9558
+ (0, import_errors.throwBadRequest)(`flowSurfaces configure action '${use}' does not support commentFormUid`);
9559
+ }
9560
+ import_lodash.default.set(stepParams, ["clickSettings", "saveResource", "commentModelUid"], import_lodash.default.cloneDeep(changes.commentFormUid));
9561
+ }
9159
9562
  if (!import_lodash.default.isUndefined(changes.openView)) {
9160
9563
  if (use === "UploadActionModel") {
9161
9564
  stepParams.selectExitRecordSettings = {
@@ -9174,6 +9577,11 @@ class FlowSurfacesService {
9174
9577
  stepParams.deleteSettings = {
9175
9578
  confirm: (0, import_service_utils.normalizeSimpleConfirm)(changes.confirm)
9176
9579
  };
9580
+ } else if (APPROVAL_CONFIRM_ACTION_USES.has(use)) {
9581
+ stepParams.clickSettings = {
9582
+ ...stepParams.clickSettings || {},
9583
+ confirm: (0, import_service_utils.normalizeSimpleConfirm)(changes.confirm)
9584
+ };
9177
9585
  } else if (CONFIRMABLE_SUBMIT_ACTION_USES.has(use)) {
9178
9586
  stepParams.submitSettings = {
9179
9587
  confirm: (0, import_service_utils.normalizeSimpleConfirm)(changes.confirm)
@@ -9187,20 +9595,28 @@ class FlowSurfacesService {
9187
9595
  }
9188
9596
  }
9189
9597
  if ((0, import_service_utils.hasOwnDefined)(changes, "assignValues")) {
9190
- if (!["UpdateRecordActionModel", "BulkUpdateActionModel"].includes(use)) {
9598
+ if (APPROVAL_ASSIGN_ACTION_USES.has(use)) {
9599
+ stepParams.clickSettings = {
9600
+ ...stepParams.clickSettings || {},
9601
+ assignFieldValues: {
9602
+ assignedValues: changes.assignValues
9603
+ }
9604
+ };
9605
+ } else if (!["UpdateRecordActionModel", "BulkUpdateActionModel"].includes(use)) {
9191
9606
  (0, import_errors.throwBadRequest)(`flowSurfaces configure action '${use}' does not support assignValues`);
9607
+ } else {
9608
+ stepParams.assignSettings = {
9609
+ ...stepParams.assignSettings || {},
9610
+ assignFieldValues: {
9611
+ assignedValues: changes.assignValues
9612
+ }
9613
+ };
9614
+ stepParams.apply = {
9615
+ apply: {
9616
+ assignedValues: changes.assignValues
9617
+ }
9618
+ };
9192
9619
  }
9193
- stepParams.assignSettings = {
9194
- ...stepParams.assignSettings || {},
9195
- assignFieldValues: {
9196
- assignedValues: changes.assignValues
9197
- }
9198
- };
9199
- stepParams.apply = {
9200
- apply: {
9201
- assignedValues: changes.assignValues
9202
- }
9203
- };
9204
9620
  }
9205
9621
  if ((0, import_service_utils.hasOwnDefined)(changes, "editMode")) {
9206
9622
  if (use !== "BulkEditActionModel") {
@@ -10050,7 +10466,7 @@ class FlowSurfacesService {
10050
10466
  async resolveContextSemantic(uid2, resolved, transaction) {
10051
10467
  const collection = await this.resolveContextOwnerCollection(uid2, transaction).catch(() => null);
10052
10468
  const ancestors = await this.loadContextAncestorChain(uid2, resolved, transaction);
10053
- const recordContextOwner = ancestors.find((node) => RECORD_CONTEXT_OWNER_USES.has(node == null ? void 0 : node.use));
10469
+ const recordContextOwner = ancestors.find((node) => RECORD_CONTEXT_OWNER_USES.has(node == null ? void 0 : node.use)) || this.resolveRecordActionContextOwner(ancestors);
10054
10470
  const recordCollection = recordContextOwner ? await this.resolveContextOwnerCollection(recordContextOwner.uid, transaction) : null;
10055
10471
  const formNode = ancestors.find((node) => FORM_BLOCK_USES.has(node == null ? void 0 : node.use));
10056
10472
  const formValuesCollection = this.resolveCollectionFromInit(
@@ -10086,6 +10502,13 @@ class FlowSurfacesService {
10086
10502
  chart: await this.buildChartContextSemantic(chartNode, transaction)
10087
10503
  };
10088
10504
  }
10505
+ resolveRecordActionContextOwner(ancestors) {
10506
+ const currentNode = ancestors[0];
10507
+ if (!String((currentNode == null ? void 0 : currentNode.use) || "").endsWith("ActionModel")) {
10508
+ return null;
10509
+ }
10510
+ return ancestors.slice(1).find((node) => (0, import_action_scope.getActionContainerScope)(node == null ? void 0 : node.use) === "record") || null;
10511
+ }
10089
10512
  async loadContextAncestorChain(uid2, resolved, transaction) {
10090
10513
  const chain = [];
10091
10514
  const visited = /* @__PURE__ */ new Set();