@nocobase/plugin-flow-engine 2.2.0-beta.1 → 2.2.0-beta.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 (72) hide show
  1. package/dist/client/index.js +1 -1
  2. package/dist/externalVersion.js +9 -9
  3. package/dist/locale/en-US.json +1 -0
  4. package/dist/locale/index.d.ts +2 -0
  5. package/dist/locale/zh-CN.json +1 -0
  6. package/dist/node_modules/@ant-design/icons-svg/package.json +1 -1
  7. package/dist/node_modules/acorn/package.json +1 -1
  8. package/dist/node_modules/acorn-jsx/package.json +1 -1
  9. package/dist/node_modules/acorn-walk/package.json +1 -1
  10. package/dist/node_modules/ses/package.json +1 -1
  11. package/dist/node_modules/zod/package.json +1 -1
  12. package/dist/server/flow-surfaces/{runjs-authoring/blocked-global-stop/index.d.ts → approval/authoring-validation.d.ts} +1 -2
  13. package/dist/server/flow-surfaces/approval/authoring-validation.js +1151 -0
  14. package/dist/server/flow-surfaces/approval/blueprint-service.js +2 -0
  15. package/dist/server/flow-surfaces/authoring-validation.d.ts +2 -1
  16. package/dist/server/flow-surfaces/authoring-validation.js +639 -59
  17. package/dist/server/flow-surfaces/blueprint/compile-blocks.js +7 -3
  18. package/dist/server/flow-surfaces/blueprint/compile-plan.js +19 -15
  19. package/dist/server/flow-surfaces/blueprint/export-document.d.ts +50 -0
  20. package/dist/server/flow-surfaces/blueprint/export-document.js +2510 -0
  21. package/dist/server/flow-surfaces/blueprint/normalize-document.js +2 -1
  22. package/dist/server/flow-surfaces/blueprint/public-types.d.ts +1 -0
  23. package/dist/server/flow-surfaces/builder.js +43 -5
  24. package/dist/server/flow-surfaces/catalog.js +13 -2
  25. package/dist/server/flow-surfaces/configure-options.js +5 -3
  26. package/dist/server/flow-surfaces/constants.d.ts +9 -2
  27. package/dist/server/flow-surfaces/constants.js +1 -0
  28. package/dist/server/flow-surfaces/contract-guard.js +37 -5
  29. package/dist/server/flow-surfaces/default-action-popup.d.ts +2 -0
  30. package/dist/server/flow-surfaces/default-action-popup.js +27 -13
  31. package/dist/server/flow-surfaces/filter-group.d.ts +19 -2
  32. package/dist/server/flow-surfaces/filter-group.js +232 -3
  33. package/dist/server/flow-surfaces/planning/compiler.d.ts +1 -0
  34. package/dist/server/flow-surfaces/planning/compiler.js +205 -82
  35. package/dist/server/flow-surfaces/planning/key-registry.d.ts +1 -1
  36. package/dist/server/flow-surfaces/planning/runtime.js +1 -0
  37. package/dist/server/flow-surfaces/planning/step-link.d.ts +1 -1
  38. package/dist/server/flow-surfaces/planning/step-link.js +22 -3
  39. package/dist/server/flow-surfaces/public-data-surface-default-filter.js +0 -9
  40. package/dist/server/flow-surfaces/reaction/field-value.d.ts +9 -0
  41. package/dist/server/flow-surfaces/reaction/field-value.js +51 -2
  42. package/dist/server/flow-surfaces/reaction/linkage.d.ts +6 -1
  43. package/dist/server/flow-surfaces/reaction/linkage.js +18 -3
  44. package/dist/server/flow-surfaces/reaction/meta.js +19 -1
  45. package/dist/server/flow-surfaces/reaction/types.d.ts +19 -0
  46. package/dist/server/flow-surfaces/relation-backing-foreign-key.d.ts +10 -0
  47. package/dist/server/flow-surfaces/relation-backing-foreign-key.js +79 -0
  48. package/dist/server/flow-surfaces/runjs-authoring/ast/source.d.ts +1 -0
  49. package/dist/server/flow-surfaces/runjs-authoring/ast/source.js +20 -0
  50. package/dist/server/flow-surfaces/runjs-authoring/rules.js +0 -2
  51. package/dist/server/flow-surfaces/runjs-authoring/runtime/constants.d.ts +0 -1
  52. package/dist/server/flow-surfaces/runjs-authoring/runtime/constants.js +11 -19
  53. package/dist/server/flow-surfaces/runjs-authoring/runtime/types.d.ts +0 -12
  54. package/dist/server/flow-surfaces/runjs-authoring/scan/filter.js +12 -2
  55. package/dist/server/flow-surfaces/runjs-authoring/scan/index.d.ts +0 -14
  56. package/dist/server/flow-surfaces/runjs-authoring/scan/index.js +10 -8
  57. package/dist/server/flow-surfaces/runjs-authoring/scan/source-patterns.d.ts +0 -14
  58. package/dist/server/flow-surfaces/runjs-authoring/scan/source-patterns.js +18 -73
  59. package/dist/server/flow-surfaces/runjs-authoring/types.d.ts +1 -1
  60. package/dist/server/flow-surfaces/runjs-authoring/validators/index.js +9 -53
  61. package/dist/server/flow-surfaces/service.d.ts +53 -0
  62. package/dist/server/flow-surfaces/service.js +997 -127
  63. package/dist/server/flow-surfaces/types.d.ts +2 -1
  64. package/dist/server/variables/records.js +7 -2
  65. package/dist/server/variables/registry.js +3 -0
  66. package/dist/swagger/flow-surfaces.d.ts +193 -0
  67. package/dist/swagger/flow-surfaces.examples.d.ts +11 -0
  68. package/dist/swagger/flow-surfaces.examples.js +11 -0
  69. package/dist/swagger/flow-surfaces.js +179 -10
  70. package/dist/swagger/index.d.ts +193 -0
  71. package/package.json +2 -2
  72. 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");
@@ -96,6 +97,7 @@ var import_meta = require("./reaction/meta");
96
97
  var import_resolver = require("./reaction/resolver");
97
98
  var import_association_title_field = require("./association-title-field");
98
99
  var import_default_action_popup = require("./default-action-popup");
100
+ var import_relation_backing_foreign_key = require("./relation-backing-foreign-key");
99
101
  var import_defaults = require("./blueprint/defaults");
100
102
  var import_service_utils = require("./service-utils");
101
103
  var import_field_type_resolver = require("./field-type-resolver");
@@ -229,9 +231,11 @@ function isFlowSurfaceChartRepairError(error) {
229
231
  var _a, _b;
230
232
  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
233
  }
234
+ const FLOW_SURFACE_EXPORT_BLUEPRINT_ROOT_ONLY_MESSAGE = "exportBlueprint v1 only supports root page export";
232
235
  const FORM_BLOCK_USES = /* @__PURE__ */ new Set(["FormBlockModel", "CreateFormModel", "EditFormModel", ...import_approval.APPROVAL_FORM_BLOCK_USES]);
233
236
  const AUTO_SUBMIT_FORM_BLOCK_USES = /* @__PURE__ */ new Set(["CreateFormModel", "EditFormModel"]);
234
237
  const FLOW_SURFACE_DEFAULT_ACTION_SETTINGS_KEYS = /* @__PURE__ */ new Set(["filter"]);
238
+ const ACTION_BUTTON_GENERAL_SETTING_KEYS = ["title", "tooltip", "icon", "iconOnly", "type", "danger", "color"];
235
239
  const DETAILS_BLOCK_USES = /* @__PURE__ */ new Set(["DetailsBlockModel", ...import_approval.APPROVAL_DETAILS_BLOCK_USES]);
236
240
  const SIMPLE_FORM_BLOCK_USES = /* @__PURE__ */ new Set([
237
241
  "FormBlockModel",
@@ -685,6 +689,8 @@ function assertNoFlowSurfaceIdTitleFieldSettings(value, options = {}) {
685
689
  };
686
690
  visit(value, options.basePath || []);
687
691
  }
692
+ const DEFAULT_ADMIN_UI_LAYOUT_UID = "admin-layout-model";
693
+ const MOBILE_UI_LAYOUT_TYPE = "mobile";
688
694
  class FlowSurfacesService {
689
695
  constructor(plugin) {
690
696
  this.plugin = plugin;
@@ -918,12 +924,12 @@ class FlowSurfacesService {
918
924
  transaction
919
925
  });
920
926
  }
921
- async findMenuGroupRoutesByTitle(title, transaction) {
927
+ async findMenuGroupRoutesByTitle(title, transaction, layoutUid) {
922
928
  const normalizedTitle = String(title || "").trim();
923
929
  if (!normalizedTitle) {
924
930
  return [];
925
931
  }
926
- return import_lodash.default.castArray(
932
+ const routes = import_lodash.default.castArray(
927
933
  await this.db.getRepository("desktopRoutes").find({
928
934
  filter: {
929
935
  type: "group",
@@ -932,6 +938,18 @@ class FlowSurfacesService {
932
938
  transaction
933
939
  })
934
940
  );
941
+ const layoutUidFilter = await this.resolveDesktopRouteLayoutUidFilter(layoutUid, transaction);
942
+ if (!layoutUidFilter.length || !this.hasDesktopRouteUiLayoutsRelation()) {
943
+ return routes;
944
+ }
945
+ const matchedRoutes = [];
946
+ for (const route of routes) {
947
+ const routeLayoutUids = await this.readDesktopRouteUiLayoutUids(this.readRouteField(route, "id"), transaction);
948
+ if (import_lodash.default.intersection(routeLayoutUids, layoutUidFilter).length) {
949
+ matchedRoutes.push(route);
950
+ }
951
+ }
952
+ return matchedRoutes;
935
953
  }
936
954
  routeParentIdMatches(routeParentId, parentId) {
937
955
  if (import_lodash.default.isNil(routeParentId) && import_lodash.default.isNil(parentId)) {
@@ -939,28 +957,42 @@ class FlowSurfacesService {
939
957
  }
940
958
  return String(routeParentId ?? "") === String(parentId ?? "");
941
959
  }
942
- async findMenuGroupRoutesByParentIdAndTitle(parentId, title, transaction) {
943
- const routes = await this.findMenuGroupRoutesByTitle(title, transaction);
960
+ async findMenuGroupRoutesByParentIdAndTitle(parentId, title, transaction, layoutUid) {
961
+ const routes = await this.findMenuGroupRoutesByTitle(title, transaction, layoutUid);
944
962
  return routes.filter(
945
963
  (route) => this.routeParentIdMatches(this.readRouteField(route, "parentId") ?? null, parentId)
946
964
  );
947
965
  }
948
- async findFlowPageRoutesByParentIdAndTitle(parentId, title, transaction) {
966
+ async findFlowPageRoutesByParentIdAndTitle(parentId, title, transaction, layoutUid) {
949
967
  const normalizedTitle = String(title || "").trim();
950
- const normalizedParentId = String(parentId ?? "").trim();
951
- if (!normalizedTitle || !normalizedParentId) {
968
+ if (!normalizedTitle) {
952
969
  return [];
953
970
  }
954
- return import_lodash.default.castArray(
971
+ const routes = import_lodash.default.castArray(
955
972
  await this.db.getRepository("desktopRoutes").find({
956
- filter: {
973
+ filter: (0, import_service_utils.buildDefinedPayload)({
957
974
  type: "flowPage",
958
975
  title: normalizedTitle,
959
- parentId: normalizedParentId
960
- },
976
+ parentId: import_lodash.default.isNil(parentId) ? void 0 : String(parentId)
977
+ }),
961
978
  transaction
962
979
  })
963
980
  );
981
+ const layoutUidFilter = await this.resolveDesktopRouteLayoutUidFilter(layoutUid, transaction);
982
+ const layoutMatchedRoutes = [];
983
+ if (!layoutUidFilter.length || !this.hasDesktopRouteUiLayoutsRelation()) {
984
+ layoutMatchedRoutes.push(...routes);
985
+ } else {
986
+ for (const route of routes) {
987
+ const routeLayoutUids = await this.readDesktopRouteUiLayoutUids(this.readRouteField(route, "id"), transaction);
988
+ if (import_lodash.default.intersection(routeLayoutUids, layoutUidFilter).length) {
989
+ layoutMatchedRoutes.push(route);
990
+ }
991
+ }
992
+ }
993
+ return layoutMatchedRoutes.filter(
994
+ (route) => this.routeParentIdMatches(this.readRouteField(route, "parentId") ?? null, parentId)
995
+ );
964
996
  }
965
997
  async assertMenuParentIsGroup(parentMenuRouteId, transaction) {
966
998
  if (import_lodash.default.isNil(parentMenuRouteId)) {
@@ -1026,6 +1058,204 @@ class FlowSurfacesService {
1026
1058
  ...extras
1027
1059
  };
1028
1060
  }
1061
+ hasDesktopRouteUiLayoutsRelation() {
1062
+ var _a, _b;
1063
+ try {
1064
+ return !!this.db.getCollection("uiLayouts") && !!((_b = (_a = this.db.getCollection("desktopRoutes")) == null ? void 0 : _a.getField) == null ? void 0 : _b.call(_a, "uiLayouts"));
1065
+ } catch (error) {
1066
+ return false;
1067
+ }
1068
+ }
1069
+ normalizeDesktopRouteRelationId(routeId) {
1070
+ return import_lodash.default.isNil(routeId) ? void 0 : routeId;
1071
+ }
1072
+ async readDesktopRouteUiLayoutUids(routeId, transaction) {
1073
+ const relationRouteId = this.normalizeDesktopRouteRelationId(routeId);
1074
+ if (import_lodash.default.isUndefined(relationRouteId) || !this.hasDesktopRouteUiLayoutsRelation()) {
1075
+ return [];
1076
+ }
1077
+ const uiLayouts = await this.db.getRepository("desktopRoutes.uiLayouts", relationRouteId).find({
1078
+ fields: ["uid"],
1079
+ transaction
1080
+ });
1081
+ return import_lodash.default.uniq(
1082
+ uiLayouts.map((uiLayout) => {
1083
+ var _a;
1084
+ return String(((_a = uiLayout == null ? void 0 : uiLayout.get) == null ? void 0 : _a.call(uiLayout, "uid")) || (uiLayout == null ? void 0 : uiLayout.uid) || "").trim();
1085
+ }).filter(Boolean)
1086
+ );
1087
+ }
1088
+ async resolveDefaultDesktopRouteUiLayoutUids(transaction) {
1089
+ if (!this.hasDesktopRouteUiLayoutsRelation()) {
1090
+ return [];
1091
+ }
1092
+ const defaultLayout = await this.db.getRepository("uiLayouts").findOne({
1093
+ filter: {
1094
+ uid: DEFAULT_ADMIN_UI_LAYOUT_UID,
1095
+ enabled: true
1096
+ },
1097
+ transaction
1098
+ });
1099
+ return defaultLayout ? [DEFAULT_ADMIN_UI_LAYOUT_UID] : [];
1100
+ }
1101
+ async findDesktopRouteUiLayoutByUid(layoutUid, transaction) {
1102
+ const normalizedLayoutUid = this.normalizeExplicitDesktopRouteLayoutUid(layoutUid);
1103
+ if (!normalizedLayoutUid || !this.hasDesktopRouteUiLayoutsRelation()) {
1104
+ return null;
1105
+ }
1106
+ return this.db.getRepository("uiLayouts").findOne({
1107
+ filter: {
1108
+ uid: normalizedLayoutUid
1109
+ },
1110
+ transaction
1111
+ });
1112
+ }
1113
+ async getDesktopRouteUiLayoutTypeByUid(layoutUid, transaction) {
1114
+ var _a;
1115
+ const uiLayout = await this.findDesktopRouteUiLayoutByUid(layoutUid, transaction);
1116
+ 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;
1117
+ }
1118
+ async isMobileDesktopRouteUiLayoutUid(layoutUid, transaction) {
1119
+ if (!layoutUid) {
1120
+ return false;
1121
+ }
1122
+ return await this.getDesktopRouteUiLayoutTypeByUid(layoutUid, transaction) === MOBILE_UI_LAYOUT_TYPE;
1123
+ }
1124
+ async resolveInheritedDesktopRouteUiLayoutUids(parentRoute, transaction) {
1125
+ const parentRouteId = this.readRouteField(parentRoute, "id");
1126
+ if (!import_lodash.default.isNil(parentRouteId)) {
1127
+ const parentLayoutUids = await this.readDesktopRouteUiLayoutUids(parentRouteId, transaction);
1128
+ if (parentLayoutUids.length) {
1129
+ return parentLayoutUids;
1130
+ }
1131
+ }
1132
+ return this.resolveDefaultDesktopRouteUiLayoutUids(transaction);
1133
+ }
1134
+ normalizeExplicitDesktopRouteLayoutUid(value) {
1135
+ const normalized = String(value || "").trim();
1136
+ return normalized || void 0;
1137
+ }
1138
+ normalizeDesktopRouteLayoutUidFilter(value) {
1139
+ return import_lodash.default.uniq(
1140
+ import_lodash.default.castArray(value).map((item) => this.normalizeExplicitDesktopRouteLayoutUid(item)).filter(Boolean)
1141
+ );
1142
+ }
1143
+ async resolveDesktopRouteLayoutUidFilter(value, transaction) {
1144
+ const explicitLayoutUids = this.normalizeDesktopRouteLayoutUidFilter(value);
1145
+ if (explicitLayoutUids.length) {
1146
+ return explicitLayoutUids;
1147
+ }
1148
+ return this.resolveDefaultDesktopRouteUiLayoutUids(transaction);
1149
+ }
1150
+ async assertEnabledDesktopRouteUiLayoutUid(layoutUid, actionName, path, transaction) {
1151
+ if (!this.hasDesktopRouteUiLayoutsRelation()) {
1152
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} ${path} requires plugin-ui-layout desktop route relation support`, {
1153
+ ruleId: "navigation-layout-unsupported",
1154
+ path,
1155
+ details: {
1156
+ layoutUid
1157
+ }
1158
+ });
1159
+ }
1160
+ const uiLayout = await this.db.getRepository("uiLayouts").findOne({
1161
+ filter: {
1162
+ uid: layoutUid,
1163
+ enabled: true
1164
+ },
1165
+ transaction
1166
+ });
1167
+ if (!uiLayout) {
1168
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} ${path} must reference an enabled ui layout`, {
1169
+ ruleId: "navigation-layout-not-found",
1170
+ path,
1171
+ details: {
1172
+ layoutUid
1173
+ }
1174
+ });
1175
+ }
1176
+ }
1177
+ async assertDesktopRouteBelongsToUiLayout(actionName, route, layoutUid, path, transaction) {
1178
+ const normalizedLayoutUid = this.normalizeExplicitDesktopRouteLayoutUid(layoutUid);
1179
+ if (!normalizedLayoutUid || !route) {
1180
+ return;
1181
+ }
1182
+ const routeId = this.readRouteField(route, "id");
1183
+ const routeLayoutUids = await this.readDesktopRouteUiLayoutUids(routeId, transaction);
1184
+ if (routeLayoutUids.includes(normalizedLayoutUid)) {
1185
+ return;
1186
+ }
1187
+ (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} ${path} does not belong to ui layout '${normalizedLayoutUid}'`, {
1188
+ ruleId: "navigation-route-layout-mismatch",
1189
+ path,
1190
+ details: {
1191
+ routeId,
1192
+ layoutUid: normalizedLayoutUid,
1193
+ routeLayoutUids
1194
+ }
1195
+ });
1196
+ }
1197
+ async resolveRequestedDesktopRouteUiLayoutUids(values, parentRoute, actionName, transaction) {
1198
+ const layoutUid = this.normalizeExplicitDesktopRouteLayoutUid(values.layoutUid);
1199
+ if (layoutUid) {
1200
+ await this.assertEnabledDesktopRouteUiLayoutUid(layoutUid, actionName, "values.layoutUid", transaction);
1201
+ if (parentRoute) {
1202
+ await this.assertDesktopRouteBelongsToUiLayout(
1203
+ actionName,
1204
+ parentRoute,
1205
+ layoutUid,
1206
+ "values.parentMenuRouteId",
1207
+ transaction
1208
+ );
1209
+ }
1210
+ return [layoutUid];
1211
+ }
1212
+ return this.resolveInheritedDesktopRouteUiLayoutUids(parentRoute, transaction);
1213
+ }
1214
+ async setDesktopRouteUiLayouts(routeId, uiLayoutUids, transaction) {
1215
+ const relationRouteId = this.normalizeDesktopRouteRelationId(routeId);
1216
+ if (import_lodash.default.isUndefined(relationRouteId) || !uiLayoutUids.length || !this.hasDesktopRouteUiLayoutsRelation()) {
1217
+ return;
1218
+ }
1219
+ await this.db.getRepository("desktopRoutes.uiLayouts", relationRouteId).set({
1220
+ tk: uiLayoutUids,
1221
+ transaction
1222
+ });
1223
+ }
1224
+ async attachDesktopRouteUiLayoutsToRouteAndChildren(routeId, uiLayoutUids, transaction) {
1225
+ if (import_lodash.default.isNil(routeId) || !uiLayoutUids.length || !this.hasDesktopRouteUiLayoutsRelation()) {
1226
+ return;
1227
+ }
1228
+ await this.setDesktopRouteUiLayouts(routeId, uiLayoutUids, transaction);
1229
+ const children = await this.db.getRepository("desktopRoutes").find({
1230
+ fields: ["id"],
1231
+ filter: {
1232
+ parentId: routeId
1233
+ },
1234
+ transaction
1235
+ });
1236
+ for (const child of children) {
1237
+ await this.attachDesktopRouteUiLayoutsToRouteAndChildren(
1238
+ this.readRouteField(child, "id"),
1239
+ uiLayoutUids,
1240
+ transaction
1241
+ );
1242
+ }
1243
+ }
1244
+ async ensureDesktopRouteUiLayouts(route, transaction) {
1245
+ const routeId = this.readRouteField(route, "id");
1246
+ if (import_lodash.default.isNil(routeId) || !this.hasDesktopRouteUiLayoutsRelation()) {
1247
+ return [];
1248
+ }
1249
+ const existingLayoutUids = await this.readDesktopRouteUiLayoutUids(routeId, transaction);
1250
+ if (existingLayoutUids.length) {
1251
+ return existingLayoutUids;
1252
+ }
1253
+ const parentRouteId = this.readRouteField(route, "parentId");
1254
+ const parentRoute = import_lodash.default.isNil(parentRouteId) ? null : await this.findMenuRouteById(parentRouteId, transaction);
1255
+ const inheritedLayoutUids = await this.resolveInheritedDesktopRouteUiLayoutUids(parentRoute, transaction);
1256
+ await this.setDesktopRouteUiLayouts(routeId, inheritedLayoutUids, transaction);
1257
+ return inheritedLayoutUids;
1258
+ }
1029
1259
  isValidMenuIconName(value) {
1030
1260
  const normalized = String(value || "").trim();
1031
1261
  return !!normalized && ANT_DESIGN_ICON_NAMES.has(normalized);
@@ -1081,8 +1311,19 @@ class FlowSurfacesService {
1081
1311
  async createFlowMenuGroup(values, transaction) {
1082
1312
  const parentRoute = await this.assertMenuParentIsGroup(values.parentMenuRouteId, transaction);
1083
1313
  const parentId = this.readRouteField(parentRoute, "id") ?? null;
1314
+ const routeUiLayoutUids = await this.resolveRequestedDesktopRouteUiLayoutUids(
1315
+ values,
1316
+ parentRoute,
1317
+ "createMenu",
1318
+ transaction
1319
+ );
1084
1320
  const title = String(values.title || "").trim();
1085
- const existingGroups = await this.findMenuGroupRoutesByParentIdAndTitle(parentId, title, transaction);
1321
+ const existingGroups = await this.findMenuGroupRoutesByParentIdAndTitle(
1322
+ parentId,
1323
+ title,
1324
+ transaction,
1325
+ routeUiLayoutUids
1326
+ );
1086
1327
  if (existingGroups.length === 1) {
1087
1328
  return this.buildMenuResult(existingGroups[0]);
1088
1329
  }
@@ -1107,7 +1348,7 @@ class FlowSurfacesService {
1107
1348
  this.assertVisibleNavigationIcon("createMenu", "values", values);
1108
1349
  const schemaUid = values.schemaUid || (0, import_utils.uid)();
1109
1350
  const desktopRoutes = this.db.getRepository("desktopRoutes");
1110
- await desktopRoutes.create({
1351
+ const route = await desktopRoutes.create({
1111
1352
  values: {
1112
1353
  type: "group",
1113
1354
  sort: this.allocateRouteSortValue(),
@@ -1120,15 +1361,22 @@ class FlowSurfacesService {
1120
1361
  },
1121
1362
  transaction
1122
1363
  });
1123
- const route = await desktopRoutes.findOne({
1124
- filter: { schemaUid },
1364
+ await this.attachDesktopRouteUiLayoutsToRouteAndChildren(
1365
+ this.readRouteField(route, "id"),
1366
+ routeUiLayoutUids,
1125
1367
  transaction
1126
- });
1368
+ );
1127
1369
  return this.buildMenuResult(route);
1128
1370
  }
1129
1371
  async createFlowMenuItem(values, transaction) {
1130
1372
  var _a;
1131
1373
  const parentRoute = await this.assertMenuParentIsGroup(values.parentMenuRouteId, transaction);
1374
+ const routeUiLayoutUids = await this.resolveRequestedDesktopRouteUiLayoutUids(
1375
+ values,
1376
+ parentRoute,
1377
+ "createMenu",
1378
+ transaction
1379
+ );
1132
1380
  this.assertVisibleNavigationIcon("createMenu", "values", values);
1133
1381
  const pageSchemaUid = values.pageSchemaUid || (0, import_utils.uid)();
1134
1382
  const menuSchemaUid = (0, import_utils.uid)();
@@ -1138,7 +1386,7 @@ class FlowSurfacesService {
1138
1386
  const title = values.title || pageSchemaUid;
1139
1387
  const tabTitle = values.tabTitle || "Untitled";
1140
1388
  const desktopRoutes = this.db.getRepository("desktopRoutes");
1141
- await desktopRoutes.create({
1389
+ const createdRoute = await desktopRoutes.create({
1142
1390
  values: {
1143
1391
  type: "flowPage",
1144
1392
  sort: this.allocateRouteSortValue(),
@@ -1173,6 +1421,11 @@ class FlowSurfacesService {
1173
1421
  },
1174
1422
  transaction
1175
1423
  });
1424
+ await this.attachDesktopRouteUiLayoutsToRouteAndChildren(
1425
+ this.readRouteField(createdRoute, "id"),
1426
+ routeUiLayoutUids,
1427
+ transaction
1428
+ );
1176
1429
  const route = await desktopRoutes.findOne({
1177
1430
  filter: { schemaUid: pageSchemaUid },
1178
1431
  appends: ["children"],
@@ -1207,7 +1460,7 @@ class FlowSurfacesService {
1207
1460
  });
1208
1461
  }
1209
1462
  sanitizePublicCreateMenuValues(values) {
1210
- return import_lodash.default.pick(values, ["title", "type", "icon", "tooltip", "hideInMenu", "parentMenuRouteId"]);
1463
+ return import_lodash.default.pick(values, ["title", "type", "layoutUid", "icon", "tooltip", "hideInMenu", "parentMenuRouteId"]);
1211
1464
  }
1212
1465
  async loadRouteBackedPageStructure(route, transaction) {
1213
1466
  const routeId = this.readRouteField(route, "id");
@@ -1581,7 +1834,7 @@ class FlowSurfacesService {
1581
1834
  return !blockScenes.some((scene) => this.isPopupCollectionBlockSceneUnsupported(scene));
1582
1835
  }
1583
1836
  resolveFieldAssociationContextFromBinding(input) {
1584
- var _a;
1837
+ var _a, _b;
1585
1838
  const parsed = this.parseFieldPath(
1586
1839
  input.collection,
1587
1840
  input.fieldPath,
@@ -1598,13 +1851,14 @@ class FlowSurfacesService {
1598
1851
  );
1599
1852
  const targetCollection = (associationField ? resolveTargetCollection(associationField) || (associationField == null ? void 0 : associationField.targetCollection) : null) || resolveTargetCollection(leafField) || (leafField == null ? void 0 : leafField.targetCollection) || null;
1600
1853
  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;
1854
+ const fallbackAssociationName = parsed.associationPathName ? `${parsed.collectionName}.${parsed.associationPathName}` : void 0;
1855
+ const associationName = associationField ? ((_a = parsed.associationPathName) == null ? void 0 : _a.includes(".")) ? fallbackAssociationName : (0, import_service_helpers.resolveAssociationNameFromField)(associationField, input.collection) : void 0;
1602
1856
  return {
1603
1857
  associationField,
1604
1858
  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,
1859
+ dataSourceKey: (targetCollection == null ? void 0 : targetCollection.dataSourceKey) || ((_b = targetCollection == null ? void 0 : targetCollection.options) == null ? void 0 : _b.dataSourceKey) || parsed.dataSourceKey || input.dataSourceKey,
1606
1860
  collectionName: targetCollectionName,
1607
- associationName
1861
+ associationName: associationName || fallbackAssociationName
1608
1862
  };
1609
1863
  }
1610
1864
  async resolvePopupHostFieldAssociationContext(hostNode, transaction) {
@@ -1945,6 +2199,9 @@ class FlowSurfacesService {
1945
2199
  if (!(popupProfile == null ? void 0 : popupProfile.currentCollection)) {
1946
2200
  return popupProfile == null ? void 0 : popupProfile.filterByTk;
1947
2201
  }
2202
+ if (popupProfile.popupKind === "recordPopup" && popupProfile.popupHostUse && POPUP_HOST_DEFAULT_RECORD_CONTEXT_ACTION_USES.has(popupProfile.popupHostUse)) {
2203
+ return "{{ctx.view.inputArgs.filterByTk}}";
2204
+ }
1948
2205
  if (popupProfile.popupKind !== "associationPopup") {
1949
2206
  return popupProfile.filterByTk;
1950
2207
  }
@@ -2300,10 +2557,18 @@ class FlowSurfacesService {
2300
2557
  if (!sameCurrentCollection || !(0, import_service_helpers.hasConfiguredFlowContextValue)(normalized.filterByTk)) {
2301
2558
  return false;
2302
2559
  }
2560
+ const expectedFilterByTk = this.resolvePopupCurrentRecordResourceFilterByTk(input.popupProfile, {
2561
+ usePopupInputArgsWhenSourceIdInferred: true
2562
+ });
2563
+ const matchesCurrentRecordFilterByTk = this.isPopupCurrentRecordFilterByTkMatch(
2564
+ input.popupProfile,
2565
+ normalized.filterByTk,
2566
+ expectedFilterByTk
2567
+ );
2303
2568
  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);
2569
+ return matchesCurrentRecordFilterByTk && normalized.associationName === input.popupProfile.associationName && this.isSameConfiguredFlowContextValue(normalized.sourceId, input.popupProfile.sourceId);
2305
2570
  }
2306
- return this.isSameConfiguredFlowContextValue(normalized.filterByTk, input.popupProfile.filterByTk) && !(0, import_service_helpers.hasConfiguredFlowContextValue)(normalized.associationName) && !(0, import_service_helpers.hasConfiguredFlowContextValue)(normalized.sourceId);
2571
+ return matchesCurrentRecordFilterByTk && !(0, import_service_helpers.hasConfiguredFlowContextValue)(normalized.associationName) && !(0, import_service_helpers.hasConfiguredFlowContextValue)(normalized.sourceId);
2307
2572
  }
2308
2573
  if (input.binding === "associatedRecords") {
2309
2574
  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 +2611,12 @@ class FlowSurfacesService {
2346
2611
  }
2347
2612
  return import_lodash.default.isEqual(this.normalizeFlowContextTemplateValue(left), this.normalizeFlowContextTemplateValue(right));
2348
2613
  }
2614
+ isPopupCurrentRecordFilterByTkMatch(popupProfile, filterByTk, expectedFilterByTk) {
2615
+ if (this.isSameConfiguredFlowContextValue(filterByTk, expectedFilterByTk)) {
2616
+ return true;
2617
+ }
2618
+ return popupProfile.popupKind === "associationPopup" && this.isSameConfiguredFlowContextValue(filterByTk, popupProfile.filterByTk);
2619
+ }
2349
2620
  isPopupAssociatedRecordsSourceIdMatch(popupProfile, associationField, sourceId) {
2350
2621
  var _a, _b;
2351
2622
  if (!(0, import_service_helpers.hasConfiguredFlowContextValue)(sourceId)) {
@@ -2621,6 +2892,28 @@ class FlowSurfacesService {
2621
2892
  }
2622
2893
  return capability;
2623
2894
  }
2895
+ async getLiveFieldValueCapability(writeTarget, resolvedTarget, node, options = {}) {
2896
+ const context = await this.context(
2897
+ {
2898
+ target: writeTarget
2899
+ },
2900
+ options
2901
+ );
2902
+ const { capabilities } = (0, import_meta.buildReactionMetaCapabilities)({
2903
+ resolvedTarget: {
2904
+ ...resolvedTarget,
2905
+ node
2906
+ },
2907
+ context
2908
+ });
2909
+ const capability = capabilities.find((item) => item.kind === "fieldValue");
2910
+ if (!capability) {
2911
+ (0, import_errors.throwBadRequest)(
2912
+ `flowSurfaces reaction target '${resolvedTarget.use || resolvedTarget.target.uid}' does not support fieldValue`
2913
+ );
2914
+ }
2915
+ return capability;
2916
+ }
2624
2917
  async getReactionMeta(values, options = {}) {
2625
2918
  (0, import_payload_shape.validateFlowSurfacePayloadShape)("getReactionMeta", values, "values");
2626
2919
  const { writeTarget, node, resolvedTarget } = await this.resolveReactionRequest("getReactionMeta", values == null ? void 0 : values.target, {
@@ -2666,6 +2959,8 @@ class FlowSurfacesService {
2666
2959
  },
2667
2960
  rules: Array.isArray(values == null ? void 0 : values.rules) ? values.rules : []
2668
2961
  });
2962
+ const liveCapability = await this.getLiveFieldValueCapability(writeTarget, resolvedTarget, node, options);
2963
+ (0, import_field_value.validateFieldValueRulesAgainstCapability)(result.normalizedRules, liveCapability);
2669
2964
  await this.persistReactionSlot(storageNode, capability.resolvedSlot, result.canonicalRules, options);
2670
2965
  return result;
2671
2966
  }
@@ -2873,6 +3168,41 @@ class FlowSurfacesService {
2873
3168
  const publicNode = this.stripInternalSurfaceMetaFromNodeTree(import_lodash.default.cloneDeep(rawNode));
2874
3169
  return this.buildSurfaceReadPayload(target, resolved, publicNode, options);
2875
3170
  }
3171
+ async exportBlueprint(input, options = {}) {
3172
+ const request = this.normalizeExportBlueprintRequest(input);
3173
+ const resolved = await this.locator.resolve(request.target, options);
3174
+ if (resolved.kind !== "page" || !resolved.pageRoute) {
3175
+ (0, import_errors.throwBadRequest)(FLOW_SURFACE_EXPORT_BLUEPRINT_ROOT_ONLY_MESSAGE);
3176
+ }
3177
+ const pageSchemaUid = this.resolveExportBlueprintPageSchemaUid(request.target, resolved);
3178
+ await this.assertExportBlueprintRootTarget(request.target, resolved, pageSchemaUid, options.transaction);
3179
+ const rawNode = await this.decorateTemplateReadbackTree(
3180
+ this.normalizePopupTreeShape(
3181
+ await this.loadResolvedNode(resolved, options.transaction, {
3182
+ persistCalendarPopupHosts: false
3183
+ })
3184
+ ),
3185
+ options.transaction
3186
+ );
3187
+ if (!(rawNode == null ? void 0 : rawNode.uid)) {
3188
+ (0, import_errors.throwBadRequest)(`flowSurfaces exportBlueprint target '${pageSchemaUid}' could not resolve a readable page tree`);
3189
+ }
3190
+ const pageRoute = resolved.pageRoute ? await this.routeSync.hydrateRoute(resolved.pageRoute, options.transaction) : void 0;
3191
+ const result = (0, import_export_document.exportFlowSurfaceBlueprintDocument)({
3192
+ page: rawNode,
3193
+ pageRoute,
3194
+ target: {
3195
+ pageSchemaUid
3196
+ },
3197
+ unsupportedPolicy: request.unsupportedPolicy
3198
+ });
3199
+ return {
3200
+ ...result,
3201
+ document: (0, import_blueprint.prepareFlowSurfaceApplyBlueprintDocument)(
3202
+ result.document
3203
+ )
3204
+ };
3205
+ }
2876
3206
  getDeclaredKeyPersistenceDeps() {
2877
3207
  return {
2878
3208
  findModelById: (uid2, findOptions) => this.repository.findModelById(uid2, findOptions),
@@ -3041,7 +3371,13 @@ class FlowSurfacesService {
3041
3371
  if (!groupTitle) {
3042
3372
  return document;
3043
3373
  }
3044
- const matchedRoutes = await this.findMenuGroupRoutesByParentIdAndTitle(null, groupTitle, transaction);
3374
+ const layoutUid = this.normalizeExplicitDesktopRouteLayoutUid(document.navigation.layoutUid);
3375
+ const matchedRoutes = await this.findMenuGroupRoutesByParentIdAndTitle(
3376
+ null,
3377
+ groupTitle,
3378
+ transaction,
3379
+ layoutUid || await this.resolveDefaultDesktopRouteUiLayoutUids(transaction)
3380
+ );
3045
3381
  if (!matchedRoutes.length) {
3046
3382
  return document;
3047
3383
  }
@@ -3066,29 +3402,89 @@ class FlowSurfacesService {
3066
3402
  }
3067
3403
  };
3068
3404
  }
3405
+ async normalizeApplyBlueprintCreateMobileNavigation(document, transaction) {
3406
+ var _a;
3407
+ if (document.mode !== "create") {
3408
+ return document;
3409
+ }
3410
+ const layoutUid = this.normalizeExplicitDesktopRouteLayoutUid((_a = document.navigation) == null ? void 0 : _a.layoutUid);
3411
+ if (!await this.isMobileDesktopRouteUiLayoutUid(layoutUid, transaction)) {
3412
+ return document;
3413
+ }
3414
+ return {
3415
+ ...document,
3416
+ navigation: (0, import_service_utils.buildDefinedPayload)({
3417
+ ...document.navigation,
3418
+ layoutUid,
3419
+ group: void 0
3420
+ })
3421
+ };
3422
+ }
3423
+ async assertApplyBlueprintCreateNavigationLayout(document, transaction) {
3424
+ var _a, _b, _c;
3425
+ if (document.mode !== "create") {
3426
+ return;
3427
+ }
3428
+ const layoutUid = this.normalizeExplicitDesktopRouteLayoutUid((_a = document.navigation) == null ? void 0 : _a.layoutUid);
3429
+ if (!layoutUid) {
3430
+ return;
3431
+ }
3432
+ await this.assertEnabledDesktopRouteUiLayoutUid(
3433
+ layoutUid,
3434
+ "applyBlueprint",
3435
+ "values.navigation.layoutUid",
3436
+ transaction
3437
+ );
3438
+ if (await this.isMobileDesktopRouteUiLayoutUid(layoutUid, transaction)) {
3439
+ return;
3440
+ }
3441
+ const groupRouteId = (_c = (_b = document.navigation) == null ? void 0 : _b.group) == null ? void 0 : _c.routeId;
3442
+ if (import_lodash.default.isNil(groupRouteId) || groupRouteId === "") {
3443
+ return;
3444
+ }
3445
+ const groupRoute = await this.assertMenuParentIsGroup(groupRouteId, transaction);
3446
+ await this.assertDesktopRouteBelongsToUiLayout(
3447
+ "applyBlueprint",
3448
+ groupRoute,
3449
+ layoutUid,
3450
+ "values.navigation.group.routeId",
3451
+ transaction
3452
+ );
3453
+ }
3069
3454
  async resolveApplyBlueprintCreatePageIdentity(document, transaction) {
3070
- var _a, _b, _c, _d, _e;
3455
+ var _a, _b, _c, _d, _e, _f;
3071
3456
  if (document.mode !== "create") {
3072
3457
  return document;
3073
3458
  }
3074
3459
  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) {
3460
+ const layoutUid = this.normalizeExplicitDesktopRouteLayoutUid((_c = document.navigation) == null ? void 0 : _c.layoutUid);
3461
+ const pageTitle = String(((_d = document.page) == null ? void 0 : _d.title) || ((_f = (_e = document.navigation) == null ? void 0 : _e.item) == null ? void 0 : _f.title) || "").trim();
3462
+ const hasGroupRouteId = !import_lodash.default.isNil(groupRouteId) && groupRouteId !== "";
3463
+ if (!pageTitle || !hasGroupRouteId && !layoutUid) {
3077
3464
  return document;
3078
3465
  }
3079
- const matchedPages = await this.findFlowPageRoutesByParentIdAndTitle(groupRouteId, pageTitle, transaction);
3466
+ const groupRoute = hasGroupRouteId ? await this.findMenuRouteById(groupRouteId, transaction) : null;
3467
+ const layoutUidFilter = layoutUid || (groupRoute ? await this.resolveInheritedDesktopRouteUiLayoutUids(groupRoute, transaction) : void 0);
3468
+ const matchedPages = await this.findFlowPageRoutesByParentIdAndTitle(
3469
+ hasGroupRouteId ? groupRouteId : null,
3470
+ pageTitle,
3471
+ transaction,
3472
+ layoutUidFilter
3473
+ );
3080
3474
  if (!matchedPages.length) {
3081
3475
  return document;
3082
3476
  }
3083
3477
  if (matchedPages.length > 1) {
3478
+ const locationLabel = hasGroupRouteId ? `under navigation.group.routeId '${groupRouteId}'` : `at the root of ui layout '${layoutUid}'`;
3084
3479
  (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`
3480
+ `flowSurfaces applyBlueprint ${locationLabel} already has ${matchedPages.length} flow pages titled '${pageTitle}'; pass target.pageSchemaUid explicitly before applyBlueprint`
3086
3481
  );
3087
3482
  }
3088
3483
  const pageSchemaUid = String(this.readRouteField(matchedPages[0], "schemaUid") || "").trim();
3089
3484
  if (!pageSchemaUid) {
3485
+ const locationLabel = hasGroupRouteId ? `under navigation.group.routeId '${groupRouteId}'` : `at the root of ui layout '${layoutUid}'`;
3090
3486
  (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`
3487
+ `flowSurfaces applyBlueprint existing flow page '${pageTitle}' ${locationLabel} is missing schemaUid; pass target.pageSchemaUid explicitly before applyBlueprint`
3092
3488
  );
3093
3489
  }
3094
3490
  return {
@@ -3103,7 +3499,15 @@ class FlowSurfacesService {
3103
3499
  async prepareApplyBlueprintRequest(values, transaction, createdKanbanSortFields) {
3104
3500
  var _a;
3105
3501
  const initialDocument = (0, import_blueprint.prepareFlowSurfaceApplyBlueprintDocument)(values);
3106
- const groupResolvedDocument = await this.resolveApplyBlueprintCreateNavigationGroup(initialDocument, transaction);
3502
+ await this.assertApplyBlueprintCreateNavigationLayout(initialDocument, transaction);
3503
+ const mobileNormalizedDocument = await this.normalizeApplyBlueprintCreateMobileNavigation(
3504
+ initialDocument,
3505
+ transaction
3506
+ );
3507
+ const groupResolvedDocument = await this.resolveApplyBlueprintCreateNavigationGroup(
3508
+ mobileNormalizedDocument,
3509
+ transaction
3510
+ );
3107
3511
  const document = await this.resolveApplyBlueprintCreatePageIdentity(groupResolvedDocument, transaction);
3108
3512
  await this.prepareApplyBlueprintKanbanBlocks(document, transaction, createdKanbanSortFields);
3109
3513
  const replaceTarget = document.mode === "replace" && document.target ? await this.resolveApplyBlueprintReplaceTargetInfo(document.target.pageSchemaUid, transaction) : void 0;
@@ -3760,7 +4164,8 @@ class FlowSurfacesService {
3760
4164
  await (0, import_authoring_validation.assertFlowSurfaceAuthoringPayload)("applyBlueprint", values, {
3761
4165
  transaction: options.transaction,
3762
4166
  enabledPackages,
3763
- findMenuGroupRoutesByTitle: (title, transaction) => this.findMenuGroupRoutesByTitle(title, transaction),
4167
+ findMenuGroupRoutesByTitle: (title, transaction, layoutUid) => this.findMenuGroupRoutesByTitle(title, transaction, layoutUid),
4168
+ getUiLayoutTypeByUid: (layoutUid, transaction) => this.getDesktopRouteUiLayoutTypeByUid(layoutUid, transaction),
3764
4169
  getCollection: (dataSourceKey, collectionName) => this.getCollection(dataSourceKey || "main", collectionName || "")
3765
4170
  });
3766
4171
  }
@@ -4399,6 +4804,7 @@ class FlowSurfacesService {
4399
4804
  );
4400
4805
  }
4401
4806
  const popupProfile = await this.resolvePopupBlockProfile(node.uid, null, node, transaction).catch(() => null);
4807
+ const sourceId = String(openView.sourceId || "").trim() || ((popupProfile == null ? void 0 : popupProfile.sourceIdInferred) ? "" : String((popupProfile == null ? void 0 : popupProfile.sourceId) || "").trim()) || void 0;
4402
4808
  const popupSourceNode = popupTargetUid ? await this.repository.findModelById(popupTargetUid, {
4403
4809
  transaction,
4404
4810
  includeAsyncNode: true
@@ -4412,7 +4818,7 @@ class FlowSurfacesService {
4412
4818
  collectionName: String(openView.collectionName || "").trim() || String((popupProfile == null ? void 0 : popupProfile.collectionName) || "").trim() || void 0,
4413
4819
  associationName: String(openView.associationName || "").trim() || String((popupProfile == null ? void 0 : popupProfile.associationName) || "").trim() || void 0,
4414
4820
  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,
4821
+ sourceId,
4416
4822
  openViewStep
4417
4823
  };
4418
4824
  }
@@ -4474,10 +4880,16 @@ class FlowSurfacesService {
4474
4880
  return this.buildPopupTemplateOpenView(template, "reference", templateTargetUid, options);
4475
4881
  }
4476
4882
  shouldHydrateDetachedPopupTemplateBlockResourceContext(blockNode, context) {
4477
- if (!this.isCollectionBlockUse(blockNode == null ? void 0 : blockNode.use) || !context.associationName || !context.sourceId) {
4883
+ if (!this.isCollectionBlockUse(blockNode == null ? void 0 : blockNode.use)) {
4478
4884
  return false;
4479
4885
  }
4480
4886
  const init = import_lodash.default.get(blockNode, ["stepParams", "resourceSettings", "init"]) || {};
4887
+ if (this.resolveDetachedPopupTemplateBlockCurrentRecordFilterByTk(init, context)) {
4888
+ return true;
4889
+ }
4890
+ if (!context.associationName || !context.sourceId) {
4891
+ return false;
4892
+ }
4481
4893
  const popupDataSourceKey = context.dataSourceKey || "main";
4482
4894
  const blockDataSourceKey = init.dataSourceKey || "main";
4483
4895
  if (!context.collectionName || blockDataSourceKey !== popupDataSourceKey || init.collectionName !== context.collectionName) {
@@ -4492,6 +4904,28 @@ class FlowSurfacesService {
4492
4904
  }
4493
4905
  return blockAssociationName !== context.associationName || !this.isSameConfiguredFlowContextValue(init.sourceId, context.sourceId);
4494
4906
  }
4907
+ resolveDetachedPopupTemplateBlockCurrentRecordFilterByTk(init, context) {
4908
+ if (!(0, import_service_helpers.hasConfiguredFlowContextValue)(init.filterByTk)) {
4909
+ return void 0;
4910
+ }
4911
+ if (this.isSameConfiguredFlowContextValue(init.filterByTk, "{{ctx.view.inputArgs.filterByTk}}")) {
4912
+ return void 0;
4913
+ }
4914
+ const popupDataSourceKey = context.dataSourceKey || "main";
4915
+ const blockDataSourceKey = init.dataSourceKey || "main";
4916
+ if (!context.collectionName || blockDataSourceKey !== popupDataSourceKey || init.collectionName !== context.collectionName) {
4917
+ return void 0;
4918
+ }
4919
+ if (context.filterByTk && this.isSameConfiguredFlowContextValue(init.filterByTk, context.filterByTk)) {
4920
+ return "{{ctx.view.inputArgs.filterByTk}}";
4921
+ }
4922
+ const collection = this.getCollection(popupDataSourceKey, context.collectionName);
4923
+ const filterTargetKey = this.getCollectionFilterTargetKey(collection);
4924
+ if (this.isSameConfiguredFlowContextValue(init.filterByTk, `{{ctx.record.${filterTargetKey}}}`)) {
4925
+ return "{{ctx.view.inputArgs.filterByTk}}";
4926
+ }
4927
+ return void 0;
4928
+ }
4495
4929
  collectDetachedPopupTemplateBlockResourceContextPatches(node, context, patches = []) {
4496
4930
  if (!node || typeof node !== "object") {
4497
4931
  return patches;
@@ -4499,6 +4933,7 @@ class FlowSurfacesService {
4499
4933
  if (node.uid && this.shouldHydrateDetachedPopupTemplateBlockResourceContext(node, context)) {
4500
4934
  const nextStepParams = import_lodash.default.cloneDeep(node.stepParams || {});
4501
4935
  const currentInit = import_lodash.default.get(nextStepParams, ["resourceSettings", "init"]) || {};
4936
+ const filterByTk = this.resolveDetachedPopupTemplateBlockCurrentRecordFilterByTk(currentInit, context);
4502
4937
  import_lodash.default.set(
4503
4938
  nextStepParams,
4504
4939
  ["resourceSettings", "init"],
@@ -4506,8 +4941,11 @@ class FlowSurfacesService {
4506
4941
  ...currentInit,
4507
4942
  dataSourceKey: context.dataSourceKey || currentInit.dataSourceKey || "main",
4508
4943
  collectionName: context.collectionName || currentInit.collectionName,
4509
- associationName: context.associationName,
4510
- sourceId: context.sourceId
4944
+ ...context.associationName && context.sourceId ? {
4945
+ associationName: context.associationName,
4946
+ sourceId: context.sourceId
4947
+ } : {},
4948
+ ...filterByTk ? { filterByTk } : {}
4511
4949
  })
4512
4950
  );
4513
4951
  patches.push({
@@ -5767,7 +6205,7 @@ class FlowSurfacesService {
5767
6205
  (0, import_errors.throwBadRequest)("flowSurfaces updateMenu requires menuRouteId");
5768
6206
  }
5769
6207
  const route = await this.assertMenuRouteUpdatable(menuRouteId, options.transaction);
5770
- await this.assertMenuParentIsGroup(values.parentMenuRouteId, options.transaction);
6208
+ const nextParentRoute = await this.assertMenuParentIsGroup(values.parentMenuRouteId, options.transaction);
5771
6209
  await this.assertMenuParentNotSelfOrDescendant(route, values.parentMenuRouteId, options.transaction);
5772
6210
  const nextOptions = { ...this.readRouteOptions(route) };
5773
6211
  const updateValues = {};
@@ -5798,6 +6236,13 @@ class FlowSurfacesService {
5798
6236
  });
5799
6237
  }
5800
6238
  const updated = await this.findMenuRouteById(menuRouteId, options.transaction);
6239
+ if (updated && Object.prototype.hasOwnProperty.call(values, "parentMenuRouteId")) {
6240
+ await this.attachDesktopRouteUiLayoutsToRouteAndChildren(
6241
+ this.readRouteField(updated, "id"),
6242
+ await this.resolveInheritedDesktopRouteUiLayoutUids(nextParentRoute, options.transaction),
6243
+ options.transaction
6244
+ );
6245
+ }
5801
6246
  return this.buildMenuResult(updated);
5802
6247
  }
5803
6248
  async initializeFlowPageForRoute(route, values, transaction) {
@@ -5805,6 +6250,12 @@ class FlowSurfacesService {
5805
6250
  const pageSchemaUid = this.readRouteField(route, "schemaUid");
5806
6251
  const structure = await this.loadRouteBackedPageStructure(route, transaction);
5807
6252
  let tabRoute = structure.tabRoutes[0];
6253
+ const layoutUid = this.normalizeExplicitDesktopRouteLayoutUid(values.layoutUid);
6254
+ if (layoutUid) {
6255
+ await this.assertEnabledDesktopRouteUiLayoutUid(layoutUid, "createPage", "values.layoutUid", transaction);
6256
+ await this.assertDesktopRouteBelongsToUiLayout("createPage", route, layoutUid, "values.menuRouteId", transaction);
6257
+ }
6258
+ const routeUiLayoutUids = await this.ensureDesktopRouteUiLayouts(route, transaction);
5808
6259
  const routeOptions = this.readRouteOptions(route);
5809
6260
  if (!routeOptions[FLOW_SURFACE_MENU_BINDABLE_OPTION_KEY]) {
5810
6261
  (0, import_errors.throwBadRequest)(`flowSurfaces createPage only accepts a bindable menu route created by createMenu(type="item")`);
@@ -5826,7 +6277,7 @@ class FlowSurfacesService {
5826
6277
  const tabSchemaUid2 = values.tabSchemaUid || (0, import_utils.uid)();
5827
6278
  const tabSchemaName2 = values.tabSchemaName || (0, import_utils.uid)();
5828
6279
  const tabTitle = values.tabTitle || "Untitled";
5829
- await this.db.getRepository("desktopRoutes").create({
6280
+ tabRoute = await this.db.getRepository("desktopRoutes").create({
5830
6281
  values: {
5831
6282
  type: "tabs",
5832
6283
  sort: this.allocateRouteSortValue(1),
@@ -5843,10 +6294,7 @@ class FlowSurfacesService {
5843
6294
  },
5844
6295
  transaction
5845
6296
  });
5846
- tabRoute = await this.db.getRepository("desktopRoutes").findOne({
5847
- filter: { schemaUid: tabSchemaUid2 },
5848
- transaction
5849
- });
6297
+ await this.setDesktopRouteUiLayouts(this.readRouteField(tabRoute, "id"), routeUiLayoutUids, transaction);
5850
6298
  } else {
5851
6299
  await this.db.getRepository("desktopRoutes").update({
5852
6300
  filterByTk: String(this.readRouteField(tabRoute, "id")),
@@ -5870,6 +6318,9 @@ class FlowSurfacesService {
5870
6318
  transaction
5871
6319
  });
5872
6320
  }
6321
+ if (tabRoute) {
6322
+ await this.setDesktopRouteUiLayouts(this.readRouteField(tabRoute, "id"), routeUiLayoutUids, transaction);
6323
+ }
5873
6324
  await this.ensureFlowRoutePageSchemaShell(pageSchemaUid, transaction);
5874
6325
  await this.db.getRepository("desktopRoutes").update({
5875
6326
  filterByTk: String(routeId),
@@ -6009,6 +6460,11 @@ class FlowSurfacesService {
6009
6460
  },
6010
6461
  transaction: options.transaction
6011
6462
  });
6463
+ await this.setDesktopRouteUiLayouts(
6464
+ route.get("id"),
6465
+ await this.ensureDesktopRouteUiLayouts(pageRoute, options.transaction),
6466
+ options.transaction
6467
+ );
6012
6468
  const gridUid = await this.ensureGridChild(tabSchemaUid, "BlockGridModel", options.transaction);
6013
6469
  const result = {
6014
6470
  pageUid: pageTarget.uid,
@@ -6679,11 +7135,6 @@ class FlowSurfacesService {
6679
7135
  requiredFieldCount: options.requiredFieldCount
6680
7136
  }
6681
7137
  );
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
7138
  }
6688
7139
  return normalizedSettings;
6689
7140
  }
@@ -11417,6 +11868,7 @@ class FlowSurfacesService {
11417
11868
  }
11418
11869
  if (this.isAIEmployeeActionUse(current == null ? void 0 : current.use) && this.hasAIEmployeePublicSettings(normalizedValues)) {
11419
11870
  const enabledPackages = await this.resolveEnabledPluginPackages(options);
11871
+ const hasRawAIEmployeeStepTasks = import_lodash.default.has(normalizedValues, ["stepParams", ...AI_EMPLOYEE_TASK_STEP_PARAMS_PATH]);
11420
11872
  const aiEmployeeSettingsPayload = await this.normalizeAIEmployeeActionPublicSettings(
11421
11873
  "updateSettings",
11422
11874
  import_lodash.default.pick(normalizedValues, AI_EMPLOYEE_PUBLIC_SETTING_KEYS),
@@ -11429,7 +11881,8 @@ class FlowSurfacesService {
11429
11881
  promptContext: {
11430
11882
  kind: "target",
11431
11883
  targetUid: (current == null ? void 0 : current.uid) || writeTarget.uid
11432
- }
11884
+ },
11885
+ skipExistingTaskWorkContextRebase: hasRawAIEmployeeStepTasks
11433
11886
  }
11434
11887
  );
11435
11888
  AI_EMPLOYEE_PUBLIC_SETTING_KEYS.forEach((key) => {
@@ -11511,6 +11964,7 @@ class FlowSurfacesService {
11511
11964
  normalizedValues,
11512
11965
  nextPayload
11513
11966
  );
11967
+ this.syncActionButtonSettingsForUpdateSettings(current, normalizedValues, nextPayload);
11514
11968
  this.syncActionTriggerWorkflowsForUpdateSettings(current, normalizedValues, nextPayload);
11515
11969
  const popupActionContext = options.popupActionContext || await this.resolveRecordContextPopupActionContextForHost(current, options.transaction);
11516
11970
  await this.normalizeOpenViewForUpdateSettings(
@@ -11562,6 +12016,12 @@ class FlowSurfacesService {
11562
12016
  if (Object.keys(nextPayload).length === 1) {
11563
12017
  return { uid: current.uid };
11564
12018
  }
12019
+ await this.assertNoDuplicateAIEmployeeActionForUpdateSettings(
12020
+ options.openViewActionName || "updateSettings",
12021
+ current,
12022
+ effectiveNode,
12023
+ options.transaction
12024
+ );
11565
12025
  if (target.kind === "tab" && target.tabRoute) {
11566
12026
  await this.routeSync.persistTabSettings(target, current, nextPayload, options.transaction);
11567
12027
  return {
@@ -11972,17 +12432,6 @@ class FlowSurfacesService {
11972
12432
  const filterValue = this.normalizeEffectivePublicDataSurfaceDefaultFilter(normalizedFilterValue, {
11973
12433
  requiredFieldCount: options.requiredFieldCount
11974
12434
  });
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
12435
  nextProps.defaultFilterValue = import_lodash.default.cloneDeep(filterValue);
11987
12436
  nextProps.filterValue = import_lodash.default.cloneDeep(filterValue);
11988
12437
  import_lodash.default.set(nextStepParams, ["filterSettings", "defaultFilter", "defaultFilter"], import_lodash.default.cloneDeep(filterValue));
@@ -12029,6 +12478,65 @@ class FlowSurfacesService {
12029
12478
  nextPayload.stepParams = nextStepParams;
12030
12479
  }
12031
12480
  }
12481
+ syncActionButtonSettingsForUpdateSettings(current, normalizedValues, nextPayload) {
12482
+ if (!this.supportsActionButtonSettingsSync(current)) {
12483
+ return;
12484
+ }
12485
+ const requestedProps = this.pickRequestedActionButtonSettings(normalizedValues.props);
12486
+ const requestedButtonGeneral = this.pickRequestedActionButtonSettings(
12487
+ import_lodash.default.get(normalizedValues, ["stepParams", "buttonSettings", "general"])
12488
+ );
12489
+ const hasRequestedProps = Object.keys(requestedProps).length > 0;
12490
+ const hasRequestedButtonGeneral = Object.keys(requestedButtonGeneral).length > 0;
12491
+ if (!hasRequestedProps && !hasRequestedButtonGeneral) {
12492
+ return;
12493
+ }
12494
+ const hasRequestedTitle = Object.prototype.hasOwnProperty.call(requestedProps, "title") || Object.prototype.hasOwnProperty.call(requestedButtonGeneral, "title");
12495
+ const shouldStripImplicitTitle = (requestedProps.iconOnly === true || requestedButtonGeneral.iconOnly === true) && !hasRequestedTitle;
12496
+ const nextProps = import_lodash.default.cloneDeep(
12497
+ import_lodash.default.isPlainObject(nextPayload.props) ? nextPayload.props : import_lodash.default.isPlainObject(current == null ? void 0 : current.props) ? current.props : {}
12498
+ );
12499
+ const nextStepParams = import_lodash.default.cloneDeep(
12500
+ import_lodash.default.isPlainObject(nextPayload.stepParams) ? nextPayload.stepParams : import_lodash.default.isPlainObject(current == null ? void 0 : current.stepParams) ? current.stepParams : {}
12501
+ );
12502
+ Object.entries(requestedProps).forEach(([key, value]) => {
12503
+ if (Object.prototype.hasOwnProperty.call(requestedButtonGeneral, key)) {
12504
+ return;
12505
+ }
12506
+ import_lodash.default.set(nextStepParams, ["buttonSettings", "general", key], import_lodash.default.cloneDeep(value));
12507
+ });
12508
+ Object.entries(requestedButtonGeneral).forEach(([key, value]) => {
12509
+ if (Object.prototype.hasOwnProperty.call(requestedProps, key)) {
12510
+ return;
12511
+ }
12512
+ nextProps[key] = import_lodash.default.cloneDeep(value);
12513
+ });
12514
+ if (shouldStripImplicitTitle) {
12515
+ delete nextProps.title;
12516
+ if (import_lodash.default.isPlainObject(import_lodash.default.get(nextStepParams, ["buttonSettings", "general"]))) {
12517
+ delete nextStepParams.buttonSettings.general.title;
12518
+ }
12519
+ }
12520
+ nextPayload.props = nextProps;
12521
+ nextPayload.stepParams = nextStepParams;
12522
+ }
12523
+ supportsActionButtonSettingsSync(current) {
12524
+ var _a, _b, _c, _d, _e, _f;
12525
+ const contract = (0, import_catalog.getNodeContract)(current == null ? void 0 : current.use);
12526
+ 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"));
12527
+ }
12528
+ pickRequestedActionButtonSettings(input) {
12529
+ const picked = {};
12530
+ if (!import_lodash.default.isPlainObject(input)) {
12531
+ return picked;
12532
+ }
12533
+ ACTION_BUTTON_GENERAL_SETTING_KEYS.forEach((key) => {
12534
+ if (Object.prototype.hasOwnProperty.call(input, key) && !import_lodash.default.isUndefined(input[key])) {
12535
+ picked[key] = import_lodash.default.cloneDeep(input[key]);
12536
+ }
12537
+ });
12538
+ return picked;
12539
+ }
12032
12540
  syncCreatedFieldWrapperTitleFieldStepParams(node) {
12033
12541
  const mirror = (UPDATE_SETTINGS_STEP_PARAM_MIRRORS_BY_USE[(node == null ? void 0 : node.use) || ""] || []).find(
12034
12542
  (item) => item.domain === "props" && item.key === "titleField"
@@ -13694,6 +14202,111 @@ class FlowSurfacesService {
13694
14202
  }
13695
14203
  return target;
13696
14204
  }
14205
+ normalizeExportBlueprintRequest(input) {
14206
+ if (!import_lodash.default.isPlainObject(input)) {
14207
+ (0, import_errors.throwBadRequest)(`flowSurfaces exportBlueprint payload must be an object`);
14208
+ }
14209
+ const unsupportedKeys = Object.keys(input).filter((key) => key !== "target" && key !== "options");
14210
+ if (unsupportedKeys.length) {
14211
+ (0, import_errors.throwBadRequest)(`flowSurfaces exportBlueprint only accepts target and options`);
14212
+ }
14213
+ if (!import_lodash.default.isPlainObject(input.target)) {
14214
+ (0, import_errors.throwBadRequest)(`flowSurfaces exportBlueprint requires target`);
14215
+ }
14216
+ const targetInput = input.target;
14217
+ const target = (0, import_service_utils.buildDefinedPayload)({
14218
+ uid: this.normalizeExportBlueprintLocatorValue(targetInput.uid, "uid"),
14219
+ pageSchemaUid: this.normalizeExportBlueprintLocatorValue(targetInput.pageSchemaUid, "pageSchemaUid"),
14220
+ tabSchemaUid: this.normalizeExportBlueprintLocatorValue(targetInput.tabSchemaUid, "tabSchemaUid"),
14221
+ routeId: this.normalizeExportBlueprintLocatorValue(targetInput.routeId, "routeId")
14222
+ });
14223
+ const unsupportedTargetKeys = Object.keys(targetInput).filter(
14224
+ (key) => !["uid", "pageSchemaUid", "tabSchemaUid", "routeId"].includes(key)
14225
+ );
14226
+ if (unsupportedTargetKeys.length) {
14227
+ (0, import_errors.throwBadRequest)(`flowSurfaces exportBlueprint target only accepts uid, pageSchemaUid, tabSchemaUid or routeId`);
14228
+ }
14229
+ if (!Object.keys(target).length) {
14230
+ (0, import_errors.throwBadRequest)(
14231
+ `flowSurfaces exportBlueprint target requires one of uid, pageSchemaUid, tabSchemaUid or routeId`
14232
+ );
14233
+ }
14234
+ if (Object.keys(target).length > 1) {
14235
+ (0, import_errors.throwBadRequest)(
14236
+ `flowSurfaces exportBlueprint target only accepts exactly one locator: uid, pageSchemaUid, tabSchemaUid or routeId`
14237
+ );
14238
+ }
14239
+ if (target.tabSchemaUid) {
14240
+ (0, import_errors.throwBadRequest)(FLOW_SURFACE_EXPORT_BLUEPRINT_ROOT_ONLY_MESSAGE);
14241
+ }
14242
+ return {
14243
+ target,
14244
+ unsupportedPolicy: this.normalizeExportBlueprintUnsupportedPolicy(input.options)
14245
+ };
14246
+ }
14247
+ normalizeExportBlueprintUnsupportedPolicy(input) {
14248
+ if (import_lodash.default.isUndefined(input)) {
14249
+ return "error";
14250
+ }
14251
+ if (!import_lodash.default.isPlainObject(input)) {
14252
+ (0, import_errors.throwBadRequest)(`flowSurfaces exportBlueprint options must be an object`);
14253
+ }
14254
+ const options = input;
14255
+ const unsupportedKeys = Object.keys(options).filter((key) => key !== "unsupported");
14256
+ if (unsupportedKeys.length) {
14257
+ (0, import_errors.throwBadRequest)(`flowSurfaces exportBlueprint options only accepts unsupported`);
14258
+ }
14259
+ const policy = options.unsupported;
14260
+ if (import_lodash.default.isUndefined(policy)) {
14261
+ return "error";
14262
+ }
14263
+ if (policy === "error" || policy === "warn") {
14264
+ return policy;
14265
+ }
14266
+ (0, import_errors.throwBadRequest)(`flowSurfaces exportBlueprint options.unsupported must be 'error' or 'warn'`);
14267
+ }
14268
+ normalizeExportBlueprintLocatorValue(value, key) {
14269
+ if (import_lodash.default.isNil(value)) {
14270
+ return void 0;
14271
+ }
14272
+ if (typeof value !== "string" && typeof value !== "number") {
14273
+ (0, import_errors.throwBadRequest)(`flowSurfaces exportBlueprint target.${key} must be a string`);
14274
+ }
14275
+ const normalized = String(value).trim();
14276
+ return normalized || void 0;
14277
+ }
14278
+ readRouteString(route, key) {
14279
+ var _a;
14280
+ const routeRecord = route;
14281
+ const value = ((_a = routeRecord == null ? void 0 : routeRecord.get) == null ? void 0 : _a.call(routeRecord, key)) ?? (routeRecord == null ? void 0 : routeRecord[key]);
14282
+ const normalized = typeof value === "string" ? value.trim() : "";
14283
+ return normalized || void 0;
14284
+ }
14285
+ resolveExportBlueprintPageSchemaUid(target, resolved) {
14286
+ const pageSchemaUid = this.readRouteString(resolved.pageRoute, "schemaUid") || (target.pageSchemaUid ? String(target.pageSchemaUid).trim() : "");
14287
+ if (!pageSchemaUid) {
14288
+ (0, import_errors.throwBadRequest)(FLOW_SURFACE_EXPORT_BLUEPRINT_ROOT_ONLY_MESSAGE);
14289
+ }
14290
+ return pageSchemaUid;
14291
+ }
14292
+ async assertExportBlueprintRootTarget(target, resolved, pageSchemaUid, transaction) {
14293
+ const targetUid = target.uid ? String(target.uid).trim() : "";
14294
+ if (!targetUid) {
14295
+ return;
14296
+ }
14297
+ if (targetUid === pageSchemaUid) {
14298
+ return;
14299
+ }
14300
+ const rootPageModel = await this.repository.findModelByParentId(pageSchemaUid, {
14301
+ transaction,
14302
+ subKey: "page",
14303
+ includeAsyncNode: false
14304
+ });
14305
+ if ((rootPageModel == null ? void 0 : rootPageModel.uid) && targetUid === String(rootPageModel.uid).trim()) {
14306
+ return;
14307
+ }
14308
+ (0, import_errors.throwBadRequest)(FLOW_SURFACE_EXPORT_BLUEPRINT_ROOT_ONLY_MESSAGE);
14309
+ }
13697
14310
  normalizeContextPath(path) {
13698
14311
  if (import_lodash.default.isUndefined(path) || import_lodash.default.isNull(path)) {
13699
14312
  return void 0;
@@ -16860,13 +17473,20 @@ class FlowSurfacesService {
16860
17473
  description: changes.description,
16861
17474
  className: changes.className
16862
17475
  }),
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
- }
17476
+ stepParams: (0, import_service_utils.hasDefinedValue)(changes, ["code", "version", "showBlockCard"]) ? {
17477
+ jsSettings: (0, import_service_utils.buildDefinedPayload)({
17478
+ ...(0, import_service_utils.hasDefinedValue)(changes, ["code", "version"]) ? {
17479
+ runJs: (0, import_service_utils.buildDefinedPayload)({
17480
+ code: changes.code,
17481
+ version: changes.version
17482
+ })
17483
+ } : {},
17484
+ ...(0, import_service_utils.hasOwnDefined)(changes, "showBlockCard") ? {
17485
+ showBlockCard: {
17486
+ showBlockCard: changes.showBlockCard
17487
+ }
17488
+ } : {}
17489
+ })
16870
17490
  } : void 0
16871
17491
  },
16872
17492
  options
@@ -17448,19 +18068,21 @@ class FlowSurfacesService {
17448
18068
  }
17449
18069
  return JSON.stringify(value);
17450
18070
  }
17451
- buildAIEmployeeActionDedupIdentity(values) {
18071
+ buildAIEmployeeActionDedupIdentity(values, defaultActionWorkContext) {
17452
18072
  var _a, _b, _c, _d, _e, _f;
17453
18073
  const username = String(((_b = (_a = values == null ? void 0 : values.props) == null ? void 0 : _a.aiEmployee) == null ? void 0 : _b.username) || "").trim();
17454
18074
  if (!username) {
17455
18075
  return "";
17456
18076
  }
18077
+ const workContext = this.normalizeAIEmployeeActionWorkContextForDedupIdentity(
18078
+ (_d = (_c = values == null ? void 0 : values.props) == null ? void 0 : _c.context) == null ? void 0 : _d.workContext,
18079
+ defaultActionWorkContext
18080
+ );
17457
18081
  return this.stableSerializeAIEmployeeValue({
17458
18082
  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
- ),
18083
+ auto: typeof ((_e = values == null ? void 0 : values.props) == null ? void 0 : _e.auto) === "boolean" ? values.props.auto : false,
18084
+ workContext,
18085
+ tasks: this.normalizeAIEmployeeTasksForDedupIdentity(this.readAIEmployeePersistedTasks(values), workContext),
17464
18086
  style: {
17465
18087
  ...AI_EMPLOYEE_DEFAULT_STYLE,
17466
18088
  ...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 +18090,35 @@ class FlowSurfacesService {
17468
18090
  });
17469
18091
  }
17470
18092
  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
- );
18093
+ return import_lodash.default.castArray(value || []).map((item) => {
18094
+ if (!import_lodash.default.isPlainObject(item)) {
18095
+ return item;
18096
+ }
18097
+ const output = import_lodash.default.pick(item, AI_EMPLOYEE_WORK_CONTEXT_PUBLIC_KEYS);
18098
+ if (!Object.prototype.hasOwnProperty.call(output, "type") || import_lodash.default.isUndefined(output.type) || output.type === null) {
18099
+ output.type = "flow-model";
18100
+ }
18101
+ return output;
18102
+ });
18103
+ }
18104
+ normalizeAIEmployeeActionWorkContextForDedupIdentity(value, defaultWorkContext) {
18105
+ if (!Array.isArray(value)) {
18106
+ return import_lodash.default.cloneDeep(defaultWorkContext || []);
18107
+ }
18108
+ return this.normalizeAIEmployeeWorkContextForDedupIdentity(value);
18109
+ }
18110
+ normalizeAIEmployeeDefaultActionWorkContextForSelfUid(selfUid) {
18111
+ const uid2 = String(selfUid || "").trim();
18112
+ return uid2 ? [{ type: "flow-model", uid: uid2 }] : [];
18113
+ }
18114
+ normalizeAIEmployeeTaskWorkContextForDedupIdentity(value, defaultWorkContext) {
18115
+ const normalized = this.normalizeAIEmployeeWorkContextForDedupIdentity(value);
18116
+ if (Array.isArray(defaultWorkContext) && !normalized.length) {
18117
+ return import_lodash.default.cloneDeep(defaultWorkContext);
18118
+ }
18119
+ return normalized;
17474
18120
  }
17475
- normalizeAIEmployeeTasksForDedupIdentity(value) {
18121
+ normalizeAIEmployeeTasksForDedupIdentity(value, defaultWorkContext) {
17476
18122
  return import_lodash.default.castArray(value || []).map((task) => {
17477
18123
  if (!import_lodash.default.isPlainObject(task)) {
17478
18124
  return task;
@@ -17481,9 +18127,19 @@ class FlowSurfacesService {
17481
18127
  if (import_lodash.default.isPlainObject(output.message)) {
17482
18128
  output.message = import_lodash.default.pick(output.message, AI_EMPLOYEE_TASK_MESSAGE_PUBLIC_KEYS);
17483
18129
  if (Object.prototype.hasOwnProperty.call(output.message, "workContext")) {
17484
- output.message.workContext = this.normalizeAIEmployeeWorkContextForDedupIdentity(output.message.workContext);
18130
+ output.message.workContext = this.normalizeAIEmployeeTaskWorkContextForDedupIdentity(
18131
+ output.message.workContext,
18132
+ defaultWorkContext
18133
+ );
17485
18134
  }
17486
18135
  }
18136
+ if (!import_lodash.default.isPlainObject(output.message) && Array.isArray(defaultWorkContext)) {
18137
+ output.message = {
18138
+ workContext: import_lodash.default.cloneDeep(defaultWorkContext)
18139
+ };
18140
+ } else if (import_lodash.default.isPlainObject(output.message) && !Object.prototype.hasOwnProperty.call(output.message, "workContext")) {
18141
+ output.message.workContext = import_lodash.default.cloneDeep(defaultWorkContext || []);
18142
+ }
17487
18143
  if (import_lodash.default.isPlainObject(output.model)) {
17488
18144
  output.model = import_lodash.default.pick(output.model, AI_EMPLOYEE_TASK_MODEL_PUBLIC_KEYS);
17489
18145
  }
@@ -17493,25 +18149,38 @@ class FlowSurfacesService {
17493
18149
  return output;
17494
18150
  });
17495
18151
  }
17496
- async assertNoDuplicateAIEmployeeAction(actionName, parentUid, values, transaction) {
18152
+ async assertNoDuplicateAIEmployeeAction(actionName, parentUid, values, transaction, excludeUid) {
17497
18153
  var _a;
17498
- const identity = this.buildAIEmployeeActionDedupIdentity(values);
17499
- if (!identity) {
17500
- return;
17501
- }
17502
18154
  const parentNode = await this.repository.findModelById(parentUid, {
17503
18155
  transaction,
17504
18156
  includeAsyncNode: true
17505
18157
  });
17506
- const duplicate = import_lodash.default.castArray(((_a = parentNode == null ? void 0 : parentNode.subModels) == null ? void 0 : _a.actions) || []).find((action) => {
18158
+ const defaultActionWorkContext = this.normalizeAIEmployeeDefaultActionWorkContextForSelfUid(
18159
+ await this.resolveAIEmployeeActionSelfUidFromParentNode(parentNode, transaction)
18160
+ );
18161
+ const identity = this.buildAIEmployeeActionDedupIdentity(values, defaultActionWorkContext);
18162
+ if (!identity) {
18163
+ return;
18164
+ }
18165
+ let duplicate;
18166
+ for (const action of import_lodash.default.castArray(((_a = parentNode == null ? void 0 : parentNode.subModels) == null ? void 0 : _a.actions) || [])) {
17507
18167
  if (!this.isAIEmployeeActionUse(action == null ? void 0 : action.use)) {
17508
- return false;
18168
+ continue;
17509
18169
  }
17510
- return this.buildAIEmployeeActionDedupIdentity({
17511
- props: action.props,
17512
- stepParams: action.stepParams
17513
- }) === identity;
17514
- });
18170
+ if (excludeUid && String((action == null ? void 0 : action.uid) || "") === excludeUid) {
18171
+ continue;
18172
+ }
18173
+ if (this.buildAIEmployeeActionDedupIdentity(
18174
+ {
18175
+ props: action.props,
18176
+ stepParams: action.stepParams
18177
+ },
18178
+ defaultActionWorkContext
18179
+ ) === identity) {
18180
+ duplicate = action;
18181
+ break;
18182
+ }
18183
+ }
17515
18184
  if (!(duplicate == null ? void 0 : duplicate.uid)) {
17516
18185
  return;
17517
18186
  }
@@ -17526,6 +18195,25 @@ class FlowSurfacesService {
17526
18195
  }
17527
18196
  );
17528
18197
  }
18198
+ async assertNoDuplicateAIEmployeeActionForUpdateSettings(actionName, current, effectiveNode, transaction) {
18199
+ if (!this.isAIEmployeeActionUse(current == null ? void 0 : current.use)) {
18200
+ return;
18201
+ }
18202
+ const parentUid = String((current == null ? void 0 : current.parentId) || "").trim() || ((current == null ? void 0 : current.uid) ? await this.locator.findParentUid(current.uid, transaction).catch(() => "") : "");
18203
+ if (!parentUid) {
18204
+ return;
18205
+ }
18206
+ await this.assertNoDuplicateAIEmployeeAction(
18207
+ actionName,
18208
+ parentUid,
18209
+ {
18210
+ props: effectiveNode == null ? void 0 : effectiveNode.props,
18211
+ stepParams: effectiveNode == null ? void 0 : effectiveNode.stepParams
18212
+ },
18213
+ transaction,
18214
+ String((current == null ? void 0 : current.uid) || "")
18215
+ );
18216
+ }
17529
18217
  hasAIEmployeePublicSettings(settings) {
17530
18218
  return import_lodash.default.isPlainObject(settings) && AI_EMPLOYEE_PUBLIC_SETTING_KEYS.some((key) => Object.prototype.hasOwnProperty.call(settings, key));
17531
18219
  }
@@ -17580,11 +18268,24 @@ class FlowSurfacesService {
17580
18268
  var _a;
17581
18269
  const stepTasks = import_lodash.default.get(current, ["stepParams", ...AI_EMPLOYEE_TASK_STEP_PARAMS_PATH]);
17582
18270
  if (Array.isArray(stepTasks)) {
17583
- return stepTasks;
18271
+ return this.normalizeAIEmployeeLegacyInheritedTaskWorkContext(stepTasks);
17584
18272
  }
17585
- const legacyPropsTasks = (_a = current == null ? void 0 : current.props) == null ? void 0 : _a.tasks;
18273
+ const legacyPropsTasks = this.normalizeAIEmployeeLegacyInheritedTaskWorkContext((_a = current == null ? void 0 : current.props) == null ? void 0 : _a.tasks);
17586
18274
  return Array.isArray(legacyPropsTasks) ? legacyPropsTasks : [];
17587
18275
  }
18276
+ normalizeAIEmployeeLegacyInheritedTaskWorkContext(tasks) {
18277
+ if (!Array.isArray(tasks)) {
18278
+ return tasks;
18279
+ }
18280
+ return tasks.map((task) => {
18281
+ if (!import_lodash.default.isPlainObject(task) || !import_lodash.default.isPlainObject(task.message) || task.message.workContext !== null) {
18282
+ return task;
18283
+ }
18284
+ const nextTask = import_lodash.default.cloneDeep(task);
18285
+ delete nextTask.message.workContext;
18286
+ return nextTask;
18287
+ });
18288
+ }
17588
18289
  buildAIEmployeeTaskStepParams(tasks) {
17589
18290
  const stepParams = {};
17590
18291
  import_lodash.default.set(stepParams, AI_EMPLOYEE_TASK_STEP_PARAMS_PATH, import_lodash.default.cloneDeep(tasks));
@@ -17613,7 +18314,7 @@ class FlowSurfacesService {
17613
18314
  if (!this.isAIEmployeeActionUse(current == null ? void 0 : current.use)) {
17614
18315
  return;
17615
18316
  }
17616
- const legacyPropsTasks = (_a = current == null ? void 0 : current.props) == null ? void 0 : _a.tasks;
18317
+ const legacyPropsTasks = this.normalizeAIEmployeeLegacyInheritedTaskWorkContext((_a = current == null ? void 0 : current.props) == null ? void 0 : _a.tasks);
17617
18318
  const hasLegacyPropsTasks = Array.isArray(legacyPropsTasks);
17618
18319
  const hasNextStepTasks = import_lodash.default.has(nextPayload, ["stepParams", ...AI_EMPLOYEE_TASK_STEP_PARAMS_PATH]);
17619
18320
  const currentStepTasks = import_lodash.default.get(current, ["stepParams", ...AI_EMPLOYEE_TASK_STEP_PARAMS_PATH]);
@@ -17785,6 +18486,20 @@ class FlowSurfacesService {
17785
18486
  };
17786
18487
  });
17787
18488
  }
18489
+ normalizeAIEmployeeEffectiveActionWorkContext(actionName, settings, currentProps, options) {
18490
+ var _a;
18491
+ const hasSettingsWorkContext = Object.prototype.hasOwnProperty.call(settings, "workContext");
18492
+ const currentWorkContext = (_a = currentProps == null ? void 0 : currentProps.context) == null ? void 0 : _a.workContext;
18493
+ if (!hasSettingsWorkContext && !Array.isArray(currentWorkContext) && !options.requireUsername && !options.selfUid) {
18494
+ return void 0;
18495
+ }
18496
+ const rawWorkContext = hasSettingsWorkContext ? settings.workContext : Array.isArray(currentWorkContext) ? currentWorkContext : [{ type: "flow-model", target: "self" }];
18497
+ return this.normalizeAIEmployeeWorkContext(actionName, rawWorkContext, {
18498
+ selfUid: options.selfUid,
18499
+ keyMap: options.keyMap,
18500
+ path: "settings.workContext"
18501
+ });
18502
+ }
17788
18503
  normalizeAIEmployeeTaskModel(actionName, path, value) {
17789
18504
  if (import_lodash.default.isUndefined(value) || value === null) {
17790
18505
  return value;
@@ -18100,6 +18815,7 @@ ${AI_EMPLOYEE_CURRENT_RECORD_PROMPT_VARIABLE}` : AI_EMPLOYEE_CURRENT_RECORD_PROM
18100
18815
  );
18101
18816
  }
18102
18817
  async normalizeAIEmployeeStepParamTasksForUpdateSettings(current, nextPayload, writeTarget, options) {
18818
+ var _a, _b, _c, _d;
18103
18819
  if (!this.isAIEmployeeActionUse(current == null ? void 0 : current.use) || !import_lodash.default.has(nextPayload, ["stepParams", ...AI_EMPLOYEE_TASK_STEP_PARAMS_PATH])) {
18104
18820
  return;
18105
18821
  }
@@ -18108,15 +18824,63 @@ ${AI_EMPLOYEE_CURRENT_RECORD_PROMPT_VARIABLE}` : AI_EMPLOYEE_CURRENT_RECORD_PROM
18108
18824
  return;
18109
18825
  }
18110
18826
  const actionName = options.openViewActionName || "updateSettings";
18111
- const normalizedTasks = this.normalizeAIEmployeeTasks(
18827
+ const selfUid = await this.resolveAIEmployeeActionSelfUid(current || { uid: writeTarget.uid }, options.transaction);
18828
+ const currentPropsForDefault = import_lodash.default.mergeWith(
18829
+ {},
18830
+ import_lodash.default.isPlainObject(current == null ? void 0 : current.props) ? current.props : {},
18831
+ import_lodash.default.isPlainObject(nextPayload.props) ? nextPayload.props : {},
18832
+ (_currentValue, nextValue) => {
18833
+ if (Array.isArray(nextValue)) {
18834
+ return import_lodash.default.cloneDeep(nextValue);
18835
+ }
18836
+ return void 0;
18837
+ }
18838
+ );
18839
+ const defaultWorkContext = this.normalizeAIEmployeeEffectiveActionWorkContext(
18112
18840
  actionName,
18113
- tasks,
18114
- this.readAIEmployeePersistedTasks(current),
18841
+ {},
18842
+ currentPropsForDefault,
18115
18843
  {
18116
- selfUid: await this.resolveAIEmployeeActionSelfUid(current || { uid: writeTarget.uid }, options.transaction),
18117
- path: "stepParams.shortcutSettings.editTasks.tasks"
18844
+ selfUid,
18845
+ requireUsername: true
18118
18846
  }
18119
18847
  );
18848
+ const currentTasks = this.readAIEmployeePersistedTasks(current);
18849
+ const previousActionWorkContext = this.normalizeAIEmployeeActionWorkContextForDedupIdentity(
18850
+ (_b = (_a = current == null ? void 0 : current.props) == null ? void 0 : _a.context) == null ? void 0 : _b.workContext,
18851
+ this.normalizeAIEmployeeDefaultActionWorkContextForSelfUid(selfUid)
18852
+ );
18853
+ const nextActionWorkContext = this.normalizeAIEmployeeActionWorkContextForDedupIdentity(
18854
+ (_c = currentPropsForDefault == null ? void 0 : currentPropsForDefault.context) == null ? void 0 : _c.workContext,
18855
+ defaultWorkContext
18856
+ );
18857
+ if (Array.isArray(defaultWorkContext) && !import_lodash.default.isEqual((_d = currentPropsForDefault == null ? void 0 : currentPropsForDefault.context) == null ? void 0 : _d.workContext, defaultWorkContext)) {
18858
+ nextPayload.props = import_lodash.default.mergeWith(
18859
+ {},
18860
+ currentPropsForDefault,
18861
+ {
18862
+ context: {
18863
+ workContext: import_lodash.default.cloneDeep(defaultWorkContext)
18864
+ }
18865
+ },
18866
+ (_currentValue, nextValue) => {
18867
+ if (Array.isArray(nextValue)) {
18868
+ return import_lodash.default.cloneDeep(nextValue);
18869
+ }
18870
+ return void 0;
18871
+ }
18872
+ );
18873
+ }
18874
+ const currentTasksForNormalization = this.rebaseAIEmployeeInheritedTaskWorkContext(
18875
+ currentTasks,
18876
+ previousActionWorkContext,
18877
+ nextActionWorkContext
18878
+ );
18879
+ const normalizedTasks = this.normalizeAIEmployeeTasks(actionName, tasks, currentTasksForNormalization, {
18880
+ selfUid,
18881
+ defaultWorkContext,
18882
+ path: "stepParams.shortcutSettings.editTasks.tasks"
18883
+ });
18120
18884
  import_lodash.default.set(nextPayload, ["stepParams", ...AI_EMPLOYEE_TASK_STEP_PARAMS_PATH], normalizedTasks);
18121
18885
  }
18122
18886
  normalizeAIEmployeeTaskMessage(actionName, path, value, existing, options) {
@@ -18145,13 +18909,18 @@ ${AI_EMPLOYEE_CURRENT_RECORD_PROMPT_VARIABLE}` : AI_EMPLOYEE_CURRENT_RECORD_PROM
18145
18909
  if (Object.prototype.hasOwnProperty.call(nextMessage, "user") && typeof nextMessage.user !== "string") {
18146
18910
  (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} ${path}.user must be a string`);
18147
18911
  }
18148
- if (Object.prototype.hasOwnProperty.call(value, "workContext")) {
18912
+ if (value.workContext === null) {
18913
+ delete nextMessage.workContext;
18914
+ } else if (Object.prototype.hasOwnProperty.call(value, "workContext")) {
18149
18915
  nextMessage.workContext = this.normalizeAIEmployeeWorkContext(actionName, value.workContext, {
18150
18916
  selfUid: options.selfUid,
18151
18917
  keyMap: options.keyMap,
18152
18918
  path: `${path}.workContext`
18153
18919
  });
18154
18920
  }
18921
+ if (!Object.prototype.hasOwnProperty.call(nextMessage, "workContext") && this.shouldMaterializeAIEmployeeTaskDefaultWorkContext(options.defaultWorkContext)) {
18922
+ nextMessage.workContext = import_lodash.default.cloneDeep(options.defaultWorkContext);
18923
+ }
18155
18924
  return nextMessage;
18156
18925
  }
18157
18926
  normalizeAIEmployeeTaskPatch(actionName, patch, existing, options) {
@@ -18175,7 +18944,8 @@ ${AI_EMPLOYEE_CURRENT_RECORD_PROMPT_VARIABLE}` : AI_EMPLOYEE_CURRENT_RECORD_PROM
18175
18944
  if (key === "message") {
18176
18945
  next.message = this.normalizeAIEmployeeTaskMessage(actionName, `${options.path}.message`, value, next.message, {
18177
18946
  selfUid: options.selfUid,
18178
- keyMap: options.keyMap
18947
+ keyMap: options.keyMap,
18948
+ defaultWorkContext: options.defaultWorkContext
18179
18949
  });
18180
18950
  return;
18181
18951
  }
@@ -18225,6 +18995,9 @@ ${AI_EMPLOYEE_CURRENT_RECORD_PROMPT_VARIABLE}` : AI_EMPLOYEE_CURRENT_RECORD_PROM
18225
18995
  if (!import_lodash.default.isPlainObject(next.message)) {
18226
18996
  next.message = {};
18227
18997
  }
18998
+ if (!Object.prototype.hasOwnProperty.call(next.message, "workContext") && this.shouldMaterializeAIEmployeeTaskDefaultWorkContext(options.defaultWorkContext)) {
18999
+ next.message.workContext = import_lodash.default.cloneDeep(options.defaultWorkContext);
19000
+ }
18228
19001
  if (import_lodash.default.isPlainObject(next.skillSettings)) {
18229
19002
  if (Array.isArray(next.skillSettings.skills) && !Object.prototype.hasOwnProperty.call(next.skillSettings, "skillsVersion")) {
18230
19003
  next.skillSettings.skillsVersion = 2;
@@ -18251,10 +19024,52 @@ ${AI_EMPLOYEE_CURRENT_RECORD_PROMPT_VARIABLE}` : AI_EMPLOYEE_CURRENT_RECORD_PROM
18251
19024
  nextTasks[index] = this.normalizeAIEmployeeTaskPatch(actionName, task, existingTasks[index], {
18252
19025
  selfUid: options.selfUid,
18253
19026
  keyMap: options.keyMap,
18254
- path: `${options.path}[${index}]`
19027
+ path: `${options.path}[${index}]`,
19028
+ defaultWorkContext: options.defaultWorkContext
18255
19029
  });
18256
19030
  });
18257
- return nextTasks;
19031
+ return this.withAIEmployeeTaskDefaultWorkContext(nextTasks, options.defaultWorkContext);
19032
+ }
19033
+ withAIEmployeeTaskDefaultWorkContext(tasks, defaultWorkContext) {
19034
+ const nextTasks = Array.isArray(tasks) ? import_lodash.default.cloneDeep(tasks) : [];
19035
+ if (!this.shouldMaterializeAIEmployeeTaskDefaultWorkContext(defaultWorkContext)) {
19036
+ return nextTasks;
19037
+ }
19038
+ return nextTasks.map((task) => {
19039
+ if (!import_lodash.default.isPlainObject(task)) {
19040
+ return task;
19041
+ }
19042
+ const nextTask = import_lodash.default.cloneDeep(task);
19043
+ if (!import_lodash.default.isPlainObject(nextTask.message)) {
19044
+ nextTask.message = {
19045
+ workContext: import_lodash.default.cloneDeep(defaultWorkContext)
19046
+ };
19047
+ } else if (!Object.prototype.hasOwnProperty.call(nextTask.message, "workContext")) {
19048
+ nextTask.message.workContext = import_lodash.default.cloneDeep(defaultWorkContext);
19049
+ }
19050
+ return nextTask;
19051
+ });
19052
+ }
19053
+ shouldMaterializeAIEmployeeTaskDefaultWorkContext(defaultWorkContext) {
19054
+ return Array.isArray(defaultWorkContext) && defaultWorkContext.length > 0;
19055
+ }
19056
+ rebaseAIEmployeeInheritedTaskWorkContext(currentTasks, previousActionWorkContext, nextActionWorkContext) {
19057
+ const tasks = this.normalizeAIEmployeeLegacyInheritedTaskWorkContext(currentTasks) || [];
19058
+ if (!previousActionWorkContext.length || import_lodash.default.isEqual(previousActionWorkContext, nextActionWorkContext)) {
19059
+ return tasks;
19060
+ }
19061
+ return tasks.map((task) => {
19062
+ const nextTask = import_lodash.default.cloneDeep(task);
19063
+ if (import_lodash.default.isPlainObject(nextTask == null ? void 0 : nextTask.message)) {
19064
+ const currentTaskWorkContext = this.normalizeAIEmployeeWorkContextForDedupIdentity(
19065
+ nextTask.message.workContext
19066
+ );
19067
+ if (import_lodash.default.isEqual(currentTaskWorkContext, previousActionWorkContext)) {
19068
+ delete nextTask.message.workContext;
19069
+ }
19070
+ }
19071
+ return nextTask;
19072
+ });
18258
19073
  }
18259
19074
  normalizeAIEmployeeActionSettingsReferences(actionName, settings, options) {
18260
19075
  if (!this.hasAIEmployeePublicSettings(settings)) {
@@ -18268,15 +19083,22 @@ ${AI_EMPLOYEE_CURRENT_RECORD_PROMPT_VARIABLE}` : AI_EMPLOYEE_CURRENT_RECORD_PROM
18268
19083
  });
18269
19084
  }
18270
19085
  if (Object.prototype.hasOwnProperty.call(nextSettings, "tasks")) {
19086
+ const defaultWorkContext = this.normalizeAIEmployeeEffectiveActionWorkContext(
19087
+ actionName,
19088
+ nextSettings,
19089
+ {},
19090
+ options
19091
+ );
18271
19092
  nextSettings.tasks = this.normalizeAIEmployeeTasks(actionName, nextSettings.tasks, [], {
18272
19093
  ...options,
18273
- path: "settings.tasks"
19094
+ path: "settings.tasks",
19095
+ defaultWorkContext
18274
19096
  });
18275
19097
  }
18276
19098
  return nextSettings;
18277
19099
  }
18278
19100
  async normalizeAIEmployeeActionPublicSettings(actionName, settings, options) {
18279
- var _a, _b;
19101
+ var _a, _b, _c, _d;
18280
19102
  this.assertAIEmployeePluginEnabled(actionName, options.enabledPackages);
18281
19103
  if (!import_lodash.default.isPlainObject(settings)) {
18282
19104
  (0, import_errors.throwBadRequest)(`flowSurfaces ${actionName} AI employee settings must be an object`);
@@ -18296,6 +19118,17 @@ ${AI_EMPLOYEE_CURRENT_RECORD_PROMPT_VARIABLE}` : AI_EMPLOYEE_CURRENT_RECORD_PROM
18296
19118
  }
18297
19119
  const props = {};
18298
19120
  const stepParams = {};
19121
+ const effectiveActionWorkContext = this.normalizeAIEmployeeEffectiveActionWorkContext(
19122
+ actionName,
19123
+ settings,
19124
+ currentProps,
19125
+ options
19126
+ );
19127
+ const previousActionWorkContext = this.normalizeAIEmployeeActionWorkContextForDedupIdentity(
19128
+ (_c = currentProps == null ? void 0 : currentProps.context) == null ? void 0 : _c.workContext,
19129
+ this.normalizeAIEmployeeDefaultActionWorkContextForSelfUid(options.selfUid)
19130
+ );
19131
+ const nextActionWorkContext = this.normalizeAIEmployeeWorkContextForDedupIdentity(effectiveActionWorkContext);
18299
19132
  if (effectiveUsername && (hasUsername || options.requireUsername)) {
18300
19133
  props.aiEmployee = {
18301
19134
  ...import_lodash.default.isPlainObject(currentProps.aiEmployee) ? import_lodash.default.cloneDeep(currentProps.aiEmployee) : {},
@@ -18309,28 +19142,25 @@ ${AI_EMPLOYEE_CURRENT_RECORD_PROMPT_VARIABLE}` : AI_EMPLOYEE_CURRENT_RECORD_PROM
18309
19142
  }
18310
19143
  props.auto = auto;
18311
19144
  }
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" }];
19145
+ 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
19146
  props.context = {
18315
19147
  ...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
- })
19148
+ workContext: import_lodash.default.cloneDeep(effectiveActionWorkContext)
18321
19149
  };
18322
19150
  }
18323
19151
  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
- }
19152
+ const currentTasks = this.readAIEmployeePersistedTasks(options.current);
19153
+ const currentTasksForNormalization = this.rebaseAIEmployeeInheritedTaskWorkContext(
19154
+ currentTasks,
19155
+ previousActionWorkContext,
19156
+ nextActionWorkContext
18333
19157
  );
19158
+ const normalizedTasks = this.normalizeAIEmployeeTasks(actionName, settings.tasks, currentTasksForNormalization, {
19159
+ selfUid: options.selfUid,
19160
+ keyMap: options.keyMap,
19161
+ path: "settings.tasks",
19162
+ defaultWorkContext: effectiveActionWorkContext
19163
+ });
18334
19164
  const validation = options.promptContext && normalizedTasks.length ? await this.buildAIEmployeePromptValidationContext(
18335
19165
  actionName,
18336
19166
  [
@@ -18351,6 +19181,17 @@ ${AI_EMPLOYEE_CURRENT_RECORD_PROMPT_VARIABLE}` : AI_EMPLOYEE_CURRENT_RECORD_PROM
18351
19181
  const tasks = this.appendAIEmployeeCurrentRecordPromptVariableToTasks(normalizedTasks, validation);
18352
19182
  this.assertAIEmployeeTaskPromptVariablesAllowed(actionName, tasks, validation);
18353
19183
  import_lodash.default.merge(stepParams, this.buildAIEmployeeTaskStepParams(tasks));
19184
+ } else if (!options.skipExistingTaskWorkContextRebase && Object.prototype.hasOwnProperty.call(settings, "workContext") && !import_lodash.default.isEqual(previousActionWorkContext, nextActionWorkContext)) {
19185
+ const currentTasks = this.readAIEmployeePersistedTasks(options.current);
19186
+ const rebasedTasks = this.rebaseAIEmployeeInheritedTaskWorkContext(
19187
+ currentTasks,
19188
+ previousActionWorkContext,
19189
+ nextActionWorkContext
19190
+ );
19191
+ const tasks = this.withAIEmployeeTaskDefaultWorkContext(rebasedTasks, effectiveActionWorkContext);
19192
+ if (tasks.length) {
19193
+ import_lodash.default.merge(stepParams, this.buildAIEmployeeTaskStepParams(tasks));
19194
+ }
18354
19195
  }
18355
19196
  if (Object.prototype.hasOwnProperty.call(settings, "style") || options.requireUsername) {
18356
19197
  const style = Object.prototype.hasOwnProperty.call(settings, "style") ? settings.style : {};
@@ -18392,7 +19233,16 @@ ${AI_EMPLOYEE_CURRENT_RECORD_PROMPT_VARIABLE}` : AI_EMPLOYEE_CURRENT_RECORD_PROM
18392
19233
  transaction,
18393
19234
  includeAsyncNode: true
18394
19235
  });
18395
- if (["TableActionsColumnModel", "ListItemModel", "GridCardItemModel"].includes(String((parentNode == null ? void 0 : parentNode.use) || ""))) {
19236
+ return await this.resolveAIEmployeeActionSelfUidFromParentNode(parentNode, transaction) || parentUid;
19237
+ }
19238
+ async resolveAIEmployeeActionSelfUidFromParentNode(parentNode, transaction) {
19239
+ const parentUid = String((parentNode == null ? void 0 : parentNode.uid) || "").trim();
19240
+ if (!parentUid) {
19241
+ return "";
19242
+ }
19243
+ if (["TableActionsColumnModel", "ListItemModel", "GridCardItemModel", "CommentItemModel"].includes(
19244
+ String((parentNode == null ? void 0 : parentNode.use) || "")
19245
+ )) {
18396
19246
  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
19247
  return ownerUid || parentUid;
18398
19248
  }
@@ -18441,13 +19291,14 @@ ${AI_EMPLOYEE_CURRENT_RECORD_PROMPT_VARIABLE}` : AI_EMPLOYEE_CURRENT_RECORD_PROM
18441
19291
  }
18442
19292
  const normalizedDefaultFilter = (0, import_service_utils.hasOwnDefined)(changes, "defaultFilter") ? this.normalizeFilterActionDefaultFilterValue(changes.defaultFilter) : void 0;
18443
19293
  const stepParams = {};
18444
- if ((0, import_service_utils.hasDefinedValue)(changes, ["title", "tooltip", "icon", "type", "danger", "color", "linkageRules"])) {
19294
+ if ((0, import_service_utils.hasDefinedValue)(changes, ["title", "tooltip", "icon", "iconOnly", "type", "danger", "color", "linkageRules"])) {
18445
19295
  stepParams.buttonSettings = {
18446
- ...(0, import_service_utils.hasDefinedValue)(changes, ["title", "tooltip", "icon", "type", "danger", "color"]) ? {
19296
+ ...(0, import_service_utils.hasDefinedValue)(changes, ["title", "tooltip", "icon", "iconOnly", "type", "danger", "color"]) ? {
18447
19297
  general: (0, import_service_utils.buildDefinedPayload)({
18448
19298
  title: changes.title,
18449
19299
  tooltip: changes.tooltip,
18450
19300
  icon: changes.icon,
19301
+ iconOnly: changes.iconOnly,
18451
19302
  type: changes.type,
18452
19303
  danger: changes.danger,
18453
19304
  color: changes.color
@@ -18657,6 +19508,7 @@ ${AI_EMPLOYEE_CURRENT_RECORD_PROMPT_VARIABLE}` : AI_EMPLOYEE_CURRENT_RECORD_PROM
18657
19508
  title: changes.title,
18658
19509
  tooltip: changes.tooltip,
18659
19510
  icon: changes.icon,
19511
+ iconOnly: changes.iconOnly,
18660
19512
  type: changes.type,
18661
19513
  htmlType: changes.htmlType,
18662
19514
  position: changes.position,
@@ -18786,6 +19638,11 @@ ${AI_EMPLOYEE_CURRENT_RECORD_PROMPT_VARIABLE}` : AI_EMPLOYEE_CURRENT_RECORD_PROM
18786
19638
  useStrictOnly: input.useStrictOnly
18787
19639
  });
18788
19640
  }
19641
+ isCollectionTitleField(collection, fieldName) {
19642
+ const normalizedFieldName = String(fieldName || "").trim();
19643
+ const titleFieldName = String((0, import_service_helpers.getCollectionTitleFieldName)(collection) || "").trim();
19644
+ return !!normalizedFieldName && normalizedFieldName === titleFieldName;
19645
+ }
18789
19646
  resolveAssociationLeafDisplaySemantics(field, dataSourceKey, enabledPackages) {
18790
19647
  const registeredBinding = this.resolveRegisteredFieldBinding({
18791
19648
  containerUse: "DetailsItemModel",
@@ -18821,6 +19678,9 @@ ${AI_EMPLOYEE_CURRENT_RECORD_PROMPT_VARIABLE}` : AI_EMPLOYEE_CURRENT_RECORD_PROM
18821
19678
  }
18822
19679
  buildFieldMenuDirectCandidates(input) {
18823
19680
  const collection = this.getCollection(input.resourceInit.dataSourceKey, input.resourceInit.collectionName);
19681
+ const explicitDefaultFieldPaths = (0, import_default_action_popup.collectFlowSurfaceDefaultActionPopupFieldGroupFieldPaths)(
19682
+ input.defaultFieldGroups
19683
+ );
18824
19684
  return (0, import_service_helpers.getCollectionFields)(collection).flatMap((field) => {
18825
19685
  var _a;
18826
19686
  const fieldName = (0, import_service_helpers.getFieldName)(field);
@@ -18831,6 +19691,9 @@ ${AI_EMPLOYEE_CURRENT_RECORD_PROMPT_VARIABLE}` : AI_EMPLOYEE_CURRENT_RECORD_PROM
18831
19691
  if (input.generatedPopupOnly && !(0, import_default_action_popup.isFlowSurfaceDefaultActionPopupBusinessField)(field)) {
18832
19692
  return [];
18833
19693
  }
19694
+ if ((0, import_relation_backing_foreign_key.isRelationBackingForeignKeyField)(collection, field) && !explicitDefaultFieldPaths.has(fieldName)) {
19695
+ return [];
19696
+ }
18834
19697
  if (input.mode === "table" && ((_a = field == null ? void 0 : field.options) == null ? void 0 : _a.treeChildren)) {
18835
19698
  return [];
18836
19699
  }
@@ -18918,6 +19781,9 @@ ${AI_EMPLOYEE_CURRENT_RECORD_PROMPT_VARIABLE}` : AI_EMPLOYEE_CURRENT_RECORD_PROM
18918
19781
  if (!targetFieldName) {
18919
19782
  continue;
18920
19783
  }
19784
+ if ((0, import_relation_backing_foreign_key.isRelationBackingForeignKeyField)(targetCollection, targetField) && !this.isCollectionTitleField(targetCollection, targetFieldName)) {
19785
+ continue;
19786
+ }
18921
19787
  nextCandidates.push({
18922
19788
  field: targetField,
18923
19789
  fieldPath: `${associationPathName}.${targetFieldName}`,
@@ -19092,7 +19958,7 @@ ${AI_EMPLOYEE_CURRENT_RECORD_PROMPT_VARIABLE}` : AI_EMPLOYEE_CURRENT_RECORD_PROM
19092
19958
  const getFields = (targetCollection) => (0, import_service_helpers.getCollectionFields)(targetCollection);
19093
19959
  const isFilterFieldVisible = (field) => (0, import_service_helpers.getFieldFilterable)(field) !== false && !!(0, import_service_helpers.getFieldInterface)(field);
19094
19960
  const directFields = getFields(collection).filter(
19095
- (field) => ["FilterFormBlockModel", "FilterFormGridModel", "FilterFormItemModel"].includes(input.ownerUse) ? isFilterFieldVisible(field) : !!(0, import_service_helpers.getFieldInterface)(field)
19961
+ (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
19962
  );
19097
19963
  if (!directFields.length && !collection) {
19098
19964
  return [];
@@ -19106,9 +19972,13 @@ ${AI_EMPLOYEE_CURRENT_RECORD_PROMPT_VARIABLE}` : AI_EMPLOYEE_CURRENT_RECORD_PROM
19106
19972
  if (!(0, import_service_helpers.isAssociationField)(field) || !targetCollection) {
19107
19973
  return [];
19108
19974
  }
19109
- return getFields(targetCollection).filter(
19110
- (targetField) => ["FilterFormBlockModel", "FilterFormGridModel", "FilterFormItemModel"].includes(input.ownerUse) ? isFilterFieldVisible(targetField) : !!(0, import_service_helpers.getFieldInterface)(targetField)
19111
- ).map((targetField) => ({
19975
+ return getFields(targetCollection).filter((targetField) => {
19976
+ const targetFieldName = (0, import_service_helpers.getFieldName)(targetField);
19977
+ if ((0, import_relation_backing_foreign_key.isRelationBackingForeignKeyField)(targetCollection, targetField) && !this.isCollectionTitleField(targetCollection, targetFieldName)) {
19978
+ return false;
19979
+ }
19980
+ return ["FilterFormBlockModel", "FilterFormGridModel", "FilterFormItemModel"].includes(input.ownerUse) ? isFilterFieldVisible(targetField) : !!(0, import_service_helpers.getFieldInterface)(targetField);
19981
+ }).map((targetField) => ({
19112
19982
  field: targetField,
19113
19983
  fieldPath: `${(0, import_service_helpers.getFieldName)(field)}.${(0, import_service_helpers.getFieldName)(targetField)}`,
19114
19984
  associationPathName: (0, import_service_helpers.getFieldName)(field),