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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. package/dist/ai/ai-employees/nathan/prompt.md +2 -0
  2. package/dist/ai/ai-employees/nathan/skills/frontend-developer/SKILLS.md +1 -0
  3. package/dist/ai/ai-employees/nathan/skills/frontend-developer/tools/getContextApis.js +2 -2
  4. package/dist/ai/ai-employees/nathan/skills/frontend-developer/tools/getContextEnvs.js +2 -2
  5. package/dist/ai/ai-employees/nathan/skills/frontend-developer/tools/getContextVars.js +2 -2
  6. package/dist/ai/ai-employees/nathan/skills/frontend-developer/tools/lintAndTestJS.js +2 -2
  7. package/dist/ai/ai-employees/nathan/skills/frontend-developer/tools/patchJSCode.js +4 -4
  8. package/dist/ai/ai-employees/nathan/skills/frontend-developer/tools/readJSCode.js +2 -2
  9. package/dist/ai/ai-employees/nathan/skills/frontend-developer/tools/writeJSCode.js +2 -2
  10. package/dist/ai/docs/runjs/context/ai.md +206 -0
  11. package/dist/client/index.js +1 -1
  12. package/dist/externalVersion.js +9 -9
  13. package/dist/locale/en-US.json +3 -0
  14. package/dist/locale/index.d.ts +6 -0
  15. package/dist/locale/zh-CN.json +3 -0
  16. package/dist/node_modules/@ant-design/icons-svg/package.json +1 -1
  17. package/dist/node_modules/acorn/package.json +1 -1
  18. package/dist/node_modules/acorn-jsx/package.json +1 -1
  19. package/dist/node_modules/acorn-walk/package.json +1 -1
  20. package/dist/node_modules/ses/package.json +1 -1
  21. package/dist/node_modules/zod/package.json +1 -1
  22. package/dist/server/flow-surfaces/{runjs-authoring/blocked-global-stop/index.d.ts → approval/authoring-validation.d.ts} +1 -2
  23. package/dist/server/flow-surfaces/approval/authoring-validation.js +1151 -0
  24. package/dist/server/flow-surfaces/approval/blueprint-service.js +2 -0
  25. package/dist/server/flow-surfaces/authoring-validation.d.ts +3 -1
  26. package/dist/server/flow-surfaces/authoring-validation.js +645 -59
  27. package/dist/server/flow-surfaces/blueprint/compile-blocks.js +7 -3
  28. package/dist/server/flow-surfaces/blueprint/compile-plan.js +23 -15
  29. package/dist/server/flow-surfaces/blueprint/export-document.d.ts +50 -0
  30. package/dist/server/flow-surfaces/blueprint/export-document.js +2510 -0
  31. package/dist/server/flow-surfaces/blueprint/normalize-document.js +18 -1
  32. package/dist/server/flow-surfaces/blueprint/public-types.d.ts +2 -0
  33. package/dist/server/flow-surfaces/builder.js +43 -5
  34. package/dist/server/flow-surfaces/catalog.js +13 -2
  35. package/dist/server/flow-surfaces/configure-options.js +5 -3
  36. package/dist/server/flow-surfaces/constants.d.ts +16 -2
  37. package/dist/server/flow-surfaces/constants.js +2 -0
  38. package/dist/server/flow-surfaces/contract-guard.js +37 -5
  39. package/dist/server/flow-surfaces/default-action-popup.d.ts +2 -0
  40. package/dist/server/flow-surfaces/default-action-popup.js +27 -13
  41. package/dist/server/flow-surfaces/errors.d.ts +2 -2
  42. package/dist/server/flow-surfaces/errors.js +4 -4
  43. package/dist/server/flow-surfaces/filter-group.d.ts +19 -2
  44. package/dist/server/flow-surfaces/filter-group.js +232 -3
  45. package/dist/server/flow-surfaces/navigation-targets.d.ts +73 -0
  46. package/dist/server/flow-surfaces/navigation-targets.js +439 -0
  47. package/dist/server/flow-surfaces/planning/compiler.d.ts +1 -0
  48. package/dist/server/flow-surfaces/planning/compiler.js +205 -82
  49. package/dist/server/flow-surfaces/planning/key-registry.d.ts +1 -1
  50. package/dist/server/flow-surfaces/planning/runtime.js +1 -0
  51. package/dist/server/flow-surfaces/planning/step-link.d.ts +1 -1
  52. package/dist/server/flow-surfaces/planning/step-link.js +22 -3
  53. package/dist/server/flow-surfaces/public-data-surface-default-filter.js +0 -9
  54. package/dist/server/flow-surfaces/reaction/field-value.d.ts +9 -0
  55. package/dist/server/flow-surfaces/reaction/field-value.js +51 -2
  56. package/dist/server/flow-surfaces/reaction/linkage.d.ts +6 -1
  57. package/dist/server/flow-surfaces/reaction/linkage.js +18 -3
  58. package/dist/server/flow-surfaces/reaction/meta.js +19 -1
  59. package/dist/server/flow-surfaces/reaction/types.d.ts +19 -0
  60. package/dist/server/flow-surfaces/relation-backing-foreign-key.d.ts +10 -0
  61. package/dist/server/flow-surfaces/relation-backing-foreign-key.js +79 -0
  62. package/dist/server/flow-surfaces/runjs-authoring/ast/source.d.ts +1 -0
  63. package/dist/server/flow-surfaces/runjs-authoring/ast/source.js +20 -0
  64. package/dist/server/flow-surfaces/runjs-authoring/rules.js +0 -2
  65. package/dist/server/flow-surfaces/runjs-authoring/runtime/constants.d.ts +0 -1
  66. package/dist/server/flow-surfaces/runjs-authoring/runtime/constants.js +12 -19
  67. package/dist/server/flow-surfaces/runjs-authoring/runtime/types.d.ts +0 -12
  68. package/dist/server/flow-surfaces/runjs-authoring/scan/filter.js +12 -2
  69. package/dist/server/flow-surfaces/runjs-authoring/scan/index.d.ts +0 -14
  70. package/dist/server/flow-surfaces/runjs-authoring/scan/index.js +10 -8
  71. package/dist/server/flow-surfaces/runjs-authoring/scan/source-patterns.d.ts +0 -14
  72. package/dist/server/flow-surfaces/runjs-authoring/scan/source-patterns.js +18 -73
  73. package/dist/server/flow-surfaces/runjs-authoring/types.d.ts +1 -1
  74. package/dist/server/flow-surfaces/runjs-authoring/validators/index.js +9 -53
  75. package/dist/server/flow-surfaces/service.d.ts +65 -0
  76. package/dist/server/flow-surfaces/service.js +1372 -148
  77. package/dist/server/flow-surfaces/types.d.ts +2 -1
  78. package/dist/server/variables/records.js +7 -2
  79. package/dist/server/variables/registry.js +3 -0
  80. package/dist/swagger/flow-surfaces.d.ts +289 -0
  81. package/dist/swagger/flow-surfaces.examples.d.ts +11 -0
  82. package/dist/swagger/flow-surfaces.examples.js +11 -0
  83. package/dist/swagger/flow-surfaces.js +261 -11
  84. package/dist/swagger/index.d.ts +289 -0
  85. package/package.json +2 -2
  86. package/dist/server/flow-surfaces/runjs-authoring/blocked-global-stop/index.js +0 -40
@@ -56,6 +56,7 @@ var import_executor = require("./executor");
56
56
  var import_reference_guards = require("./reference-guards");
57
57
  var import_key_registry = require("./planning/key-registry");
58
58
  var import_blueprint = require("./blueprint");
59
+ var import_export_document = require("./blueprint/export-document");
59
60
  var import_compile_blocks = require("./blueprint/compile-blocks");
60
61
  var import_default_block_actions = require("./default-block-actions");
61
62
  var import_template_reference = require("./template-reference");
@@ -65,6 +66,7 @@ var import_runtime = require("./planning/runtime");
65
66
  var import_created_keys = require("./planning/created-keys");
66
67
  var import_key_persistence = require("./planning/key-persistence");
67
68
  var import_payload_shape = require("./payload-shape");
69
+ var import_navigation_targets = require("./navigation-targets");
68
70
  var import_field_semantics = require("./field-semantics");
69
71
  var import_field_grid_layout = require("./field-grid-layout");
70
72
  var import_authoring_validation = require("./authoring-validation");
@@ -96,6 +98,7 @@ var import_meta = require("./reaction/meta");
96
98
  var import_resolver = require("./reaction/resolver");
97
99
  var import_association_title_field = require("./association-title-field");
98
100
  var import_default_action_popup = require("./default-action-popup");
101
+ var import_relation_backing_foreign_key = require("./relation-backing-foreign-key");
99
102
  var import_defaults = require("./blueprint/defaults");
100
103
  var import_service_utils = require("./service-utils");
101
104
  var import_field_type_resolver = require("./field-type-resolver");
@@ -229,9 +232,11 @@ function isFlowSurfaceChartRepairError(error) {
229
232
  var _a, _b;
230
233
  return error instanceof import_errors.FlowSurfaceBadRequestError && ((_b = (_a = error.options) == null ? void 0 : _a.details) == null ? void 0 : _b.repairHint) === FLOW_SURFACE_CHART_REPAIR_HINT;
231
234
  }
235
+ const FLOW_SURFACE_EXPORT_BLUEPRINT_ROOT_ONLY_MESSAGE = "exportBlueprint v1 only supports root page export";
232
236
  const FORM_BLOCK_USES = /* @__PURE__ */ new Set(["FormBlockModel", "CreateFormModel", "EditFormModel", ...import_approval.APPROVAL_FORM_BLOCK_USES]);
233
237
  const AUTO_SUBMIT_FORM_BLOCK_USES = /* @__PURE__ */ new Set(["CreateFormModel", "EditFormModel"]);
234
238
  const FLOW_SURFACE_DEFAULT_ACTION_SETTINGS_KEYS = /* @__PURE__ */ new Set(["filter"]);
239
+ const ACTION_BUTTON_GENERAL_SETTING_KEYS = ["title", "tooltip", "icon", "iconOnly", "type", "danger", "color"];
235
240
  const DETAILS_BLOCK_USES = /* @__PURE__ */ new Set(["DetailsBlockModel", ...import_approval.APPROVAL_DETAILS_BLOCK_USES]);
236
241
  const SIMPLE_FORM_BLOCK_USES = /* @__PURE__ */ new Set([
237
242
  "FormBlockModel",
@@ -685,6 +690,7 @@ function assertNoFlowSurfaceIdTitleFieldSettings(value, options = {}) {
685
690
  };
686
691
  visit(value, options.basePath || []);
687
692
  }
693
+ const MOBILE_UI_LAYOUT_TYPE = "mobile";
688
694
  class FlowSurfacesService {
689
695
  constructor(plugin) {
690
696
  this.plugin = plugin;
@@ -705,6 +711,9 @@ class FlowSurfacesService {
705
711
  (values, options) => this.patchFlowSurfaceModelOptions(values, options)
706
712
  );
707
713
  }
714
+ get navigationTargets() {
715
+ return new import_navigation_targets.FlowSurfaceNavigationTargetsService(this.db);
716
+ }
708
717
  getFlowTemplateRepository(actionName) {
709
718
  try {
710
719
  const repo = this.db.getRepository("flowModelTemplates");
@@ -918,12 +927,12 @@ class FlowSurfacesService {
918
927
  transaction
919
928
  });
920
929
  }
921
- async findMenuGroupRoutesByTitle(title, transaction) {
930
+ async findMenuGroupRoutesByTitle(title, transaction, layoutUid, portalUid) {
922
931
  const normalizedTitle = String(title || "").trim();
923
932
  if (!normalizedTitle) {
924
933
  return [];
925
934
  }
926
- return import_lodash.default.castArray(
935
+ const routes = import_lodash.default.castArray(
927
936
  await this.db.getRepository("desktopRoutes").find({
928
937
  filter: {
929
938
  type: "group",
@@ -932,6 +941,32 @@ class FlowSurfacesService {
932
941
  transaction
933
942
  })
934
943
  );
944
+ const normalizedPortalUid = this.navigationTargets.normalizePortalUid(portalUid);
945
+ if (normalizedPortalUid) {
946
+ const matchedRoutes2 = [];
947
+ for (const route of routes) {
948
+ const routePortalUids = await this.navigationTargets.readRoutePortalUids(
949
+ this.readRouteField(route, "id"),
950
+ transaction
951
+ );
952
+ if (routePortalUids.includes(normalizedPortalUid)) {
953
+ matchedRoutes2.push(route);
954
+ }
955
+ }
956
+ return matchedRoutes2;
957
+ }
958
+ const layoutUidFilter = await this.resolveDesktopRouteLayoutUidFilter(layoutUid, transaction);
959
+ if (!layoutUidFilter.length || !this.hasDesktopRouteUiLayoutsRelation()) {
960
+ return routes;
961
+ }
962
+ const matchedRoutes = [];
963
+ for (const route of routes) {
964
+ const routeLayoutUids = await this.readDesktopRouteUiLayoutUids(this.readRouteField(route, "id"), transaction);
965
+ if (import_lodash.default.intersection(routeLayoutUids, layoutUidFilter).length) {
966
+ matchedRoutes.push(route);
967
+ }
968
+ }
969
+ return matchedRoutes;
935
970
  }
936
971
  routeParentIdMatches(routeParentId, parentId) {
937
972
  if (import_lodash.default.isNil(routeParentId) && import_lodash.default.isNil(parentId)) {
@@ -939,28 +974,58 @@ class FlowSurfacesService {
939
974
  }
940
975
  return String(routeParentId ?? "") === String(parentId ?? "");
941
976
  }
942
- async findMenuGroupRoutesByParentIdAndTitle(parentId, title, transaction) {
943
- const routes = await this.findMenuGroupRoutesByTitle(title, transaction);
977
+ async findMenuGroupRoutesByParentIdAndTitle(parentId, title, transaction, layoutUid, portalUid) {
978
+ const routes = await this.findMenuGroupRoutesByTitle(title, transaction, layoutUid, portalUid);
944
979
  return routes.filter(
945
980
  (route) => this.routeParentIdMatches(this.readRouteField(route, "parentId") ?? null, parentId)
946
981
  );
947
982
  }
948
- async findFlowPageRoutesByParentIdAndTitle(parentId, title, transaction) {
983
+ async findFlowPageRoutesByParentIdAndTitle(parentId, title, transaction, layoutUid, portalUid) {
949
984
  const normalizedTitle = String(title || "").trim();
950
- const normalizedParentId = String(parentId ?? "").trim();
951
- if (!normalizedTitle || !normalizedParentId) {
985
+ if (!normalizedTitle) {
952
986
  return [];
953
987
  }
954
- return import_lodash.default.castArray(
988
+ const routes = import_lodash.default.castArray(
955
989
  await this.db.getRepository("desktopRoutes").find({
956
- filter: {
990
+ filter: (0, import_service_utils.buildDefinedPayload)({
957
991
  type: "flowPage",
958
992
  title: normalizedTitle,
959
- parentId: normalizedParentId
960
- },
993
+ parentId: import_lodash.default.isNil(parentId) ? void 0 : String(parentId)
994
+ }),
961
995
  transaction
962
996
  })
963
997
  );
998
+ const normalizedPortalUid = this.navigationTargets.normalizePortalUid(portalUid);
999
+ if (normalizedPortalUid) {
1000
+ const portalMatchedRoutes = [];
1001
+ for (const route of routes) {
1002
+ const routePortalUids = await this.navigationTargets.readRoutePortalUids(
1003
+ this.readRouteField(route, "id"),
1004
+ transaction
1005
+ );
1006
+ if (routePortalUids.includes(normalizedPortalUid)) {
1007
+ portalMatchedRoutes.push(route);
1008
+ }
1009
+ }
1010
+ return portalMatchedRoutes.filter(
1011
+ (route) => this.routeParentIdMatches(this.readRouteField(route, "parentId") ?? null, parentId)
1012
+ );
1013
+ }
1014
+ const layoutUidFilter = await this.resolveDesktopRouteLayoutUidFilter(layoutUid, transaction);
1015
+ const layoutMatchedRoutes = [];
1016
+ if (!layoutUidFilter.length || !this.hasDesktopRouteUiLayoutsRelation()) {
1017
+ layoutMatchedRoutes.push(...routes);
1018
+ } else {
1019
+ for (const route of routes) {
1020
+ const routeLayoutUids = await this.readDesktopRouteUiLayoutUids(this.readRouteField(route, "id"), transaction);
1021
+ if (import_lodash.default.intersection(routeLayoutUids, layoutUidFilter).length) {
1022
+ layoutMatchedRoutes.push(route);
1023
+ }
1024
+ }
1025
+ }
1026
+ return layoutMatchedRoutes.filter(
1027
+ (route) => this.routeParentIdMatches(this.readRouteField(route, "parentId") ?? null, parentId)
1028
+ );
964
1029
  }
965
1030
  async assertMenuParentIsGroup(parentMenuRouteId, transaction) {
966
1031
  if (import_lodash.default.isNil(parentMenuRouteId)) {
@@ -1026,6 +1091,380 @@ class FlowSurfacesService {
1026
1091
  ...extras
1027
1092
  };
1028
1093
  }
1094
+ hasDesktopRouteUiLayoutsRelation() {
1095
+ var _a, _b;
1096
+ try {
1097
+ return !!this.db.getCollection("uiLayouts") && !!((_b = (_a = this.db.getCollection("desktopRoutes")) == null ? void 0 : _a.getField) == null ? void 0 : _b.call(_a, "uiLayouts"));
1098
+ } catch (error) {
1099
+ return false;
1100
+ }
1101
+ }
1102
+ normalizeDesktopRouteRelationId(routeId) {
1103
+ return import_lodash.default.isNil(routeId) ? void 0 : routeId;
1104
+ }
1105
+ async readDesktopRouteUiLayoutUids(routeId, transaction) {
1106
+ const relationRouteId = this.normalizeDesktopRouteRelationId(routeId);
1107
+ if (import_lodash.default.isUndefined(relationRouteId) || !this.hasDesktopRouteUiLayoutsRelation()) {
1108
+ return [];
1109
+ }
1110
+ const uiLayouts = await this.db.getRepository("desktopRoutes.uiLayouts", relationRouteId).find({
1111
+ fields: ["uid"],
1112
+ transaction
1113
+ });
1114
+ return import_lodash.default.uniq(
1115
+ uiLayouts.map((uiLayout) => {
1116
+ var _a;
1117
+ return String(((_a = uiLayout == null ? void 0 : uiLayout.get) == null ? void 0 : _a.call(uiLayout, "uid")) || (uiLayout == null ? void 0 : uiLayout.uid) || "").trim();
1118
+ }).filter(Boolean)
1119
+ );
1120
+ }
1121
+ async resolveDefaultDesktopRouteUiLayoutUids(transaction) {
1122
+ if (!this.hasDesktopRouteUiLayoutsRelation()) {
1123
+ return [];
1124
+ }
1125
+ const defaultLayout = await this.db.getRepository("uiLayouts").findOne({
1126
+ filter: {
1127
+ uid: import_navigation_targets.DEFAULT_ADMIN_UI_LAYOUT_UID,
1128
+ enabled: true
1129
+ },
1130
+ transaction
1131
+ });
1132
+ return defaultLayout ? [import_navigation_targets.DEFAULT_ADMIN_UI_LAYOUT_UID] : [];
1133
+ }
1134
+ async findDesktopRouteUiLayoutByUid(layoutUid, transaction) {
1135
+ const normalizedLayoutUid = this.normalizeExplicitDesktopRouteLayoutUid(layoutUid);
1136
+ if (!normalizedLayoutUid || !this.hasDesktopRouteUiLayoutsRelation()) {
1137
+ return null;
1138
+ }
1139
+ return this.db.getRepository("uiLayouts").findOne({
1140
+ filter: {
1141
+ uid: normalizedLayoutUid
1142
+ },
1143
+ transaction
1144
+ });
1145
+ }
1146
+ async getDesktopRouteUiLayoutTypeByUid(layoutUid, transaction) {
1147
+ var _a;
1148
+ const uiLayout = await this.findDesktopRouteUiLayoutByUid(layoutUid, transaction);
1149
+ return String(((_a = uiLayout == null ? void 0 : uiLayout.get) == null ? void 0 : _a.call(uiLayout, "layoutType")) || (uiLayout == null ? void 0 : uiLayout.layoutType) || "").trim() || void 0;
1150
+ }
1151
+ async isMobileDesktopRouteUiLayoutUid(layoutUid, transaction) {
1152
+ if (!layoutUid) {
1153
+ return false;
1154
+ }
1155
+ return await this.getDesktopRouteUiLayoutTypeByUid(layoutUid, transaction) === MOBILE_UI_LAYOUT_TYPE;
1156
+ }
1157
+ async resolveInheritedDesktopRouteUiLayoutUids(parentRoute, transaction) {
1158
+ const parentRouteId = this.readRouteField(parentRoute, "id");
1159
+ if (!import_lodash.default.isNil(parentRouteId)) {
1160
+ const parentLayoutUids = await this.readDesktopRouteUiLayoutUids(parentRouteId, transaction);
1161
+ if (parentLayoutUids.length) {
1162
+ return parentLayoutUids;
1163
+ }
1164
+ }
1165
+ return this.resolveDefaultDesktopRouteUiLayoutUids(transaction);
1166
+ }
1167
+ normalizeExplicitDesktopRouteLayoutUid(value) {
1168
+ const normalized = String(value || "").trim();
1169
+ return normalized || void 0;
1170
+ }
1171
+ normalizeDesktopRouteLayoutUidFilter(value) {
1172
+ return import_lodash.default.uniq(
1173
+ import_lodash.default.castArray(value).map((item) => this.normalizeExplicitDesktopRouteLayoutUid(item)).filter(Boolean)
1174
+ );
1175
+ }
1176
+ async resolveDesktopRouteLayoutUidFilter(value, transaction) {
1177
+ const explicitLayoutUids = this.normalizeDesktopRouteLayoutUidFilter(value);
1178
+ if (explicitLayoutUids.length) {
1179
+ return explicitLayoutUids;
1180
+ }
1181
+ return this.resolveDefaultDesktopRouteUiLayoutUids(transaction);
1182
+ }
1183
+ assertNavigationTargetIsExclusive(actionName, layoutUid, portalUid, paths) {
1184
+ const normalizedLayoutUid = this.normalizeExplicitDesktopRouteLayoutUid(layoutUid);
1185
+ const normalizedPortalUid = this.navigationTargets.normalizePortalUid(portalUid);
1186
+ if (!normalizedLayoutUid || !normalizedPortalUid) {
1187
+ return;
1188
+ }
1189
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} cannot use layoutUid and portalUid together`, {
1190
+ ruleId: "navigation-target-mutually-exclusive",
1191
+ path: paths.portal,
1192
+ details: {
1193
+ layoutUid: normalizedLayoutUid,
1194
+ portalUid: normalizedPortalUid,
1195
+ layoutPath: paths.layout,
1196
+ portalPath: paths.portal
1197
+ }
1198
+ });
1199
+ }
1200
+ async readDesktopRouteScope(route, transaction) {
1201
+ const routeId = this.readRouteField(route, "id");
1202
+ return {
1203
+ portalUids: await this.navigationTargets.readRoutePortalUids(routeId, transaction),
1204
+ layoutUids: await this.readDesktopRouteUiLayoutUids(routeId, transaction)
1205
+ };
1206
+ }
1207
+ async resolveRequestedDesktopRouteScope(values, parentRoute, actionName, options = {}) {
1208
+ const layoutUid = this.normalizeExplicitDesktopRouteLayoutUid(values.layoutUid);
1209
+ const portalUid = this.navigationTargets.normalizePortalUid(values.portalUid);
1210
+ this.assertNavigationTargetIsExclusive(actionName, layoutUid, portalUid, {
1211
+ layout: "values.layoutUid",
1212
+ portal: "values.portalUid"
1213
+ });
1214
+ if (portalUid) {
1215
+ const portal = await this.navigationTargets.resolvePortal(portalUid, {
1216
+ actionName,
1217
+ path: "values.portalUid",
1218
+ currentRoles: options.currentRoles,
1219
+ transaction: options.transaction
1220
+ });
1221
+ if (parentRoute) {
1222
+ await this.navigationTargets.assertRouteBelongsToPortal(
1223
+ actionName,
1224
+ this.readRouteField(parentRoute, "id"),
1225
+ portal.uid,
1226
+ "values.parentMenuRouteId",
1227
+ options.transaction
1228
+ );
1229
+ }
1230
+ return {
1231
+ portalUids: [portal.uid],
1232
+ layoutUids: [],
1233
+ selectedPortal: portal,
1234
+ layoutType: portal.layoutType
1235
+ };
1236
+ }
1237
+ if (layoutUid) {
1238
+ await this.assertEnabledDesktopRouteUiLayoutUid(layoutUid, actionName, "values.layoutUid", options.transaction);
1239
+ if (parentRoute) {
1240
+ await this.assertDesktopRouteBelongsToUiLayout(
1241
+ actionName,
1242
+ parentRoute,
1243
+ layoutUid,
1244
+ "values.parentMenuRouteId",
1245
+ options.transaction
1246
+ );
1247
+ }
1248
+ return {
1249
+ portalUids: [],
1250
+ layoutUids: [layoutUid],
1251
+ layoutType: await this.getDesktopRouteUiLayoutTypeByUid(layoutUid, options.transaction)
1252
+ };
1253
+ }
1254
+ if (parentRoute) {
1255
+ const inheritedScope = await this.readDesktopRouteScope(parentRoute, options.transaction);
1256
+ if (inheritedScope.portalUids.length > 1) {
1257
+ (0, import_errors.throwBadRequest)(
1258
+ `flowSurfaces ${actionName} parent route belongs to multiple portals; pass values.portalUid explicitly`,
1259
+ {
1260
+ ruleId: "navigation-route-scope-ambiguous",
1261
+ path: "values.parentMenuRouteId",
1262
+ details: {
1263
+ routeId: this.readRouteField(parentRoute, "id"),
1264
+ portalUids: inheritedScope.portalUids
1265
+ }
1266
+ }
1267
+ );
1268
+ }
1269
+ if (inheritedScope.portalUids.length === 1) {
1270
+ const portal = await this.navigationTargets.resolvePortal(inheritedScope.portalUids[0], {
1271
+ actionName,
1272
+ path: "values.parentMenuRouteId",
1273
+ currentRoles: options.currentRoles,
1274
+ transaction: options.transaction
1275
+ });
1276
+ return {
1277
+ ...inheritedScope,
1278
+ selectedPortal: portal,
1279
+ layoutType: portal.layoutType
1280
+ };
1281
+ }
1282
+ }
1283
+ const layoutUids = await this.resolveInheritedDesktopRouteUiLayoutUids(parentRoute, options.transaction);
1284
+ return {
1285
+ portalUids: [],
1286
+ layoutUids,
1287
+ layoutType: layoutUids.length === 1 ? await this.getDesktopRouteUiLayoutTypeByUid(layoutUids[0], options.transaction) : void 0
1288
+ };
1289
+ }
1290
+ async resolveExistingDesktopRouteScope(values, route, actionName, options = {}) {
1291
+ const layoutUid = this.normalizeExplicitDesktopRouteLayoutUid(values.layoutUid);
1292
+ const portalUid = this.navigationTargets.normalizePortalUid(values.portalUid);
1293
+ this.assertNavigationTargetIsExclusive(actionName, layoutUid, portalUid, {
1294
+ layout: "values.layoutUid",
1295
+ portal: "values.portalUid"
1296
+ });
1297
+ const routeScope = await this.readDesktopRouteScope(route, options.transaction);
1298
+ if (portalUid) {
1299
+ const portal = await this.navigationTargets.resolvePortal(portalUid, {
1300
+ actionName,
1301
+ path: "values.portalUid",
1302
+ currentRoles: options.currentRoles,
1303
+ transaction: options.transaction
1304
+ });
1305
+ await this.navigationTargets.assertRouteBelongsToPortal(
1306
+ actionName,
1307
+ this.readRouteField(route, "id"),
1308
+ portal.uid,
1309
+ "values.menuRouteId",
1310
+ options.transaction
1311
+ );
1312
+ return {
1313
+ ...routeScope,
1314
+ selectedPortal: portal,
1315
+ layoutType: portal.layoutType
1316
+ };
1317
+ }
1318
+ if (layoutUid) {
1319
+ await this.assertEnabledDesktopRouteUiLayoutUid(layoutUid, actionName, "values.layoutUid", options.transaction);
1320
+ await this.assertDesktopRouteBelongsToUiLayout(
1321
+ actionName,
1322
+ route,
1323
+ layoutUid,
1324
+ "values.menuRouteId",
1325
+ options.transaction
1326
+ );
1327
+ return {
1328
+ ...routeScope,
1329
+ layoutType: await this.getDesktopRouteUiLayoutTypeByUid(layoutUid, options.transaction)
1330
+ };
1331
+ }
1332
+ if (routeScope.portalUids.length > 1) {
1333
+ (0, import_errors.throwBadRequest)(
1334
+ `flowSurfaces ${actionName} menu route belongs to multiple portals; pass values.portalUid explicitly`,
1335
+ {
1336
+ ruleId: "navigation-route-scope-ambiguous",
1337
+ path: "values.menuRouteId",
1338
+ details: {
1339
+ routeId: this.readRouteField(route, "id"),
1340
+ portalUids: routeScope.portalUids
1341
+ }
1342
+ }
1343
+ );
1344
+ }
1345
+ if (routeScope.portalUids.length === 1) {
1346
+ const portal = await this.navigationTargets.resolvePortal(routeScope.portalUids[0], {
1347
+ actionName,
1348
+ path: "values.menuRouteId",
1349
+ currentRoles: options.currentRoles,
1350
+ transaction: options.transaction
1351
+ });
1352
+ return {
1353
+ ...routeScope,
1354
+ selectedPortal: portal,
1355
+ layoutType: portal.layoutType
1356
+ };
1357
+ }
1358
+ const layoutUids = routeScope.layoutUids.length ? routeScope.layoutUids : await this.ensureDesktopRouteUiLayouts(route, options.transaction);
1359
+ return {
1360
+ portalUids: [],
1361
+ layoutUids,
1362
+ layoutType: layoutUids.length === 1 ? await this.getDesktopRouteUiLayoutTypeByUid(layoutUids[0], options.transaction) : void 0
1363
+ };
1364
+ }
1365
+ async attachDesktopRouteScopeToRouteAndChildren(routeId, scope, transaction) {
1366
+ if (scope.layoutUids.length) {
1367
+ await this.attachDesktopRouteUiLayoutsToRouteAndChildren(routeId, scope.layoutUids, transaction);
1368
+ }
1369
+ if (scope.portalUids.length) {
1370
+ await this.navigationTargets.attachRouteTreeToPortals(routeId, scope.portalUids, {
1371
+ portalOnly: scope.layoutUids.length === 0,
1372
+ transaction
1373
+ });
1374
+ }
1375
+ }
1376
+ async assertEnabledDesktopRouteUiLayoutUid(layoutUid, actionName, path, transaction) {
1377
+ if (!this.hasDesktopRouteUiLayoutsRelation()) {
1378
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} ${path} requires plugin-ui-layout desktop route relation support`, {
1379
+ ruleId: "navigation-layout-unsupported",
1380
+ path,
1381
+ details: {
1382
+ layoutUid
1383
+ }
1384
+ });
1385
+ }
1386
+ const uiLayout = await this.db.getRepository("uiLayouts").findOne({
1387
+ filter: {
1388
+ uid: layoutUid,
1389
+ enabled: true
1390
+ },
1391
+ transaction
1392
+ });
1393
+ if (!uiLayout) {
1394
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} ${path} must reference an enabled ui layout`, {
1395
+ ruleId: "navigation-layout-not-found",
1396
+ path,
1397
+ details: {
1398
+ layoutUid
1399
+ }
1400
+ });
1401
+ }
1402
+ }
1403
+ async assertDesktopRouteBelongsToUiLayout(actionName, route, layoutUid, path, transaction) {
1404
+ const normalizedLayoutUid = this.normalizeExplicitDesktopRouteLayoutUid(layoutUid);
1405
+ if (!normalizedLayoutUid || !route) {
1406
+ return;
1407
+ }
1408
+ const routeId = this.readRouteField(route, "id");
1409
+ const routeLayoutUids = await this.readDesktopRouteUiLayoutUids(routeId, transaction);
1410
+ if (routeLayoutUids.includes(normalizedLayoutUid)) {
1411
+ return;
1412
+ }
1413
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} ${path} does not belong to ui layout '${normalizedLayoutUid}'`, {
1414
+ ruleId: "navigation-route-layout-mismatch",
1415
+ path,
1416
+ details: {
1417
+ routeId,
1418
+ layoutUid: normalizedLayoutUid,
1419
+ routeLayoutUids
1420
+ }
1421
+ });
1422
+ }
1423
+ async setDesktopRouteUiLayouts(routeId, uiLayoutUids, transaction) {
1424
+ const relationRouteId = this.normalizeDesktopRouteRelationId(routeId);
1425
+ if (import_lodash.default.isUndefined(relationRouteId) || !uiLayoutUids.length || !this.hasDesktopRouteUiLayoutsRelation()) {
1426
+ return;
1427
+ }
1428
+ await this.db.getRepository("desktopRoutes.uiLayouts", relationRouteId).set({
1429
+ tk: uiLayoutUids,
1430
+ transaction
1431
+ });
1432
+ }
1433
+ async attachDesktopRouteUiLayoutsToRouteAndChildren(routeId, uiLayoutUids, transaction) {
1434
+ if (import_lodash.default.isNil(routeId) || !uiLayoutUids.length || !this.hasDesktopRouteUiLayoutsRelation()) {
1435
+ return;
1436
+ }
1437
+ await this.setDesktopRouteUiLayouts(routeId, uiLayoutUids, transaction);
1438
+ const children = await this.db.getRepository("desktopRoutes").find({
1439
+ fields: ["id"],
1440
+ filter: {
1441
+ parentId: routeId
1442
+ },
1443
+ transaction
1444
+ });
1445
+ for (const child of children) {
1446
+ await this.attachDesktopRouteUiLayoutsToRouteAndChildren(
1447
+ this.readRouteField(child, "id"),
1448
+ uiLayoutUids,
1449
+ transaction
1450
+ );
1451
+ }
1452
+ }
1453
+ async ensureDesktopRouteUiLayouts(route, transaction) {
1454
+ const routeId = this.readRouteField(route, "id");
1455
+ if (import_lodash.default.isNil(routeId) || !this.hasDesktopRouteUiLayoutsRelation()) {
1456
+ return [];
1457
+ }
1458
+ const existingLayoutUids = await this.readDesktopRouteUiLayoutUids(routeId, transaction);
1459
+ if (existingLayoutUids.length) {
1460
+ return existingLayoutUids;
1461
+ }
1462
+ const parentRouteId = this.readRouteField(route, "parentId");
1463
+ const parentRoute = import_lodash.default.isNil(parentRouteId) ? null : await this.findMenuRouteById(parentRouteId, transaction);
1464
+ const inheritedLayoutUids = await this.resolveInheritedDesktopRouteUiLayoutUids(parentRoute, transaction);
1465
+ await this.setDesktopRouteUiLayouts(routeId, inheritedLayoutUids, transaction);
1466
+ return inheritedLayoutUids;
1467
+ }
1029
1468
  isValidMenuIconName(value) {
1030
1469
  const normalized = String(value || "").trim();
1031
1470
  return !!normalized && ANT_DESIGN_ICON_NAMES.has(normalized);
@@ -1078,11 +1517,19 @@ class FlowSurfacesService {
1078
1517
  });
1079
1518
  }
1080
1519
  }
1081
- async createFlowMenuGroup(values, transaction) {
1082
- const parentRoute = await this.assertMenuParentIsGroup(values.parentMenuRouteId, transaction);
1520
+ async createFlowMenuGroup(values, options = {}) {
1521
+ var _a;
1522
+ const parentRoute = await this.assertMenuParentIsGroup(values.parentMenuRouteId, options.transaction);
1083
1523
  const parentId = this.readRouteField(parentRoute, "id") ?? null;
1524
+ const routeScope = await this.resolveRequestedDesktopRouteScope(values, parentRoute, "createMenu", options);
1084
1525
  const title = String(values.title || "").trim();
1085
- const existingGroups = await this.findMenuGroupRoutesByParentIdAndTitle(parentId, title, transaction);
1526
+ const existingGroups = await this.findMenuGroupRoutesByParentIdAndTitle(
1527
+ parentId,
1528
+ title,
1529
+ options.transaction,
1530
+ routeScope.layoutUids,
1531
+ (_a = routeScope.selectedPortal) == null ? void 0 : _a.uid
1532
+ );
1086
1533
  if (existingGroups.length === 1) {
1087
1534
  return this.buildMenuResult(existingGroups[0]);
1088
1535
  }
@@ -1107,7 +1554,7 @@ class FlowSurfacesService {
1107
1554
  this.assertVisibleNavigationIcon("createMenu", "values", values);
1108
1555
  const schemaUid = values.schemaUid || (0, import_utils.uid)();
1109
1556
  const desktopRoutes = this.db.getRepository("desktopRoutes");
1110
- await desktopRoutes.create({
1557
+ const route = await desktopRoutes.create({
1111
1558
  values: {
1112
1559
  type: "group",
1113
1560
  sort: this.allocateRouteSortValue(),
@@ -1118,17 +1565,19 @@ class FlowSurfacesService {
1118
1565
  hideInMenu: !!values.hideInMenu,
1119
1566
  parentId
1120
1567
  },
1121
- transaction
1122
- });
1123
- const route = await desktopRoutes.findOne({
1124
- filter: { schemaUid },
1125
- transaction
1568
+ transaction: options.transaction
1126
1569
  });
1570
+ await this.attachDesktopRouteScopeToRouteAndChildren(
1571
+ this.readRouteField(route, "id"),
1572
+ routeScope,
1573
+ options.transaction
1574
+ );
1127
1575
  return this.buildMenuResult(route);
1128
1576
  }
1129
- async createFlowMenuItem(values, transaction) {
1577
+ async createFlowMenuItem(values, options = {}) {
1130
1578
  var _a;
1131
- const parentRoute = await this.assertMenuParentIsGroup(values.parentMenuRouteId, transaction);
1579
+ const parentRoute = await this.assertMenuParentIsGroup(values.parentMenuRouteId, options.transaction);
1580
+ const routeScope = await this.resolveRequestedDesktopRouteScope(values, parentRoute, "createMenu", options);
1132
1581
  this.assertVisibleNavigationIcon("createMenu", "values", values);
1133
1582
  const pageSchemaUid = values.pageSchemaUid || (0, import_utils.uid)();
1134
1583
  const menuSchemaUid = (0, import_utils.uid)();
@@ -1138,7 +1587,7 @@ class FlowSurfacesService {
1138
1587
  const title = values.title || pageSchemaUid;
1139
1588
  const tabTitle = values.tabTitle || "Untitled";
1140
1589
  const desktopRoutes = this.db.getRepository("desktopRoutes");
1141
- await desktopRoutes.create({
1590
+ const createdRoute = await desktopRoutes.create({
1142
1591
  values: {
1143
1592
  type: "flowPage",
1144
1593
  sort: this.allocateRouteSortValue(),
@@ -1171,15 +1620,20 @@ class FlowSurfacesService {
1171
1620
  }
1172
1621
  ]
1173
1622
  },
1174
- transaction
1623
+ transaction: options.transaction
1175
1624
  });
1625
+ await this.attachDesktopRouteScopeToRouteAndChildren(
1626
+ this.readRouteField(createdRoute, "id"),
1627
+ routeScope,
1628
+ options.transaction
1629
+ );
1176
1630
  const route = await desktopRoutes.findOne({
1177
1631
  filter: { schemaUid: pageSchemaUid },
1178
1632
  appends: ["children"],
1179
- transaction
1633
+ transaction: options.transaction
1180
1634
  });
1181
1635
  const tabRoute = import_lodash.default.sortBy(import_lodash.default.castArray(((_a = route == null ? void 0 : route.get) == null ? void 0 : _a.call(route, "children")) || []), "sort")[0];
1182
- await this.ensureFlowRoutePageSchemaShell(pageSchemaUid, transaction);
1636
+ await this.ensureFlowRoutePageSchemaShell(pageSchemaUid, options.transaction);
1183
1637
  const pageTree = (0, import_builder.buildPersistedRootPageModel)({
1184
1638
  pageUid,
1185
1639
  pageTitle: title,
@@ -1195,7 +1649,7 @@ class FlowSurfacesService {
1195
1649
  subType: "object",
1196
1650
  ...pageTree
1197
1651
  },
1198
- { transaction }
1652
+ { transaction: options.transaction }
1199
1653
  );
1200
1654
  return this.buildMenuResult(route, {
1201
1655
  pageSchemaUid,
@@ -1207,7 +1661,16 @@ class FlowSurfacesService {
1207
1661
  });
1208
1662
  }
1209
1663
  sanitizePublicCreateMenuValues(values) {
1210
- return import_lodash.default.pick(values, ["title", "type", "icon", "tooltip", "hideInMenu", "parentMenuRouteId"]);
1664
+ return import_lodash.default.pick(values, [
1665
+ "title",
1666
+ "type",
1667
+ "layoutUid",
1668
+ "portalUid",
1669
+ "icon",
1670
+ "tooltip",
1671
+ "hideInMenu",
1672
+ "parentMenuRouteId"
1673
+ ]);
1211
1674
  }
1212
1675
  async loadRouteBackedPageStructure(route, transaction) {
1213
1676
  const routeId = this.readRouteField(route, "id");
@@ -1581,7 +2044,7 @@ class FlowSurfacesService {
1581
2044
  return !blockScenes.some((scene) => this.isPopupCollectionBlockSceneUnsupported(scene));
1582
2045
  }
1583
2046
  resolveFieldAssociationContextFromBinding(input) {
1584
- var _a;
2047
+ var _a, _b;
1585
2048
  const parsed = this.parseFieldPath(
1586
2049
  input.collection,
1587
2050
  input.fieldPath,
@@ -1598,13 +2061,14 @@ class FlowSurfacesService {
1598
2061
  );
1599
2062
  const targetCollection = (associationField ? resolveTargetCollection(associationField) || (associationField == null ? void 0 : associationField.targetCollection) : null) || resolveTargetCollection(leafField) || (leafField == null ? void 0 : leafField.targetCollection) || null;
1600
2063
  const targetCollectionName = (0, import_service_helpers.getCollectionName)(targetCollection) || (associationField ? (0, import_service_helpers.getFieldTarget)(associationField) : void 0) || parsed.collectionName || input.collectionName;
1601
- const associationName = parsed.associationPathName ? `${parsed.collectionName}.${parsed.associationPathName}` : associationField ? (0, import_service_helpers.resolveAssociationNameFromField)(associationField, input.collection) : void 0;
2064
+ const fallbackAssociationName = parsed.associationPathName ? `${parsed.collectionName}.${parsed.associationPathName}` : void 0;
2065
+ const associationName = associationField ? ((_a = parsed.associationPathName) == null ? void 0 : _a.includes(".")) ? fallbackAssociationName : (0, import_service_helpers.resolveAssociationNameFromField)(associationField, input.collection) : void 0;
1602
2066
  return {
1603
2067
  associationField,
1604
2068
  targetCollection,
1605
- dataSourceKey: (targetCollection == null ? void 0 : targetCollection.dataSourceKey) || ((_a = targetCollection == null ? void 0 : targetCollection.options) == null ? void 0 : _a.dataSourceKey) || parsed.dataSourceKey || input.dataSourceKey,
2069
+ dataSourceKey: (targetCollection == null ? void 0 : targetCollection.dataSourceKey) || ((_b = targetCollection == null ? void 0 : targetCollection.options) == null ? void 0 : _b.dataSourceKey) || parsed.dataSourceKey || input.dataSourceKey,
1606
2070
  collectionName: targetCollectionName,
1607
- associationName
2071
+ associationName: associationName || fallbackAssociationName
1608
2072
  };
1609
2073
  }
1610
2074
  async resolvePopupHostFieldAssociationContext(hostNode, transaction) {
@@ -1945,6 +2409,9 @@ class FlowSurfacesService {
1945
2409
  if (!(popupProfile == null ? void 0 : popupProfile.currentCollection)) {
1946
2410
  return popupProfile == null ? void 0 : popupProfile.filterByTk;
1947
2411
  }
2412
+ if (popupProfile.popupKind === "recordPopup" && popupProfile.popupHostUse && POPUP_HOST_DEFAULT_RECORD_CONTEXT_ACTION_USES.has(popupProfile.popupHostUse)) {
2413
+ return "{{ctx.view.inputArgs.filterByTk}}";
2414
+ }
1948
2415
  if (popupProfile.popupKind !== "associationPopup") {
1949
2416
  return popupProfile.filterByTk;
1950
2417
  }
@@ -2300,10 +2767,18 @@ class FlowSurfacesService {
2300
2767
  if (!sameCurrentCollection || !(0, import_service_helpers.hasConfiguredFlowContextValue)(normalized.filterByTk)) {
2301
2768
  return false;
2302
2769
  }
2770
+ const expectedFilterByTk = this.resolvePopupCurrentRecordResourceFilterByTk(input.popupProfile, {
2771
+ usePopupInputArgsWhenSourceIdInferred: true
2772
+ });
2773
+ const matchesCurrentRecordFilterByTk = this.isPopupCurrentRecordFilterByTkMatch(
2774
+ input.popupProfile,
2775
+ normalized.filterByTk,
2776
+ expectedFilterByTk
2777
+ );
2303
2778
  if (input.popupProfile.hasAssociationContext) {
2304
- return this.isSameConfiguredFlowContextValue(normalized.filterByTk, input.popupProfile.filterByTk) && normalized.associationName === input.popupProfile.associationName && this.isSameConfiguredFlowContextValue(normalized.sourceId, input.popupProfile.sourceId);
2779
+ return matchesCurrentRecordFilterByTk && normalized.associationName === input.popupProfile.associationName && this.isSameConfiguredFlowContextValue(normalized.sourceId, input.popupProfile.sourceId);
2305
2780
  }
2306
- return this.isSameConfiguredFlowContextValue(normalized.filterByTk, input.popupProfile.filterByTk) && !(0, import_service_helpers.hasConfiguredFlowContextValue)(normalized.associationName) && !(0, import_service_helpers.hasConfiguredFlowContextValue)(normalized.sourceId);
2781
+ return matchesCurrentRecordFilterByTk && !(0, import_service_helpers.hasConfiguredFlowContextValue)(normalized.associationName) && !(0, import_service_helpers.hasConfiguredFlowContextValue)(normalized.sourceId);
2307
2782
  }
2308
2783
  if (input.binding === "associatedRecords") {
2309
2784
  if (!(0, import_service_helpers.hasConfiguredFlowContextValue)(normalized.collectionName) || !(0, import_service_helpers.hasConfiguredFlowContextValue)(normalized.associationName) || !(0, import_service_helpers.hasConfiguredFlowContextValue)(normalized.sourceId) || (0, import_service_helpers.hasConfiguredFlowContextValue)(normalized.filterByTk)) {
@@ -2346,6 +2821,12 @@ class FlowSurfacesService {
2346
2821
  }
2347
2822
  return import_lodash.default.isEqual(this.normalizeFlowContextTemplateValue(left), this.normalizeFlowContextTemplateValue(right));
2348
2823
  }
2824
+ isPopupCurrentRecordFilterByTkMatch(popupProfile, filterByTk, expectedFilterByTk) {
2825
+ if (this.isSameConfiguredFlowContextValue(filterByTk, expectedFilterByTk)) {
2826
+ return true;
2827
+ }
2828
+ return popupProfile.popupKind === "associationPopup" && this.isSameConfiguredFlowContextValue(filterByTk, popupProfile.filterByTk);
2829
+ }
2349
2830
  isPopupAssociatedRecordsSourceIdMatch(popupProfile, associationField, sourceId) {
2350
2831
  var _a, _b;
2351
2832
  if (!(0, import_service_helpers.hasConfiguredFlowContextValue)(sourceId)) {
@@ -2621,6 +3102,28 @@ class FlowSurfacesService {
2621
3102
  }
2622
3103
  return capability;
2623
3104
  }
3105
+ async getLiveFieldValueCapability(writeTarget, resolvedTarget, node, options = {}) {
3106
+ const context = await this.context(
3107
+ {
3108
+ target: writeTarget
3109
+ },
3110
+ options
3111
+ );
3112
+ const { capabilities } = (0, import_meta.buildReactionMetaCapabilities)({
3113
+ resolvedTarget: {
3114
+ ...resolvedTarget,
3115
+ node
3116
+ },
3117
+ context
3118
+ });
3119
+ const capability = capabilities.find((item) => item.kind === "fieldValue");
3120
+ if (!capability) {
3121
+ (0, import_errors.throwBadRequest)(
3122
+ `flowSurfaces reaction target '${resolvedTarget.use || resolvedTarget.target.uid}' does not support fieldValue`
3123
+ );
3124
+ }
3125
+ return capability;
3126
+ }
2624
3127
  async getReactionMeta(values, options = {}) {
2625
3128
  (0, import_payload_shape.validateFlowSurfacePayloadShape)("getReactionMeta", values, "values");
2626
3129
  const { writeTarget, node, resolvedTarget } = await this.resolveReactionRequest("getReactionMeta", values == null ? void 0 : values.target, {
@@ -2666,6 +3169,8 @@ class FlowSurfacesService {
2666
3169
  },
2667
3170
  rules: Array.isArray(values == null ? void 0 : values.rules) ? values.rules : []
2668
3171
  });
3172
+ const liveCapability = await this.getLiveFieldValueCapability(writeTarget, resolvedTarget, node, options);
3173
+ (0, import_field_value.validateFieldValueRulesAgainstCapability)(result.normalizedRules, liveCapability);
2669
3174
  await this.persistReactionSlot(storageNode, capability.resolvedSlot, result.canonicalRules, options);
2670
3175
  return result;
2671
3176
  }
@@ -2873,6 +3378,41 @@ class FlowSurfacesService {
2873
3378
  const publicNode = this.stripInternalSurfaceMetaFromNodeTree(import_lodash.default.cloneDeep(rawNode));
2874
3379
  return this.buildSurfaceReadPayload(target, resolved, publicNode, options);
2875
3380
  }
3381
+ async exportBlueprint(input, options = {}) {
3382
+ const request = this.normalizeExportBlueprintRequest(input);
3383
+ const resolved = await this.locator.resolve(request.target, options);
3384
+ if (resolved.kind !== "page" || !resolved.pageRoute) {
3385
+ (0, import_errors.throwBadRequest)(FLOW_SURFACE_EXPORT_BLUEPRINT_ROOT_ONLY_MESSAGE);
3386
+ }
3387
+ const pageSchemaUid = this.resolveExportBlueprintPageSchemaUid(request.target, resolved);
3388
+ await this.assertExportBlueprintRootTarget(request.target, resolved, pageSchemaUid, options.transaction);
3389
+ const rawNode = await this.decorateTemplateReadbackTree(
3390
+ this.normalizePopupTreeShape(
3391
+ await this.loadResolvedNode(resolved, options.transaction, {
3392
+ persistCalendarPopupHosts: false
3393
+ })
3394
+ ),
3395
+ options.transaction
3396
+ );
3397
+ if (!(rawNode == null ? void 0 : rawNode.uid)) {
3398
+ (0, import_errors.throwBadRequest)(`flowSurfaces exportBlueprint target '${pageSchemaUid}' could not resolve a readable page tree`);
3399
+ }
3400
+ const pageRoute = resolved.pageRoute ? await this.routeSync.hydrateRoute(resolved.pageRoute, options.transaction) : void 0;
3401
+ const result = (0, import_export_document.exportFlowSurfaceBlueprintDocument)({
3402
+ page: rawNode,
3403
+ pageRoute,
3404
+ target: {
3405
+ pageSchemaUid
3406
+ },
3407
+ unsupportedPolicy: request.unsupportedPolicy
3408
+ });
3409
+ return {
3410
+ ...result,
3411
+ document: (0, import_blueprint.prepareFlowSurfaceApplyBlueprintDocument)(
3412
+ result.document
3413
+ )
3414
+ };
3415
+ }
2876
3416
  getDeclaredKeyPersistenceDeps() {
2877
3417
  return {
2878
3418
  findModelById: (uid2, findOptions) => this.repository.findModelById(uid2, findOptions),
@@ -3041,7 +3581,15 @@ class FlowSurfacesService {
3041
3581
  if (!groupTitle) {
3042
3582
  return document;
3043
3583
  }
3044
- const matchedRoutes = await this.findMenuGroupRoutesByParentIdAndTitle(null, groupTitle, transaction);
3584
+ const layoutUid = this.normalizeExplicitDesktopRouteLayoutUid(document.navigation.layoutUid);
3585
+ const portalUid = this.navigationTargets.normalizePortalUid(document.navigation.portalUid);
3586
+ const matchedRoutes = await this.findMenuGroupRoutesByParentIdAndTitle(
3587
+ null,
3588
+ groupTitle,
3589
+ transaction,
3590
+ layoutUid || await this.resolveDefaultDesktopRouteUiLayoutUids(transaction),
3591
+ portalUid
3592
+ );
3045
3593
  if (!matchedRoutes.length) {
3046
3594
  return document;
3047
3595
  }
@@ -3066,29 +3614,148 @@ class FlowSurfacesService {
3066
3614
  }
3067
3615
  };
3068
3616
  }
3617
+ async normalizeApplyBlueprintCreateMobileNavigation(document, options = {}) {
3618
+ var _a, _b;
3619
+ if (document.mode !== "create") {
3620
+ return document;
3621
+ }
3622
+ const layoutUid = this.normalizeExplicitDesktopRouteLayoutUid((_a = document.navigation) == null ? void 0 : _a.layoutUid);
3623
+ const portalUid = this.navigationTargets.normalizePortalUid((_b = document.navigation) == null ? void 0 : _b.portalUid);
3624
+ const layoutType = portalUid ? (await this.navigationTargets.resolvePortal(portalUid, {
3625
+ actionName: "applyBlueprint",
3626
+ path: "values.navigation.portalUid",
3627
+ currentRoles: options.currentRoles,
3628
+ transaction: options.transaction
3629
+ })).layoutType : await this.getDesktopRouteUiLayoutTypeByUid(layoutUid || "", options.transaction);
3630
+ if (layoutType !== MOBILE_UI_LAYOUT_TYPE) {
3631
+ return document;
3632
+ }
3633
+ return {
3634
+ ...document,
3635
+ navigation: (0, import_service_utils.buildDefinedPayload)({
3636
+ ...document.navigation,
3637
+ layoutUid,
3638
+ portalUid,
3639
+ group: void 0
3640
+ })
3641
+ };
3642
+ }
3643
+ async assertApplyBlueprintCreateNavigationTarget(document, options = {}) {
3644
+ var _a, _b, _c, _d, _e, _f;
3645
+ if (document.mode !== "create") {
3646
+ return;
3647
+ }
3648
+ const layoutUid = this.normalizeExplicitDesktopRouteLayoutUid((_a = document.navigation) == null ? void 0 : _a.layoutUid);
3649
+ const portalUid = this.navigationTargets.normalizePortalUid((_b = document.navigation) == null ? void 0 : _b.portalUid);
3650
+ this.assertNavigationTargetIsExclusive("applyBlueprint", layoutUid, portalUid, {
3651
+ layout: "values.navigation.layoutUid",
3652
+ portal: "values.navigation.portalUid"
3653
+ });
3654
+ if (!layoutUid && !portalUid) {
3655
+ return;
3656
+ }
3657
+ if (portalUid) {
3658
+ const portal = await this.navigationTargets.resolvePortal(portalUid, {
3659
+ actionName: "applyBlueprint",
3660
+ path: "values.navigation.portalUid",
3661
+ currentRoles: options.currentRoles,
3662
+ transaction: options.transaction
3663
+ });
3664
+ if (portal.layoutType === MOBILE_UI_LAYOUT_TYPE) {
3665
+ return;
3666
+ }
3667
+ const groupRouteId2 = (_d = (_c = document.navigation) == null ? void 0 : _c.group) == null ? void 0 : _d.routeId;
3668
+ if (import_lodash.default.isNil(groupRouteId2) || groupRouteId2 === "") {
3669
+ return;
3670
+ }
3671
+ const groupRoute2 = await this.assertMenuParentIsGroup(groupRouteId2, options.transaction);
3672
+ await this.navigationTargets.assertRouteBelongsToPortal(
3673
+ "applyBlueprint",
3674
+ this.readRouteField(groupRoute2, "id"),
3675
+ portal.uid,
3676
+ "values.navigation.group.routeId",
3677
+ options.transaction
3678
+ );
3679
+ return;
3680
+ }
3681
+ await this.assertEnabledDesktopRouteUiLayoutUid(
3682
+ layoutUid,
3683
+ "applyBlueprint",
3684
+ "values.navigation.layoutUid",
3685
+ options.transaction
3686
+ );
3687
+ if (await this.isMobileDesktopRouteUiLayoutUid(layoutUid, options.transaction)) {
3688
+ return;
3689
+ }
3690
+ const groupRouteId = (_f = (_e = document.navigation) == null ? void 0 : _e.group) == null ? void 0 : _f.routeId;
3691
+ if (import_lodash.default.isNil(groupRouteId) || groupRouteId === "") {
3692
+ return;
3693
+ }
3694
+ const groupRoute = await this.assertMenuParentIsGroup(groupRouteId, options.transaction);
3695
+ await this.assertDesktopRouteBelongsToUiLayout(
3696
+ "applyBlueprint",
3697
+ groupRoute,
3698
+ layoutUid,
3699
+ "values.navigation.group.routeId",
3700
+ options.transaction
3701
+ );
3702
+ }
3069
3703
  async resolveApplyBlueprintCreatePageIdentity(document, transaction) {
3070
- var _a, _b, _c, _d, _e;
3704
+ var _a, _b, _c, _d, _e, _f, _g;
3071
3705
  if (document.mode !== "create") {
3072
3706
  return document;
3073
3707
  }
3074
3708
  const groupRouteId = (_b = (_a = document.navigation) == null ? void 0 : _a.group) == null ? void 0 : _b.routeId;
3075
- const pageTitle = String(((_c = document.page) == null ? void 0 : _c.title) || ((_e = (_d = document.navigation) == null ? void 0 : _d.item) == null ? void 0 : _e.title) || "").trim();
3076
- if (import_lodash.default.isNil(groupRouteId) || groupRouteId === "" || !pageTitle) {
3709
+ const layoutUid = this.normalizeExplicitDesktopRouteLayoutUid((_c = document.navigation) == null ? void 0 : _c.layoutUid);
3710
+ let portalUid = this.navigationTargets.normalizePortalUid((_d = document.navigation) == null ? void 0 : _d.portalUid);
3711
+ const pageTitle = String(((_e = document.page) == null ? void 0 : _e.title) || ((_g = (_f = document.navigation) == null ? void 0 : _f.item) == null ? void 0 : _g.title) || "").trim();
3712
+ const hasGroupRouteId = !import_lodash.default.isNil(groupRouteId) && groupRouteId !== "";
3713
+ if (!pageTitle || !hasGroupRouteId && !layoutUid && !portalUid) {
3077
3714
  return document;
3078
3715
  }
3079
- const matchedPages = await this.findFlowPageRoutesByParentIdAndTitle(groupRouteId, pageTitle, transaction);
3716
+ const groupRoute = hasGroupRouteId ? await this.findMenuRouteById(groupRouteId, transaction) : null;
3717
+ if (!portalUid && groupRoute) {
3718
+ const groupPortalUids = await this.navigationTargets.readRoutePortalUids(
3719
+ this.readRouteField(groupRoute, "id"),
3720
+ transaction
3721
+ );
3722
+ if (groupPortalUids.length > 1) {
3723
+ (0, import_errors.throwBadRequest)(
3724
+ `flowSurfaces applyBlueprint navigation.group.routeId '${groupRouteId}' belongs to multiple portals; pass navigation.portalUid explicitly`,
3725
+ {
3726
+ ruleId: "navigation-route-scope-ambiguous",
3727
+ path: "values.navigation.group.routeId",
3728
+ details: {
3729
+ routeId: groupRouteId,
3730
+ portalUids: groupPortalUids
3731
+ }
3732
+ }
3733
+ );
3734
+ }
3735
+ portalUid = groupPortalUids[0];
3736
+ }
3737
+ const layoutUidFilter = portalUid ? void 0 : layoutUid || (groupRoute ? await this.resolveInheritedDesktopRouteUiLayoutUids(groupRoute, transaction) : void 0);
3738
+ const matchedPages = await this.findFlowPageRoutesByParentIdAndTitle(
3739
+ hasGroupRouteId ? groupRouteId : null,
3740
+ pageTitle,
3741
+ transaction,
3742
+ layoutUidFilter,
3743
+ portalUid
3744
+ );
3080
3745
  if (!matchedPages.length) {
3081
3746
  return document;
3082
3747
  }
3083
3748
  if (matchedPages.length > 1) {
3749
+ const locationLabel = hasGroupRouteId ? `under navigation.group.routeId '${groupRouteId}'` : portalUid ? `at the root of portal '${portalUid}'` : `at the root of ui layout '${layoutUid}'`;
3084
3750
  (0, import_errors.throwBadRequest)(
3085
- `flowSurfaces applyBlueprint navigation.group.routeId '${groupRouteId}' already has ${matchedPages.length} flow pages titled '${pageTitle}'; pass target.pageSchemaUid explicitly before applyBlueprint`
3751
+ `flowSurfaces applyBlueprint ${locationLabel} already has ${matchedPages.length} flow pages titled '${pageTitle}'; pass target.pageSchemaUid explicitly before applyBlueprint`
3086
3752
  );
3087
3753
  }
3088
3754
  const pageSchemaUid = String(this.readRouteField(matchedPages[0], "schemaUid") || "").trim();
3089
3755
  if (!pageSchemaUid) {
3756
+ const locationLabel = hasGroupRouteId ? `under navigation.group.routeId '${groupRouteId}'` : portalUid ? `at the root of portal '${portalUid}'` : `at the root of ui layout '${layoutUid}'`;
3090
3757
  (0, import_errors.throwBadRequest)(
3091
- `flowSurfaces applyBlueprint existing flow page '${pageTitle}' under navigation.group.routeId '${groupRouteId}' is missing schemaUid; pass target.pageSchemaUid explicitly before applyBlueprint`
3758
+ `flowSurfaces applyBlueprint existing flow page '${pageTitle}' ${locationLabel} is missing schemaUid; pass target.pageSchemaUid explicitly before applyBlueprint`
3092
3759
  );
3093
3760
  }
3094
3761
  return {
@@ -3100,13 +3767,18 @@ class FlowSurfacesService {
3100
3767
  navigation: void 0
3101
3768
  };
3102
3769
  }
3103
- async prepareApplyBlueprintRequest(values, transaction, createdKanbanSortFields) {
3770
+ async prepareApplyBlueprintRequest(values, options = {}, createdKanbanSortFields) {
3104
3771
  var _a;
3105
3772
  const initialDocument = (0, import_blueprint.prepareFlowSurfaceApplyBlueprintDocument)(values);
3106
- const groupResolvedDocument = await this.resolveApplyBlueprintCreateNavigationGroup(initialDocument, transaction);
3107
- const document = await this.resolveApplyBlueprintCreatePageIdentity(groupResolvedDocument, transaction);
3108
- await this.prepareApplyBlueprintKanbanBlocks(document, transaction, createdKanbanSortFields);
3109
- const replaceTarget = document.mode === "replace" && document.target ? await this.resolveApplyBlueprintReplaceTargetInfo(document.target.pageSchemaUid, transaction) : void 0;
3773
+ await this.assertApplyBlueprintCreateNavigationTarget(initialDocument, options);
3774
+ const mobileNormalizedDocument = await this.normalizeApplyBlueprintCreateMobileNavigation(initialDocument, options);
3775
+ const groupResolvedDocument = await this.resolveApplyBlueprintCreateNavigationGroup(
3776
+ mobileNormalizedDocument,
3777
+ options.transaction
3778
+ );
3779
+ const document = await this.resolveApplyBlueprintCreatePageIdentity(groupResolvedDocument, options.transaction);
3780
+ await this.prepareApplyBlueprintKanbanBlocks(document, options.transaction, createdKanbanSortFields);
3781
+ const replaceTarget = document.mode === "replace" && document.target ? await this.resolveApplyBlueprintReplaceTargetInfo(document.target.pageSchemaUid, options.transaction) : void 0;
3110
3782
  if (document.mode === "replace" && document.tabs.length > 1 && typeof ((_a = document.page) == null ? void 0 : _a.enableTabs) === "undefined" && (replaceTarget == null ? void 0 : replaceTarget.pageEnableTabs) === false) {
3111
3783
  (0, import_errors.throwBadRequest)(
3112
3784
  `flowSurfaces applyBlueprint replace mode requires page.enableTabs=true when tabs.length > 1 and the current page has enableTabs=false`
@@ -3756,11 +4428,36 @@ class FlowSurfacesService {
3756
4428
  }
3757
4429
  }
3758
4430
  async assertApplyBlueprintAuthoringPayload(values, options = {}) {
4431
+ var _a, _b;
3759
4432
  const enabledPackages = await this.resolveEnabledPluginPackages(options);
4433
+ const layoutUid = this.normalizeExplicitDesktopRouteLayoutUid((_a = values == null ? void 0 : values.navigation) == null ? void 0 : _a.layoutUid);
4434
+ const portalUid = this.navigationTargets.normalizePortalUid((_b = values == null ? void 0 : values.navigation) == null ? void 0 : _b.portalUid);
4435
+ this.assertNavigationTargetIsExclusive("applyBlueprint", layoutUid, portalUid, {
4436
+ layout: "values.navigation.layoutUid",
4437
+ portal: "values.navigation.portalUid"
4438
+ });
4439
+ const resolvedPortal = portalUid ? await this.navigationTargets.resolvePortal(portalUid, {
4440
+ actionName: "applyBlueprint",
4441
+ path: "values.navigation.portalUid",
4442
+ currentRoles: options.currentRoles,
4443
+ transaction: options.transaction
4444
+ }) : void 0;
3760
4445
  await (0, import_authoring_validation.assertFlowSurfaceAuthoringPayload)("applyBlueprint", values, {
3761
4446
  transaction: options.transaction,
3762
4447
  enabledPackages,
3763
- findMenuGroupRoutesByTitle: (title, transaction) => this.findMenuGroupRoutesByTitle(title, transaction),
4448
+ findMenuGroupRoutesByTitle: (title, transaction, targetLayoutUid, targetPortalUid) => this.findMenuGroupRoutesByTitle(title, transaction, targetLayoutUid, targetPortalUid),
4449
+ getUiLayoutTypeByUid: (layoutUid2, transaction) => this.getDesktopRouteUiLayoutTypeByUid(layoutUid2, transaction),
4450
+ getPortalLayoutTypeByUid: async (targetPortalUid, transaction) => {
4451
+ if ((resolvedPortal == null ? void 0 : resolvedPortal.uid) === targetPortalUid) {
4452
+ return resolvedPortal.layoutType;
4453
+ }
4454
+ return (await this.navigationTargets.resolvePortal(targetPortalUid, {
4455
+ actionName: "applyBlueprint",
4456
+ path: "values.navigation.portalUid",
4457
+ currentRoles: options.currentRoles,
4458
+ transaction
4459
+ })).layoutType;
4460
+ },
3764
4461
  getCollection: (dataSourceKey, collectionName) => this.getCollection(dataSourceKey || "main", collectionName || "")
3765
4462
  });
3766
4463
  }
@@ -3768,7 +4465,7 @@ class FlowSurfacesService {
3768
4465
  if (options.skipAuthoringValidation !== true) {
3769
4466
  await this.assertApplyBlueprintAuthoringPayload(values, options);
3770
4467
  }
3771
- const prepared = await this.prepareApplyBlueprintRequest(values, options.transaction, createdKanbanSortFields);
4468
+ const prepared = await this.prepareApplyBlueprintRequest(values, options, createdKanbanSortFields);
3772
4469
  const popupTemplateAliasSession = this.createPopupTemplateAliasSession();
3773
4470
  const popupTemplateTreeCache = /* @__PURE__ */ new Map();
3774
4471
  this.validateApplyBlueprintPopupTemplateAliases(prepared.document, popupTemplateAliasSession);
@@ -4399,6 +5096,7 @@ class FlowSurfacesService {
4399
5096
  );
4400
5097
  }
4401
5098
  const popupProfile = await this.resolvePopupBlockProfile(node.uid, null, node, transaction).catch(() => null);
5099
+ const sourceId = String(openView.sourceId || "").trim() || ((popupProfile == null ? void 0 : popupProfile.sourceIdInferred) ? "" : String((popupProfile == null ? void 0 : popupProfile.sourceId) || "").trim()) || void 0;
4402
5100
  const popupSourceNode = popupTargetUid ? await this.repository.findModelById(popupTargetUid, {
4403
5101
  transaction,
4404
5102
  includeAsyncNode: true
@@ -4412,7 +5110,7 @@ class FlowSurfacesService {
4412
5110
  collectionName: String(openView.collectionName || "").trim() || String((popupProfile == null ? void 0 : popupProfile.collectionName) || "").trim() || void 0,
4413
5111
  associationName: String(openView.associationName || "").trim() || String((popupProfile == null ? void 0 : popupProfile.associationName) || "").trim() || void 0,
4414
5112
  filterByTk: String(openView.filterByTk || "").trim() || String((popupProfile == null ? void 0 : popupProfile.filterByTk) || "").trim() || void 0,
4415
- sourceId: String(openView.sourceId || "").trim() || String((popupProfile == null ? void 0 : popupProfile.sourceId) || "").trim() || void 0,
5113
+ sourceId,
4416
5114
  openViewStep
4417
5115
  };
4418
5116
  }
@@ -4474,10 +5172,16 @@ class FlowSurfacesService {
4474
5172
  return this.buildPopupTemplateOpenView(template, "reference", templateTargetUid, options);
4475
5173
  }
4476
5174
  shouldHydrateDetachedPopupTemplateBlockResourceContext(blockNode, context) {
4477
- if (!this.isCollectionBlockUse(blockNode == null ? void 0 : blockNode.use) || !context.associationName || !context.sourceId) {
5175
+ if (!this.isCollectionBlockUse(blockNode == null ? void 0 : blockNode.use)) {
4478
5176
  return false;
4479
5177
  }
4480
5178
  const init = import_lodash.default.get(blockNode, ["stepParams", "resourceSettings", "init"]) || {};
5179
+ if (this.resolveDetachedPopupTemplateBlockCurrentRecordFilterByTk(init, context)) {
5180
+ return true;
5181
+ }
5182
+ if (!context.associationName || !context.sourceId) {
5183
+ return false;
5184
+ }
4481
5185
  const popupDataSourceKey = context.dataSourceKey || "main";
4482
5186
  const blockDataSourceKey = init.dataSourceKey || "main";
4483
5187
  if (!context.collectionName || blockDataSourceKey !== popupDataSourceKey || init.collectionName !== context.collectionName) {
@@ -4492,6 +5196,28 @@ class FlowSurfacesService {
4492
5196
  }
4493
5197
  return blockAssociationName !== context.associationName || !this.isSameConfiguredFlowContextValue(init.sourceId, context.sourceId);
4494
5198
  }
5199
+ resolveDetachedPopupTemplateBlockCurrentRecordFilterByTk(init, context) {
5200
+ if (!(0, import_service_helpers.hasConfiguredFlowContextValue)(init.filterByTk)) {
5201
+ return void 0;
5202
+ }
5203
+ if (this.isSameConfiguredFlowContextValue(init.filterByTk, "{{ctx.view.inputArgs.filterByTk}}")) {
5204
+ return void 0;
5205
+ }
5206
+ const popupDataSourceKey = context.dataSourceKey || "main";
5207
+ const blockDataSourceKey = init.dataSourceKey || "main";
5208
+ if (!context.collectionName || blockDataSourceKey !== popupDataSourceKey || init.collectionName !== context.collectionName) {
5209
+ return void 0;
5210
+ }
5211
+ if (context.filterByTk && this.isSameConfiguredFlowContextValue(init.filterByTk, context.filterByTk)) {
5212
+ return "{{ctx.view.inputArgs.filterByTk}}";
5213
+ }
5214
+ const collection = this.getCollection(popupDataSourceKey, context.collectionName);
5215
+ const filterTargetKey = this.getCollectionFilterTargetKey(collection);
5216
+ if (this.isSameConfiguredFlowContextValue(init.filterByTk, `{{ctx.record.${filterTargetKey}}}`)) {
5217
+ return "{{ctx.view.inputArgs.filterByTk}}";
5218
+ }
5219
+ return void 0;
5220
+ }
4495
5221
  collectDetachedPopupTemplateBlockResourceContextPatches(node, context, patches = []) {
4496
5222
  if (!node || typeof node !== "object") {
4497
5223
  return patches;
@@ -4499,6 +5225,7 @@ class FlowSurfacesService {
4499
5225
  if (node.uid && this.shouldHydrateDetachedPopupTemplateBlockResourceContext(node, context)) {
4500
5226
  const nextStepParams = import_lodash.default.cloneDeep(node.stepParams || {});
4501
5227
  const currentInit = import_lodash.default.get(nextStepParams, ["resourceSettings", "init"]) || {};
5228
+ const filterByTk = this.resolveDetachedPopupTemplateBlockCurrentRecordFilterByTk(currentInit, context);
4502
5229
  import_lodash.default.set(
4503
5230
  nextStepParams,
4504
5231
  ["resourceSettings", "init"],
@@ -4506,8 +5233,11 @@ class FlowSurfacesService {
4506
5233
  ...currentInit,
4507
5234
  dataSourceKey: context.dataSourceKey || currentInit.dataSourceKey || "main",
4508
5235
  collectionName: context.collectionName || currentInit.collectionName,
4509
- associationName: context.associationName,
4510
- sourceId: context.sourceId
5236
+ ...context.associationName && context.sourceId ? {
5237
+ associationName: context.associationName,
5238
+ sourceId: context.sourceId
5239
+ } : {},
5240
+ ...filterByTk ? { filterByTk } : {}
4511
5241
  })
4512
5242
  );
4513
5243
  patches.push({
@@ -5750,6 +6480,9 @@ class FlowSurfacesService {
5750
6480
  }
5751
6481
  (0, import_errors.throwBadRequest)(`flowSurfaces configure does not support configureOptions on '${(current == null ? void 0 : current.use) || resolved.uid}'`);
5752
6482
  }
6483
+ async listNavigationTargets(_values = {}, options = {}) {
6484
+ return this.navigationTargets.listNavigationTargets(options.currentRoles, options.transaction);
6485
+ }
5753
6486
  async createMenu(values, options = {}) {
5754
6487
  const publicValues = this.sanitizePublicCreateMenuValues(values || {});
5755
6488
  const type = publicValues.type === "group" ? "group" : "item";
@@ -5757,9 +6490,9 @@ class FlowSurfacesService {
5757
6490
  (0, import_errors.throwBadRequest)("flowSurfaces createMenu requires title");
5758
6491
  }
5759
6492
  if (type === "group") {
5760
- return this.createFlowMenuGroup(publicValues, options.transaction);
6493
+ return this.createFlowMenuGroup(publicValues, options);
5761
6494
  }
5762
- return this.createFlowMenuItem(publicValues, options.transaction);
6495
+ return this.createFlowMenuItem(publicValues, options);
5763
6496
  }
5764
6497
  async updateMenu(values, options = {}) {
5765
6498
  const menuRouteId = values.menuRouteId;
@@ -5767,8 +6500,55 @@ class FlowSurfacesService {
5767
6500
  (0, import_errors.throwBadRequest)("flowSurfaces updateMenu requires menuRouteId");
5768
6501
  }
5769
6502
  const route = await this.assertMenuRouteUpdatable(menuRouteId, options.transaction);
5770
- await this.assertMenuParentIsGroup(values.parentMenuRouteId, options.transaction);
6503
+ const nextParentRoute = await this.assertMenuParentIsGroup(values.parentMenuRouteId, options.transaction);
5771
6504
  await this.assertMenuParentNotSelfOrDescendant(route, values.parentMenuRouteId, options.transaction);
6505
+ const portalUid = this.navigationTargets.normalizePortalUid(values.portalUid);
6506
+ this.assertNavigationTargetIsExclusive("updateMenu", values.layoutUid, portalUid, {
6507
+ layout: "values.layoutUid",
6508
+ portal: "values.portalUid"
6509
+ });
6510
+ const routeScope = await this.readDesktopRouteScope(route, options.transaction);
6511
+ if (portalUid) {
6512
+ const portal = await this.navigationTargets.resolvePortal(portalUid, {
6513
+ actionName: "updateMenu",
6514
+ path: "values.portalUid",
6515
+ currentRoles: options.currentRoles,
6516
+ transaction: options.transaction
6517
+ });
6518
+ await this.navigationTargets.assertRouteBelongsToPortal(
6519
+ "updateMenu",
6520
+ this.readRouteField(route, "id"),
6521
+ portal.uid,
6522
+ "values.menuRouteId",
6523
+ options.transaction
6524
+ );
6525
+ if (nextParentRoute) {
6526
+ await this.navigationTargets.assertRouteBelongsToPortal(
6527
+ "updateMenu",
6528
+ this.readRouteField(nextParentRoute, "id"),
6529
+ portal.uid,
6530
+ "values.parentMenuRouteId",
6531
+ options.transaction
6532
+ );
6533
+ }
6534
+ }
6535
+ if (Object.prototype.hasOwnProperty.call(values, "parentMenuRouteId") && nextParentRoute) {
6536
+ const parentScope = await this.readDesktopRouteScope(nextParentRoute, options.transaction);
6537
+ const routePortalUids = [...routeScope.portalUids].sort();
6538
+ const parentPortalUids = [...parentScope.portalUids].sort();
6539
+ if (!import_lodash.default.isEqual(routePortalUids, parentPortalUids) && (routePortalUids.length || parentPortalUids.length)) {
6540
+ (0, import_errors.throwBadRequest)(`flowSurfaces updateMenu cannot move a menu route across portal scopes`, {
6541
+ ruleId: "navigation-route-portal-mismatch",
6542
+ path: "values.parentMenuRouteId",
6543
+ details: {
6544
+ routeId: this.readRouteField(route, "id"),
6545
+ routePortalUids,
6546
+ parentRouteId: this.readRouteField(nextParentRoute, "id"),
6547
+ parentPortalUids
6548
+ }
6549
+ });
6550
+ }
6551
+ }
5772
6552
  const nextOptions = { ...this.readRouteOptions(route) };
5773
6553
  const updateValues = {};
5774
6554
  if (Object.prototype.hasOwnProperty.call(values, "title")) {
@@ -5798,13 +6578,30 @@ class FlowSurfacesService {
5798
6578
  });
5799
6579
  }
5800
6580
  const updated = await this.findMenuRouteById(menuRouteId, options.transaction);
6581
+ if (updated && Object.prototype.hasOwnProperty.call(values, "parentMenuRouteId")) {
6582
+ if (routeScope.portalUids.length) {
6583
+ await this.attachDesktopRouteScopeToRouteAndChildren(
6584
+ this.readRouteField(updated, "id"),
6585
+ routeScope,
6586
+ options.transaction
6587
+ );
6588
+ } else {
6589
+ await this.attachDesktopRouteUiLayoutsToRouteAndChildren(
6590
+ this.readRouteField(updated, "id"),
6591
+ await this.resolveInheritedDesktopRouteUiLayoutUids(nextParentRoute, options.transaction),
6592
+ options.transaction
6593
+ );
6594
+ }
6595
+ }
5801
6596
  return this.buildMenuResult(updated);
5802
6597
  }
5803
- async initializeFlowPageForRoute(route, values, transaction) {
6598
+ async initializeFlowPageForRoute(route, values, options = {}) {
6599
+ const transaction = options.transaction;
5804
6600
  const routeId = this.readRouteField(route, "id");
5805
6601
  const pageSchemaUid = this.readRouteField(route, "schemaUid");
5806
6602
  const structure = await this.loadRouteBackedPageStructure(route, transaction);
5807
6603
  let tabRoute = structure.tabRoutes[0];
6604
+ const routeScope = await this.resolveExistingDesktopRouteScope(values, route, "createPage", options);
5808
6605
  const routeOptions = this.readRouteOptions(route);
5809
6606
  if (!routeOptions[FLOW_SURFACE_MENU_BINDABLE_OPTION_KEY]) {
5810
6607
  (0, import_errors.throwBadRequest)(`flowSurfaces createPage only accepts a bindable menu route created by createMenu(type="item")`);
@@ -5826,7 +6623,7 @@ class FlowSurfacesService {
5826
6623
  const tabSchemaUid2 = values.tabSchemaUid || (0, import_utils.uid)();
5827
6624
  const tabSchemaName2 = values.tabSchemaName || (0, import_utils.uid)();
5828
6625
  const tabTitle = values.tabTitle || "Untitled";
5829
- await this.db.getRepository("desktopRoutes").create({
6626
+ tabRoute = await this.db.getRepository("desktopRoutes").create({
5830
6627
  values: {
5831
6628
  type: "tabs",
5832
6629
  sort: this.allocateRouteSortValue(1),
@@ -5843,10 +6640,11 @@ class FlowSurfacesService {
5843
6640
  },
5844
6641
  transaction
5845
6642
  });
5846
- tabRoute = await this.db.getRepository("desktopRoutes").findOne({
5847
- filter: { schemaUid: tabSchemaUid2 },
5848
- transaction
5849
- });
6643
+ await this.attachDesktopRouteScopeToRouteAndChildren(
6644
+ this.readRouteField(tabRoute, "id"),
6645
+ routeScope,
6646
+ transaction
6647
+ );
5850
6648
  } else {
5851
6649
  await this.db.getRepository("desktopRoutes").update({
5852
6650
  filterByTk: String(this.readRouteField(tabRoute, "id")),
@@ -5870,6 +6668,13 @@ class FlowSurfacesService {
5870
6668
  transaction
5871
6669
  });
5872
6670
  }
6671
+ if (tabRoute) {
6672
+ await this.attachDesktopRouteScopeToRouteAndChildren(
6673
+ this.readRouteField(tabRoute, "id"),
6674
+ routeScope,
6675
+ transaction
6676
+ );
6677
+ }
5873
6678
  await this.ensureFlowRoutePageSchemaShell(pageSchemaUid, transaction);
5874
6679
  await this.db.getRepository("desktopRoutes").update({
5875
6680
  filterByTk: String(routeId),
@@ -5920,11 +6725,11 @@ class FlowSurfacesService {
5920
6725
  let result;
5921
6726
  if (!import_lodash.default.isNil(values.menuRouteId) && values.menuRouteId !== "") {
5922
6727
  const route = await this.assertMenuRouteBindable(values.menuRouteId, options.transaction);
5923
- result = await this.initializeFlowPageForRoute(route, values, options.transaction);
6728
+ result = await this.initializeFlowPageForRoute(route, values, options);
5924
6729
  } else {
5925
- const createdMenu = await this.createFlowMenuItem(values, options.transaction);
6730
+ const createdMenu = await this.createFlowMenuItem(values, options);
5926
6731
  const route = await this.assertMenuRouteBindable(createdMenu.routeId, options.transaction);
5927
- result = await this.initializeFlowPageForRoute(route, values, options.transaction);
6732
+ result = await this.initializeFlowPageForRoute(route, values, options);
5928
6733
  }
5929
6734
  await this.persistCreatedKeysForAction("createPage", values, result, options.transaction);
5930
6735
  return result;
@@ -6009,6 +6814,11 @@ class FlowSurfacesService {
6009
6814
  },
6010
6815
  transaction: options.transaction
6011
6816
  });
6817
+ const pageRouteScope = await this.readDesktopRouteScope(pageRoute, options.transaction);
6818
+ if (!pageRouteScope.portalUids.length && !pageRouteScope.layoutUids.length) {
6819
+ pageRouteScope.layoutUids = await this.ensureDesktopRouteUiLayouts(pageRoute, options.transaction);
6820
+ }
6821
+ await this.attachDesktopRouteScopeToRouteAndChildren(route.get("id"), pageRouteScope, options.transaction);
6012
6822
  const gridUid = await this.ensureGridChild(tabSchemaUid, "BlockGridModel", options.transaction);
6013
6823
  const result = {
6014
6824
  pageUid: pageTarget.uid,
@@ -6679,11 +7489,6 @@ class FlowSurfacesService {
6679
7489
  requiredFieldCount: options.requiredFieldCount
6680
7490
  }
6681
7491
  );
6682
- if (!(0, import_service_utils.hasOwnDefined)(normalizedSettings, "filterableFieldNames")) {
6683
- normalizedSettings.filterableFieldNames = (0, import_public_data_surface_default_filter.resolveFlowSurfaceDefaultFilterFieldNames)(
6684
- normalizedSettings.defaultFilter
6685
- );
6686
- }
6687
7492
  }
6688
7493
  return normalizedSettings;
6689
7494
  }
@@ -11417,6 +12222,7 @@ class FlowSurfacesService {
11417
12222
  }
11418
12223
  if (this.isAIEmployeeActionUse(current == null ? void 0 : current.use) && this.hasAIEmployeePublicSettings(normalizedValues)) {
11419
12224
  const enabledPackages = await this.resolveEnabledPluginPackages(options);
12225
+ const hasRawAIEmployeeStepTasks = import_lodash.default.has(normalizedValues, ["stepParams", ...AI_EMPLOYEE_TASK_STEP_PARAMS_PATH]);
11420
12226
  const aiEmployeeSettingsPayload = await this.normalizeAIEmployeeActionPublicSettings(
11421
12227
  "updateSettings",
11422
12228
  import_lodash.default.pick(normalizedValues, AI_EMPLOYEE_PUBLIC_SETTING_KEYS),
@@ -11429,7 +12235,8 @@ class FlowSurfacesService {
11429
12235
  promptContext: {
11430
12236
  kind: "target",
11431
12237
  targetUid: (current == null ? void 0 : current.uid) || writeTarget.uid
11432
- }
12238
+ },
12239
+ skipExistingTaskWorkContextRebase: hasRawAIEmployeeStepTasks
11433
12240
  }
11434
12241
  );
11435
12242
  AI_EMPLOYEE_PUBLIC_SETTING_KEYS.forEach((key) => {
@@ -11511,6 +12318,7 @@ class FlowSurfacesService {
11511
12318
  normalizedValues,
11512
12319
  nextPayload
11513
12320
  );
12321
+ this.syncActionButtonSettingsForUpdateSettings(current, normalizedValues, nextPayload);
11514
12322
  this.syncActionTriggerWorkflowsForUpdateSettings(current, normalizedValues, nextPayload);
11515
12323
  const popupActionContext = options.popupActionContext || await this.resolveRecordContextPopupActionContextForHost(current, options.transaction);
11516
12324
  await this.normalizeOpenViewForUpdateSettings(
@@ -11562,6 +12370,12 @@ class FlowSurfacesService {
11562
12370
  if (Object.keys(nextPayload).length === 1) {
11563
12371
  return { uid: current.uid };
11564
12372
  }
12373
+ await this.assertNoDuplicateAIEmployeeActionForUpdateSettings(
12374
+ options.openViewActionName || "updateSettings",
12375
+ current,
12376
+ effectiveNode,
12377
+ options.transaction
12378
+ );
11565
12379
  if (target.kind === "tab" && target.tabRoute) {
11566
12380
  await this.routeSync.persistTabSettings(target, current, nextPayload, options.transaction);
11567
12381
  return {
@@ -11972,17 +12786,6 @@ class FlowSurfacesService {
11972
12786
  const filterValue = this.normalizeEffectivePublicDataSurfaceDefaultFilter(normalizedFilterValue, {
11973
12787
  requiredFieldCount: options.requiredFieldCount
11974
12788
  });
11975
- if (!hasPropsFilterableFieldNames && !hasStepFilterableFieldNames) {
11976
- const filterableFieldNames = (0, import_public_data_surface_default_filter.resolveFlowSurfaceDefaultFilterFieldNames)(filterValue);
11977
- if (filterableFieldNames.length) {
11978
- nextProps.filterableFieldNames = filterableFieldNames;
11979
- import_lodash.default.set(
11980
- nextStepParams,
11981
- ["filterSettings", "filterableFieldNames", "filterableFieldNames"],
11982
- import_lodash.default.cloneDeep(filterableFieldNames)
11983
- );
11984
- }
11985
- }
11986
12789
  nextProps.defaultFilterValue = import_lodash.default.cloneDeep(filterValue);
11987
12790
  nextProps.filterValue = import_lodash.default.cloneDeep(filterValue);
11988
12791
  import_lodash.default.set(nextStepParams, ["filterSettings", "defaultFilter", "defaultFilter"], import_lodash.default.cloneDeep(filterValue));
@@ -12029,6 +12832,65 @@ class FlowSurfacesService {
12029
12832
  nextPayload.stepParams = nextStepParams;
12030
12833
  }
12031
12834
  }
12835
+ syncActionButtonSettingsForUpdateSettings(current, normalizedValues, nextPayload) {
12836
+ if (!this.supportsActionButtonSettingsSync(current)) {
12837
+ return;
12838
+ }
12839
+ const requestedProps = this.pickRequestedActionButtonSettings(normalizedValues.props);
12840
+ const requestedButtonGeneral = this.pickRequestedActionButtonSettings(
12841
+ import_lodash.default.get(normalizedValues, ["stepParams", "buttonSettings", "general"])
12842
+ );
12843
+ const hasRequestedProps = Object.keys(requestedProps).length > 0;
12844
+ const hasRequestedButtonGeneral = Object.keys(requestedButtonGeneral).length > 0;
12845
+ if (!hasRequestedProps && !hasRequestedButtonGeneral) {
12846
+ return;
12847
+ }
12848
+ const hasRequestedTitle = Object.prototype.hasOwnProperty.call(requestedProps, "title") || Object.prototype.hasOwnProperty.call(requestedButtonGeneral, "title");
12849
+ const shouldStripImplicitTitle = (requestedProps.iconOnly === true || requestedButtonGeneral.iconOnly === true) && !hasRequestedTitle;
12850
+ const nextProps = import_lodash.default.cloneDeep(
12851
+ import_lodash.default.isPlainObject(nextPayload.props) ? nextPayload.props : import_lodash.default.isPlainObject(current == null ? void 0 : current.props) ? current.props : {}
12852
+ );
12853
+ const nextStepParams = import_lodash.default.cloneDeep(
12854
+ import_lodash.default.isPlainObject(nextPayload.stepParams) ? nextPayload.stepParams : import_lodash.default.isPlainObject(current == null ? void 0 : current.stepParams) ? current.stepParams : {}
12855
+ );
12856
+ Object.entries(requestedProps).forEach(([key, value]) => {
12857
+ if (Object.prototype.hasOwnProperty.call(requestedButtonGeneral, key)) {
12858
+ return;
12859
+ }
12860
+ import_lodash.default.set(nextStepParams, ["buttonSettings", "general", key], import_lodash.default.cloneDeep(value));
12861
+ });
12862
+ Object.entries(requestedButtonGeneral).forEach(([key, value]) => {
12863
+ if (Object.prototype.hasOwnProperty.call(requestedProps, key)) {
12864
+ return;
12865
+ }
12866
+ nextProps[key] = import_lodash.default.cloneDeep(value);
12867
+ });
12868
+ if (shouldStripImplicitTitle) {
12869
+ delete nextProps.title;
12870
+ if (import_lodash.default.isPlainObject(import_lodash.default.get(nextStepParams, ["buttonSettings", "general"]))) {
12871
+ delete nextStepParams.buttonSettings.general.title;
12872
+ }
12873
+ }
12874
+ nextPayload.props = nextProps;
12875
+ nextPayload.stepParams = nextStepParams;
12876
+ }
12877
+ supportsActionButtonSettingsSync(current) {
12878
+ var _a, _b, _c, _d, _e, _f;
12879
+ const contract = (0, import_catalog.getNodeContract)(current == null ? void 0 : current.use);
12880
+ return ((_b = (_a = contract.domains.props) == null ? void 0 : _a.allowedKeys) == null ? void 0 : _b.includes("iconOnly")) && ((_f = (_e = (_d = (_c = contract.domains.stepParams) == null ? void 0 : _c.groups) == null ? void 0 : _d.buttonSettings) == null ? void 0 : _e.allowedPaths) == null ? void 0 : _f.includes("general.iconOnly"));
12881
+ }
12882
+ pickRequestedActionButtonSettings(input) {
12883
+ const picked = {};
12884
+ if (!import_lodash.default.isPlainObject(input)) {
12885
+ return picked;
12886
+ }
12887
+ ACTION_BUTTON_GENERAL_SETTING_KEYS.forEach((key) => {
12888
+ if (Object.prototype.hasOwnProperty.call(input, key) && !import_lodash.default.isUndefined(input[key])) {
12889
+ picked[key] = import_lodash.default.cloneDeep(input[key]);
12890
+ }
12891
+ });
12892
+ return picked;
12893
+ }
12032
12894
  syncCreatedFieldWrapperTitleFieldStepParams(node) {
12033
12895
  const mirror = (UPDATE_SETTINGS_STEP_PARAM_MIRRORS_BY_USE[(node == null ? void 0 : node.use) || ""] || []).find(
12034
12896
  (item) => item.domain === "props" && item.key === "titleField"
@@ -13694,6 +14556,111 @@ class FlowSurfacesService {
13694
14556
  }
13695
14557
  return target;
13696
14558
  }
14559
+ normalizeExportBlueprintRequest(input) {
14560
+ if (!import_lodash.default.isPlainObject(input)) {
14561
+ (0, import_errors.throwBadRequest)(`flowSurfaces exportBlueprint payload must be an object`);
14562
+ }
14563
+ const unsupportedKeys = Object.keys(input).filter((key) => key !== "target" && key !== "options");
14564
+ if (unsupportedKeys.length) {
14565
+ (0, import_errors.throwBadRequest)(`flowSurfaces exportBlueprint only accepts target and options`);
14566
+ }
14567
+ if (!import_lodash.default.isPlainObject(input.target)) {
14568
+ (0, import_errors.throwBadRequest)(`flowSurfaces exportBlueprint requires target`);
14569
+ }
14570
+ const targetInput = input.target;
14571
+ const target = (0, import_service_utils.buildDefinedPayload)({
14572
+ uid: this.normalizeExportBlueprintLocatorValue(targetInput.uid, "uid"),
14573
+ pageSchemaUid: this.normalizeExportBlueprintLocatorValue(targetInput.pageSchemaUid, "pageSchemaUid"),
14574
+ tabSchemaUid: this.normalizeExportBlueprintLocatorValue(targetInput.tabSchemaUid, "tabSchemaUid"),
14575
+ routeId: this.normalizeExportBlueprintLocatorValue(targetInput.routeId, "routeId")
14576
+ });
14577
+ const unsupportedTargetKeys = Object.keys(targetInput).filter(
14578
+ (key) => !["uid", "pageSchemaUid", "tabSchemaUid", "routeId"].includes(key)
14579
+ );
14580
+ if (unsupportedTargetKeys.length) {
14581
+ (0, import_errors.throwBadRequest)(`flowSurfaces exportBlueprint target only accepts uid, pageSchemaUid, tabSchemaUid or routeId`);
14582
+ }
14583
+ if (!Object.keys(target).length) {
14584
+ (0, import_errors.throwBadRequest)(
14585
+ `flowSurfaces exportBlueprint target requires one of uid, pageSchemaUid, tabSchemaUid or routeId`
14586
+ );
14587
+ }
14588
+ if (Object.keys(target).length > 1) {
14589
+ (0, import_errors.throwBadRequest)(
14590
+ `flowSurfaces exportBlueprint target only accepts exactly one locator: uid, pageSchemaUid, tabSchemaUid or routeId`
14591
+ );
14592
+ }
14593
+ if (target.tabSchemaUid) {
14594
+ (0, import_errors.throwBadRequest)(FLOW_SURFACE_EXPORT_BLUEPRINT_ROOT_ONLY_MESSAGE);
14595
+ }
14596
+ return {
14597
+ target,
14598
+ unsupportedPolicy: this.normalizeExportBlueprintUnsupportedPolicy(input.options)
14599
+ };
14600
+ }
14601
+ normalizeExportBlueprintUnsupportedPolicy(input) {
14602
+ if (import_lodash.default.isUndefined(input)) {
14603
+ return "error";
14604
+ }
14605
+ if (!import_lodash.default.isPlainObject(input)) {
14606
+ (0, import_errors.throwBadRequest)(`flowSurfaces exportBlueprint options must be an object`);
14607
+ }
14608
+ const options = input;
14609
+ const unsupportedKeys = Object.keys(options).filter((key) => key !== "unsupported");
14610
+ if (unsupportedKeys.length) {
14611
+ (0, import_errors.throwBadRequest)(`flowSurfaces exportBlueprint options only accepts unsupported`);
14612
+ }
14613
+ const policy = options.unsupported;
14614
+ if (import_lodash.default.isUndefined(policy)) {
14615
+ return "error";
14616
+ }
14617
+ if (policy === "error" || policy === "warn") {
14618
+ return policy;
14619
+ }
14620
+ (0, import_errors.throwBadRequest)(`flowSurfaces exportBlueprint options.unsupported must be 'error' or 'warn'`);
14621
+ }
14622
+ normalizeExportBlueprintLocatorValue(value, key) {
14623
+ if (import_lodash.default.isNil(value)) {
14624
+ return void 0;
14625
+ }
14626
+ if (typeof value !== "string" && typeof value !== "number") {
14627
+ (0, import_errors.throwBadRequest)(`flowSurfaces exportBlueprint target.${key} must be a string`);
14628
+ }
14629
+ const normalized = String(value).trim();
14630
+ return normalized || void 0;
14631
+ }
14632
+ readRouteString(route, key) {
14633
+ var _a;
14634
+ const routeRecord = route;
14635
+ const value = ((_a = routeRecord == null ? void 0 : routeRecord.get) == null ? void 0 : _a.call(routeRecord, key)) ?? (routeRecord == null ? void 0 : routeRecord[key]);
14636
+ const normalized = typeof value === "string" ? value.trim() : "";
14637
+ return normalized || void 0;
14638
+ }
14639
+ resolveExportBlueprintPageSchemaUid(target, resolved) {
14640
+ const pageSchemaUid = this.readRouteString(resolved.pageRoute, "schemaUid") || (target.pageSchemaUid ? String(target.pageSchemaUid).trim() : "");
14641
+ if (!pageSchemaUid) {
14642
+ (0, import_errors.throwBadRequest)(FLOW_SURFACE_EXPORT_BLUEPRINT_ROOT_ONLY_MESSAGE);
14643
+ }
14644
+ return pageSchemaUid;
14645
+ }
14646
+ async assertExportBlueprintRootTarget(target, resolved, pageSchemaUid, transaction) {
14647
+ const targetUid = target.uid ? String(target.uid).trim() : "";
14648
+ if (!targetUid) {
14649
+ return;
14650
+ }
14651
+ if (targetUid === pageSchemaUid) {
14652
+ return;
14653
+ }
14654
+ const rootPageModel = await this.repository.findModelByParentId(pageSchemaUid, {
14655
+ transaction,
14656
+ subKey: "page",
14657
+ includeAsyncNode: false
14658
+ });
14659
+ if ((rootPageModel == null ? void 0 : rootPageModel.uid) && targetUid === String(rootPageModel.uid).trim()) {
14660
+ return;
14661
+ }
14662
+ (0, import_errors.throwBadRequest)(FLOW_SURFACE_EXPORT_BLUEPRINT_ROOT_ONLY_MESSAGE);
14663
+ }
13697
14664
  normalizeContextPath(path) {
13698
14665
  if (import_lodash.default.isUndefined(path) || import_lodash.default.isNull(path)) {
13699
14666
  return void 0;
@@ -16860,13 +17827,20 @@ class FlowSurfacesService {
16860
17827
  description: changes.description,
16861
17828
  className: changes.className
16862
17829
  }),
16863
- stepParams: (0, import_service_utils.hasDefinedValue)(changes, ["code", "version"]) ? {
16864
- jsSettings: {
16865
- runJs: (0, import_service_utils.buildDefinedPayload)({
16866
- code: changes.code,
16867
- version: changes.version
16868
- })
16869
- }
17830
+ stepParams: (0, import_service_utils.hasDefinedValue)(changes, ["code", "version", "showBlockCard"]) ? {
17831
+ jsSettings: (0, import_service_utils.buildDefinedPayload)({
17832
+ ...(0, import_service_utils.hasDefinedValue)(changes, ["code", "version"]) ? {
17833
+ runJs: (0, import_service_utils.buildDefinedPayload)({
17834
+ code: changes.code,
17835
+ version: changes.version
17836
+ })
17837
+ } : {},
17838
+ ...(0, import_service_utils.hasOwnDefined)(changes, "showBlockCard") ? {
17839
+ showBlockCard: {
17840
+ showBlockCard: changes.showBlockCard
17841
+ }
17842
+ } : {}
17843
+ })
16870
17844
  } : void 0
16871
17845
  },
16872
17846
  options
@@ -17448,19 +18422,21 @@ class FlowSurfacesService {
17448
18422
  }
17449
18423
  return JSON.stringify(value);
17450
18424
  }
17451
- buildAIEmployeeActionDedupIdentity(values) {
18425
+ buildAIEmployeeActionDedupIdentity(values, defaultActionWorkContext) {
17452
18426
  var _a, _b, _c, _d, _e, _f;
17453
18427
  const username = String(((_b = (_a = values == null ? void 0 : values.props) == null ? void 0 : _a.aiEmployee) == null ? void 0 : _b.username) || "").trim();
17454
18428
  if (!username) {
17455
18429
  return "";
17456
18430
  }
18431
+ const workContext = this.normalizeAIEmployeeActionWorkContextForDedupIdentity(
18432
+ (_d = (_c = values == null ? void 0 : values.props) == null ? void 0 : _c.context) == null ? void 0 : _d.workContext,
18433
+ defaultActionWorkContext
18434
+ );
17457
18435
  return this.stableSerializeAIEmployeeValue({
17458
18436
  username,
17459
- auto: typeof ((_c = values == null ? void 0 : values.props) == null ? void 0 : _c.auto) === "boolean" ? values.props.auto : false,
17460
- workContext: this.normalizeAIEmployeeWorkContextForDedupIdentity((_e = (_d = values == null ? void 0 : values.props) == null ? void 0 : _d.context) == null ? void 0 : _e.workContext),
17461
- tasks: this.normalizeAIEmployeeTasksForDedupIdentity(
17462
- import_lodash.default.get(values, ["stepParams", ...AI_EMPLOYEE_TASK_STEP_PARAMS_PATH])
17463
- ),
18437
+ auto: typeof ((_e = values == null ? void 0 : values.props) == null ? void 0 : _e.auto) === "boolean" ? values.props.auto : false,
18438
+ workContext,
18439
+ tasks: this.normalizeAIEmployeeTasksForDedupIdentity(this.readAIEmployeePersistedTasks(values), workContext),
17464
18440
  style: {
17465
18441
  ...AI_EMPLOYEE_DEFAULT_STYLE,
17466
18442
  ...import_lodash.default.isPlainObject((_f = values == null ? void 0 : values.props) == null ? void 0 : _f.style) ? import_lodash.default.pick(values.props.style, AI_EMPLOYEE_STYLE_PUBLIC_KEYS) : {}
@@ -17468,11 +18444,35 @@ class FlowSurfacesService {
17468
18444
  });
17469
18445
  }
17470
18446
  normalizeAIEmployeeWorkContextForDedupIdentity(value) {
17471
- return import_lodash.default.castArray(value || []).map(
17472
- (item) => import_lodash.default.isPlainObject(item) ? import_lodash.default.pick(item, AI_EMPLOYEE_WORK_CONTEXT_PUBLIC_KEYS) : item
17473
- );
18447
+ return import_lodash.default.castArray(value || []).map((item) => {
18448
+ if (!import_lodash.default.isPlainObject(item)) {
18449
+ return item;
18450
+ }
18451
+ const output = import_lodash.default.pick(item, AI_EMPLOYEE_WORK_CONTEXT_PUBLIC_KEYS);
18452
+ if (!Object.prototype.hasOwnProperty.call(output, "type") || import_lodash.default.isUndefined(output.type) || output.type === null) {
18453
+ output.type = "flow-model";
18454
+ }
18455
+ return output;
18456
+ });
18457
+ }
18458
+ normalizeAIEmployeeActionWorkContextForDedupIdentity(value, defaultWorkContext) {
18459
+ if (!Array.isArray(value)) {
18460
+ return import_lodash.default.cloneDeep(defaultWorkContext || []);
18461
+ }
18462
+ return this.normalizeAIEmployeeWorkContextForDedupIdentity(value);
17474
18463
  }
17475
- normalizeAIEmployeeTasksForDedupIdentity(value) {
18464
+ normalizeAIEmployeeDefaultActionWorkContextForSelfUid(selfUid) {
18465
+ const uid2 = String(selfUid || "").trim();
18466
+ return uid2 ? [{ type: "flow-model", uid: uid2 }] : [];
18467
+ }
18468
+ normalizeAIEmployeeTaskWorkContextForDedupIdentity(value, defaultWorkContext) {
18469
+ const normalized = this.normalizeAIEmployeeWorkContextForDedupIdentity(value);
18470
+ if (Array.isArray(defaultWorkContext) && !normalized.length) {
18471
+ return import_lodash.default.cloneDeep(defaultWorkContext);
18472
+ }
18473
+ return normalized;
18474
+ }
18475
+ normalizeAIEmployeeTasksForDedupIdentity(value, defaultWorkContext) {
17476
18476
  return import_lodash.default.castArray(value || []).map((task) => {
17477
18477
  if (!import_lodash.default.isPlainObject(task)) {
17478
18478
  return task;
@@ -17481,9 +18481,19 @@ class FlowSurfacesService {
17481
18481
  if (import_lodash.default.isPlainObject(output.message)) {
17482
18482
  output.message = import_lodash.default.pick(output.message, AI_EMPLOYEE_TASK_MESSAGE_PUBLIC_KEYS);
17483
18483
  if (Object.prototype.hasOwnProperty.call(output.message, "workContext")) {
17484
- output.message.workContext = this.normalizeAIEmployeeWorkContextForDedupIdentity(output.message.workContext);
18484
+ output.message.workContext = this.normalizeAIEmployeeTaskWorkContextForDedupIdentity(
18485
+ output.message.workContext,
18486
+ defaultWorkContext
18487
+ );
17485
18488
  }
17486
18489
  }
18490
+ if (!import_lodash.default.isPlainObject(output.message) && Array.isArray(defaultWorkContext)) {
18491
+ output.message = {
18492
+ workContext: import_lodash.default.cloneDeep(defaultWorkContext)
18493
+ };
18494
+ } else if (import_lodash.default.isPlainObject(output.message) && !Object.prototype.hasOwnProperty.call(output.message, "workContext")) {
18495
+ output.message.workContext = import_lodash.default.cloneDeep(defaultWorkContext || []);
18496
+ }
17487
18497
  if (import_lodash.default.isPlainObject(output.model)) {
17488
18498
  output.model = import_lodash.default.pick(output.model, AI_EMPLOYEE_TASK_MODEL_PUBLIC_KEYS);
17489
18499
  }
@@ -17493,25 +18503,38 @@ class FlowSurfacesService {
17493
18503
  return output;
17494
18504
  });
17495
18505
  }
17496
- async assertNoDuplicateAIEmployeeAction(actionName, parentUid, values, transaction) {
18506
+ async assertNoDuplicateAIEmployeeAction(actionName, parentUid, values, transaction, excludeUid) {
17497
18507
  var _a;
17498
- const identity = this.buildAIEmployeeActionDedupIdentity(values);
17499
- if (!identity) {
17500
- return;
17501
- }
17502
18508
  const parentNode = await this.repository.findModelById(parentUid, {
17503
18509
  transaction,
17504
18510
  includeAsyncNode: true
17505
18511
  });
17506
- const duplicate = import_lodash.default.castArray(((_a = parentNode == null ? void 0 : parentNode.subModels) == null ? void 0 : _a.actions) || []).find((action) => {
18512
+ const defaultActionWorkContext = this.normalizeAIEmployeeDefaultActionWorkContextForSelfUid(
18513
+ await this.resolveAIEmployeeActionSelfUidFromParentNode(parentNode, transaction)
18514
+ );
18515
+ const identity = this.buildAIEmployeeActionDedupIdentity(values, defaultActionWorkContext);
18516
+ if (!identity) {
18517
+ return;
18518
+ }
18519
+ let duplicate;
18520
+ for (const action of import_lodash.default.castArray(((_a = parentNode == null ? void 0 : parentNode.subModels) == null ? void 0 : _a.actions) || [])) {
17507
18521
  if (!this.isAIEmployeeActionUse(action == null ? void 0 : action.use)) {
17508
- return false;
18522
+ continue;
17509
18523
  }
17510
- return this.buildAIEmployeeActionDedupIdentity({
17511
- props: action.props,
17512
- stepParams: action.stepParams
17513
- }) === identity;
17514
- });
18524
+ if (excludeUid && String((action == null ? void 0 : action.uid) || "") === excludeUid) {
18525
+ continue;
18526
+ }
18527
+ if (this.buildAIEmployeeActionDedupIdentity(
18528
+ {
18529
+ props: action.props,
18530
+ stepParams: action.stepParams
18531
+ },
18532
+ defaultActionWorkContext
18533
+ ) === identity) {
18534
+ duplicate = action;
18535
+ break;
18536
+ }
18537
+ }
17515
18538
  if (!(duplicate == null ? void 0 : duplicate.uid)) {
17516
18539
  return;
17517
18540
  }
@@ -17526,6 +18549,25 @@ class FlowSurfacesService {
17526
18549
  }
17527
18550
  );
17528
18551
  }
18552
+ async assertNoDuplicateAIEmployeeActionForUpdateSettings(actionName, current, effectiveNode, transaction) {
18553
+ if (!this.isAIEmployeeActionUse(current == null ? void 0 : current.use)) {
18554
+ return;
18555
+ }
18556
+ const parentUid = String((current == null ? void 0 : current.parentId) || "").trim() || ((current == null ? void 0 : current.uid) ? await this.locator.findParentUid(current.uid, transaction).catch(() => "") : "");
18557
+ if (!parentUid) {
18558
+ return;
18559
+ }
18560
+ await this.assertNoDuplicateAIEmployeeAction(
18561
+ actionName,
18562
+ parentUid,
18563
+ {
18564
+ props: effectiveNode == null ? void 0 : effectiveNode.props,
18565
+ stepParams: effectiveNode == null ? void 0 : effectiveNode.stepParams
18566
+ },
18567
+ transaction,
18568
+ String((current == null ? void 0 : current.uid) || "")
18569
+ );
18570
+ }
17529
18571
  hasAIEmployeePublicSettings(settings) {
17530
18572
  return import_lodash.default.isPlainObject(settings) && AI_EMPLOYEE_PUBLIC_SETTING_KEYS.some((key) => Object.prototype.hasOwnProperty.call(settings, key));
17531
18573
  }
@@ -17580,11 +18622,24 @@ class FlowSurfacesService {
17580
18622
  var _a;
17581
18623
  const stepTasks = import_lodash.default.get(current, ["stepParams", ...AI_EMPLOYEE_TASK_STEP_PARAMS_PATH]);
17582
18624
  if (Array.isArray(stepTasks)) {
17583
- return stepTasks;
18625
+ return this.normalizeAIEmployeeLegacyInheritedTaskWorkContext(stepTasks);
17584
18626
  }
17585
- const legacyPropsTasks = (_a = current == null ? void 0 : current.props) == null ? void 0 : _a.tasks;
18627
+ const legacyPropsTasks = this.normalizeAIEmployeeLegacyInheritedTaskWorkContext((_a = current == null ? void 0 : current.props) == null ? void 0 : _a.tasks);
17586
18628
  return Array.isArray(legacyPropsTasks) ? legacyPropsTasks : [];
17587
18629
  }
18630
+ normalizeAIEmployeeLegacyInheritedTaskWorkContext(tasks) {
18631
+ if (!Array.isArray(tasks)) {
18632
+ return tasks;
18633
+ }
18634
+ return tasks.map((task) => {
18635
+ if (!import_lodash.default.isPlainObject(task) || !import_lodash.default.isPlainObject(task.message) || task.message.workContext !== null) {
18636
+ return task;
18637
+ }
18638
+ const nextTask = import_lodash.default.cloneDeep(task);
18639
+ delete nextTask.message.workContext;
18640
+ return nextTask;
18641
+ });
18642
+ }
17588
18643
  buildAIEmployeeTaskStepParams(tasks) {
17589
18644
  const stepParams = {};
17590
18645
  import_lodash.default.set(stepParams, AI_EMPLOYEE_TASK_STEP_PARAMS_PATH, import_lodash.default.cloneDeep(tasks));
@@ -17613,7 +18668,7 @@ class FlowSurfacesService {
17613
18668
  if (!this.isAIEmployeeActionUse(current == null ? void 0 : current.use)) {
17614
18669
  return;
17615
18670
  }
17616
- const legacyPropsTasks = (_a = current == null ? void 0 : current.props) == null ? void 0 : _a.tasks;
18671
+ const legacyPropsTasks = this.normalizeAIEmployeeLegacyInheritedTaskWorkContext((_a = current == null ? void 0 : current.props) == null ? void 0 : _a.tasks);
17617
18672
  const hasLegacyPropsTasks = Array.isArray(legacyPropsTasks);
17618
18673
  const hasNextStepTasks = import_lodash.default.has(nextPayload, ["stepParams", ...AI_EMPLOYEE_TASK_STEP_PARAMS_PATH]);
17619
18674
  const currentStepTasks = import_lodash.default.get(current, ["stepParams", ...AI_EMPLOYEE_TASK_STEP_PARAMS_PATH]);
@@ -17785,6 +18840,20 @@ class FlowSurfacesService {
17785
18840
  };
17786
18841
  });
17787
18842
  }
18843
+ normalizeAIEmployeeEffectiveActionWorkContext(actionName, settings, currentProps, options) {
18844
+ var _a;
18845
+ const hasSettingsWorkContext = Object.prototype.hasOwnProperty.call(settings, "workContext");
18846
+ const currentWorkContext = (_a = currentProps == null ? void 0 : currentProps.context) == null ? void 0 : _a.workContext;
18847
+ if (!hasSettingsWorkContext && !Array.isArray(currentWorkContext) && !options.requireUsername && !options.selfUid) {
18848
+ return void 0;
18849
+ }
18850
+ const rawWorkContext = hasSettingsWorkContext ? settings.workContext : Array.isArray(currentWorkContext) ? currentWorkContext : [{ type: "flow-model", target: "self" }];
18851
+ return this.normalizeAIEmployeeWorkContext(actionName, rawWorkContext, {
18852
+ selfUid: options.selfUid,
18853
+ keyMap: options.keyMap,
18854
+ path: "settings.workContext"
18855
+ });
18856
+ }
17788
18857
  normalizeAIEmployeeTaskModel(actionName, path, value) {
17789
18858
  if (import_lodash.default.isUndefined(value) || value === null) {
17790
18859
  return value;
@@ -18100,6 +19169,7 @@ ${AI_EMPLOYEE_CURRENT_RECORD_PROMPT_VARIABLE}` : AI_EMPLOYEE_CURRENT_RECORD_PROM
18100
19169
  );
18101
19170
  }
18102
19171
  async normalizeAIEmployeeStepParamTasksForUpdateSettings(current, nextPayload, writeTarget, options) {
19172
+ var _a, _b, _c, _d;
18103
19173
  if (!this.isAIEmployeeActionUse(current == null ? void 0 : current.use) || !import_lodash.default.has(nextPayload, ["stepParams", ...AI_EMPLOYEE_TASK_STEP_PARAMS_PATH])) {
18104
19174
  return;
18105
19175
  }
@@ -18108,15 +19178,63 @@ ${AI_EMPLOYEE_CURRENT_RECORD_PROMPT_VARIABLE}` : AI_EMPLOYEE_CURRENT_RECORD_PROM
18108
19178
  return;
18109
19179
  }
18110
19180
  const actionName = options.openViewActionName || "updateSettings";
18111
- const normalizedTasks = this.normalizeAIEmployeeTasks(
19181
+ const selfUid = await this.resolveAIEmployeeActionSelfUid(current || { uid: writeTarget.uid }, options.transaction);
19182
+ const currentPropsForDefault = import_lodash.default.mergeWith(
19183
+ {},
19184
+ import_lodash.default.isPlainObject(current == null ? void 0 : current.props) ? current.props : {},
19185
+ import_lodash.default.isPlainObject(nextPayload.props) ? nextPayload.props : {},
19186
+ (_currentValue, nextValue) => {
19187
+ if (Array.isArray(nextValue)) {
19188
+ return import_lodash.default.cloneDeep(nextValue);
19189
+ }
19190
+ return void 0;
19191
+ }
19192
+ );
19193
+ const defaultWorkContext = this.normalizeAIEmployeeEffectiveActionWorkContext(
18112
19194
  actionName,
18113
- tasks,
18114
- this.readAIEmployeePersistedTasks(current),
19195
+ {},
19196
+ currentPropsForDefault,
18115
19197
  {
18116
- selfUid: await this.resolveAIEmployeeActionSelfUid(current || { uid: writeTarget.uid }, options.transaction),
18117
- path: "stepParams.shortcutSettings.editTasks.tasks"
19198
+ selfUid,
19199
+ requireUsername: true
18118
19200
  }
18119
19201
  );
19202
+ const currentTasks = this.readAIEmployeePersistedTasks(current);
19203
+ const previousActionWorkContext = this.normalizeAIEmployeeActionWorkContextForDedupIdentity(
19204
+ (_b = (_a = current == null ? void 0 : current.props) == null ? void 0 : _a.context) == null ? void 0 : _b.workContext,
19205
+ this.normalizeAIEmployeeDefaultActionWorkContextForSelfUid(selfUid)
19206
+ );
19207
+ const nextActionWorkContext = this.normalizeAIEmployeeActionWorkContextForDedupIdentity(
19208
+ (_c = currentPropsForDefault == null ? void 0 : currentPropsForDefault.context) == null ? void 0 : _c.workContext,
19209
+ defaultWorkContext
19210
+ );
19211
+ if (Array.isArray(defaultWorkContext) && !import_lodash.default.isEqual((_d = currentPropsForDefault == null ? void 0 : currentPropsForDefault.context) == null ? void 0 : _d.workContext, defaultWorkContext)) {
19212
+ nextPayload.props = import_lodash.default.mergeWith(
19213
+ {},
19214
+ currentPropsForDefault,
19215
+ {
19216
+ context: {
19217
+ workContext: import_lodash.default.cloneDeep(defaultWorkContext)
19218
+ }
19219
+ },
19220
+ (_currentValue, nextValue) => {
19221
+ if (Array.isArray(nextValue)) {
19222
+ return import_lodash.default.cloneDeep(nextValue);
19223
+ }
19224
+ return void 0;
19225
+ }
19226
+ );
19227
+ }
19228
+ const currentTasksForNormalization = this.rebaseAIEmployeeInheritedTaskWorkContext(
19229
+ currentTasks,
19230
+ previousActionWorkContext,
19231
+ nextActionWorkContext
19232
+ );
19233
+ const normalizedTasks = this.normalizeAIEmployeeTasks(actionName, tasks, currentTasksForNormalization, {
19234
+ selfUid,
19235
+ defaultWorkContext,
19236
+ path: "stepParams.shortcutSettings.editTasks.tasks"
19237
+ });
18120
19238
  import_lodash.default.set(nextPayload, ["stepParams", ...AI_EMPLOYEE_TASK_STEP_PARAMS_PATH], normalizedTasks);
18121
19239
  }
18122
19240
  normalizeAIEmployeeTaskMessage(actionName, path, value, existing, options) {
@@ -18145,13 +19263,18 @@ ${AI_EMPLOYEE_CURRENT_RECORD_PROMPT_VARIABLE}` : AI_EMPLOYEE_CURRENT_RECORD_PROM
18145
19263
  if (Object.prototype.hasOwnProperty.call(nextMessage, "user") && typeof nextMessage.user !== "string") {
18146
19264
  (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} ${path}.user must be a string`);
18147
19265
  }
18148
- if (Object.prototype.hasOwnProperty.call(value, "workContext")) {
19266
+ if (value.workContext === null) {
19267
+ delete nextMessage.workContext;
19268
+ } else if (Object.prototype.hasOwnProperty.call(value, "workContext")) {
18149
19269
  nextMessage.workContext = this.normalizeAIEmployeeWorkContext(actionName, value.workContext, {
18150
19270
  selfUid: options.selfUid,
18151
19271
  keyMap: options.keyMap,
18152
19272
  path: `${path}.workContext`
18153
19273
  });
18154
19274
  }
19275
+ if (!Object.prototype.hasOwnProperty.call(nextMessage, "workContext") && this.shouldMaterializeAIEmployeeTaskDefaultWorkContext(options.defaultWorkContext)) {
19276
+ nextMessage.workContext = import_lodash.default.cloneDeep(options.defaultWorkContext);
19277
+ }
18155
19278
  return nextMessage;
18156
19279
  }
18157
19280
  normalizeAIEmployeeTaskPatch(actionName, patch, existing, options) {
@@ -18175,7 +19298,8 @@ ${AI_EMPLOYEE_CURRENT_RECORD_PROMPT_VARIABLE}` : AI_EMPLOYEE_CURRENT_RECORD_PROM
18175
19298
  if (key === "message") {
18176
19299
  next.message = this.normalizeAIEmployeeTaskMessage(actionName, `${options.path}.message`, value, next.message, {
18177
19300
  selfUid: options.selfUid,
18178
- keyMap: options.keyMap
19301
+ keyMap: options.keyMap,
19302
+ defaultWorkContext: options.defaultWorkContext
18179
19303
  });
18180
19304
  return;
18181
19305
  }
@@ -18225,6 +19349,9 @@ ${AI_EMPLOYEE_CURRENT_RECORD_PROMPT_VARIABLE}` : AI_EMPLOYEE_CURRENT_RECORD_PROM
18225
19349
  if (!import_lodash.default.isPlainObject(next.message)) {
18226
19350
  next.message = {};
18227
19351
  }
19352
+ if (!Object.prototype.hasOwnProperty.call(next.message, "workContext") && this.shouldMaterializeAIEmployeeTaskDefaultWorkContext(options.defaultWorkContext)) {
19353
+ next.message.workContext = import_lodash.default.cloneDeep(options.defaultWorkContext);
19354
+ }
18228
19355
  if (import_lodash.default.isPlainObject(next.skillSettings)) {
18229
19356
  if (Array.isArray(next.skillSettings.skills) && !Object.prototype.hasOwnProperty.call(next.skillSettings, "skillsVersion")) {
18230
19357
  next.skillSettings.skillsVersion = 2;
@@ -18251,10 +19378,52 @@ ${AI_EMPLOYEE_CURRENT_RECORD_PROMPT_VARIABLE}` : AI_EMPLOYEE_CURRENT_RECORD_PROM
18251
19378
  nextTasks[index] = this.normalizeAIEmployeeTaskPatch(actionName, task, existingTasks[index], {
18252
19379
  selfUid: options.selfUid,
18253
19380
  keyMap: options.keyMap,
18254
- path: `${options.path}[${index}]`
19381
+ path: `${options.path}[${index}]`,
19382
+ defaultWorkContext: options.defaultWorkContext
18255
19383
  });
18256
19384
  });
18257
- return nextTasks;
19385
+ return this.withAIEmployeeTaskDefaultWorkContext(nextTasks, options.defaultWorkContext);
19386
+ }
19387
+ withAIEmployeeTaskDefaultWorkContext(tasks, defaultWorkContext) {
19388
+ const nextTasks = Array.isArray(tasks) ? import_lodash.default.cloneDeep(tasks) : [];
19389
+ if (!this.shouldMaterializeAIEmployeeTaskDefaultWorkContext(defaultWorkContext)) {
19390
+ return nextTasks;
19391
+ }
19392
+ return nextTasks.map((task) => {
19393
+ if (!import_lodash.default.isPlainObject(task)) {
19394
+ return task;
19395
+ }
19396
+ const nextTask = import_lodash.default.cloneDeep(task);
19397
+ if (!import_lodash.default.isPlainObject(nextTask.message)) {
19398
+ nextTask.message = {
19399
+ workContext: import_lodash.default.cloneDeep(defaultWorkContext)
19400
+ };
19401
+ } else if (!Object.prototype.hasOwnProperty.call(nextTask.message, "workContext")) {
19402
+ nextTask.message.workContext = import_lodash.default.cloneDeep(defaultWorkContext);
19403
+ }
19404
+ return nextTask;
19405
+ });
19406
+ }
19407
+ shouldMaterializeAIEmployeeTaskDefaultWorkContext(defaultWorkContext) {
19408
+ return Array.isArray(defaultWorkContext) && defaultWorkContext.length > 0;
19409
+ }
19410
+ rebaseAIEmployeeInheritedTaskWorkContext(currentTasks, previousActionWorkContext, nextActionWorkContext) {
19411
+ const tasks = this.normalizeAIEmployeeLegacyInheritedTaskWorkContext(currentTasks) || [];
19412
+ if (!previousActionWorkContext.length || import_lodash.default.isEqual(previousActionWorkContext, nextActionWorkContext)) {
19413
+ return tasks;
19414
+ }
19415
+ return tasks.map((task) => {
19416
+ const nextTask = import_lodash.default.cloneDeep(task);
19417
+ if (import_lodash.default.isPlainObject(nextTask == null ? void 0 : nextTask.message)) {
19418
+ const currentTaskWorkContext = this.normalizeAIEmployeeWorkContextForDedupIdentity(
19419
+ nextTask.message.workContext
19420
+ );
19421
+ if (import_lodash.default.isEqual(currentTaskWorkContext, previousActionWorkContext)) {
19422
+ delete nextTask.message.workContext;
19423
+ }
19424
+ }
19425
+ return nextTask;
19426
+ });
18258
19427
  }
18259
19428
  normalizeAIEmployeeActionSettingsReferences(actionName, settings, options) {
18260
19429
  if (!this.hasAIEmployeePublicSettings(settings)) {
@@ -18268,15 +19437,22 @@ ${AI_EMPLOYEE_CURRENT_RECORD_PROMPT_VARIABLE}` : AI_EMPLOYEE_CURRENT_RECORD_PROM
18268
19437
  });
18269
19438
  }
18270
19439
  if (Object.prototype.hasOwnProperty.call(nextSettings, "tasks")) {
19440
+ const defaultWorkContext = this.normalizeAIEmployeeEffectiveActionWorkContext(
19441
+ actionName,
19442
+ nextSettings,
19443
+ {},
19444
+ options
19445
+ );
18271
19446
  nextSettings.tasks = this.normalizeAIEmployeeTasks(actionName, nextSettings.tasks, [], {
18272
19447
  ...options,
18273
- path: "settings.tasks"
19448
+ path: "settings.tasks",
19449
+ defaultWorkContext
18274
19450
  });
18275
19451
  }
18276
19452
  return nextSettings;
18277
19453
  }
18278
19454
  async normalizeAIEmployeeActionPublicSettings(actionName, settings, options) {
18279
- var _a, _b;
19455
+ var _a, _b, _c, _d;
18280
19456
  this.assertAIEmployeePluginEnabled(actionName, options.enabledPackages);
18281
19457
  if (!import_lodash.default.isPlainObject(settings)) {
18282
19458
  (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} AI employee settings must be an object`);
@@ -18296,6 +19472,17 @@ ${AI_EMPLOYEE_CURRENT_RECORD_PROMPT_VARIABLE}` : AI_EMPLOYEE_CURRENT_RECORD_PROM
18296
19472
  }
18297
19473
  const props = {};
18298
19474
  const stepParams = {};
19475
+ const effectiveActionWorkContext = this.normalizeAIEmployeeEffectiveActionWorkContext(
19476
+ actionName,
19477
+ settings,
19478
+ currentProps,
19479
+ options
19480
+ );
19481
+ const previousActionWorkContext = this.normalizeAIEmployeeActionWorkContextForDedupIdentity(
19482
+ (_c = currentProps == null ? void 0 : currentProps.context) == null ? void 0 : _c.workContext,
19483
+ this.normalizeAIEmployeeDefaultActionWorkContextForSelfUid(options.selfUid)
19484
+ );
19485
+ const nextActionWorkContext = this.normalizeAIEmployeeWorkContextForDedupIdentity(effectiveActionWorkContext);
18299
19486
  if (effectiveUsername && (hasUsername || options.requireUsername)) {
18300
19487
  props.aiEmployee = {
18301
19488
  ...import_lodash.default.isPlainObject(currentProps.aiEmployee) ? import_lodash.default.cloneDeep(currentProps.aiEmployee) : {},
@@ -18309,28 +19496,25 @@ ${AI_EMPLOYEE_CURRENT_RECORD_PROMPT_VARIABLE}` : AI_EMPLOYEE_CURRENT_RECORD_PROM
18309
19496
  }
18310
19497
  props.auto = auto;
18311
19498
  }
18312
- if (Object.prototype.hasOwnProperty.call(settings, "workContext") || options.requireUsername) {
18313
- const rawWorkContext = Object.prototype.hasOwnProperty.call(settings, "workContext") ? settings.workContext : [{ type: "flow-model", target: "self" }];
19499
+ if (Array.isArray(effectiveActionWorkContext) && (Object.prototype.hasOwnProperty.call(settings, "workContext") || options.requireUsername || !import_lodash.default.isEqual((_d = currentProps == null ? void 0 : currentProps.context) == null ? void 0 : _d.workContext, effectiveActionWorkContext))) {
18314
19500
  props.context = {
18315
19501
  ...import_lodash.default.isPlainObject(currentProps.context) ? import_lodash.default.cloneDeep(currentProps.context) : {},
18316
- workContext: this.normalizeAIEmployeeWorkContext(actionName, rawWorkContext, {
18317
- selfUid: options.selfUid,
18318
- keyMap: options.keyMap,
18319
- path: "settings.workContext"
18320
- })
19502
+ workContext: import_lodash.default.cloneDeep(effectiveActionWorkContext)
18321
19503
  };
18322
19504
  }
18323
19505
  if (Object.prototype.hasOwnProperty.call(settings, "tasks")) {
18324
- const normalizedTasks = this.normalizeAIEmployeeTasks(
18325
- actionName,
18326
- settings.tasks,
18327
- this.readAIEmployeePersistedTasks(options.current),
18328
- {
18329
- selfUid: options.selfUid,
18330
- keyMap: options.keyMap,
18331
- path: "settings.tasks"
18332
- }
19506
+ const currentTasks = this.readAIEmployeePersistedTasks(options.current);
19507
+ const currentTasksForNormalization = this.rebaseAIEmployeeInheritedTaskWorkContext(
19508
+ currentTasks,
19509
+ previousActionWorkContext,
19510
+ nextActionWorkContext
18333
19511
  );
19512
+ const normalizedTasks = this.normalizeAIEmployeeTasks(actionName, settings.tasks, currentTasksForNormalization, {
19513
+ selfUid: options.selfUid,
19514
+ keyMap: options.keyMap,
19515
+ path: "settings.tasks",
19516
+ defaultWorkContext: effectiveActionWorkContext
19517
+ });
18334
19518
  const validation = options.promptContext && normalizedTasks.length ? await this.buildAIEmployeePromptValidationContext(
18335
19519
  actionName,
18336
19520
  [
@@ -18351,6 +19535,17 @@ ${AI_EMPLOYEE_CURRENT_RECORD_PROMPT_VARIABLE}` : AI_EMPLOYEE_CURRENT_RECORD_PROM
18351
19535
  const tasks = this.appendAIEmployeeCurrentRecordPromptVariableToTasks(normalizedTasks, validation);
18352
19536
  this.assertAIEmployeeTaskPromptVariablesAllowed(actionName, tasks, validation);
18353
19537
  import_lodash.default.merge(stepParams, this.buildAIEmployeeTaskStepParams(tasks));
19538
+ } else if (!options.skipExistingTaskWorkContextRebase && Object.prototype.hasOwnProperty.call(settings, "workContext") && !import_lodash.default.isEqual(previousActionWorkContext, nextActionWorkContext)) {
19539
+ const currentTasks = this.readAIEmployeePersistedTasks(options.current);
19540
+ const rebasedTasks = this.rebaseAIEmployeeInheritedTaskWorkContext(
19541
+ currentTasks,
19542
+ previousActionWorkContext,
19543
+ nextActionWorkContext
19544
+ );
19545
+ const tasks = this.withAIEmployeeTaskDefaultWorkContext(rebasedTasks, effectiveActionWorkContext);
19546
+ if (tasks.length) {
19547
+ import_lodash.default.merge(stepParams, this.buildAIEmployeeTaskStepParams(tasks));
19548
+ }
18354
19549
  }
18355
19550
  if (Object.prototype.hasOwnProperty.call(settings, "style") || options.requireUsername) {
18356
19551
  const style = Object.prototype.hasOwnProperty.call(settings, "style") ? settings.style : {};
@@ -18392,7 +19587,16 @@ ${AI_EMPLOYEE_CURRENT_RECORD_PROMPT_VARIABLE}` : AI_EMPLOYEE_CURRENT_RECORD_PROM
18392
19587
  transaction,
18393
19588
  includeAsyncNode: true
18394
19589
  });
18395
- if (["TableActionsColumnModel", "ListItemModel", "GridCardItemModel"].includes(String((parentNode == null ? void 0 : parentNode.use) || ""))) {
19590
+ return await this.resolveAIEmployeeActionSelfUidFromParentNode(parentNode, transaction) || parentUid;
19591
+ }
19592
+ async resolveAIEmployeeActionSelfUidFromParentNode(parentNode, transaction) {
19593
+ const parentUid = String((parentNode == null ? void 0 : parentNode.uid) || "").trim();
19594
+ if (!parentUid) {
19595
+ return "";
19596
+ }
19597
+ if (["TableActionsColumnModel", "ListItemModel", "GridCardItemModel", "CommentItemModel"].includes(
19598
+ String((parentNode == null ? void 0 : parentNode.use) || "")
19599
+ )) {
18396
19600
  const ownerUid = String((parentNode == null ? void 0 : parentNode.parentId) || "").trim() || ((parentNode == null ? void 0 : parentNode.uid) ? await this.locator.findParentUid(parentNode.uid, transaction).catch(() => "") : "");
18397
19601
  return ownerUid || parentUid;
18398
19602
  }
@@ -18441,13 +19645,14 @@ ${AI_EMPLOYEE_CURRENT_RECORD_PROMPT_VARIABLE}` : AI_EMPLOYEE_CURRENT_RECORD_PROM
18441
19645
  }
18442
19646
  const normalizedDefaultFilter = (0, import_service_utils.hasOwnDefined)(changes, "defaultFilter") ? this.normalizeFilterActionDefaultFilterValue(changes.defaultFilter) : void 0;
18443
19647
  const stepParams = {};
18444
- if ((0, import_service_utils.hasDefinedValue)(changes, ["title", "tooltip", "icon", "type", "danger", "color", "linkageRules"])) {
19648
+ if ((0, import_service_utils.hasDefinedValue)(changes, ["title", "tooltip", "icon", "iconOnly", "type", "danger", "color", "linkageRules"])) {
18445
19649
  stepParams.buttonSettings = {
18446
- ...(0, import_service_utils.hasDefinedValue)(changes, ["title", "tooltip", "icon", "type", "danger", "color"]) ? {
19650
+ ...(0, import_service_utils.hasDefinedValue)(changes, ["title", "tooltip", "icon", "iconOnly", "type", "danger", "color"]) ? {
18447
19651
  general: (0, import_service_utils.buildDefinedPayload)({
18448
19652
  title: changes.title,
18449
19653
  tooltip: changes.tooltip,
18450
19654
  icon: changes.icon,
19655
+ iconOnly: changes.iconOnly,
18451
19656
  type: changes.type,
18452
19657
  danger: changes.danger,
18453
19658
  color: changes.color
@@ -18657,6 +19862,7 @@ ${AI_EMPLOYEE_CURRENT_RECORD_PROMPT_VARIABLE}` : AI_EMPLOYEE_CURRENT_RECORD_PROM
18657
19862
  title: changes.title,
18658
19863
  tooltip: changes.tooltip,
18659
19864
  icon: changes.icon,
19865
+ iconOnly: changes.iconOnly,
18660
19866
  type: changes.type,
18661
19867
  htmlType: changes.htmlType,
18662
19868
  position: changes.position,
@@ -18786,6 +19992,11 @@ ${AI_EMPLOYEE_CURRENT_RECORD_PROMPT_VARIABLE}` : AI_EMPLOYEE_CURRENT_RECORD_PROM
18786
19992
  useStrictOnly: input.useStrictOnly
18787
19993
  });
18788
19994
  }
19995
+ isCollectionTitleField(collection, fieldName) {
19996
+ const normalizedFieldName = String(fieldName || "").trim();
19997
+ const titleFieldName = String((0, import_service_helpers.getCollectionTitleFieldName)(collection) || "").trim();
19998
+ return !!normalizedFieldName && normalizedFieldName === titleFieldName;
19999
+ }
18789
20000
  resolveAssociationLeafDisplaySemantics(field, dataSourceKey, enabledPackages) {
18790
20001
  const registeredBinding = this.resolveRegisteredFieldBinding({
18791
20002
  containerUse: "DetailsItemModel",
@@ -18821,6 +20032,9 @@ ${AI_EMPLOYEE_CURRENT_RECORD_PROMPT_VARIABLE}` : AI_EMPLOYEE_CURRENT_RECORD_PROM
18821
20032
  }
18822
20033
  buildFieldMenuDirectCandidates(input) {
18823
20034
  const collection = this.getCollection(input.resourceInit.dataSourceKey, input.resourceInit.collectionName);
20035
+ const explicitDefaultFieldPaths = (0, import_default_action_popup.collectFlowSurfaceDefaultActionPopupFieldGroupFieldPaths)(
20036
+ input.defaultFieldGroups
20037
+ );
18824
20038
  return (0, import_service_helpers.getCollectionFields)(collection).flatMap((field) => {
18825
20039
  var _a;
18826
20040
  const fieldName = (0, import_service_helpers.getFieldName)(field);
@@ -18831,6 +20045,9 @@ ${AI_EMPLOYEE_CURRENT_RECORD_PROMPT_VARIABLE}` : AI_EMPLOYEE_CURRENT_RECORD_PROM
18831
20045
  if (input.generatedPopupOnly && !(0, import_default_action_popup.isFlowSurfaceDefaultActionPopupBusinessField)(field)) {
18832
20046
  return [];
18833
20047
  }
20048
+ if ((0, import_relation_backing_foreign_key.isRelationBackingForeignKeyField)(collection, field) && !explicitDefaultFieldPaths.has(fieldName)) {
20049
+ return [];
20050
+ }
18834
20051
  if (input.mode === "table" && ((_a = field == null ? void 0 : field.options) == null ? void 0 : _a.treeChildren)) {
18835
20052
  return [];
18836
20053
  }
@@ -18918,6 +20135,9 @@ ${AI_EMPLOYEE_CURRENT_RECORD_PROMPT_VARIABLE}` : AI_EMPLOYEE_CURRENT_RECORD_PROM
18918
20135
  if (!targetFieldName) {
18919
20136
  continue;
18920
20137
  }
20138
+ if ((0, import_relation_backing_foreign_key.isRelationBackingForeignKeyField)(targetCollection, targetField) && !this.isCollectionTitleField(targetCollection, targetFieldName)) {
20139
+ continue;
20140
+ }
18921
20141
  nextCandidates.push({
18922
20142
  field: targetField,
18923
20143
  fieldPath: `${associationPathName}.${targetFieldName}`,
@@ -19092,7 +20312,7 @@ ${AI_EMPLOYEE_CURRENT_RECORD_PROMPT_VARIABLE}` : AI_EMPLOYEE_CURRENT_RECORD_PROM
19092
20312
  const getFields = (targetCollection) => (0, import_service_helpers.getCollectionFields)(targetCollection);
19093
20313
  const isFilterFieldVisible = (field) => (0, import_service_helpers.getFieldFilterable)(field) !== false && !!(0, import_service_helpers.getFieldInterface)(field);
19094
20314
  const directFields = getFields(collection).filter(
19095
- (field) => ["FilterFormBlockModel", "FilterFormGridModel", "FilterFormItemModel"].includes(input.ownerUse) ? isFilterFieldVisible(field) : !!(0, import_service_helpers.getFieldInterface)(field)
20315
+ (field) => !(0, import_relation_backing_foreign_key.isRelationBackingForeignKeyField)(collection, field) && (["FilterFormBlockModel", "FilterFormGridModel", "FilterFormItemModel"].includes(input.ownerUse) ? isFilterFieldVisible(field) : !!(0, import_service_helpers.getFieldInterface)(field))
19096
20316
  );
19097
20317
  if (!directFields.length && !collection) {
19098
20318
  return [];
@@ -19106,9 +20326,13 @@ ${AI_EMPLOYEE_CURRENT_RECORD_PROMPT_VARIABLE}` : AI_EMPLOYEE_CURRENT_RECORD_PROM
19106
20326
  if (!(0, import_service_helpers.isAssociationField)(field) || !targetCollection) {
19107
20327
  return [];
19108
20328
  }
19109
- return getFields(targetCollection).filter(
19110
- (targetField) => ["FilterFormBlockModel", "FilterFormGridModel", "FilterFormItemModel"].includes(input.ownerUse) ? isFilterFieldVisible(targetField) : !!(0, import_service_helpers.getFieldInterface)(targetField)
19111
- ).map((targetField) => ({
20329
+ return getFields(targetCollection).filter((targetField) => {
20330
+ const targetFieldName = (0, import_service_helpers.getFieldName)(targetField);
20331
+ if ((0, import_relation_backing_foreign_key.isRelationBackingForeignKeyField)(targetCollection, targetField) && !this.isCollectionTitleField(targetCollection, targetFieldName)) {
20332
+ return false;
20333
+ }
20334
+ return ["FilterFormBlockModel", "FilterFormGridModel", "FilterFormItemModel"].includes(input.ownerUse) ? isFilterFieldVisible(targetField) : !!(0, import_service_helpers.getFieldInterface)(targetField);
20335
+ }).map((targetField) => ({
19112
20336
  field: targetField,
19113
20337
  fieldPath: `${(0, import_service_helpers.getFieldName)(field)}.${(0, import_service_helpers.getFieldName)(targetField)}`,
19114
20338
  associationPathName: (0, import_service_helpers.getFieldName)(field),