@nocobase/plugin-flow-engine 2.1.0-beta.35 → 2.1.0-beta.36

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 (67) hide show
  1. package/dist/externalVersion.js +9 -9
  2. package/dist/node_modules/@ant-design/icons-svg/package.json +1 -1
  3. package/dist/node_modules/acorn/LICENSE +21 -0
  4. package/dist/node_modules/acorn/bin/acorn +4 -0
  5. package/dist/node_modules/acorn/dist/acorn.d.mts +857 -0
  6. package/dist/node_modules/acorn/dist/acorn.d.ts +857 -0
  7. package/dist/node_modules/acorn/dist/acorn.js +1 -0
  8. package/dist/node_modules/acorn/dist/bin.js +90 -0
  9. package/dist/node_modules/acorn/package.json +1 -0
  10. package/dist/node_modules/acorn-jsx/LICENSE +19 -0
  11. package/dist/node_modules/acorn-jsx/index.d.ts +12 -0
  12. package/dist/node_modules/acorn-jsx/index.js +1 -0
  13. package/dist/node_modules/acorn-jsx/package.json +1 -0
  14. package/dist/node_modules/acorn-jsx/xhtml.js +255 -0
  15. package/dist/node_modules/acorn-walk/LICENSE +21 -0
  16. package/dist/node_modules/acorn-walk/dist/walk.d.mts +177 -0
  17. package/dist/node_modules/acorn-walk/dist/walk.d.ts +177 -0
  18. package/dist/node_modules/acorn-walk/dist/walk.js +1 -0
  19. package/dist/node_modules/acorn-walk/node_modules/acorn/bin/acorn +4 -0
  20. package/dist/node_modules/acorn-walk/node_modules/acorn/dist/acorn.d.mts +866 -0
  21. package/dist/node_modules/acorn-walk/node_modules/acorn/dist/acorn.d.ts +866 -0
  22. package/dist/node_modules/acorn-walk/node_modules/acorn/dist/acorn.js +6174 -0
  23. package/dist/node_modules/acorn-walk/node_modules/acorn/dist/bin.js +90 -0
  24. package/dist/node_modules/acorn-walk/node_modules/acorn/package.json +50 -0
  25. package/dist/node_modules/acorn-walk/package.json +1 -0
  26. package/dist/node_modules/ses/package.json +1 -1
  27. package/dist/node_modules/zod/package.json +1 -1
  28. package/dist/server/flow-surfaces/action-scope.d.ts +2 -0
  29. package/dist/server/flow-surfaces/action-scope.js +8 -0
  30. package/dist/server/flow-surfaces/authoring-validation.d.ts +3 -0
  31. package/dist/server/flow-surfaces/authoring-validation.js +317 -9
  32. package/dist/server/flow-surfaces/blueprint/compile-blocks.js +143 -3
  33. package/dist/server/flow-surfaces/blueprint/public-types.d.ts +1 -1
  34. package/dist/server/flow-surfaces/builder.js +54 -1
  35. package/dist/server/flow-surfaces/catalog.js +148 -2
  36. package/dist/server/flow-surfaces/chart-config.d.ts +58 -54
  37. package/dist/server/flow-surfaces/chart-config.js +18 -5
  38. package/dist/server/flow-surfaces/compose-compiler.d.ts +1 -1
  39. package/dist/server/flow-surfaces/compose-runtime.d.ts +1 -0
  40. package/dist/server/flow-surfaces/compose-runtime.js +24 -6
  41. package/dist/server/flow-surfaces/configure-options.js +40 -1
  42. package/dist/server/flow-surfaces/default-block-actions.js +11 -0
  43. package/dist/server/flow-surfaces/index.js +4 -2
  44. package/dist/server/flow-surfaces/node-use-sets.js +2 -0
  45. package/dist/server/flow-surfaces/runjs-authoring/index.d.ts +14 -2
  46. package/dist/server/flow-surfaces/runjs-authoring/index.js +4213 -242
  47. package/dist/server/flow-surfaces/runjs-authoring/nested-runjs-stop/index.d.ts +10 -0
  48. package/dist/server/flow-surfaces/runjs-authoring/nested-runjs-stop/index.js +40 -0
  49. package/dist/server/flow-surfaces/runjs-authoring/rules.js +6 -0
  50. package/dist/server/flow-surfaces/runjs-authoring/source-limit-stop/index.d.ts +10 -0
  51. package/dist/server/flow-surfaces/runjs-authoring/source-limit-stop/index.js +40 -0
  52. package/dist/server/flow-surfaces/runjs-authoring/syntax-stop/index.d.ts +10 -0
  53. package/dist/server/flow-surfaces/runjs-authoring/syntax-stop/index.js +40 -0
  54. package/dist/server/flow-surfaces/runjs-authoring/types.d.ts +1 -1
  55. package/dist/server/flow-surfaces/service-utils.d.ts +1 -1
  56. package/dist/server/flow-surfaces/service-utils.js +3 -0
  57. package/dist/server/flow-surfaces/service.d.ts +61 -3
  58. package/dist/server/flow-surfaces/service.js +1199 -101
  59. package/dist/server/flow-surfaces/support-matrix.d.ts +1 -1
  60. package/dist/server/flow-surfaces/support-matrix.js +13 -1
  61. package/dist/server/flow-surfaces/surface-context.js +4 -13
  62. package/dist/swagger/flow-surfaces.d.ts +147 -0
  63. package/dist/swagger/flow-surfaces.examples.d.ts +194 -1
  64. package/dist/swagger/flow-surfaces.examples.js +75 -3
  65. package/dist/swagger/flow-surfaces.js +180 -7
  66. package/dist/swagger/index.d.ts +147 -0
  67. package/package.json +5 -2
@@ -146,10 +146,24 @@ const CANONICAL_BLOCK_HEADER_USES = /* @__PURE__ */ new Set([
146
146
  "ChartBlockModel",
147
147
  "ActionPanelBlockModel",
148
148
  "MapBlockModel",
149
- "CommentsBlockModel"
149
+ "CommentsBlockModel",
150
+ "RecordHistoryBlockModel"
150
151
  ]);
152
+ const COMMENTS_PAGE_SIZE_VALUES = /* @__PURE__ */ new Set([5, 10, 20, 50, 100, 200]);
153
+ const RECORD_HISTORY_INTERNAL_COLLECTIONS = /* @__PURE__ */ new Set(["recordHistories", "recordFieldHistories"]);
151
154
  const CARD_FIELD_COMPOSE_BLOCK_TYPES = /* @__PURE__ */ new Set(["list", "gridCard", "kanban"]);
152
- const RECORD_ACTION_COMPOSE_BLOCK_TYPES = /* @__PURE__ */ new Set(["list", "gridCard"]);
155
+ const RECORD_ACTION_COMPOSE_BLOCK_TYPES = /* @__PURE__ */ new Set(["list", "gridCard", "comments"]);
156
+ const COMMENT_ACTION_SINGLETON_USES = /* @__PURE__ */ new Set([
157
+ "EditCommentActionModel",
158
+ "DeleteCommentActionModel",
159
+ "QuoteReplyActionModel"
160
+ ]);
161
+ const RECORD_HISTORY_ACTION_SINGLETON_USES = /* @__PURE__ */ new Set([
162
+ "FilterActionModel",
163
+ "RefreshActionModel",
164
+ "RecordHistoryExpandActionModel",
165
+ "RecordHistoryCollapseActionModel"
166
+ ]);
153
167
  const GRID_SETTINGS_FLOW_KEY = "gridSettings";
154
168
  const GRID_SETTINGS_LAYOUT_STEP_KEY = "grid";
155
169
  const OPEN_VIEW_MODE_ALIASES = {
@@ -167,7 +181,8 @@ const FILTER_TARGET_BLOCK_USES = /* @__PURE__ */ new Set([
167
181
  "GridCardBlockModel",
168
182
  "ChartBlockModel",
169
183
  "MapBlockModel",
170
- "CommentsBlockModel"
184
+ "CommentsBlockModel",
185
+ "RecordHistoryBlockModel"
171
186
  ]);
172
187
  const TREE_CONNECT_TARGET_BLOCK_USES = new Set(FILTER_TARGET_BLOCK_USES);
173
188
  const EDITABLE_FIELD_WRAPPER_USES = /* @__PURE__ */ new Set(["FormItemModel", "FilterFormItemModel", "PatternFormItemModel"]);
@@ -315,6 +330,7 @@ const POPUP_COLLECTION_BLOCK_SCENES = {
315
330
  ProcessFormModel: ["one"],
316
331
  ApprovalDetailsModel: ["one"],
317
332
  CommentsBlockModel: ["one", "many"],
333
+ RecordHistoryBlockModel: ["one", "many"],
318
334
  TableBlockModel: ["many"],
319
335
  CalendarBlockModel: ["many"],
320
336
  TreeBlockModel: ["filter"],
@@ -441,6 +457,20 @@ const UPDATE_SETTINGS_STEP_PARAM_MIRRORS_BY_USE = {
441
457
  DividerItemModel: DIVIDER_ITEM_STEP_PARAM_MIRRORS
442
458
  };
443
459
  const FLOW_SURFACE_MENU_BINDABLE_OPTION_KEY = "flowSurfaceMenuBindable";
460
+ const AI_EMPLOYEE_ACTION_USE = "AIEmployeeButtonModel";
461
+ const AI_EMPLOYEE_OWNER_PLUGIN = "@nocobase/plugin-ai";
462
+ const AI_EMPLOYEE_PUBLIC_SETTING_KEYS = ["username", "auto", "workContext", "tasks", "style"];
463
+ const AI_EMPLOYEE_INTERNAL_PROP_KEYS = ["aiEmployee", "context", "auto", "tasks", "style"];
464
+ const AI_EMPLOYEE_WORK_CONTEXT_PUBLIC_KEYS = ["type", "uid", "target"];
465
+ const AI_EMPLOYEE_TASK_PUBLIC_SETTING_KEYS = ["title", "message", "autoSend", "skillSettings", "model", "webSearch"];
466
+ const AI_EMPLOYEE_TASK_MESSAGE_PUBLIC_KEYS = ["system", "user", "workContext"];
467
+ const AI_EMPLOYEE_TASK_MODEL_PUBLIC_KEYS = ["llmService", "model"];
468
+ const AI_EMPLOYEE_SKILL_SETTINGS_PUBLIC_KEYS = ["skills", "tools", "skillsVersion", "toolsVersion"];
469
+ const AI_EMPLOYEE_STYLE_PUBLIC_KEYS = ["size", "mask"];
470
+ const AI_EMPLOYEE_DEFAULT_STYLE = {
471
+ size: 40,
472
+ mask: false
473
+ };
444
474
  function normalizeCalendarFieldCapabilityValues(source, defaults) {
445
475
  const rawValues = Array.isArray(source) ? source : source instanceof Set ? Array.from(source) : typeof source === "string" ? [source] : source && typeof source === "object" ? Object.keys(source) : [];
446
476
  const values = rawValues.map((item) => String(item || "").trim()).filter(Boolean);
@@ -1456,12 +1486,26 @@ class FlowSurfacesService {
1456
1486
  if (this.isPopupCollectionBlockSceneUnsupported(popupProfile.scene)) {
1457
1487
  return [];
1458
1488
  }
1489
+ const associationFields = this.listPopupAssociatedRecordFields(popupProfile, blockUse);
1490
+ if (blockUse === "CommentsBlockModel") {
1491
+ if (!popupProfile.currentCollection || !popupProfile.hasCurrentRecord || !associationFields.length) {
1492
+ return [];
1493
+ }
1494
+ return [
1495
+ {
1496
+ key: "associatedRecords",
1497
+ label: "Associated records",
1498
+ description: "Bind comments to a comment-template association of the popup current record.",
1499
+ requires: ["associationField"],
1500
+ associationFields
1501
+ }
1502
+ ];
1503
+ }
1459
1504
  const bindings = [];
1460
1505
  const currentCollectionName = popupProfile.currentCollection ? popupProfile.collectionName || (0, import_service_helpers.getCollectionTitle)(popupProfile.currentCollection) : void 0;
1461
1506
  const blockScenes = this.getPopupCollectionBlockScenes(blockUse);
1462
1507
  const supportsCurrentCollection = blockScenes.includes("new") || !popupProfile.hasCurrentRecord && blockScenes.includes("many");
1463
- const supportsCurrentRecord = blockScenes.includes("one");
1464
- const associationFields = this.listPopupAssociatedRecordFields(popupProfile, blockUse);
1508
+ const supportsCurrentRecord = blockScenes.includes("one") && (blockUse !== "RecordHistoryBlockModel" || popupProfile.scene === "one");
1465
1509
  if (!popupProfile.currentCollection) {
1466
1510
  bindings.push({
1467
1511
  key: "otherRecords",
@@ -1521,7 +1565,11 @@ class FlowSurfacesService {
1521
1565
  popupProfile.dataSourceKey || "main",
1522
1566
  (dataSourceKey, collectionName) => this.getCollection(dataSourceKey, collectionName)
1523
1567
  );
1524
- if (!(targetCollection == null ? void 0 : targetCollection.filterTargetKey)) {
1568
+ if (blockUse === "CommentsBlockModel") {
1569
+ if (!this.isCommentsAssociationField(field, targetCollection)) {
1570
+ return null;
1571
+ }
1572
+ } else if (!(targetCollection == null ? void 0 : targetCollection.filterTargetKey)) {
1525
1573
  return null;
1526
1574
  }
1527
1575
  const associationName = (0, import_service_helpers.resolveAssociationNameFromField)(field, popupProfile.currentCollection);
@@ -1601,7 +1649,10 @@ class FlowSurfacesService {
1601
1649
  hostDataSourceKey: popupProfile.dataSourceKey,
1602
1650
  hostCollectionName: popupProfile.collectionName,
1603
1651
  currentDataSourceKey: popupProfile.dataSourceKey,
1604
- currentCollectionName: popupProfile.collectionName
1652
+ currentCollectionName: popupProfile.collectionName,
1653
+ isPopupSurface: popupProfile.isPopupSurface,
1654
+ popupScene: popupProfile.scene,
1655
+ popupHasCurrentRecord: popupProfile.hasCurrentRecord
1605
1656
  });
1606
1657
  }
1607
1658
  async buildTargetAuthoringContext(input) {
@@ -1660,6 +1711,9 @@ class FlowSurfacesService {
1660
1711
  popupProfile.dataSourceKey || "main",
1661
1712
  (dataSourceKey, collectionName) => this.getCollection(dataSourceKey, collectionName)
1662
1713
  );
1714
+ if (blockUse === "CommentsBlockModel") {
1715
+ return this.isCommentsAssociationField(field, targetCollection);
1716
+ }
1663
1717
  return !!(targetCollection == null ? void 0 : targetCollection.filterTargetKey);
1664
1718
  } catch (error) {
1665
1719
  return false;
@@ -2630,6 +2684,7 @@ class FlowSurfacesService {
2630
2684
  async dispatchPlanOnlyAction(action, payload, transaction, options = {}) {
2631
2685
  const actionOptions = {
2632
2686
  transaction,
2687
+ currentRoles: options.currentRoles,
2633
2688
  popupTemplateAliasSession: options.popupTemplateAliasSession,
2634
2689
  popupTemplateTreeCache: options.popupTemplateTreeCache,
2635
2690
  skipGeneratedLayoutSingleColumnErrors: options.skipGeneratedLayoutSingleColumnErrors === true
@@ -3214,6 +3269,7 @@ class FlowSurfacesService {
3214
3269
  }
3215
3270
  },
3216
3271
  this.buildPlanningRuntimeDeps({
3272
+ currentRoles: options.currentRoles,
3217
3273
  popupTemplateAliasSession,
3218
3274
  popupTemplateTreeCache,
3219
3275
  skipGeneratedLayoutSingleColumnErrors: true
@@ -4925,6 +4981,7 @@ class FlowSurfacesService {
4925
4981
  await this.applyInlineNodeSettings(actionName, targetUid, settings, runtimeOptions);
4926
4982
  },
4927
4983
  resolveBlockSettings: (settings, state, block) => this.resolveComposeBlockSettings(settings, state.keyMap, block),
4984
+ resolveActionSettings: (settings, state, block, action, actionName) => this.resolveComposeActionSettings(settings, state.keyMap, block, action, actionName),
4928
4985
  createField: async (payload) => this.addField(payload, {
4929
4986
  ...runtimeOptions,
4930
4987
  popupTemplateAliasSession
@@ -5021,11 +5078,16 @@ class FlowSurfacesService {
5021
5078
  const inheritedResourceInit = (currentResourceInit == null ? void 0 : currentResourceInit.collectionName) ? currentResourceInit : (_a = await this.locator.resolveCollectionContext(current == null ? void 0 : current.uid, options.transaction).catch(() => null)) == null ? void 0 : _a.resourceInit;
5022
5079
  const enabledPackages = await this.resolveEnabledPluginPackages(options);
5023
5080
  const popupDefaultsMetadata = options.skipConfigureGeneratedDefaultPopup ? void 0 : this.buildPopupDefaultsMetadata(values == null ? void 0 : values.defaults);
5081
+ const popupProfile = await this.resolvePopupBlockProfile(target.uid, resolved, current, options.transaction).catch(
5082
+ () => null
5083
+ );
5084
+ const popupAuthoringContext = import_lodash.default.isPlainObject(changes == null ? void 0 : changes.resource) && Object.prototype.hasOwnProperty.call(changes.resource, "binding") ? this.buildAuthoringContextFromPopupProfile(popupProfile) : {};
5024
5085
  await (0, import_authoring_validation.assertFlowSurfaceAuthoringPayload)("configure", values, {
5025
5086
  transaction: options.transaction,
5026
5087
  hostBlockType: current == null ? void 0 : current.use,
5027
5088
  hostDataSourceKey: inheritedResourceInit == null ? void 0 : inheritedResourceInit.dataSourceKey,
5028
5089
  hostCollectionName: inheritedResourceInit == null ? void 0 : inheritedResourceInit.collectionName,
5090
+ ...popupAuthoringContext,
5029
5091
  enabledPackages,
5030
5092
  getCollection: (dataSourceKey, collectionName) => this.getCollection(dataSourceKey || "main", collectionName || ""),
5031
5093
  currentNode: current,
@@ -5098,6 +5160,9 @@ class FlowSurfacesService {
5098
5160
  if ((current == null ? void 0 : current.use) === "CommentsBlockModel") {
5099
5161
  return this.configureCommentsBlock(target, changes, options);
5100
5162
  }
5163
+ if ((current == null ? void 0 : current.use) === "RecordHistoryBlockModel") {
5164
+ return this.configureRecordHistoryBlock(target, current, changes, options);
5165
+ }
5101
5166
  if ((current == null ? void 0 : current.use) === "TableActionsColumnModel") {
5102
5167
  return this.configureActionColumn(target, changes, options);
5103
5168
  }
@@ -5676,21 +5741,24 @@ class FlowSurfacesService {
5676
5741
  return nextGrid;
5677
5742
  }
5678
5743
  buildBlockCreateResult(tree, parentUid, subKey, popupSurface) {
5679
- var _a, _b, _c, _d, _e;
5744
+ var _a, _b, _c, _d, _e, _f;
5680
5745
  const gridNode = (0, import_service_utils.getSingleNodeSubModel)((_a = tree == null ? void 0 : tree.subModels) == null ? void 0 : _a.grid);
5681
5746
  const itemNode = (0, import_service_utils.getSingleNodeSubModel)((_b = tree == null ? void 0 : tree.subModels) == null ? void 0 : _b.item);
5682
- const itemGridNode = (0, import_service_utils.getSingleNodeSubModel)((_c = itemNode == null ? void 0 : itemNode.subModels) == null ? void 0 : _c.grid);
5683
- const columnNodes = (0, import_service_utils.getNodeSubModelList)((_d = tree == null ? void 0 : tree.subModels) == null ? void 0 : _d.columns);
5747
+ const commentItemNode = (0, import_service_utils.getNodeSubModelList)((_c = tree == null ? void 0 : tree.subModels) == null ? void 0 : _c.items).find(
5748
+ (item) => (item == null ? void 0 : item.use) === "CommentItemModel"
5749
+ );
5750
+ const itemGridNode = (0, import_service_utils.getSingleNodeSubModel)((_d = itemNode == null ? void 0 : itemNode.subModels) == null ? void 0 : _d.grid);
5751
+ const columnNodes = (0, import_service_utils.getNodeSubModelList)((_e = tree == null ? void 0 : tree.subModels) == null ? void 0 : _e.columns);
5684
5752
  const blockGridUid = (gridNode == null ? void 0 : gridNode.uid) || (itemGridNode == null ? void 0 : itemGridNode.uid);
5685
5753
  const popupGridUid = popupSurface == null ? void 0 : popupSurface.gridUid;
5686
- const actionsColumnUid = (_e = columnNodes.find((item) => item.use === "TableActionsColumnModel")) == null ? void 0 : _e.uid;
5754
+ const actionsColumnUid = (_f = columnNodes.find((item) => item.use === "TableActionsColumnModel")) == null ? void 0 : _f.uid;
5687
5755
  return {
5688
5756
  uid: tree.uid,
5689
5757
  parentUid,
5690
5758
  subKey,
5691
5759
  ...blockGridUid || popupGridUid ? { gridUid: blockGridUid || popupGridUid } : {},
5692
5760
  ...blockGridUid ? { blockGridUid } : {},
5693
- ...(itemNode == null ? void 0 : itemNode.uid) ? { itemUid: itemNode.uid } : {},
5761
+ ...(itemNode == null ? void 0 : itemNode.uid) || (commentItemNode == null ? void 0 : commentItemNode.uid) ? { itemUid: (itemNode == null ? void 0 : itemNode.uid) || commentItemNode.uid } : {},
5694
5762
  ...(itemGridNode == null ? void 0 : itemGridNode.uid) ? { itemGridUid: itemGridNode.uid } : {},
5695
5763
  ...actionsColumnUid ? { actionsColumnUid } : {},
5696
5764
  ...popupSurface ? {
@@ -6131,7 +6199,7 @@ class FlowSurfacesService {
6131
6199
  };
6132
6200
  }
6133
6201
  async addBlock(values, options = {}) {
6134
- var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k;
6202
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l;
6135
6203
  const enabledPackages = await this.resolveEnabledPluginPackages(options);
6136
6204
  const templateRef = import_lodash.default.isUndefined(values == null ? void 0 : values.template) || !(0, import_template_reference.hasFlowSurfaceTemplateReference)(values == null ? void 0 : values.template) ? void 0 : this.normalizeFlowTemplateReference("addBlock", values.template, {
6137
6205
  allowUsage: true,
@@ -6241,10 +6309,22 @@ class FlowSurfacesService {
6241
6309
  resourceInit: resolvedResourceInit,
6242
6310
  resourceField: rawResourceInit ? "resourceInit" : (semanticResource == null ? void 0 : semanticResource.kind) === "raw" ? "resource" : void 0
6243
6311
  });
6244
- const effectiveResourceInit = (catalogItem.use === "CalendarBlockModel" || catalogItem.use === "KanbanBlockModel") && resolvedResourceInit.collectionName && !resolvedResourceInit.dataSourceKey ? {
6312
+ let effectiveResourceInit = (catalogItem.use === "CalendarBlockModel" || catalogItem.use === "KanbanBlockModel") && resolvedResourceInit.collectionName && !resolvedResourceInit.dataSourceKey ? {
6245
6313
  ...resolvedResourceInit,
6246
6314
  dataSourceKey: "main"
6247
6315
  } : resolvedResourceInit;
6316
+ if (catalogItem.use === "RecordHistoryBlockModel") {
6317
+ const normalizedRecordHistoryCreate = this.normalizeRecordHistoryBlockCreateState({
6318
+ actionName: "addBlock",
6319
+ resourceInit: effectiveResourceInit,
6320
+ popupProfile,
6321
+ stepParams: values.stepParams
6322
+ });
6323
+ effectiveResourceInit = normalizedRecordHistoryCreate.resourceInit;
6324
+ values.stepParams = normalizedRecordHistoryCreate.stepParams;
6325
+ }
6326
+ this.assertInitialBlockResourceCompatible("addBlock", catalogItem.use, effectiveResourceInit, popupProfile);
6327
+ this.assertInitialBlockSettingsCompatible("addBlock", catalogItem.use, inlineSettings);
6248
6328
  const inlineFields = hasInlineFields ? this.normalizeComposeBlock(
6249
6329
  {
6250
6330
  key: String((values == null ? void 0 : values.key) || catalogItem.key || (values == null ? void 0 : values.type) || (values == null ? void 0 : values.use) || "addBlock_inline").trim() || "addBlock_inline",
@@ -6349,18 +6429,21 @@ class FlowSurfacesService {
6349
6429
  );
6350
6430
  const gridNode = (0, import_service_utils.getSingleNodeSubModel)((_b = tree.subModels) == null ? void 0 : _b.grid);
6351
6431
  const itemNode = (0, import_service_utils.getSingleNodeSubModel)((_c = tree.subModels) == null ? void 0 : _c.item);
6352
- const itemGridNode = (0, import_service_utils.getSingleNodeSubModel)((_d = itemNode == null ? void 0 : itemNode.subModels) == null ? void 0 : _d.grid);
6353
- const columnNodes = (0, import_service_utils.getNodeSubModelList)((_e = tree.subModels) == null ? void 0 : _e.columns);
6432
+ const commentItemNode = (0, import_service_utils.getNodeSubModelList)((_d = tree.subModels) == null ? void 0 : _d.items).find(
6433
+ (item) => (item == null ? void 0 : item.use) === "CommentItemModel"
6434
+ );
6435
+ const itemGridNode = (0, import_service_utils.getSingleNodeSubModel)((_e = itemNode == null ? void 0 : itemNode.subModels) == null ? void 0 : _e.grid);
6436
+ const columnNodes = (0, import_service_utils.getNodeSubModelList)((_f = tree.subModels) == null ? void 0 : _f.columns);
6354
6437
  const blockGridUid = (gridNode == null ? void 0 : gridNode.uid) || (itemGridNode == null ? void 0 : itemGridNode.uid);
6355
6438
  const popupGridUid = popupSurface == null ? void 0 : popupSurface.gridUid;
6356
- const actionsColumnUid = catalogItem.use === "TableBlockModel" ? await this.ensureTableActionsColumn(created, options.transaction) : (_f = columnNodes.find((item) => item.use === "TableActionsColumnModel")) == null ? void 0 : _f.uid;
6439
+ const actionsColumnUid = catalogItem.use === "TableBlockModel" ? await this.ensureTableActionsColumn(created, options.transaction) : (_g = columnNodes.find((item) => item.use === "TableActionsColumnModel")) == null ? void 0 : _g.uid;
6357
6440
  const result = {
6358
6441
  uid: created,
6359
6442
  parentUid,
6360
6443
  subKey,
6361
6444
  ...blockGridUid || popupGridUid ? { gridUid: blockGridUid || popupGridUid } : {},
6362
6445
  ...blockGridUid ? { blockGridUid } : {},
6363
- ...(itemNode == null ? void 0 : itemNode.uid) ? { itemUid: itemNode.uid } : {},
6446
+ ...(itemNode == null ? void 0 : itemNode.uid) || (commentItemNode == null ? void 0 : commentItemNode.uid) ? { itemUid: (itemNode == null ? void 0 : itemNode.uid) || commentItemNode.uid } : {},
6364
6447
  ...(itemGridNode == null ? void 0 : itemGridNode.uid) ? { itemGridUid: itemGridNode.uid } : {},
6365
6448
  ...actionsColumnUid ? { actionsColumnUid } : {},
6366
6449
  ...popupSurface ? {
@@ -6420,7 +6503,7 @@ class FlowSurfacesService {
6420
6503
  ) : catalogItem.use === "KanbanBlockModel" ? this.omitHiddenPopupSettingsForConfigure(inlineSettings, "kanban") : inlineSettings;
6421
6504
  await this.applyInlineNodeSettings("addBlock", created, inlineSettingsForConfigure, options);
6422
6505
  await ensureInitialBlockPopupHosts();
6423
- if ((_g = inlineFields == null ? void 0 : inlineFields.fields) == null ? void 0 : _g.length) {
6506
+ if ((_h = inlineFields == null ? void 0 : inlineFields.fields) == null ? void 0 : _h.length) {
6424
6507
  const fieldTargetUid = this.resolveComposeFieldContainerUid(inlineFields, result);
6425
6508
  const createdByKey = {};
6426
6509
  for (const fieldSpec of inlineFields.fields) {
@@ -6470,7 +6553,7 @@ class FlowSurfacesService {
6470
6553
  includeAsyncNode: true
6471
6554
  });
6472
6555
  const layoutItems = import_lodash.default.castArray(
6473
- ((_j = (_i = (_h = layoutHost == null ? void 0 : layoutHost.subModels) == null ? void 0 : _h.grid) == null ? void 0 : _i.subModels) == null ? void 0 : _j.items) || ((_k = layoutHost == null ? void 0 : layoutHost.subModels) == null ? void 0 : _k.items) || []
6556
+ ((_k = (_j = (_i = layoutHost == null ? void 0 : layoutHost.subModels) == null ? void 0 : _i.grid) == null ? void 0 : _j.subModels) == null ? void 0 : _k.items) || ((_l = layoutHost == null ? void 0 : layoutHost.subModels) == null ? void 0 : _l.items) || []
6474
6557
  );
6475
6558
  const layoutPayload = this.buildComposeLayoutPayload({
6476
6559
  layout: inlineFields.fieldsLayout,
@@ -6958,11 +7041,18 @@ class FlowSurfacesService {
6958
7041
  return result2;
6959
7042
  }
6960
7043
  const resourceContext = container.ownerUid ? await this.locator.resolveCollectionContext(container.ownerUid, options.transaction).catch(() => null) : null;
7044
+ const aiEmployeeProps = this.isAIEmployeeActionUse(actionCatalogItem.use) ? await this.normalizeAIEmployeeActionPublicSettings("addAction", inlineSettings || {}, {
7045
+ transaction: options.transaction,
7046
+ enabledPackages,
7047
+ requireUsername: true,
7048
+ currentRoles: options.currentRoles,
7049
+ selfUid: container.ownerUid
7050
+ }) : void 0;
6961
7051
  const action = (0, import_builder.buildActionTree)({
6962
7052
  use: actionCatalogItem.use,
6963
7053
  containerUse: container.ownerUse,
6964
7054
  resourceInit: values.resourceInit || (resourceContext == null ? void 0 : resourceContext.resourceInit),
6965
- props: values.props,
7055
+ props: aiEmployeeProps || values.props,
6966
7056
  decoratorProps: values.decoratorProps,
6967
7057
  stepParams: values.stepParams,
6968
7058
  flowRegistry: values.flowRegistry
@@ -6977,7 +7067,9 @@ class FlowSurfacesService {
6977
7067
  },
6978
7068
  { transaction: options.transaction }
6979
7069
  );
6980
- await this.applyInlineNodeSettings("addAction", created, inlineSettings, options);
7070
+ if (!this.isAIEmployeeActionUse(actionCatalogItem.use)) {
7071
+ await this.applyInlineNodeSettings("addAction", created, inlineSettings, options);
7072
+ }
6981
7073
  await this.applyInlineActionPopup("addAction", created, inlinePopup, {
6982
7074
  ...options,
6983
7075
  enabledPackages,
@@ -7029,13 +7121,38 @@ class FlowSurfacesService {
7029
7121
  context: "addRecordAction"
7030
7122
  });
7031
7123
  const materializedContainer = await this.materializeRecordActionContainer(container, options.transaction);
7124
+ const reusableAction = await this.resolveReusableSingletonAction({
7125
+ parentUid: materializedContainer.parentUid,
7126
+ ownerUse: container.ownerUse,
7127
+ actionUse: actionCatalogItem.use,
7128
+ transaction: options.transaction
7129
+ });
7130
+ if (reusableAction == null ? void 0 : reusableAction.uid) {
7131
+ await this.applyInlineNodeSettings("addRecordAction", reusableAction.uid, inlineSettings, options);
7132
+ const result2 = {
7133
+ uid: reusableAction.uid,
7134
+ parentUid: materializedContainer.parentUid,
7135
+ subKey: materializedContainer.subKey,
7136
+ scope: actionCatalogItem.scope,
7137
+ ...await this.collectComposeActionKeys(reusableAction.uid, options.transaction)
7138
+ };
7139
+ await this.persistCreatedKeysForAction("addRecordAction", values, result2, options.transaction);
7140
+ return result2;
7141
+ }
7032
7142
  const resourceContext = container.ownerUid ? await this.locator.resolveCollectionContext(container.ownerUid, options.transaction).catch(() => null) : null;
7033
7143
  const resourceInit = this.isAddChildCatalogItem(actionCatalogItem) ? await this.resolveAddChildResourceInitForOwnerNode(container.ownerNode, options.transaction) : values.resourceInit || (resourceContext == null ? void 0 : resourceContext.resourceInit);
7144
+ const aiEmployeeProps = this.isAIEmployeeActionUse(actionCatalogItem.use) ? await this.normalizeAIEmployeeActionPublicSettings("addRecordAction", inlineSettings || {}, {
7145
+ transaction: options.transaction,
7146
+ enabledPackages,
7147
+ requireUsername: true,
7148
+ currentRoles: options.currentRoles,
7149
+ selfUid: container.ownerUid
7150
+ }) : void 0;
7034
7151
  const action = (0, import_builder.buildActionTree)({
7035
7152
  use: actionCatalogItem.use,
7036
7153
  containerUse: container.containerUse,
7037
7154
  resourceInit,
7038
- props: values.props,
7155
+ props: aiEmployeeProps || values.props,
7039
7156
  decoratorProps: values.decoratorProps,
7040
7157
  stepParams: values.stepParams,
7041
7158
  flowRegistry: values.flowRegistry
@@ -7050,7 +7167,9 @@ class FlowSurfacesService {
7050
7167
  },
7051
7168
  { transaction: options.transaction }
7052
7169
  );
7053
- await this.applyInlineNodeSettings("addRecordAction", created, inlineSettings, options);
7170
+ if (!this.isAIEmployeeActionUse(actionCatalogItem.use)) {
7171
+ await this.applyInlineNodeSettings("addRecordAction", created, inlineSettings, options);
7172
+ }
7054
7173
  await this.applyInlineActionPopup("addRecordAction", created, inlinePopup, {
7055
7174
  ...options,
7056
7175
  enabledPackages,
@@ -7120,22 +7239,24 @@ class FlowSurfacesService {
7120
7239
  invoke: (itemValues, options) => this.addField(itemValues, options)
7121
7240
  });
7122
7241
  }
7123
- async addActions(values) {
7242
+ async addActions(values, options = {}) {
7124
7243
  return this.runBatchCreate({
7125
7244
  actionName: "addActions",
7126
7245
  values,
7127
7246
  itemField: "actions",
7128
7247
  resultField: "actions",
7129
- invoke: (itemValues, options) => this.addAction(itemValues, options)
7248
+ currentRoles: options.currentRoles,
7249
+ invoke: (itemValues, options2) => this.addAction(itemValues, options2)
7130
7250
  });
7131
7251
  }
7132
- async addRecordActions(values) {
7252
+ async addRecordActions(values, options = {}) {
7133
7253
  return this.runBatchCreate({
7134
7254
  actionName: "addRecordActions",
7135
7255
  values,
7136
7256
  itemField: "recordActions",
7137
7257
  resultField: "recordActions",
7138
- invoke: (itemValues, options) => this.addRecordAction(itemValues, options)
7258
+ currentRoles: options.currentRoles,
7259
+ invoke: (itemValues, options2) => this.addRecordAction(itemValues, options2)
7139
7260
  });
7140
7261
  }
7141
7262
  createPopupTemplateAliasSession() {
@@ -8943,6 +9064,16 @@ class FlowSurfacesService {
8943
9064
  };
8944
9065
  return resolvedSettings;
8945
9066
  }
9067
+ resolveComposeActionSettings(settings, keyMap, block, action, actionName) {
9068
+ var _a;
9069
+ if ((action == null ? void 0 : action.type) !== "aiEmployee") {
9070
+ return settings;
9071
+ }
9072
+ return this.normalizeAIEmployeeActionSettingsReferences(actionName, settings, {
9073
+ selfUid: (_a = block == null ? void 0 : block.result) == null ? void 0 : _a.uid,
9074
+ keyMap
9075
+ });
9076
+ }
8946
9077
  async applyInlineFieldPopup(actionName, result, popup, options) {
8947
9078
  popup = this.prepareInlinePopupTemplateAliases(actionName, popup, options.popupTemplateAliasSession);
8948
9079
  const fieldHostUid = result.fieldUid || result.uid;
@@ -10505,11 +10636,35 @@ class FlowSurfacesService {
10505
10636
  const target = await this.locator.resolve(writeTarget, options);
10506
10637
  const current = await this.loadResolvedNode(target, options.transaction);
10507
10638
  const normalizedValues = import_lodash.default.cloneDeep(values || {});
10639
+ if (this.isAIEmployeeActionUse(current == null ? void 0 : current.use) && !options.allowAIEmployeeInternalProps) {
10640
+ this.assertNoAIEmployeeInternalPropSettings("updateSettings", normalizedValues);
10641
+ }
10642
+ if (this.isAIEmployeeActionUse(current == null ? void 0 : current.use) && this.hasAIEmployeePublicSettings(normalizedValues)) {
10643
+ const enabledPackages = await this.resolveEnabledPluginPackages(options);
10644
+ const aiEmployeeProps = await this.normalizeAIEmployeeActionPublicSettings(
10645
+ "updateSettings",
10646
+ import_lodash.default.pick(normalizedValues, AI_EMPLOYEE_PUBLIC_SETTING_KEYS),
10647
+ {
10648
+ transaction: options.transaction,
10649
+ enabledPackages,
10650
+ current,
10651
+ currentRoles: options.currentRoles,
10652
+ selfUid: await this.resolveAIEmployeeActionSelfUid(current, options.transaction)
10653
+ }
10654
+ );
10655
+ AI_EMPLOYEE_PUBLIC_SETTING_KEYS.forEach((key) => {
10656
+ delete normalizedValues[key];
10657
+ });
10658
+ normalizedValues.props = import_lodash.default.merge({}, normalizedValues.props || {}, aiEmployeeProps);
10659
+ }
10508
10660
  assertNoFlowSurfaceIdTitleFieldSettings(normalizedValues, {
10509
10661
  action: "updateSettings",
10510
10662
  titleFieldErrorOptions: this.resolveRelationTitleFieldErrorOptionsForNode(current)
10511
10663
  });
10512
10664
  this.normalizeCanonicalBlockHeaderWriteForUpdateSettings(current, normalizedValues);
10665
+ if ((current == null ? void 0 : current.use) === "RecordHistoryBlockModel") {
10666
+ await this.assertRecordHistoryRecordIdWriteAllowed(current, normalizedValues, options.transaction);
10667
+ }
10513
10668
  const contract = (0, import_catalog.getNodeContract)(current.use);
10514
10669
  const nextPayload = { uid: current.uid };
10515
10670
  const shouldStripLegacyBlockHeader = import_lodash.default.has(normalizedValues, ["stepParams", "cardSettings", "titleDescription"]);
@@ -10542,6 +10697,12 @@ class FlowSurfacesService {
10542
10697
  nextPayload,
10543
10698
  options.replacePopupStepParamSubtrees === true
10544
10699
  );
10700
+ this.replaceRecordHistorySettingsForUpdateSettings(
10701
+ current,
10702
+ normalizedValues,
10703
+ nextPayload,
10704
+ options.replaceRecordHistorySettings === true
10705
+ );
10545
10706
  this.syncCalendarPopupPropsForUpdateSettings(current, normalizedValues, nextPayload);
10546
10707
  this.syncKanbanPopupPropsForUpdateSettings(current, normalizedValues, nextPayload);
10547
10708
  this.syncDefaultSortingForUpdateSettings(current, normalizedValues, nextPayload);
@@ -10572,6 +10733,7 @@ class FlowSurfacesService {
10572
10733
  popupTemplateTreeCache: options.popupTemplateTreeCache
10573
10734
  }
10574
10735
  );
10736
+ this.validateBuilderChartFieldsForUpdateSettings(current, nextPayload);
10575
10737
  this.syncChartConfigureForUpdateSettings(current, nextPayload);
10576
10738
  await this.validateChartConfigureForUpdateSettings(current, nextPayload, options.transaction);
10577
10739
  this.syncCanonicalBlockHeaderForUpdateSettings(current, nextPayload);
@@ -10598,7 +10760,12 @@ class FlowSurfacesService {
10598
10760
  this.validateKanbanBlockState("updateSettings", effectiveNode);
10599
10761
  if (shouldValidateFlowRegistry && import_lodash.default.isPlainObject(effectiveNode.flowRegistry) && Object.keys(effectiveNode.flowRegistry).length) {
10600
10762
  this.contractGuard.validateFlowRegistry(effectiveNode, effectiveNode.flowRegistry);
10601
- this.assertFlowRegistryRunJsAuthoringPayload(effectiveNode.flowRegistry);
10763
+ await this.assertFlowRegistryRunJsAuthoringPayload(effectiveNode.flowRegistry, {
10764
+ current: effectiveNode,
10765
+ resolved: target,
10766
+ target: writeTarget,
10767
+ transaction: options.transaction
10768
+ });
10602
10769
  }
10603
10770
  if (Object.keys(nextPayload).length === 1) {
10604
10771
  return { uid: current.uid };
@@ -10683,6 +10850,27 @@ class FlowSurfacesService {
10683
10850
  import_lodash.default.set(stepParams, [groupKey, "dataScope", "filter"], import_lodash.default.cloneDeep(value.filter));
10684
10851
  });
10685
10852
  }
10853
+ async assertRecordHistoryRecordIdWriteAllowed(current, normalizedValues, transaction) {
10854
+ const recordIdPath = ["stepParams", "recordHistorySettings", "recordId", "recordId"];
10855
+ if ((current == null ? void 0 : current.use) !== "RecordHistoryBlockModel" || !import_lodash.default.has(normalizedValues, recordIdPath)) {
10856
+ return;
10857
+ }
10858
+ const recordId = import_lodash.default.get(normalizedValues, recordIdPath);
10859
+ if (import_lodash.default.isNil(recordId) || String(recordId).trim() === "") {
10860
+ return;
10861
+ }
10862
+ if (this.normalizeFlowContextTemplateValue(recordId) !== "{{ctx.view.inputArgs.filterByTk}}") {
10863
+ (0, import_errors.throwBadRequest)(
10864
+ `flowSurfaces updateSettings recordHistory recordId.recordId only supports the popup current record`
10865
+ );
10866
+ }
10867
+ const popupProfile = await this.resolvePopupBlockProfile(current.uid, void 0, void 0, transaction);
10868
+ if (!(popupProfile == null ? void 0 : popupProfile.isPopupSurface) || !popupProfile.hasCurrentRecord || popupProfile.scene !== "one") {
10869
+ (0, import_errors.throwBadRequest)(
10870
+ `flowSurfaces updateSettings recordHistory current-record history is only supported in one-record popup/details scenes`
10871
+ );
10872
+ }
10873
+ }
10686
10874
  syncCalendarPopupPropsForUpdateSettings(current, normalizedValues, nextPayload) {
10687
10875
  if ((current == null ? void 0 : current.use) !== "CalendarBlockModel" || !import_lodash.default.isPlainObject(normalizedValues == null ? void 0 : normalizedValues.props)) {
10688
10876
  return;
@@ -10739,6 +10927,14 @@ class FlowSurfacesService {
10739
10927
  nextPayload.stepParams = nextStepParams;
10740
10928
  }
10741
10929
  }
10930
+ replaceRecordHistorySettingsForUpdateSettings(current, normalizedValues, nextPayload, replaceRecordHistorySettings = false) {
10931
+ if (!replaceRecordHistorySettings || (current == null ? void 0 : current.use) !== "RecordHistoryBlockModel" || !import_lodash.default.has(normalizedValues, ["stepParams", "recordHistorySettings"])) {
10932
+ return;
10933
+ }
10934
+ const nextStepParams = import_lodash.default.cloneDeep(nextPayload.stepParams ?? (current == null ? void 0 : current.stepParams) ?? {});
10935
+ nextStepParams.recordHistorySettings = import_lodash.default.cloneDeep(normalizedValues.stepParams.recordHistorySettings || {});
10936
+ nextPayload.stepParams = nextStepParams;
10937
+ }
10742
10938
  normalizePopupStepParamReplacementForUpdateSettings(current, path, value, currentValue, replacePopupStepParamSubtrees = false) {
10743
10939
  if (!import_lodash.default.isPlainObject(value)) {
10744
10940
  return {};
@@ -11365,6 +11561,16 @@ class FlowSurfacesService {
11365
11561
  }
11366
11562
  import_lodash.default.set(nextPayload, ["stepParams", "chartSettings", "configure"], (0, import_chart_config.canonicalizeChartConfigure)(nextConfigure));
11367
11563
  }
11564
+ validateBuilderChartFieldsForUpdateSettings(current, nextPayload) {
11565
+ if ((current == null ? void 0 : current.use) !== "ChartBlockModel") {
11566
+ return;
11567
+ }
11568
+ const configure = import_lodash.default.get(nextPayload, ["stepParams", "chartSettings", "configure"]);
11569
+ if (!import_lodash.default.isPlainObject(configure)) {
11570
+ return;
11571
+ }
11572
+ this.validateBuilderChartFieldsForRuntime("updateSettings", configure);
11573
+ }
11368
11574
  async validateChartConfigureForUpdateSettings(current, nextPayload, transaction) {
11369
11575
  var _a, _b, _c;
11370
11576
  if ((current == null ? void 0 : current.use) !== "ChartBlockModel") {
@@ -11398,6 +11604,81 @@ class FlowSurfacesService {
11398
11604
  }
11399
11605
  }
11400
11606
  }
11607
+ normalizeChartSelectionFieldPath(input) {
11608
+ if (Array.isArray(input)) {
11609
+ return input.map((item) => String(item || "").trim()).filter(Boolean).join(".");
11610
+ }
11611
+ return String(input || "").trim();
11612
+ }
11613
+ validateBuilderChartFieldsForRuntime(actionName, configure) {
11614
+ var _a, _b;
11615
+ const resourceInit = (0, import_chart_config.getChartBuilderResourceInit)(configure);
11616
+ if (!(resourceInit == null ? void 0 : resourceInit.collectionName)) {
11617
+ return;
11618
+ }
11619
+ const dataSourceKey = resourceInit.dataSourceKey || "main";
11620
+ const collectionName = resourceInit.collectionName;
11621
+ const collection = this.getCollection(dataSourceKey, collectionName);
11622
+ if (!collection) {
11623
+ return;
11624
+ }
11625
+ const state = (0, import_chart_config.deriveChartSemanticState)(configure);
11626
+ if (((_a = state.query) == null ? void 0 : _a.mode) !== "builder") {
11627
+ return;
11628
+ }
11629
+ const selections = [
11630
+ ...import_lodash.default.castArray(state.query.measures || []).map((selection, index) => ({
11631
+ selection,
11632
+ path: `chart query.measures[${index}].field`
11633
+ })),
11634
+ ...import_lodash.default.castArray(state.query.dimensions || []).map((selection, index) => ({
11635
+ selection,
11636
+ path: `chart query.dimensions[${index}].field`
11637
+ }))
11638
+ ];
11639
+ for (const item of selections) {
11640
+ const fieldPath = this.normalizeChartSelectionFieldPath((_b = item.selection) == null ? void 0 : _b.field);
11641
+ if (!fieldPath) {
11642
+ continue;
11643
+ }
11644
+ const parsed = this.parseFieldPath(collection, fieldPath, void 0, dataSourceKey, collectionName);
11645
+ const field = (0, import_service_helpers.resolveFieldFromCollection)(parsed.leafCollection, parsed.leafFieldPath);
11646
+ if (!field) {
11647
+ if (this.collectionHasConcreteField(parsed.leafCollection, parsed.leafFieldPath)) {
11648
+ continue;
11649
+ }
11650
+ (0, import_errors.throwBadRequest)(
11651
+ `flowSurfaces ${actionName} ${item.path} '${fieldPath}' does not exist on collection '${dataSourceKey}.${collectionName}'`
11652
+ );
11653
+ }
11654
+ if (!fieldPath.includes(".") && (0, import_service_helpers.isAssociationField)(field)) {
11655
+ const suggestion = this.resolveBuilderChartAssociationSubfieldSuggestion(fieldPath, field, dataSourceKey);
11656
+ (0, import_errors.throwBadRequest)(
11657
+ `flowSurfaces ${actionName} ${item.path} '${fieldPath}' references an association field directly; use scalar subfield '${suggestion.suggestedFieldPath}' for builder charts`
11658
+ );
11659
+ }
11660
+ }
11661
+ }
11662
+ resolveBuilderChartAssociationSubfieldSuggestion(fieldPath, field, dataSourceKey) {
11663
+ try {
11664
+ const resolved = (0, import_association_title_field.resolveAssociationSafeTitleField)(
11665
+ field,
11666
+ dataSourceKey,
11667
+ (targetDataSourceKey, targetCollectionName) => this.getCollection(targetDataSourceKey, targetCollectionName),
11668
+ { fieldPath }
11669
+ );
11670
+ const titleField = String((resolved == null ? void 0 : resolved.fieldName) || "").trim();
11671
+ if (titleField) {
11672
+ return {
11673
+ suggestedFieldPath: `${fieldPath}.${titleField}`
11674
+ };
11675
+ }
11676
+ } catch {
11677
+ }
11678
+ return {
11679
+ suggestedFieldPath: `${fieldPath}.<field>`
11680
+ };
11681
+ }
11401
11682
  stripChartSqlForInspection(sql) {
11402
11683
  return sql.replace(/\/\*[\s\S]*?\*\//g, " ").replace(/--[^\r\n]*/g, " ").replace(/'(?:''|[^'])*'/g, "''").replace(/"(?:[""]|[^"])*"/g, '""');
11403
11684
  }
@@ -11797,7 +12078,12 @@ class FlowSurfacesService {
11797
12078
  async persistEventFlowRegistry(actionName, target, current, flowRegistry, options = {}) {
11798
12079
  this.assertNoTreeConnectFieldsFlowRegistry(current, flowRegistry, actionName);
11799
12080
  this.contractGuard.validateFlowRegistry(current, flowRegistry);
11800
- this.assertFlowRegistryRunJsAuthoringPayload(flowRegistry);
12081
+ await this.assertFlowRegistryRunJsAuthoringPayload(flowRegistry, {
12082
+ current,
12083
+ resolved: target,
12084
+ target,
12085
+ transaction: options.transaction
12086
+ });
11801
12087
  if (target.kind === "tab" && target.tabRoute) {
11802
12088
  await this.routeSync.persistTabSettings(
11803
12089
  target,
@@ -11827,8 +12113,33 @@ class FlowSurfacesService {
11827
12113
  fingerprint: this.buildEventFlowFingerprint(flowRegistry)
11828
12114
  };
11829
12115
  }
11830
- assertFlowRegistryRunJsAuthoringPayload(flowRegistry) {
11831
- const errors = (0, import_runjs_authoring.collectFlowRegistryRunJsAuthoringErrors)(flowRegistry);
12116
+ async buildFlowRegistryRunJsAuthoringContext(input) {
12117
+ var _a, _b, _c, _d;
12118
+ const currentResourceInit = this.getDataBlockResourceInit(input.current);
12119
+ const inheritedResourceInit = (currentResourceInit == null ? void 0 : currentResourceInit.collectionName) ? currentResourceInit : ((_a = input.current) == null ? void 0 : _a.uid) ? (_b = await this.locator.resolveCollectionContext(input.current.uid, input.transaction).catch(() => null)) == null ? void 0 : _b.resourceInit : null;
12120
+ const resourceDataSourceKey = (inheritedResourceInit == null ? void 0 : inheritedResourceInit.dataSourceKey) || ((inheritedResourceInit == null ? void 0 : inheritedResourceInit.collectionName) ? "main" : void 0);
12121
+ const popupProfile = ((_c = input.target) == null ? void 0 : _c.uid) ? await this.resolvePopupBlockProfile(
12122
+ input.target.uid,
12123
+ input.resolved || input.target,
12124
+ input.current,
12125
+ input.transaction
12126
+ ).catch(() => null) : null;
12127
+ return (0, import_service_utils.buildDefinedPayload)({
12128
+ hostBlockType: (_d = input.current) == null ? void 0 : _d.use,
12129
+ hostDataSourceKey: resourceDataSourceKey,
12130
+ hostCollectionName: inheritedResourceInit == null ? void 0 : inheritedResourceInit.collectionName,
12131
+ currentDataSourceKey: resourceDataSourceKey,
12132
+ currentCollectionName: inheritedResourceInit == null ? void 0 : inheritedResourceInit.collectionName,
12133
+ ...this.buildAuthoringContextFromPopupProfile(popupProfile),
12134
+ currentNode: input.current
12135
+ });
12136
+ }
12137
+ async assertFlowRegistryRunJsAuthoringPayload(flowRegistry, context = {}) {
12138
+ const authoringContext = await this.buildFlowRegistryRunJsAuthoringContext(context);
12139
+ const errors = (0, import_runjs_authoring.collectFlowRegistryRunJsAuthoringErrors)(flowRegistry, "$.flowRegistry", {
12140
+ ...authoringContext,
12141
+ getCollection: (dataSourceKey, collectionName) => this.getCollection(dataSourceKey, collectionName)
12142
+ });
11832
12143
  if (errors.length) {
11833
12144
  (0, import_errors.throwAggregateBadRequest)(errors);
11834
12145
  }
@@ -12024,6 +12335,7 @@ class FlowSurfacesService {
12024
12335
  async dispatchOp(op, resolvedValues, ctx, runtimeOptions = {}) {
12025
12336
  const options = {
12026
12337
  transaction: ctx.transaction,
12338
+ currentRoles: runtimeOptions.currentRoles,
12027
12339
  popupTemplateAliasSession: runtimeOptions.popupTemplateAliasSession,
12028
12340
  popupTemplateTreeCache: runtimeOptions.popupTemplateTreeCache
12029
12341
  };
@@ -12582,7 +12894,7 @@ class FlowSurfacesService {
12582
12894
  const recordContainerUse = (0, import_service_utils.getCatalogRecordActionContainerUse)(blockUse);
12583
12895
  if (!recordContainerUse) {
12584
12896
  (0, import_errors.throwBadRequest)(
12585
- `flowSurfaces compose recordActions only support 'table', 'details', 'list' or 'gridCard' blocks`
12897
+ `flowSurfaces compose recordActions only support 'table', 'details', 'list', 'gridCard' or 'comments' blocks`
12586
12898
  );
12587
12899
  }
12588
12900
  const item = this.tryResolveActionCatalogItem(
@@ -13168,7 +13480,7 @@ class FlowSurfacesService {
13168
13480
  return filteredItems.filter((item) => !this.isAddChildCatalogItem(item));
13169
13481
  }
13170
13482
  async inspectRecordActionContainer(target, transaction) {
13171
- var _a, _b;
13483
+ var _a, _b, _c, _d;
13172
13484
  const resolved = await this.locator.resolve(target, { transaction });
13173
13485
  const node = resolved.node || await this.repository.findModelById(resolved.uid, { transaction, includeAsyncNode: true });
13174
13486
  const use = node == null ? void 0 : node.use;
@@ -13211,6 +13523,24 @@ class FlowSurfacesService {
13211
13523
  subType: "array"
13212
13524
  };
13213
13525
  }
13526
+ if (use === "CommentsBlockModel") {
13527
+ const itemUid = (_d = import_lodash.default.castArray(((_c = node.subModels) == null ? void 0 : _c.items) || [])[0]) == null ? void 0 : _d.uid;
13528
+ if (!itemUid) {
13529
+ (0, import_errors.throwConflict)(
13530
+ `flowSurfaces addRecordAction target '${use}' is missing its comment item subtree`,
13531
+ "FLOW_SURFACE_RECORD_ACTION_ITEM_SUBTREE_MISSING"
13532
+ );
13533
+ }
13534
+ return {
13535
+ ownerNode: node,
13536
+ ownerUid: node.uid,
13537
+ ownerUse: use,
13538
+ containerUse: "CommentItemModel",
13539
+ parentUid: itemUid,
13540
+ subKey: "actions",
13541
+ subType: "array"
13542
+ };
13543
+ }
13214
13544
  if (use === "KanbanBlockModel") {
13215
13545
  (0, import_errors.throwBadRequest)(
13216
13546
  `flowSurfaces addRecordAction target '${use}' is not supported; kanban record actions are not exposed in the public API v1`
@@ -13221,9 +13551,9 @@ class FlowSurfacesService {
13221
13551
  `flowSurfaces addRecordAction target '${use}' is an internal record action container; pass the owning table block uid instead`
13222
13552
  );
13223
13553
  }
13224
- if (use === "ListItemModel" || use === "GridCardItemModel") {
13554
+ if (use === "ListItemModel" || use === "GridCardItemModel" || use === "CommentItemModel") {
13225
13555
  (0, import_errors.throwBadRequest)(
13226
- `flowSurfaces addRecordAction target '${use}' is an internal record action container; pass the owning ${use === "ListItemModel" ? "list" : "gridCard"} block uid instead`
13556
+ `flowSurfaces addRecordAction target '${use}' is an internal record action container; pass the owning ${use === "ListItemModel" ? "list" : use === "GridCardItemModel" ? "gridCard" : "comments"} block uid instead`
13227
13557
  );
13228
13558
  }
13229
13559
  (0, import_errors.throwBadRequest)(
@@ -13277,6 +13607,7 @@ class FlowSurfacesService {
13277
13607
  result.result = await this.transaction(
13278
13608
  (transaction) => options.invoke(itemValues, {
13279
13609
  transaction,
13610
+ currentRoles: options.currentRoles,
13280
13611
  enabledPackages
13281
13612
  })
13282
13613
  );
@@ -13497,17 +13828,35 @@ class FlowSurfacesService {
13497
13828
  }
13498
13829
  }
13499
13830
  async resolveReusableSingletonAction(input) {
13500
- var _a;
13501
- if (!AUTO_SUBMIT_FORM_BLOCK_USES.has(input.ownerUse || "") || input.actionUse !== "FormSubmitActionModel") {
13502
- return null;
13831
+ var _a, _b, _c;
13832
+ if (AUTO_SUBMIT_FORM_BLOCK_USES.has(input.ownerUse || "") && input.actionUse === "FormSubmitActionModel") {
13833
+ const parentNode = await this.repository.findModelById(input.parentUid, {
13834
+ transaction: input.transaction,
13835
+ includeAsyncNode: true
13836
+ });
13837
+ return import_lodash.default.castArray(((_a = parentNode == null ? void 0 : parentNode.subModels) == null ? void 0 : _a.actions) || []).find(
13838
+ (action) => (action == null ? void 0 : action.use) === "FormSubmitActionModel" && (action == null ? void 0 : action.uid)
13839
+ ) || null;
13503
13840
  }
13504
- const parentNode = await this.repository.findModelById(input.parentUid, {
13505
- transaction: input.transaction,
13506
- includeAsyncNode: true
13507
- });
13508
- return import_lodash.default.castArray(((_a = parentNode == null ? void 0 : parentNode.subModels) == null ? void 0 : _a.actions) || []).find(
13509
- (action) => (action == null ? void 0 : action.use) === "FormSubmitActionModel" && (action == null ? void 0 : action.uid)
13510
- ) || null;
13841
+ if (input.ownerUse === "CommentsBlockModel" && COMMENT_ACTION_SINGLETON_USES.has(input.actionUse || "")) {
13842
+ const parentNode = await this.repository.findModelById(input.parentUid, {
13843
+ transaction: input.transaction,
13844
+ includeAsyncNode: true
13845
+ });
13846
+ return import_lodash.default.castArray(((_b = parentNode == null ? void 0 : parentNode.subModels) == null ? void 0 : _b.actions) || []).find(
13847
+ (action) => (action == null ? void 0 : action.use) === input.actionUse && (action == null ? void 0 : action.uid)
13848
+ ) || null;
13849
+ }
13850
+ if (input.ownerUse === "RecordHistoryBlockModel" && RECORD_HISTORY_ACTION_SINGLETON_USES.has(input.actionUse || "")) {
13851
+ const parentNode = await this.repository.findModelById(input.parentUid, {
13852
+ transaction: input.transaction,
13853
+ includeAsyncNode: true
13854
+ });
13855
+ return import_lodash.default.castArray(((_c = parentNode == null ? void 0 : parentNode.subModels) == null ? void 0 : _c.actions) || []).find(
13856
+ (action) => (action == null ? void 0 : action.use) === input.actionUse && (action == null ? void 0 : action.uid)
13857
+ ) || null;
13858
+ }
13859
+ return null;
13511
13860
  }
13512
13861
  normalizeComposeBlock(input, index, enabledPackages, preserveSingleScopeDataBlockTitle = false, popupDefaultsMetadata, resourceFallback) {
13513
13862
  if (!import_lodash.default.isPlainObject(input)) {
@@ -13729,6 +14078,7 @@ class FlowSurfacesService {
13729
14078
  return blockResult.uid;
13730
14079
  }
13731
14080
  async resolveComposeRecordActionContainerUid(blockSpec, blockResult, transaction) {
14081
+ var _a, _b, _c;
13732
14082
  if (blockSpec.type === "table") {
13733
14083
  return this.ensureTableActionsColumn(blockResult.uid, transaction);
13734
14084
  }
@@ -13737,9 +14087,19 @@ class FlowSurfacesService {
13737
14087
  }
13738
14088
  if (!RECORD_ACTION_COMPOSE_BLOCK_TYPES.has(blockSpec.type)) {
13739
14089
  (0, import_errors.throwBadRequest)(
13740
- `flowSurfaces compose recordActions only support 'table', 'details', 'list' or 'gridCard' blocks`
14090
+ `flowSurfaces compose recordActions only support 'table', 'details', 'list', 'gridCard' or 'comments' blocks`
13741
14091
  );
13742
14092
  }
14093
+ if (blockSpec.type === "comments") {
14094
+ const itemUid = ((_c = import_lodash.default.castArray(((_b = (_a = blockResult == null ? void 0 : blockResult.tree) == null ? void 0 : _a.subModels) == null ? void 0 : _b.items) || [])[0]) == null ? void 0 : _c.uid) || blockResult.itemUid;
14095
+ if (!itemUid) {
14096
+ (0, import_errors.throwConflict)(
14097
+ `flowSurfaces compose block '${blockSpec.key}' is missing its comment item subtree`,
14098
+ "FLOW_SURFACE_COMPOSE_ITEM_SUBTREE_MISSING"
14099
+ );
14100
+ }
14101
+ return itemUid;
14102
+ }
13743
14103
  if (!blockResult.itemUid) {
13744
14104
  (0, import_errors.throwConflict)(
13745
14105
  `flowSurfaces compose block '${blockSpec.key}' is missing its item subtree`,
@@ -13752,7 +14112,7 @@ class FlowSurfacesService {
13752
14112
  const recordContainerUse = (0, import_service_utils.getCatalogRecordActionContainerUse)(blockUse);
13753
14113
  if (recordActions.length && !recordContainerUse) {
13754
14114
  (0, import_errors.throwBadRequest)(
13755
- `flowSurfaces compose recordActions only support 'table', 'details', 'list' or 'gridCard' blocks`
14115
+ `flowSurfaces compose recordActions only support 'table', 'details', 'list', 'gridCard' or 'comments' blocks`
13756
14116
  );
13757
14117
  }
13758
14118
  actions.forEach((action) => {
@@ -15117,61 +15477,324 @@ class FlowSurfacesService {
15117
15477
  options
15118
15478
  );
15119
15479
  }
15120
- async configureCommentsBlock(target, changes, options) {
15121
- const allowedKeys = (0, import_configure_options.getConfigureOptionKeysForUse)("CommentsBlockModel");
15122
- const cardSettings = (0, import_service_utils.buildBlockTitleDescriptionFromSemanticChanges)(changes);
15123
- (0, import_service_utils.assertSupportedSimpleChanges)("comments", changes, allowedKeys);
15124
- return this.updateSettings(
15125
- {
15126
- target,
15127
- stepParams: (0, import_service_utils.buildDefinedPayload)({
15128
- ...cardSettings ? { cardSettings } : {},
15129
- ...changes.resource ? {
15130
- resourceSettings: {
15131
- init: (0, import_service_utils.normalizeSimpleResourceInit)(changes.resource)
15132
- }
15133
- } : {},
15134
- ...(0, import_service_utils.hasDefinedValue)(changes, ["pageSize", "dataScope"]) ? {
15135
- commentsSettings: (0, import_service_utils.buildDefinedPayload)({
15136
- ...(0, import_service_utils.hasOwnDefined)(changes, "pageSize") ? { pageSize: { pageSize: changes.pageSize } } : {},
15137
- ...(0, import_service_utils.hasOwnDefined)(changes, "dataScope") ? { dataScope: { filter: changes.dataScope } } : {}
15138
- })
15139
- } : {}
15140
- })
15141
- },
15142
- options
15143
- );
15480
+ normalizeBlockResourceForValidation(resourceInit) {
15481
+ const init = (0, import_service_utils.normalizeSimpleResourceInit)(resourceInit || {}) || {};
15482
+ if (init.collectionName && !init.dataSourceKey) {
15483
+ init.dataSourceKey = "main";
15484
+ }
15485
+ return init;
15144
15486
  }
15145
- async configureJSBlock(target, changes, options) {
15146
- const allowedKeys = (0, import_configure_options.getConfigureOptionKeysForUse)("JSBlockModel");
15147
- (0, import_service_utils.assertSupportedSimpleChanges)("jsBlock", changes, allowedKeys);
15148
- return this.updateSettings(
15149
- {
15150
- target,
15151
- decoratorProps: (0, import_service_utils.buildDefinedPayload)({
15152
- title: changes.title,
15153
- description: changes.description,
15154
- className: changes.className
15155
- }),
15156
- stepParams: (0, import_service_utils.hasDefinedValue)(changes, ["code", "version"]) ? {
15157
- jsSettings: {
15158
- runJs: (0, import_service_utils.buildDefinedPayload)({
15159
- code: changes.code,
15160
- version: changes.version
15161
- })
15162
- }
15163
- } : void 0
15164
- },
15165
- options
15166
- );
15487
+ isCommentTemplateCollection(collection) {
15488
+ var _a;
15489
+ return (collection == null ? void 0 : collection.template) === "comment" || ((_a = collection == null ? void 0 : collection.options) == null ? void 0 : _a.template) === "comment";
15167
15490
  }
15168
- async configureActionColumn(target, changes, options) {
15169
- const allowedKeys = (0, import_configure_options.getConfigureOptionKeysForUse)("TableActionsColumnModel");
15170
- (0, import_service_utils.assertSupportedSimpleChanges)("action column", changes, allowedKeys);
15171
- return this.updateSettings(
15172
- {
15173
- target,
15174
- props: (0, import_service_utils.buildDefinedPayload)({
15491
+ isCommentsAssociationField(field, targetCollection) {
15492
+ const fieldType = String((0, import_service_helpers.getFieldType)(field) || "").trim().toLowerCase();
15493
+ return (fieldType === "hasmany" || fieldType === "belongstomany") && this.isCommentTemplateCollection(targetCollection);
15494
+ }
15495
+ getRecordHistoryDeclaredFilterTargetKey(collection) {
15496
+ var _a, _b;
15497
+ const raw = Array.isArray(collection == null ? void 0 : collection.filterTargetKey) ? collection.filterTargetKey[0] : !import_lodash.default.isUndefined(collection == null ? void 0 : collection.filterTargetKey) ? collection.filterTargetKey : Array.isArray((_a = collection == null ? void 0 : collection.options) == null ? void 0 : _a.filterTargetKey) ? collection.options.filterTargetKey[0] : (_b = collection == null ? void 0 : collection.options) == null ? void 0 : _b.filterTargetKey;
15498
+ return String(raw || "").trim();
15499
+ }
15500
+ collectionHasConcreteField(collection, fieldName) {
15501
+ var _a, _b, _c, _d, _e, _f;
15502
+ const normalized = String(fieldName || "").trim();
15503
+ if (!normalized) {
15504
+ return false;
15505
+ }
15506
+ const modelAttributes = (typeof ((_a = collection == null ? void 0 : collection.model) == null ? void 0 : _a.getAttributes) === "function" ? collection.model.getAttributes() : null) || ((_b = collection == null ? void 0 : collection.model) == null ? void 0 : _b.rawAttributes) || ((_c = collection == null ? void 0 : collection.model) == null ? void 0 : _c.attributes) || {};
15507
+ const primaryKeyAttributes = import_lodash.default.castArray(
15508
+ ((_d = collection == null ? void 0 : collection.model) == null ? void 0 : _d.primaryKeyAttributes) || ((_e = collection == null ? void 0 : collection.model) == null ? void 0 : _e.primaryKeyAttribute) || []
15509
+ );
15510
+ const modelAttribute = modelAttributes == null ? void 0 : modelAttributes[normalized];
15511
+ const isModelPrimaryKey = primaryKeyAttributes.includes(normalized) || !!(modelAttribute == null ? void 0 : modelAttribute.primaryKey);
15512
+ return !!((0, import_service_helpers.resolveFieldFromCollection)(collection, normalized) || ((_f = collection == null ? void 0 : collection.getField) == null ? void 0 : _f.call(collection, normalized)) || (0, import_service_helpers.getCollectionFields)(collection).some((field) => (0, import_service_helpers.getFieldName)(field) === normalized) || isModelPrimaryKey);
15513
+ }
15514
+ assertInitialBlockResourceCompatible(actionName, blockUse, resourceInit, popupProfile) {
15515
+ if (blockUse === "CommentsBlockModel") {
15516
+ this.assertCommentsBlockResourceCompatible(actionName, resourceInit, popupProfile);
15517
+ }
15518
+ if (blockUse === "RecordHistoryBlockModel") {
15519
+ this.assertRecordHistoryBlockResourceCompatible(actionName, resourceInit, popupProfile);
15520
+ }
15521
+ }
15522
+ assertInitialBlockSettingsCompatible(actionName, blockUse, settings) {
15523
+ if (blockUse === "CommentsBlockModel") {
15524
+ this.assertCommentsSettingValues(actionName, settings);
15525
+ }
15526
+ if (blockUse === "RecordHistoryBlockModel") {
15527
+ this.assertRecordHistorySettingValues(actionName, settings);
15528
+ }
15529
+ }
15530
+ assertCommentsBlockResourceCompatible(actionName, resourceInit, popupProfile) {
15531
+ const init = this.normalizeBlockResourceForValidation(resourceInit);
15532
+ const collectionName = String(init.collectionName || "").trim();
15533
+ const dataSourceKey = String(init.dataSourceKey || "main").trim() || "main";
15534
+ if (!collectionName) {
15535
+ return;
15536
+ }
15537
+ const collection = this.getCollection(dataSourceKey, collectionName);
15538
+ if (!collection || !this.isCommentTemplateCollection(collection)) {
15539
+ (0, import_errors.throwBadRequest)(
15540
+ `flowSurfaces ${actionName} comments block requires a comment template collection; '${dataSourceKey}.${collectionName}' is not a comment template collection`
15541
+ );
15542
+ }
15543
+ const hasAssociationResource = (0, import_service_helpers.hasConfiguredFlowContextValue)(init.associationName) || (0, import_service_helpers.hasConfiguredFlowContextValue)(init.sourceId);
15544
+ if (popupProfile == null ? void 0 : popupProfile.isPopupSurface) {
15545
+ if (!hasAssociationResource || (0, import_service_helpers.hasConfiguredFlowContextValue)(init.filterByTk)) {
15546
+ (0, import_errors.throwBadRequest)(
15547
+ `flowSurfaces ${actionName} comments block in popups only supports resource.binding='associatedRecords'`
15548
+ );
15549
+ }
15550
+ return;
15551
+ }
15552
+ if (hasAssociationResource || (0, import_service_helpers.hasConfiguredFlowContextValue)(init.associationPathName) || (0, import_service_helpers.hasConfiguredFlowContextValue)(init.filterByTk)) {
15553
+ (0, import_errors.throwBadRequest)(
15554
+ `flowSurfaces ${actionName} comments block outside popups only supports a direct comment template collection resource`
15555
+ );
15556
+ }
15557
+ }
15558
+ assertRecordHistoryBlockResourceCompatible(actionName, resourceInit, popupProfile) {
15559
+ const init = this.normalizeBlockResourceForValidation(resourceInit);
15560
+ const collectionName = String(init.collectionName || "").trim();
15561
+ const dataSourceKey = String(init.dataSourceKey || "main").trim() || "main";
15562
+ if (!collectionName) {
15563
+ return;
15564
+ }
15565
+ if (RECORD_HISTORY_INTERNAL_COLLECTIONS.has(collectionName)) {
15566
+ (0, import_errors.throwBadRequest)(
15567
+ `flowSurfaces ${actionName} recordHistory block does not support internal collection '${collectionName}'`
15568
+ );
15569
+ }
15570
+ if ((0, import_service_helpers.hasConfiguredFlowContextValue)(init.associationName) || (0, import_service_helpers.hasConfiguredFlowContextValue)(init.associationPathName) || (0, import_service_helpers.hasConfiguredFlowContextValue)(init.sourceId)) {
15571
+ (0, import_errors.throwBadRequest)(
15572
+ `flowSurfaces ${actionName} recordHistory block does not support association resources; use a collection resource or resource.binding='currentRecord' in a one-record popup`
15573
+ );
15574
+ }
15575
+ if ((0, import_service_helpers.hasConfiguredFlowContextValue)(init.filterByTk)) {
15576
+ if (!(popupProfile == null ? void 0 : popupProfile.isPopupSurface) || !popupProfile.hasCurrentRecord || popupProfile.scene !== "one") {
15577
+ (0, import_errors.throwBadRequest)(
15578
+ `flowSurfaces ${actionName} recordHistory current-record history is only supported in one-record popup/details scenes`
15579
+ );
15580
+ }
15581
+ }
15582
+ const collection = this.getCollection(dataSourceKey, collectionName);
15583
+ if (!collection) {
15584
+ (0, import_errors.throwBadRequest)(
15585
+ `flowSurfaces ${actionName} recordHistory collection '${dataSourceKey}.${collectionName}' not found`
15586
+ );
15587
+ }
15588
+ const filterTargetKey = this.getRecordHistoryDeclaredFilterTargetKey(collection);
15589
+ if (!filterTargetKey || !this.collectionHasConcreteField(collection, filterTargetKey)) {
15590
+ (0, import_errors.throwBadRequest)(
15591
+ `flowSurfaces ${actionName} recordHistory block requires a real filterTargetKey on collection '${dataSourceKey}.${collectionName}'`
15592
+ );
15593
+ }
15594
+ }
15595
+ normalizeRecordHistoryBlockCreateState(input) {
15596
+ var _a;
15597
+ const init = this.normalizeBlockResourceForValidation(input.resourceInit);
15598
+ if (!(0, import_service_helpers.hasConfiguredFlowContextValue)(init.filterByTk)) {
15599
+ return {
15600
+ resourceInit: init,
15601
+ stepParams: input.stepParams
15602
+ };
15603
+ }
15604
+ if (!((_a = input.popupProfile) == null ? void 0 : _a.isPopupSurface) || !input.popupProfile.hasCurrentRecord || input.popupProfile.scene !== "one") {
15605
+ (0, import_errors.throwBadRequest)(
15606
+ `flowSurfaces ${input.actionName} recordHistory current-record history is only supported in one-record popup/details scenes`
15607
+ );
15608
+ }
15609
+ const nextResourceInit = import_lodash.default.omit(init, ["filterByTk", "associationName", "associationPathName", "sourceId"]);
15610
+ const nextStepParams = import_lodash.default.merge({}, import_lodash.default.cloneDeep(input.stepParams || {}), {
15611
+ recordHistorySettings: {
15612
+ recordId: {
15613
+ recordId: "{{ctx.view.inputArgs.filterByTk}}"
15614
+ }
15615
+ }
15616
+ });
15617
+ return {
15618
+ resourceInit: nextResourceInit,
15619
+ stepParams: nextStepParams
15620
+ };
15621
+ }
15622
+ async normalizeConfigureCollectionBlockResource(input) {
15623
+ const popupProfile = await this.resolvePopupBlockProfile(input.target.uid, void 0, void 0, input.transaction);
15624
+ const normalizedResource = this.normalizeResourceInput(input.resource);
15625
+ const resourceInit = await this.resolvePopupCollectionBlockResourceInit({
15626
+ actionName: input.actionName,
15627
+ blockUse: input.blockUse,
15628
+ popupProfile,
15629
+ semanticResource: (normalizedResource == null ? void 0 : normalizedResource.kind) === "semantic" ? normalizedResource.value : void 0,
15630
+ resourceInit: (normalizedResource == null ? void 0 : normalizedResource.kind) === "raw" ? normalizedResource.value : void 0
15631
+ });
15632
+ return {
15633
+ popupProfile,
15634
+ resourceInit
15635
+ };
15636
+ }
15637
+ assertCommentsSettingValues(actionName, settings) {
15638
+ if (!import_lodash.default.isPlainObject(settings) || !(0, import_service_utils.hasOwnDefined)(settings, "pageSize")) {
15639
+ return;
15640
+ }
15641
+ if (!COMMENTS_PAGE_SIZE_VALUES.has(Number(settings.pageSize))) {
15642
+ (0, import_errors.throwBadRequest)(
15643
+ `flowSurfaces ${actionName} comments pageSize must be one of ${Array.from(COMMENTS_PAGE_SIZE_VALUES).join(
15644
+ ", "
15645
+ )}`
15646
+ );
15647
+ }
15648
+ }
15649
+ assertRecordHistorySettingValues(actionName, settings) {
15650
+ var _a;
15651
+ if (!import_lodash.default.isPlainObject(settings)) {
15652
+ return;
15653
+ }
15654
+ if ((0, import_service_utils.hasOwnDefined)(settings, "sortOrder")) {
15655
+ const order = String(((_a = settings.sortOrder) == null ? void 0 : _a.order) || "").trim();
15656
+ if (!import_lodash.default.isPlainObject(settings.sortOrder) || order !== "asc" && order !== "desc") {
15657
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} recordHistory sortOrder.order must be 'asc' or 'desc'`);
15658
+ }
15659
+ }
15660
+ if ((0, import_service_utils.hasOwnDefined)(settings, "expand")) {
15661
+ if (!import_lodash.default.isPlainObject(settings.expand) || typeof settings.expand.expand !== "boolean") {
15662
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} recordHistory expand.expand must be a boolean`);
15663
+ }
15664
+ }
15665
+ if ((0, import_service_utils.hasOwnDefined)(settings, "template")) {
15666
+ if (!import_lodash.default.isPlainObject(settings.template) || settings.template.apply !== "current") {
15667
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} recordHistory template only supports apply='current'`);
15668
+ }
15669
+ }
15670
+ }
15671
+ async configureCommentsBlock(target, changes, options) {
15672
+ const allowedKeys = (0, import_configure_options.getConfigureOptionKeysForUse)("CommentsBlockModel");
15673
+ const cardSettings = (0, import_service_utils.buildBlockTitleDescriptionFromSemanticChanges)(changes);
15674
+ (0, import_service_utils.assertSupportedSimpleChanges)("comments", changes, allowedKeys);
15675
+ this.assertCommentsSettingValues("configure", changes);
15676
+ const resourceChange = changes.resource ? await this.normalizeConfigureCollectionBlockResource({
15677
+ actionName: "configure",
15678
+ blockUse: "CommentsBlockModel",
15679
+ target,
15680
+ resource: changes.resource,
15681
+ transaction: options.transaction
15682
+ }) : void 0;
15683
+ if (resourceChange) {
15684
+ this.assertCommentsBlockResourceCompatible("configure", resourceChange.resourceInit, resourceChange.popupProfile);
15685
+ }
15686
+ return this.updateSettings(
15687
+ {
15688
+ target,
15689
+ stepParams: (0, import_service_utils.buildDefinedPayload)({
15690
+ ...cardSettings ? { cardSettings } : {},
15691
+ ...changes.resource ? {
15692
+ resourceSettings: {
15693
+ init: resourceChange == null ? void 0 : resourceChange.resourceInit
15694
+ }
15695
+ } : {},
15696
+ ...(0, import_service_utils.hasDefinedValue)(changes, ["pageSize", "dataScope"]) ? {
15697
+ commentsSettings: (0, import_service_utils.buildDefinedPayload)({
15698
+ ...(0, import_service_utils.hasOwnDefined)(changes, "pageSize") ? { pageSize: { pageSize: changes.pageSize } } : {},
15699
+ ...(0, import_service_utils.hasOwnDefined)(changes, "dataScope") ? { dataScope: { filter: changes.dataScope } } : {}
15700
+ })
15701
+ } : {}
15702
+ })
15703
+ },
15704
+ options
15705
+ );
15706
+ }
15707
+ async configureRecordHistoryBlock(target, current, changes, options) {
15708
+ var _a, _b, _c;
15709
+ const allowedKeys = (0, import_configure_options.getConfigureOptionKeysForUse)("RecordHistoryBlockModel");
15710
+ const cardSettings = (0, import_service_utils.buildBlockTitleDescriptionFromSemanticChanges)(changes);
15711
+ (0, import_service_utils.assertSupportedSimpleChanges)("recordHistory", changes, allowedKeys);
15712
+ this.assertRecordHistorySettingValues("configure", changes);
15713
+ const resourceChange = changes.resource ? await this.normalizeConfigureCollectionBlockResource({
15714
+ actionName: "configure",
15715
+ blockUse: "RecordHistoryBlockModel",
15716
+ target,
15717
+ resource: changes.resource,
15718
+ transaction: options.transaction
15719
+ }) : void 0;
15720
+ const normalizedRecordHistoryResourceChange = resourceChange ? this.normalizeRecordHistoryBlockCreateState({
15721
+ actionName: "configure",
15722
+ resourceInit: resourceChange.resourceInit,
15723
+ popupProfile: resourceChange.popupProfile
15724
+ }) : void 0;
15725
+ if (resourceChange) {
15726
+ this.assertRecordHistoryBlockResourceCompatible(
15727
+ "configure",
15728
+ normalizedRecordHistoryResourceChange == null ? void 0 : normalizedRecordHistoryResourceChange.resourceInit,
15729
+ resourceChange.popupProfile
15730
+ );
15731
+ }
15732
+ const recordHistorySettingChanges = (0, import_service_utils.buildDefinedPayload)({
15733
+ ...(0, import_service_utils.hasOwnDefined)(changes, "sortOrder") ? { sortOrder: { order: changes.sortOrder.order } } : {},
15734
+ ...(0, import_service_utils.hasOwnDefined)(changes, "dataScope") ? { dataScope: { filter: changes.dataScope } } : {},
15735
+ ...(0, import_service_utils.hasOwnDefined)(changes, "expand") ? { expand: { expand: changes.expand.expand } } : {},
15736
+ ...(0, import_service_utils.hasOwnDefined)(changes, "template") ? { template: { apply: "current" } } : {}
15737
+ });
15738
+ const recordHistorySettings = resourceChange ? import_lodash.default.merge(
15739
+ {},
15740
+ import_lodash.default.cloneDeep(((_a = current == null ? void 0 : current.stepParams) == null ? void 0 : _a.recordHistorySettings) || {}),
15741
+ ((_b = normalizedRecordHistoryResourceChange == null ? void 0 : normalizedRecordHistoryResourceChange.stepParams) == null ? void 0 : _b.recordHistorySettings) || {},
15742
+ recordHistorySettingChanges
15743
+ ) : Object.keys(recordHistorySettingChanges).length ? recordHistorySettingChanges : void 0;
15744
+ if (resourceChange && !((_c = normalizedRecordHistoryResourceChange == null ? void 0 : normalizedRecordHistoryResourceChange.stepParams) == null ? void 0 : _c.recordHistorySettings)) {
15745
+ import_lodash.default.unset(recordHistorySettings, ["recordId"]);
15746
+ }
15747
+ return this.updateSettings(
15748
+ {
15749
+ target,
15750
+ stepParams: (0, import_service_utils.buildDefinedPayload)({
15751
+ ...cardSettings ? { cardSettings } : {},
15752
+ ...changes.resource ? {
15753
+ resourceSettings: {
15754
+ init: normalizedRecordHistoryResourceChange == null ? void 0 : normalizedRecordHistoryResourceChange.resourceInit
15755
+ }
15756
+ } : {},
15757
+ ...recordHistorySettings ? {
15758
+ recordHistorySettings
15759
+ } : {}
15760
+ })
15761
+ },
15762
+ {
15763
+ ...options,
15764
+ replaceRecordHistorySettings: !!resourceChange
15765
+ }
15766
+ );
15767
+ }
15768
+ async configureJSBlock(target, changes, options) {
15769
+ const allowedKeys = (0, import_configure_options.getConfigureOptionKeysForUse)("JSBlockModel");
15770
+ (0, import_service_utils.assertSupportedSimpleChanges)("jsBlock", changes, allowedKeys);
15771
+ return this.updateSettings(
15772
+ {
15773
+ target,
15774
+ decoratorProps: (0, import_service_utils.buildDefinedPayload)({
15775
+ title: changes.title,
15776
+ description: changes.description,
15777
+ className: changes.className
15778
+ }),
15779
+ stepParams: (0, import_service_utils.hasDefinedValue)(changes, ["code", "version"]) ? {
15780
+ jsSettings: {
15781
+ runJs: (0, import_service_utils.buildDefinedPayload)({
15782
+ code: changes.code,
15783
+ version: changes.version
15784
+ })
15785
+ }
15786
+ } : void 0
15787
+ },
15788
+ options
15789
+ );
15790
+ }
15791
+ async configureActionColumn(target, changes, options) {
15792
+ const allowedKeys = (0, import_configure_options.getConfigureOptionKeysForUse)("TableActionsColumnModel");
15793
+ (0, import_service_utils.assertSupportedSimpleChanges)("action column", changes, allowedKeys);
15794
+ return this.updateSettings(
15795
+ {
15796
+ target,
15797
+ props: (0, import_service_utils.buildDefinedPayload)({
15175
15798
  title: changes.title,
15176
15799
  tooltip: changes.tooltip,
15177
15800
  width: changes.width,
@@ -15720,6 +16343,460 @@ class FlowSurfacesService {
15720
16343
  });
15721
16344
  });
15722
16345
  }
16346
+ isAIEmployeeActionUse(use) {
16347
+ return String(use || "").trim() === AI_EMPLOYEE_ACTION_USE;
16348
+ }
16349
+ hasAIEmployeePublicSettings(settings) {
16350
+ return import_lodash.default.isPlainObject(settings) && AI_EMPLOYEE_PUBLIC_SETTING_KEYS.some((key) => Object.prototype.hasOwnProperty.call(settings, key));
16351
+ }
16352
+ assertOnlyAIEmployeePublicSettings(actionName, settings) {
16353
+ const unsupportedKeys = Object.keys(settings || {}).filter((key) => !AI_EMPLOYEE_PUBLIC_SETTING_KEYS.includes(key));
16354
+ if (unsupportedKeys.length) {
16355
+ (0, import_errors.throwBadRequest)(
16356
+ `flowSurfaces ${actionName} AI employee settings do not support keys: ${unsupportedKeys.join(", ")}`
16357
+ );
16358
+ }
16359
+ }
16360
+ assertOnlyAIEmployeeNestedPublicSettings(actionName, path, value, allowedKeys) {
16361
+ const unsupportedKeys = Object.keys(value || {}).filter((key) => !allowedKeys.includes(key));
16362
+ if (!unsupportedKeys.length) {
16363
+ return;
16364
+ }
16365
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} ${path} does not support key '${unsupportedKeys[0]}'`);
16366
+ }
16367
+ assertNoAIEmployeeInternalPropSettings(actionName, values) {
16368
+ const props = values == null ? void 0 : values.props;
16369
+ if (!import_lodash.default.isPlainObject(props)) {
16370
+ return;
16371
+ }
16372
+ const unsupportedKeys = AI_EMPLOYEE_INTERNAL_PROP_KEYS.filter(
16373
+ (key) => Object.prototype.hasOwnProperty.call(props, key)
16374
+ );
16375
+ if (!unsupportedKeys.length) {
16376
+ return;
16377
+ }
16378
+ (0, import_errors.throwBadRequest)(
16379
+ `flowSurfaces ${actionName} AI employee action does not accept raw props.${unsupportedKeys.join(
16380
+ ", props."
16381
+ )}; use top-level username, auto, workContext, tasks or style instead`
16382
+ );
16383
+ }
16384
+ assertAIEmployeePluginEnabled(actionName, enabledPackages) {
16385
+ if (!enabledPackages.has(AI_EMPLOYEE_OWNER_PLUGIN)) {
16386
+ (0, import_errors.throwBadRequest)(
16387
+ `flowSurfaces ${actionName} action 'aiEmployee' is not available in the current app instance because plugin '${AI_EMPLOYEE_OWNER_PLUGIN}' is not enabled`
16388
+ );
16389
+ }
16390
+ }
16391
+ readRecordPlainObject(record) {
16392
+ if (!record) {
16393
+ return null;
16394
+ }
16395
+ if (typeof record.toJSON === "function") {
16396
+ return record.toJSON();
16397
+ }
16398
+ if (typeof record.get === "function") {
16399
+ try {
16400
+ return record.get({ plain: true });
16401
+ } catch (error) {
16402
+ return record.get();
16403
+ }
16404
+ }
16405
+ return record;
16406
+ }
16407
+ readRecordField(record, field) {
16408
+ var _a;
16409
+ return ((_a = record == null ? void 0 : record.get) == null ? void 0 : _a.call(record, field)) ?? (record == null ? void 0 : record[field]);
16410
+ }
16411
+ normalizeFlowSurfaceRequestRoles(currentRoles) {
16412
+ return import_lodash.default.castArray(currentRoles || []).map((role) => String(role || "").trim()).filter(Boolean);
16413
+ }
16414
+ async assertRequestRolesCanUseAIEmployeeUsername(actionName, username, options) {
16415
+ const currentRoles = this.normalizeFlowSurfaceRequestRoles(options.currentRoles);
16416
+ if (!currentRoles.length || currentRoles.includes("root")) {
16417
+ return;
16418
+ }
16419
+ if (!this.db.getCollection("rolesAiEmployees")) {
16420
+ (0, import_errors.throwBadRequest)(
16421
+ `flowSurfaces ${actionName} action 'aiEmployee' cannot validate role visibility because collection 'rolesAiEmployees' is unavailable; enable plugin '${AI_EMPLOYEE_OWNER_PLUGIN}' first`
16422
+ );
16423
+ }
16424
+ const grants = await this.db.getRepository("rolesAiEmployees").find({
16425
+ filter: {
16426
+ roleName: currentRoles,
16427
+ aiEmployee: username
16428
+ },
16429
+ transaction: options.transaction
16430
+ });
16431
+ if (!import_lodash.default.castArray(grants).length) {
16432
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} AI employee username '${username}' is not visible to current roles`);
16433
+ }
16434
+ }
16435
+ async assertVisibleAIEmployeeUsername(actionName, username, options = {}) {
16436
+ if (!this.db.getCollection("aiEmployees")) {
16437
+ (0, import_errors.throwBadRequest)(
16438
+ `flowSurfaces ${actionName} action 'aiEmployee' cannot validate username because collection 'aiEmployees' is unavailable; enable plugin '${AI_EMPLOYEE_OWNER_PLUGIN}' first`
16439
+ );
16440
+ }
16441
+ const record = await this.db.getRepository("aiEmployees").findOne({
16442
+ filter: {
16443
+ username
16444
+ },
16445
+ transaction: options.transaction
16446
+ });
16447
+ if (!record) {
16448
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} AI employee username '${username}' does not exist`);
16449
+ }
16450
+ const plain = this.readRecordPlainObject(record) || {};
16451
+ const enabled = this.readRecordField(record, "enabled") ?? plain.enabled;
16452
+ const deprecated = this.readRecordField(record, "deprecated") ?? plain.deprecated;
16453
+ const category = this.readRecordField(record, "category") ?? plain.category;
16454
+ if (enabled === false || deprecated === true || category === "developer") {
16455
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} AI employee username '${username}' is not visible`);
16456
+ }
16457
+ await this.assertRequestRolesCanUseAIEmployeeUsername(actionName, username, options);
16458
+ }
16459
+ normalizeAIEmployeeUsername(actionName, value) {
16460
+ const username = typeof value === "string" ? value.trim() : "";
16461
+ if (!username) {
16462
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} AI employee settings.username must be a non-empty string`);
16463
+ }
16464
+ return username;
16465
+ }
16466
+ assertAIEmployeeWorkContextType(actionName, itemPath, item) {
16467
+ if (String(item.type || "").trim() !== "flow-model") {
16468
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} ${itemPath}.type must be 'flow-model'`);
16469
+ }
16470
+ }
16471
+ normalizeAIEmployeeWorkContext(actionName, value, options) {
16472
+ if (import_lodash.default.isUndefined(value) || value === null) {
16473
+ return [];
16474
+ }
16475
+ if (!Array.isArray(value)) {
16476
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} ${options.path} must be an array`);
16477
+ }
16478
+ return value.map((item, index) => {
16479
+ const itemPath = `${options.path}[${index}]`;
16480
+ if (!import_lodash.default.isPlainObject(item)) {
16481
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} ${itemPath} must be an object`);
16482
+ }
16483
+ this.assertOnlyAIEmployeeNestedPublicSettings(
16484
+ actionName,
16485
+ itemPath,
16486
+ item,
16487
+ AI_EMPLOYEE_WORK_CONTEXT_PUBLIC_KEYS
16488
+ );
16489
+ this.assertAIEmployeeWorkContextType(actionName, itemPath, item);
16490
+ if (Object.prototype.hasOwnProperty.call(item, "target") && typeof item.target !== "string") {
16491
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} ${itemPath}.target must be 'self' or a string block key`);
16492
+ }
16493
+ const hasTarget = Object.prototype.hasOwnProperty.call(item, "target");
16494
+ const target = hasTarget ? item.target.trim() : "";
16495
+ if (hasTarget && !target) {
16496
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} ${itemPath}.target must be 'self' or a string block key`);
16497
+ }
16498
+ const uidValue = typeof item.uid === "string" ? item.uid.trim() : "";
16499
+ if (!target) {
16500
+ if (!uidValue) {
16501
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} ${itemPath} requires uid or target`);
16502
+ }
16503
+ return {
16504
+ type: "flow-model",
16505
+ uid: uidValue
16506
+ };
16507
+ }
16508
+ let uidValueFromTarget;
16509
+ if (target === "self") {
16510
+ uidValueFromTarget = options.selfUid;
16511
+ } else if (options.keyMap) {
16512
+ uidValueFromTarget = (0, import_compose_compiler.resolveComposeTargetKey)(target, options.keyMap, "AI employee workContext");
16513
+ } else {
16514
+ (0, import_errors.throwBadRequest)(
16515
+ `flowSurfaces ${actionName} ${itemPath}.target only supports 'self' in localized writes; pass uid for existing Flow Model context`
16516
+ );
16517
+ }
16518
+ if (!uidValueFromTarget) {
16519
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} ${itemPath}.target could not resolve a Flow Model uid`);
16520
+ }
16521
+ return {
16522
+ type: "flow-model",
16523
+ uid: uidValueFromTarget
16524
+ };
16525
+ });
16526
+ }
16527
+ normalizeAIEmployeeTaskModel(actionName, path, value) {
16528
+ if (import_lodash.default.isUndefined(value) || value === null) {
16529
+ return value;
16530
+ }
16531
+ if (!import_lodash.default.isPlainObject(value)) {
16532
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} ${path} must be an object or null`);
16533
+ }
16534
+ this.assertOnlyAIEmployeeNestedPublicSettings(
16535
+ actionName,
16536
+ path,
16537
+ value,
16538
+ AI_EMPLOYEE_TASK_MODEL_PUBLIC_KEYS
16539
+ );
16540
+ const llmService = typeof value.llmService === "string" ? value.llmService.trim() : "";
16541
+ const model = typeof value.model === "string" ? value.model.trim() : "";
16542
+ if (!llmService || !model) {
16543
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} ${path} requires non-empty llmService and model`);
16544
+ }
16545
+ return {
16546
+ ...import_lodash.default.cloneDeep(value),
16547
+ llmService,
16548
+ model
16549
+ };
16550
+ }
16551
+ normalizeAIEmployeeSkillSettings(actionName, path, value) {
16552
+ if (import_lodash.default.isUndefined(value) || value === null) {
16553
+ return value;
16554
+ }
16555
+ if (!import_lodash.default.isPlainObject(value)) {
16556
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} ${path} must be an object or null`);
16557
+ }
16558
+ this.assertOnlyAIEmployeeNestedPublicSettings(
16559
+ actionName,
16560
+ path,
16561
+ value,
16562
+ AI_EMPLOYEE_SKILL_SETTINGS_PUBLIC_KEYS
16563
+ );
16564
+ const next = import_lodash.default.cloneDeep(value);
16565
+ if (Object.prototype.hasOwnProperty.call(next, "skills") && !Array.isArray(next.skills)) {
16566
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} ${path}.skills must be an array`);
16567
+ }
16568
+ if (Object.prototype.hasOwnProperty.call(next, "tools") && !Array.isArray(next.tools)) {
16569
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} ${path}.tools must be an array`);
16570
+ }
16571
+ if (Object.prototype.hasOwnProperty.call(next, "skillsVersion") && typeof next.skillsVersion !== "number") {
16572
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} ${path}.skillsVersion must be a number`);
16573
+ }
16574
+ if (Object.prototype.hasOwnProperty.call(next, "toolsVersion") && typeof next.toolsVersion !== "number") {
16575
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} ${path}.toolsVersion must be a number`);
16576
+ }
16577
+ return next;
16578
+ }
16579
+ normalizeAIEmployeeTaskMessage(actionName, path, value, existing, options) {
16580
+ if (!import_lodash.default.isPlainObject(value)) {
16581
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} ${path} must be an object`);
16582
+ }
16583
+ this.assertOnlyAIEmployeeNestedPublicSettings(
16584
+ actionName,
16585
+ path,
16586
+ value,
16587
+ AI_EMPLOYEE_TASK_MESSAGE_PUBLIC_KEYS
16588
+ );
16589
+ const nextMessage = import_lodash.default.pick(
16590
+ import_lodash.default.isPlainObject(existing) ? import_lodash.default.cloneDeep(existing) : {},
16591
+ AI_EMPLOYEE_TASK_MESSAGE_PUBLIC_KEYS
16592
+ );
16593
+ if (Object.prototype.hasOwnProperty.call(value, "system")) {
16594
+ nextMessage.system = value.system;
16595
+ }
16596
+ if (Object.prototype.hasOwnProperty.call(value, "user")) {
16597
+ nextMessage.user = value.user;
16598
+ }
16599
+ if (Object.prototype.hasOwnProperty.call(nextMessage, "system") && typeof nextMessage.system !== "string") {
16600
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} ${path}.system must be a string`);
16601
+ }
16602
+ if (Object.prototype.hasOwnProperty.call(nextMessage, "user") && typeof nextMessage.user !== "string") {
16603
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} ${path}.user must be a string`);
16604
+ }
16605
+ if (Object.prototype.hasOwnProperty.call(value, "workContext")) {
16606
+ nextMessage.workContext = this.normalizeAIEmployeeWorkContext(actionName, value.workContext, {
16607
+ selfUid: options.selfUid,
16608
+ keyMap: options.keyMap,
16609
+ path: `${path}.workContext`
16610
+ });
16611
+ }
16612
+ return nextMessage;
16613
+ }
16614
+ normalizeAIEmployeeTaskPatch(actionName, patch, existing, options) {
16615
+ if (!import_lodash.default.isPlainObject(patch)) {
16616
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} ${options.path} must be an object`);
16617
+ }
16618
+ const next = import_lodash.default.pick(import_lodash.default.isPlainObject(existing) ? import_lodash.default.cloneDeep(existing) : {}, AI_EMPLOYEE_TASK_PUBLIC_SETTING_KEYS);
16619
+ Object.entries(patch).forEach(([key, value]) => {
16620
+ if (!AI_EMPLOYEE_TASK_PUBLIC_SETTING_KEYS.includes(key)) {
16621
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} ${options.path} does not support key '${key}'`);
16622
+ }
16623
+ if (key === "message") {
16624
+ next.message = this.normalizeAIEmployeeTaskMessage(actionName, `${options.path}.message`, value, next.message, {
16625
+ selfUid: options.selfUid,
16626
+ keyMap: options.keyMap
16627
+ });
16628
+ return;
16629
+ }
16630
+ if (key === "title") {
16631
+ if (typeof value !== "string") {
16632
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} ${options.path}.title must be a string`);
16633
+ }
16634
+ next.title = value;
16635
+ return;
16636
+ }
16637
+ if (key === "autoSend" || key === "webSearch") {
16638
+ if (typeof value !== "boolean") {
16639
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} ${options.path}.${key} must be a boolean`);
16640
+ }
16641
+ next[key] = value;
16642
+ return;
16643
+ }
16644
+ if (key === "model") {
16645
+ next.model = this.normalizeAIEmployeeTaskModel(actionName, `${options.path}.model`, value);
16646
+ return;
16647
+ }
16648
+ if (key === "skillSettings") {
16649
+ const normalizedSkillSettings = this.normalizeAIEmployeeSkillSettings(
16650
+ actionName,
16651
+ `${options.path}.skillSettings`,
16652
+ value
16653
+ );
16654
+ next.skillSettings = normalizedSkillSettings && import_lodash.default.isPlainObject(normalizedSkillSettings) ? {
16655
+ ...import_lodash.default.isPlainObject(next.skillSettings) ? import_lodash.default.cloneDeep(next.skillSettings) : {},
16656
+ ...normalizedSkillSettings
16657
+ } : normalizedSkillSettings;
16658
+ return;
16659
+ }
16660
+ });
16661
+ if (!import_lodash.default.isPlainObject(next.message)) {
16662
+ next.message = {};
16663
+ }
16664
+ return next;
16665
+ }
16666
+ normalizeAIEmployeeTasks(actionName, value, currentTasks, options) {
16667
+ if (import_lodash.default.isUndefined(value) || value === null) {
16668
+ return [];
16669
+ }
16670
+ if (!Array.isArray(value)) {
16671
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} ${options.path} must be an array`);
16672
+ }
16673
+ if (!value.length) {
16674
+ return [];
16675
+ }
16676
+ const existingTasks = Array.isArray(currentTasks) ? import_lodash.default.cloneDeep(currentTasks) : [];
16677
+ const nextTasks = [...existingTasks];
16678
+ value.forEach((task, index) => {
16679
+ nextTasks[index] = this.normalizeAIEmployeeTaskPatch(actionName, task, existingTasks[index], {
16680
+ selfUid: options.selfUid,
16681
+ keyMap: options.keyMap,
16682
+ path: `${options.path}[${index}]`
16683
+ });
16684
+ });
16685
+ return nextTasks;
16686
+ }
16687
+ normalizeAIEmployeeActionSettingsReferences(actionName, settings, options) {
16688
+ if (!this.hasAIEmployeePublicSettings(settings)) {
16689
+ return settings;
16690
+ }
16691
+ const nextSettings = import_lodash.default.cloneDeep(settings || {});
16692
+ if (Object.prototype.hasOwnProperty.call(nextSettings, "workContext")) {
16693
+ nextSettings.workContext = this.normalizeAIEmployeeWorkContext(actionName, nextSettings.workContext, {
16694
+ ...options,
16695
+ path: "settings.workContext"
16696
+ });
16697
+ }
16698
+ if (Object.prototype.hasOwnProperty.call(nextSettings, "tasks")) {
16699
+ nextSettings.tasks = this.normalizeAIEmployeeTasks(actionName, nextSettings.tasks, [], {
16700
+ ...options,
16701
+ path: "settings.tasks"
16702
+ });
16703
+ }
16704
+ return nextSettings;
16705
+ }
16706
+ async normalizeAIEmployeeActionPublicSettings(actionName, settings, options) {
16707
+ var _a, _b;
16708
+ this.assertAIEmployeePluginEnabled(actionName, options.enabledPackages);
16709
+ if (!import_lodash.default.isPlainObject(settings)) {
16710
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} AI employee settings must be an object`);
16711
+ }
16712
+ this.assertOnlyAIEmployeePublicSettings(actionName, settings);
16713
+ const currentProps = import_lodash.default.isPlainObject((_a = options.current) == null ? void 0 : _a.props) ? options.current.props : {};
16714
+ const hasUsername = Object.prototype.hasOwnProperty.call(settings, "username");
16715
+ const effectiveUsername = hasUsername ? this.normalizeAIEmployeeUsername(actionName, settings.username) : String(((_b = currentProps == null ? void 0 : currentProps.aiEmployee) == null ? void 0 : _b.username) || "").trim();
16716
+ if (!effectiveUsername && (options.requireUsername || this.hasAIEmployeePublicSettings(settings))) {
16717
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} AI employee settings.username is required`);
16718
+ }
16719
+ if (effectiveUsername) {
16720
+ await this.assertVisibleAIEmployeeUsername(actionName, effectiveUsername, {
16721
+ currentRoles: options.currentRoles,
16722
+ transaction: options.transaction
16723
+ });
16724
+ }
16725
+ const props = {};
16726
+ if (effectiveUsername && (hasUsername || options.requireUsername)) {
16727
+ props.aiEmployee = {
16728
+ ...import_lodash.default.isPlainObject(currentProps.aiEmployee) ? import_lodash.default.cloneDeep(currentProps.aiEmployee) : {},
16729
+ username: effectiveUsername
16730
+ };
16731
+ }
16732
+ if (Object.prototype.hasOwnProperty.call(settings, "auto") || options.requireUsername) {
16733
+ const auto = Object.prototype.hasOwnProperty.call(settings, "auto") ? settings.auto : typeof currentProps.auto === "boolean" ? currentProps.auto : false;
16734
+ if (typeof auto !== "boolean") {
16735
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} AI employee settings.auto must be a boolean`);
16736
+ }
16737
+ props.auto = auto;
16738
+ }
16739
+ if (Object.prototype.hasOwnProperty.call(settings, "workContext") || options.requireUsername) {
16740
+ const rawWorkContext = Object.prototype.hasOwnProperty.call(settings, "workContext") ? settings.workContext : [{ type: "flow-model", target: "self" }];
16741
+ props.context = {
16742
+ ...import_lodash.default.isPlainObject(currentProps.context) ? import_lodash.default.cloneDeep(currentProps.context) : {},
16743
+ workContext: this.normalizeAIEmployeeWorkContext(actionName, rawWorkContext, {
16744
+ selfUid: options.selfUid,
16745
+ keyMap: options.keyMap,
16746
+ path: "settings.workContext"
16747
+ })
16748
+ };
16749
+ }
16750
+ if (Object.prototype.hasOwnProperty.call(settings, "tasks")) {
16751
+ props.tasks = this.normalizeAIEmployeeTasks(actionName, settings.tasks, currentProps.tasks, {
16752
+ selfUid: options.selfUid,
16753
+ keyMap: options.keyMap,
16754
+ path: "settings.tasks"
16755
+ });
16756
+ }
16757
+ if (Object.prototype.hasOwnProperty.call(settings, "style") || options.requireUsername) {
16758
+ const style = Object.prototype.hasOwnProperty.call(settings, "style") ? settings.style : {};
16759
+ if (!import_lodash.default.isUndefined(style) && style !== null && !import_lodash.default.isPlainObject(style)) {
16760
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} AI employee settings.style must be an object`);
16761
+ }
16762
+ if (import_lodash.default.isPlainObject(style)) {
16763
+ this.assertOnlyAIEmployeeNestedPublicSettings(
16764
+ actionName,
16765
+ "settings.style",
16766
+ style,
16767
+ AI_EMPLOYEE_STYLE_PUBLIC_KEYS
16768
+ );
16769
+ if (Object.prototype.hasOwnProperty.call(style, "size") && typeof style.size !== "number") {
16770
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} AI employee settings.style.size must be a number`);
16771
+ }
16772
+ if (Object.prototype.hasOwnProperty.call(style, "mask") && typeof style.mask !== "boolean") {
16773
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} AI employee settings.style.mask must be a boolean`);
16774
+ }
16775
+ }
16776
+ props.style = import_lodash.default.merge(
16777
+ {},
16778
+ import_lodash.default.cloneDeep(AI_EMPLOYEE_DEFAULT_STYLE),
16779
+ import_lodash.default.isPlainObject(currentProps.style) ? import_lodash.default.pick(import_lodash.default.cloneDeep(currentProps.style), AI_EMPLOYEE_STYLE_PUBLIC_KEYS) : {},
16780
+ import_lodash.default.isPlainObject(style) ? import_lodash.default.pick(import_lodash.default.cloneDeep(style), AI_EMPLOYEE_STYLE_PUBLIC_KEYS) : {}
16781
+ );
16782
+ }
16783
+ return props;
16784
+ }
16785
+ async resolveAIEmployeeActionSelfUid(actionNode, transaction) {
16786
+ const parentUid = String((actionNode == null ? void 0 : actionNode.parentId) || "").trim() || ((actionNode == null ? void 0 : actionNode.uid) ? await this.locator.findParentUid(actionNode.uid, transaction).catch(() => "") : "");
16787
+ if (!parentUid) {
16788
+ return actionNode == null ? void 0 : actionNode.uid;
16789
+ }
16790
+ const parentNode = await this.repository.findModelById(parentUid, {
16791
+ transaction,
16792
+ includeAsyncNode: true
16793
+ });
16794
+ if (["TableActionsColumnModel", "ListItemModel", "GridCardItemModel"].includes(String((parentNode == null ? void 0 : parentNode.use) || ""))) {
16795
+ const ownerUid = String((parentNode == null ? void 0 : parentNode.parentId) || "").trim() || ((parentNode == null ? void 0 : parentNode.uid) ? await this.locator.findParentUid(parentNode.uid, transaction).catch(() => "") : "");
16796
+ return ownerUid || parentUid;
16797
+ }
16798
+ return parentUid;
16799
+ }
15723
16800
  async configureActionNode(target, use, changes, options) {
15724
16801
  const currentNode = options.current || (target.uid ? await this.repository.findModelById(target.uid, {
15725
16802
  transaction: options.transaction,
@@ -15728,6 +16805,27 @@ class FlowSurfacesService {
15728
16805
  changes = await this.normalizeActionPanelActionChanges(changes, options);
15729
16806
  const allowedKeys = (0, import_configure_options.getConfigureOptionKeysForUse)(use);
15730
16807
  (0, import_service_utils.assertSupportedSimpleChanges)("action", changes, allowedKeys);
16808
+ if (this.isAIEmployeeActionUse(use)) {
16809
+ const props2 = await this.normalizeAIEmployeeActionPublicSettings("configure action", changes, {
16810
+ transaction: options.transaction,
16811
+ enabledPackages: options.enabledPackages || await this.resolveEnabledPluginPackages(options),
16812
+ current: currentNode,
16813
+ currentRoles: options.currentRoles,
16814
+ selfUid: await this.resolveAIEmployeeActionSelfUid(currentNode, options.transaction)
16815
+ });
16816
+ return this.updateSettings(
16817
+ {
16818
+ target,
16819
+ props: props2
16820
+ },
16821
+ {
16822
+ ...options,
16823
+ openViewActionName: options.openViewActionName || "configure action",
16824
+ popupTemplateHostUid: target.uid,
16825
+ allowAIEmployeeInternalProps: true
16826
+ }
16827
+ );
16828
+ }
15731
16829
  const normalizedDefaultFilter = (0, import_service_utils.hasOwnDefined)(changes, "defaultFilter") ? this.normalizeFilterActionDefaultFilterValue(changes.defaultFilter) : void 0;
15732
16830
  const stepParams = {};
15733
16831
  if ((0, import_service_utils.hasDefinedValue)(changes, ["title", "tooltip", "icon", "type", "danger", "color", "linkageRules"])) {