@nocobase/plugin-flow-engine 2.1.0-alpha.40 → 2.1.0-alpha.46

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 (105) hide show
  1. package/dist/client/index.js +1 -1
  2. package/dist/externalVersion.js +9 -9
  3. package/dist/node_modules/@ant-design/icons-svg/package.json +1 -1
  4. package/dist/node_modules/acorn/package.json +1 -1
  5. package/dist/node_modules/acorn-jsx/package.json +1 -1
  6. package/dist/node_modules/acorn-walk/package.json +1 -1
  7. package/dist/node_modules/ses/package.json +1 -1
  8. package/dist/node_modules/zod/package.json +1 -1
  9. package/dist/server/flow-surfaces/apply/compiler.js +28 -14
  10. package/dist/server/flow-surfaces/apply/matching.js +2 -0
  11. package/dist/server/flow-surfaces/authoring-validation.d.ts +1 -0
  12. package/dist/server/flow-surfaces/authoring-validation.js +1453 -151
  13. package/dist/server/flow-surfaces/blueprint/compile-blocks.js +21 -3
  14. package/dist/server/flow-surfaces/blueprint/compile-plan.js +9 -9
  15. package/dist/server/flow-surfaces/blueprint/normalize-document.js +5 -1
  16. package/dist/server/flow-surfaces/catalog.js +26 -9
  17. package/dist/server/flow-surfaces/chart-config.js +231 -14
  18. package/dist/server/flow-surfaces/compose-compiler.d.ts +2 -0
  19. package/dist/server/flow-surfaces/compose-compiler.js +2 -0
  20. package/dist/server/flow-surfaces/compose-runtime.js +4 -7
  21. package/dist/server/flow-surfaces/configure-options.js +19 -8
  22. package/dist/server/flow-surfaces/contract-guard.js +40 -6
  23. package/dist/server/flow-surfaces/default-block-actions.js +2 -0
  24. package/dist/server/flow-surfaces/errors.d.ts +15 -0
  25. package/dist/server/flow-surfaces/errors.js +49 -3
  26. package/dist/server/flow-surfaces/event-flow-normalizer.d.ts +19 -0
  27. package/dist/server/flow-surfaces/event-flow-normalizer.js +128 -0
  28. package/dist/server/flow-surfaces/filter-group.d.ts +9 -1
  29. package/dist/server/flow-surfaces/filter-group.js +402 -3
  30. package/dist/server/flow-surfaces/locator.js +16 -2
  31. package/dist/server/flow-surfaces/public-data-surface-default-filter.js +2 -1
  32. package/dist/server/flow-surfaces/route-sync.js +19 -2
  33. package/dist/server/flow-surfaces/runjs-authoring/ast/bindings.d.ts +66 -0
  34. package/dist/server/flow-surfaces/runjs-authoring/ast/bindings.js +661 -0
  35. package/dist/server/flow-surfaces/runjs-authoring/ast/execution.d.ts +20 -0
  36. package/dist/server/flow-surfaces/runjs-authoring/ast/execution.js +275 -0
  37. package/dist/server/flow-surfaces/runjs-authoring/ast/parser.d.ts +16 -0
  38. package/dist/server/flow-surfaces/runjs-authoring/ast/parser.js +130 -0
  39. package/dist/server/flow-surfaces/runjs-authoring/ast/react-values.d.ts +20 -0
  40. package/dist/server/flow-surfaces/runjs-authoring/ast/react-values.js +401 -0
  41. package/dist/server/flow-surfaces/runjs-authoring/ast/request-config.d.ts +21 -0
  42. package/dist/server/flow-surfaces/runjs-authoring/ast/request-config.js +199 -0
  43. package/dist/server/flow-surfaces/runjs-authoring/ast/source.d.ts +70 -0
  44. package/dist/server/flow-surfaces/runjs-authoring/ast/source.js +895 -0
  45. package/dist/server/flow-surfaces/runjs-authoring/ast/static-bindings.d.ts +23 -0
  46. package/dist/server/flow-surfaces/runjs-authoring/ast/static-bindings.js +618 -0
  47. package/dist/server/flow-surfaces/runjs-authoring/ast/static-values.d.ts +196 -0
  48. package/dist/server/flow-surfaces/runjs-authoring/ast/static-values.js +1777 -0
  49. package/dist/server/flow-surfaces/runjs-authoring/ast/walk.d.ts +10 -0
  50. package/dist/server/flow-surfaces/runjs-authoring/ast/walk.js +55 -0
  51. package/dist/server/flow-surfaces/runjs-authoring/collectors.d.ts +12 -0
  52. package/dist/server/flow-surfaces/runjs-authoring/collectors.js +589 -0
  53. package/dist/server/flow-surfaces/runjs-authoring/ctx-libs-member-mismatch-stop/index.js +1 -1
  54. package/dist/server/flow-surfaces/runjs-authoring/index.d.ts +2 -25
  55. package/dist/server/flow-surfaces/runjs-authoring/index.js +5 -7033
  56. package/dist/server/flow-surfaces/runjs-authoring/inspect.d.ts +13 -0
  57. package/dist/server/flow-surfaces/runjs-authoring/inspect.js +149 -0
  58. package/dist/server/flow-surfaces/runjs-authoring/internal-types.d.ts +333 -0
  59. package/dist/server/flow-surfaces/runjs-authoring/internal-types.js +36 -0
  60. package/dist/server/flow-surfaces/runjs-authoring/rules.js +2 -0
  61. package/dist/server/flow-surfaces/runjs-authoring/runtime/constants.d.ts +67 -0
  62. package/dist/server/flow-surfaces/runjs-authoring/runtime/constants.js +757 -0
  63. package/dist/server/flow-surfaces/runjs-authoring/runtime/errors.d.ts +22 -0
  64. package/dist/server/flow-surfaces/runjs-authoring/runtime/errors.js +91 -0
  65. package/dist/server/flow-surfaces/runjs-authoring/runtime/source-budget.d.ts +16 -0
  66. package/dist/server/flow-surfaces/runjs-authoring/runtime/source-budget.js +115 -0
  67. package/dist/server/flow-surfaces/runjs-authoring/runtime/surface.d.ts +19 -0
  68. package/dist/server/flow-surfaces/runjs-authoring/runtime/surface.js +140 -0
  69. package/dist/server/flow-surfaces/runjs-authoring/runtime/types.d.ts +91 -0
  70. package/dist/server/flow-surfaces/runjs-authoring/runtime/types.js +24 -0
  71. package/dist/server/flow-surfaces/runjs-authoring/scan/ctx-api.d.ts +138 -0
  72. package/dist/server/flow-surfaces/runjs-authoring/scan/ctx-api.js +1779 -0
  73. package/dist/server/flow-surfaces/runjs-authoring/scan/filter.d.ts +10 -0
  74. package/dist/server/flow-surfaces/runjs-authoring/scan/filter.js +1583 -0
  75. package/dist/server/flow-surfaces/runjs-authoring/scan/index.d.ts +195 -0
  76. package/dist/server/flow-surfaces/runjs-authoring/scan/index.js +463 -0
  77. package/dist/server/flow-surfaces/runjs-authoring/scan/react-render.d.ts +48 -0
  78. package/dist/server/flow-surfaces/runjs-authoring/scan/react-render.js +379 -0
  79. package/dist/server/flow-surfaces/runjs-authoring/scan/react.d.ts +26 -0
  80. package/dist/server/flow-surfaces/runjs-authoring/scan/react.js +1441 -0
  81. package/dist/server/flow-surfaces/runjs-authoring/scan/resource.d.ts +23 -0
  82. package/dist/server/flow-surfaces/runjs-authoring/scan/resource.js +1427 -0
  83. package/dist/server/flow-surfaces/runjs-authoring/scan/source-patterns.d.ts +91 -0
  84. package/dist/server/flow-surfaces/runjs-authoring/scan/source-patterns.js +889 -0
  85. package/dist/server/flow-surfaces/runjs-authoring/types.d.ts +1 -1
  86. package/dist/server/flow-surfaces/runjs-authoring/unknown-global-stop/index.d.ts +10 -0
  87. package/dist/server/flow-surfaces/runjs-authoring/unknown-global-stop/index.js +40 -0
  88. package/dist/server/flow-surfaces/runjs-authoring/validators/index.d.ts +12 -0
  89. package/dist/server/flow-surfaces/runjs-authoring/validators/index.js +887 -0
  90. package/dist/server/flow-surfaces/service-helpers.d.ts +29 -0
  91. package/dist/server/flow-surfaces/service-helpers.js +105 -0
  92. package/dist/server/flow-surfaces/service-utils.d.ts +17 -3
  93. package/dist/server/flow-surfaces/service-utils.js +14 -5
  94. package/dist/server/flow-surfaces/service.d.ts +74 -15
  95. package/dist/server/flow-surfaces/service.js +1781 -193
  96. package/dist/server/flow-surfaces/template-service-utils.d.ts +1 -0
  97. package/dist/server/flow-surfaces/types.d.ts +3 -0
  98. package/dist/server/repository.d.ts +12 -1
  99. package/dist/server/repository.js +195 -23
  100. package/dist/swagger/flow-surfaces.d.ts +180 -2
  101. package/dist/swagger/flow-surfaces.examples.d.ts +11 -37
  102. package/dist/swagger/flow-surfaces.examples.js +6 -6
  103. package/dist/swagger/flow-surfaces.js +136 -54
  104. package/dist/swagger/index.d.ts +180 -2
  105. package/package.json +2 -2
@@ -59,6 +59,8 @@ var import_template_reference = require("./template-reference");
59
59
  var import_association_interfaces = require("./association-interfaces");
60
60
  var import_defaults = require("./blueprint/defaults");
61
61
  var import_runjs_authoring = require("./runjs-authoring");
62
+ var import_configure_options = require("./configure-options");
63
+ var import_filter_group = require("./filter-group");
62
64
  const MAIN_BLOCK_UNSUPPORTED_SECTIONS = {
63
65
  calendar: ["fields", "fieldGroups", "recordActions", "fieldsLayout"],
64
66
  kanban: ["fieldGroups", "recordActions", "fieldsLayout"],
@@ -71,6 +73,62 @@ const SORTABLE_BLOCK_TYPES = /* @__PURE__ */ new Set(["table", "details", "list"
71
73
  const CHART_BLOCK_TYPES = /* @__PURE__ */ new Set(["chart"]);
72
74
  const COMMENTS_PAGE_SIZE_VALUES = /* @__PURE__ */ new Set([5, 10, 20, 50, 100, 200]);
73
75
  const RECORD_HISTORY_INTERNAL_COLLECTIONS = /* @__PURE__ */ new Set(["recordHistories", "recordFieldHistories"]);
76
+ const VISIBLE_FIELD_REQUIRED_DATA_BLOCK_TYPES = /* @__PURE__ */ new Set([
77
+ "table",
78
+ "list",
79
+ "gridCard",
80
+ "details",
81
+ "createForm",
82
+ "editForm",
83
+ "filterForm",
84
+ "kanban"
85
+ ]);
86
+ const VISIBLE_FIELD_MINIMUM_DATA_BLOCK_TYPES = /* @__PURE__ */ new Set(["table", "list", "gridCard", "details"]);
87
+ const IMPLICIT_RELATION_TITLE_FIELD_DISPLAY_BLOCK_TYPES = /* @__PURE__ */ new Set(["table", "list", "gridCard", "details"]);
88
+ const IMPLICIT_RELATION_TITLE_FIELD_CONTAINER_USE_BY_BLOCK_TYPE = {
89
+ details: "DetailsItemModel",
90
+ gridCard: "GridCardItemModel",
91
+ list: "ListItemModel",
92
+ table: "TableColumnModel"
93
+ };
94
+ const RICH_COLLECTION_VISIBLE_FIELD_THRESHOLD = import_public_data_surface_default_filter.FLOW_SURFACE_DEFAULT_FILTER_REQUIRED_FIELD_COUNT * 2;
95
+ const RICH_DATA_BLOCK_VISIBLE_FIELD_MINIMUM = 3;
96
+ const NON_BUSINESS_VISIBLE_FIELD_NAMES = /* @__PURE__ */ new Set([
97
+ "id",
98
+ "uid",
99
+ "createdAt",
100
+ "updatedAt",
101
+ "deletedAt",
102
+ "createdBy",
103
+ "updatedBy",
104
+ "deletedBy",
105
+ "createdById",
106
+ "updatedById",
107
+ "deletedById",
108
+ "created_at",
109
+ "updated_at",
110
+ "deleted_at",
111
+ "created_by",
112
+ "updated_by",
113
+ "deleted_by"
114
+ ]);
115
+ const NON_BUSINESS_VISIBLE_FIELD_INTERFACES = /* @__PURE__ */ new Set([
116
+ "id",
117
+ "createdAt",
118
+ "updatedAt",
119
+ "createdBy",
120
+ "updatedBy",
121
+ "sort"
122
+ ]);
123
+ const NON_BUSINESS_VISIBLE_FIELD_TYPES = /* @__PURE__ */ new Set([
124
+ "action",
125
+ "actions",
126
+ "button",
127
+ "divider",
128
+ "operation",
129
+ "operations",
130
+ "sort"
131
+ ]);
74
132
  const ANT_DESIGN_ICON_NAMES = new Set(Object.keys(antDesignIconAsn || {}));
75
133
  const PUBLIC_BLOCK_TYPE_BY_MODEL_USE = {
76
134
  TableBlockModel: "table",
@@ -106,12 +164,43 @@ const GRID_CARD_ALLOWED_SETTINGS_KEYS = /* @__PURE__ */ new Set([
106
164
  "sorting",
107
165
  "layout"
108
166
  ]);
167
+ const TABLE_ALLOWED_SETTINGS_KEYS = /* @__PURE__ */ new Set([...(0, import_configure_options.getConfigureOptionKeysForUse)("TableBlockModel"), "sort"]);
168
+ const TABLE_INTERNAL_AUTHORING_KEYS = ["tableSettings", "defaultSorting", "stepParams"];
169
+ const TABLE_SETTINGS_REPAIR_HINT = "Use public table settings keys such as settings.pageSize, settings.sorting, settings.dataScope, settings.density, settings.showRowNumbers, settings.treeTable, settings.dragSort, and settings.dragSortBy. Do not nest persisted tableSettings/defaultSorting/stepParams payloads.";
109
170
  const JS_BLOCK_ALLOWED_SETTINGS_KEYS = /* @__PURE__ */ new Set(["title", "description", "className", "code", "version"]);
110
171
  const JS_BLOCK_TOP_LEVEL_JS_KEYS = ["code", "version"];
111
172
  const JS_BLOCK_INTERNAL_AUTHORING_KEYS = ["props", "decoratorProps", "flowRegistry", "stepParams"];
173
+ const JS_BLOCK_REPAIR_HINT = "This is a jsBlock payload shape problem. Repair this jsBlock using inline settings.code/settings.version, or applyBlueprint assets.scripts.<key>.code plus block.script. Do not change this block type to table, chart, actionPanel, gridCard, or another block type.";
174
+ const CHART_REPAIR_HINT = "This is a chart payload shape problem. Keep using chart and repair this chart using assets.charts.<key>.query/visual plus block.chart, or localized settings.query/settings.visual. Do not change this block type to table, jsBlock, actionPanel, gridCard, or another block type, and do not drop or defer the chart. KPI / summary numbers should use jsBlock; charts are for trends, distributions, rankings, and visual analysis.";
175
+ const REPAIR_ALL_ERRORS_AGENT_INSTRUCTION = "If this response contains errors[], fix every listed error in one payload revision before retrying the same write. Do not fix only this error and immediately retry.";
176
+ const JS_BLOCK_AGENT_INSTRUCTION = `${REPAIR_ALL_ERRORS_AGENT_INSTRUCTION} Do not skip, drop, defer, or replace this required jsBlock. Repair it as jsBlock.`;
177
+ const CHART_AGENT_INSTRUCTION = `${REPAIR_ALL_ERRORS_AGENT_INSTRUCTION} Do not skip, drop, defer, or replace this required chart. Repair it as chart.`;
178
+ const VISIBLE_DATA_BLOCK_FIELDS_REPAIR_HINT = "Add direct visible collection fields to this block. Do not rely on defaults.collections.*.fieldGroups, action-only fields, dividers, or generated popup/form defaults as a substitute for visible block fields.";
179
+ const JS_BLOCK_FORBIDDEN_FALLBACKS = [
180
+ "table",
181
+ "list",
182
+ "chart",
183
+ "actionPanel",
184
+ "gridCard",
185
+ "markdown",
186
+ "drop jsBlock",
187
+ "defer jsBlock"
188
+ ];
189
+ const CHART_FORBIDDEN_FALLBACKS = [
190
+ "table",
191
+ "list",
192
+ "jsBlock",
193
+ "actionPanel",
194
+ "gridCard",
195
+ "markdown",
196
+ "drop chart",
197
+ "defer chart"
198
+ ];
112
199
  const CHART_QUERY_MODE_SET = new Set(import_chart_config.CHART_QUERY_MODES);
113
200
  const CHART_VISUAL_MODE_SET = new Set(import_chart_config.CHART_VISUAL_MODES);
114
201
  const CHART_BASIC_VISUAL_TYPE_SET = new Set(import_chart_config.CHART_BASIC_VISUAL_TYPES);
202
+ const CHART_BASIC_VISUAL_TYPE_LIST = import_chart_config.CHART_BASIC_VISUAL_TYPES.join(", ");
203
+ const STRICT_LOCALIZED_CHART_ACTIONS = /* @__PURE__ */ new Set(["compose", "addBlocks"]);
115
204
  const CHART_VISUAL_LEGACY_BUILDER_KEYS = /* @__PURE__ */ new Set([
116
205
  "xField",
117
206
  "yField",
@@ -146,6 +235,7 @@ const CHART_SQL_QUERY_FORBIDDEN_KEYS = /* @__PURE__ */ new Set([
146
235
  "offset"
147
236
  ]);
148
237
  const CHART_CUSTOM_VISUAL_FORBIDDEN_KEYS = /* @__PURE__ */ new Set(["type", "mappings", "style"]);
238
+ const CHART_DEFAULT_DATA_SOURCE_KEY = "main";
149
239
  const JS_ITEM_COLLECTION_ACTION_HOST_BLOCK_TYPES = /* @__PURE__ */ new Set(["table", "list", "gridCard", "calendar", "kanban"]);
150
240
  const JS_ITEM_RECORD_ACTION_HOST_BLOCK_TYPES = /* @__PURE__ */ new Set(["table", "details", "list", "gridCard"]);
151
241
  const JS_ITEM_FORM_ACTION_HOST_BLOCK_TYPES = /* @__PURE__ */ new Set(["createForm", "editForm"]);
@@ -264,6 +354,67 @@ const DEFAULT_POPUPS_ALLOWED_KEYS = ["view", "addNew", "edit", "associations"];
264
354
  const DEFAULT_POPUP_ACTION_ALLOWED_KEYS = ["name", "description"];
265
355
  const DEFAULT_POPUP_ASSOCIATION_ALLOWED_KEYS = ["view", "addNew", "edit"];
266
356
  const DEFAULT_POPUP_ACTIONS = ["view", "addNew", "edit"];
357
+ const AUTHORING_AI_EMPLOYEE_WORK_CONTEXT_PUBLIC_KEYS = ["type", "uid", "target"];
358
+ const AUTHORING_AI_EMPLOYEE_TASK_PUBLIC_SETTING_KEYS = [
359
+ "title",
360
+ "message",
361
+ "autoSend",
362
+ "skillSettings",
363
+ "model",
364
+ "webSearch"
365
+ ];
366
+ const AUTHORING_AI_EMPLOYEE_TASK_MESSAGE_PUBLIC_KEYS = ["system", "user", "workContext"];
367
+ const AUTHORING_AI_EMPLOYEE_TASK_MODEL_PUBLIC_KEYS = ["llmService", "model"];
368
+ const AUTHORING_AI_EMPLOYEE_SKILL_SETTINGS_PUBLIC_KEYS = ["skills", "tools", "skillsVersion", "toolsVersion"];
369
+ const AUTHORING_AI_EMPLOYEE_STYLE_PUBLIC_KEYS = ["size", "mask"];
370
+ const AUTHORING_AI_EMPLOYEE_DEFAULT_STYLE = {
371
+ size: 40,
372
+ mask: false
373
+ };
374
+ function buildCalendarMainBlockRepairDetails(section) {
375
+ const popupSectionHint = section === "fieldGroups" || section === "recordActions" || section === "fieldsLayout" ? " Put event form/details content under settings.quickCreatePopup or settings.eventPopup instead of on the calendar main block." : "";
376
+ return {
377
+ repairHint: "Calendar main block payload shape issue. Put event bindings under settings.titleField, settings.startField, settings.endField, and optional settings.colorField; do not put collection fields in block fields. Keep block type calendar and repair this payload." + popupSectionHint,
378
+ example: {
379
+ type: "calendar",
380
+ collection: "tasks",
381
+ settings: {
382
+ titleField: "title",
383
+ startField: "startAt",
384
+ endField: "endAt"
385
+ }
386
+ }
387
+ };
388
+ }
389
+ function buildKanbanMainBlockRepairDetails(section) {
390
+ return {
391
+ repairHint: "Kanban main block payload shape issue. Put card display fields in block fields, grouping in settings.groupField, and quick-create/card details under settings.quickCreatePopup or settings.cardPopup. Keep block type kanban and repair this payload.",
392
+ section,
393
+ example: {
394
+ type: "kanban",
395
+ collection: "tasks",
396
+ fields: ["title", "priority"],
397
+ settings: {
398
+ groupField: "status"
399
+ }
400
+ }
401
+ };
402
+ }
403
+ function buildTwoColumnLayoutRepairDetails() {
404
+ return {
405
+ repairHint: "When multiple non-filter blocks should share a row, put them in the same layout row. Do not place every block on a separate row.",
406
+ example: {
407
+ layout: {
408
+ rows: [
409
+ [
410
+ { key: "calendar", span: 12 },
411
+ { key: "kanban", span: 12 }
412
+ ]
413
+ ]
414
+ }
415
+ }
416
+ };
417
+ }
267
418
  async function assertFlowSurfaceAuthoringPayload(actionName, values, context = {}) {
268
419
  const errors = await collectFlowSurfaceAuthoringErrors(actionName, values, context);
269
420
  if (errors.length) {
@@ -280,6 +431,14 @@ async function collectFlowSurfaceAuthoringErrors(actionName, values, context = {
280
431
  if (!_.isPlainObject(values)) {
281
432
  return errors;
282
433
  }
434
+ validationContext.getDefaultFieldGroups = validationContext.getDefaultFieldGroups || ((dataSourceKey, collectionName) => {
435
+ var _a2;
436
+ return (_a2 = (0, import_defaults.resolveFlowSurfaceApplyBlueprintDefaultCollection)({
437
+ metadata: values == null ? void 0 : values.defaults,
438
+ dataSourceKey,
439
+ collectionName
440
+ }).collectionDefaults) == null ? void 0 : _a2.fieldGroups;
441
+ });
283
442
  if (actionName === "applyBlueprint" && _.isPlainObject((_a = values == null ? void 0 : values.assets) == null ? void 0 : _a.scripts)) {
284
443
  validationContext.applyBlueprintScriptAssets = values.assets.scripts;
285
444
  }
@@ -292,7 +451,7 @@ async function collectFlowSurfaceAuthoringErrors(actionName, values, context = {
292
451
  collectApplyBlueprintChartAssetErrors(actionName, values, validationContext, errors);
293
452
  if (actionName === "configure") {
294
453
  await collectConfigureErrors(values, errors, validationContext);
295
- errors.push(...(0, import_runjs_authoring.collectRunJsAuthoringErrors)(actionName, values, validationContext));
454
+ appendRunJsAuthoringErrors(actionName, values, validationContext, errors);
296
455
  if (!validationContext.skipGeneratedPopupDefaultFieldGroups) {
297
456
  collectGeneratedPopupDefaultFieldGroupErrors(actionName, values, validationContext, errors);
298
457
  }
@@ -313,9 +472,42 @@ async function collectFlowSurfaceAuthoringErrors(actionName, values, context = {
313
472
  if (!validationContext.skipGeneratedPopupDefaultFieldGroups) {
314
473
  collectGeneratedPopupDefaultFieldGroupErrors(actionName, values, validationContext, errors);
315
474
  }
316
- errors.push(...(0, import_runjs_authoring.collectRunJsAuthoringErrors)(actionName, values, validationContext));
475
+ appendRunJsAuthoringErrors(actionName, values, validationContext, errors);
317
476
  return errors;
318
477
  }
478
+ function appendRunJsAuthoringErrors(actionName, values, context, errors) {
479
+ try {
480
+ errors.push(...(0, import_runjs_authoring.collectRunJsAuthoringErrors)(actionName, values, context));
481
+ } catch (error) {
482
+ if (shouldKeepExistingChartAuthoringErrors(error, errors)) {
483
+ return;
484
+ }
485
+ if (isChartBadRequestError(error)) {
486
+ pushChartBadRequestAuthoringError(errors, error, actionName === "configure" ? "$.changes" : "$");
487
+ return;
488
+ }
489
+ throw error;
490
+ }
491
+ }
492
+ function isChartBadRequestError(error) {
493
+ return error instanceof import_errors.FlowSurfaceBadRequestError && String(error.message || "").startsWith("chart ");
494
+ }
495
+ function shouldKeepExistingChartAuthoringErrors(error, errors) {
496
+ return isChartBadRequestError(error) && errors.some((item) => {
497
+ var _a;
498
+ return ((_a = item.details) == null ? void 0 : _a.repairHint) === CHART_REPAIR_HINT;
499
+ });
500
+ }
501
+ function pushChartBadRequestAuthoringError(errors, error, fallbackPath) {
502
+ var _a, _b, _c;
503
+ const details = _.isPlainObject((_a = error.options) == null ? void 0 : _a.details) ? error.options.details : {};
504
+ pushAuthoringError(errors, {
505
+ path: typeof ((_b = error.options) == null ? void 0 : _b.path) === "string" && error.options.path ? error.options.path : fallbackPath,
506
+ ruleId: typeof ((_c = error.options) == null ? void 0 : _c.ruleId) === "string" && error.options.ruleId ? error.options.ruleId : "chart-configure-invalid",
507
+ message: error.message,
508
+ details: withChartRepairHint(details)
509
+ });
510
+ }
319
511
  async function collectNavigationGroupErrors(actionName, values, context, errors) {
320
512
  var _a;
321
513
  if (actionName !== "applyBlueprint" || (values == null ? void 0 : values.mode) !== "create" || !_.isPlainObject((_a = values == null ? void 0 : values.navigation) == null ? void 0 : _a.group)) {
@@ -329,38 +521,43 @@ async function collectNavigationGroupErrors(actionName, values, context, errors)
329
521
  return;
330
522
  }
331
523
  const matchedRoutes = await context.findMenuGroupRoutesByTitle(groupTitle, context.transaction);
332
- if (matchedRoutes.length <= 1) {
524
+ const rootMatchedRoutes = filterRootMenuGroupRoutes(matchedRoutes);
525
+ if (rootMatchedRoutes.length <= 1) {
333
526
  return;
334
527
  }
335
528
  pushAuthoringError(errors, {
336
529
  path: "$.navigation.group.title",
337
530
  ruleId: "navigation-group-title-ambiguous",
338
- message: `flowSurfaces authoring $.navigation.group.title '${groupTitle}' matches ${matchedRoutes.length} existing menu groups; pass navigation.group.routeId explicitly`,
531
+ message: `flowSurfaces authoring $.navigation.group.title '${groupTitle}' matches ${rootMatchedRoutes.length} existing root menu groups; pass navigation.group.routeId explicitly`,
339
532
  details: {
340
533
  title: groupTitle,
341
- matches: matchedRoutes.length
534
+ parentMenuRouteId: null,
535
+ matches: rootMatchedRoutes.length
342
536
  }
343
537
  });
344
538
  }
345
539
  async function collectNavigationIconErrors(actionName, values, context, errors) {
346
- var _a, _b;
540
+ var _a, _b, _c;
347
541
  if (actionName !== "applyBlueprint" || (values == null ? void 0 : values.mode) !== "create") {
348
542
  return;
349
543
  }
350
544
  const group = _.isPlainObject((_a = values == null ? void 0 : values.navigation) == null ? void 0 : _a.group) ? values.navigation.group : null;
351
545
  const groupRouteId = String((group == null ? void 0 : group.routeId) || "").trim();
352
- if (group && !groupRouteId) {
546
+ if (group && !groupRouteId && group.hideInMenu !== true) {
353
547
  const groupIcon = String(group.icon || "").trim();
354
548
  if (!groupIcon && await shouldRequireNewNavigationGroupIcon(group, context)) {
355
549
  pushAuthoringError(errors, {
356
550
  path: "$.navigation.group.icon",
357
- ruleId: "missing-menu-group-icon",
358
- message: "flowSurfaces authoring $.navigation.group.icon is required when creating a new navigation group"
551
+ ruleId: "navigation-icon-required",
552
+ message: "flowSurfaces authoring $.navigation.group.icon is required when creating a visible navigation group",
553
+ details: {
554
+ repairHint: "Pass a valid Ant Design icon name such as AppstoreOutlined, DashboardOutlined, or FolderOpenOutlined."
555
+ }
359
556
  });
360
557
  } else if (groupIcon && !isValidAntDesignIconName(groupIcon)) {
361
558
  pushAuthoringError(errors, {
362
559
  path: "$.navigation.group.icon",
363
- ruleId: "invalid-menu-group-icon",
560
+ ruleId: "navigation-icon-unknown",
364
561
  message: "flowSurfaces authoring $.navigation.group.icon must be a valid Ant Design icon name",
365
562
  details: {
366
563
  icon: groupIcon
@@ -370,7 +567,7 @@ async function collectNavigationIconErrors(actionName, values, context, errors)
370
567
  } else if (group && String(group.icon || "").trim() && !isValidAntDesignIconName(group.icon)) {
371
568
  pushAuthoringError(errors, {
372
569
  path: "$.navigation.group.icon",
373
- ruleId: "invalid-menu-group-icon",
570
+ ruleId: "navigation-icon-unknown",
374
571
  message: "flowSurfaces authoring $.navigation.group.icon must be a valid Ant Design icon name",
375
572
  details: {
376
573
  icon: String(group.icon || "").trim()
@@ -382,13 +579,24 @@ async function collectNavigationIconErrors(actionName, values, context, errors)
382
579
  if (itemIcon && !isValidAntDesignIconName(itemIcon)) {
383
580
  pushAuthoringError(errors, {
384
581
  path: "$.navigation.item.icon",
385
- ruleId: "invalid-menu-item-icon",
582
+ ruleId: "navigation-icon-unknown",
386
583
  message: "flowSurfaces authoring $.navigation.item.icon must be a valid Ant Design icon name",
387
584
  details: {
388
585
  icon: itemIcon
389
586
  }
390
587
  });
391
588
  }
589
+ const pageIcon = String(((_c = values == null ? void 0 : values.page) == null ? void 0 : _c.icon) || "").trim();
590
+ if (pageIcon && !isValidAntDesignIconName(pageIcon)) {
591
+ pushAuthoringError(errors, {
592
+ path: "$.page.icon",
593
+ ruleId: "navigation-icon-unknown",
594
+ message: "flowSurfaces authoring $.page.icon must be a valid Ant Design icon name when used as the create-mode page route icon",
595
+ details: {
596
+ icon: pageIcon
597
+ }
598
+ });
599
+ }
392
600
  }
393
601
  async function shouldRequireNewNavigationGroupIcon(group, context) {
394
602
  const groupTitle = String((group == null ? void 0 : group.title) || "").trim();
@@ -396,7 +604,22 @@ async function shouldRequireNewNavigationGroupIcon(group, context) {
396
604
  return true;
397
605
  }
398
606
  const matchedRoutes = await context.findMenuGroupRoutesByTitle(groupTitle, context.transaction);
399
- return matchedRoutes.length === 0;
607
+ return filterRootMenuGroupRoutes(matchedRoutes).length === 0;
608
+ }
609
+ function filterRootMenuGroupRoutes(routes) {
610
+ return _.castArray(routes || []).filter(
611
+ (route) => routeParentIdMatches(readAuthoringRouteField(route, "parentId"), null)
612
+ );
613
+ }
614
+ function readAuthoringRouteField(route, key) {
615
+ var _a;
616
+ return ((_a = route == null ? void 0 : route.get) == null ? void 0 : _a.call(route, key)) ?? (route == null ? void 0 : route[key]);
617
+ }
618
+ function routeParentIdMatches(routeParentId, parentId) {
619
+ if (_.isNil(routeParentId) && _.isNil(parentId)) {
620
+ return true;
621
+ }
622
+ return String(routeParentId ?? "") === String(parentId ?? "");
400
623
  }
401
624
  function isValidAntDesignIconName(value) {
402
625
  const normalized = String(value || "").trim();
@@ -494,6 +717,355 @@ function collectChartAssetBlockTreeErrors(block, path, chartAssets, errors) {
494
717
  );
495
718
  });
496
719
  }
720
+ function withJsBlockRepairHint(details = {}) {
721
+ return {
722
+ ...details,
723
+ requiredBlockType: "jsBlock",
724
+ fixStrategy: "repair_same_block_type",
725
+ repairHint: JS_BLOCK_REPAIR_HINT,
726
+ agentInstruction: JS_BLOCK_AGENT_INSTRUCTION,
727
+ repairExample: {
728
+ inlineBlock: {
729
+ type: "jsBlock",
730
+ settings: {
731
+ code: 'ctx.render("Replace this with the required rendered UI");'
732
+ }
733
+ },
734
+ assetBlock: {
735
+ assets: {
736
+ scripts: {
737
+ scriptKey: {
738
+ code: 'ctx.render("Replace this with the required rendered UI");'
739
+ }
740
+ }
741
+ },
742
+ block: {
743
+ type: "jsBlock",
744
+ script: "scriptKey"
745
+ }
746
+ }
747
+ },
748
+ forbiddenFallbacks: JS_BLOCK_FORBIDDEN_FALLBACKS
749
+ };
750
+ }
751
+ function withChartRepairHint(details = {}) {
752
+ return {
753
+ ...details,
754
+ requiredBlockType: "chart",
755
+ fixStrategy: "repair_same_block_type",
756
+ repairHint: CHART_REPAIR_HINT,
757
+ agentInstruction: CHART_AGENT_INSTRUCTION,
758
+ repairSteps: [
759
+ "Keep the block type as chart.",
760
+ "Define assets.charts.<key>.query and assets.charts.<key>.visual.",
761
+ "Reference that asset from the chart block with block.chart = <key>.",
762
+ "Retry the chart payload instead of replacing the chart with another block type or omitting it."
763
+ ],
764
+ expectedShape: {
765
+ settings: {
766
+ query: {
767
+ mode: "builder",
768
+ resource: {
769
+ dataSourceKey: "main",
770
+ collectionName: "employees"
771
+ },
772
+ measures: [
773
+ {
774
+ field: "id",
775
+ aggregation: "count",
776
+ alias: "employeeCount"
777
+ }
778
+ ]
779
+ },
780
+ visual: {
781
+ mode: "basic",
782
+ type: "bar",
783
+ mappings: {
784
+ x: "status",
785
+ y: "employeeCount"
786
+ }
787
+ }
788
+ },
789
+ legacySettings: {
790
+ configure: {
791
+ query: {
792
+ mode: "builder",
793
+ resource: {
794
+ dataSourceKey: "main",
795
+ collectionName: "employees"
796
+ },
797
+ measures: [
798
+ {
799
+ field: "id",
800
+ aggregation: "count",
801
+ alias: "employeeCount"
802
+ }
803
+ ]
804
+ },
805
+ chart: {
806
+ option: {
807
+ mode: "basic",
808
+ builder: {
809
+ type: "bar",
810
+ xField: "status",
811
+ yField: "employeeCount"
812
+ }
813
+ }
814
+ }
815
+ }
816
+ },
817
+ assets: {
818
+ charts: {
819
+ chartKey: {
820
+ query: "builder/sql query configuration",
821
+ visual: "basic/custom visual configuration"
822
+ }
823
+ }
824
+ },
825
+ block: {
826
+ type: "chart",
827
+ chart: "chartKey"
828
+ }
829
+ },
830
+ repairExample: {
831
+ settings: {
832
+ query: {
833
+ mode: "builder",
834
+ resource: {
835
+ dataSourceKey: "main",
836
+ collectionName: "<collectionName>"
837
+ },
838
+ measures: [
839
+ {
840
+ field: "id",
841
+ aggregation: "count",
842
+ alias: "recordCount"
843
+ }
844
+ ],
845
+ dimensions: [
846
+ {
847
+ field: "<dimensionField>"
848
+ }
849
+ ]
850
+ },
851
+ visual: {
852
+ mode: "basic",
853
+ type: "bar",
854
+ mappings: {
855
+ x: "<dimensionField>",
856
+ y: "recordCount"
857
+ }
858
+ }
859
+ },
860
+ assets: {
861
+ charts: {
862
+ chartKey: {
863
+ query: {
864
+ mode: "builder",
865
+ resource: {
866
+ dataSourceKey: "main",
867
+ collectionName: "<collectionName>"
868
+ },
869
+ measures: [
870
+ {
871
+ field: "id",
872
+ aggregation: "count",
873
+ alias: "recordCount"
874
+ }
875
+ ],
876
+ dimensions: [
877
+ {
878
+ field: "<dimensionField>"
879
+ }
880
+ ]
881
+ },
882
+ visual: {
883
+ mode: "basic",
884
+ type: "bar",
885
+ mappings: {
886
+ x: "<dimensionField>",
887
+ y: "recordCount"
888
+ }
889
+ }
890
+ }
891
+ }
892
+ },
893
+ block: {
894
+ type: "chart",
895
+ chart: "chartKey"
896
+ }
897
+ },
898
+ forbiddenFallbacks: CHART_FORBIDDEN_FALLBACKS
899
+ };
900
+ }
901
+ function withUnsupportedChartVisualTypeHint(details = {}) {
902
+ const jsBlockHint = `Supported basic chart visual types are: ${CHART_BASIC_VISUAL_TYPE_LIST}. If the required visualization cannot be represented by these chart types, use a jsBlock instead.`;
903
+ return {
904
+ ...details,
905
+ fixStrategy: "use_supported_chart_type_or_jsBlock",
906
+ repairHint: jsBlockHint,
907
+ agentInstruction: `${REPAIR_ALL_ERRORS_AGENT_INSTRUCTION} Use one of the supported chart visual types, or use a jsBlock when the requested visualization is outside the chart plugin capabilities.`,
908
+ supportedVisualTypes: [...import_chart_config.CHART_BASIC_VISUAL_TYPES],
909
+ alternativeBlockType: "jsBlock",
910
+ alternativeHint: jsBlockHint,
911
+ forbiddenFallbacks: CHART_FORBIDDEN_FALLBACKS.filter((item) => item !== "jsBlock")
912
+ };
913
+ }
914
+ function collectLocalizedChartSettingsErrors(block, blockType, path, errors, context) {
915
+ if (blockType !== "chart" || !STRICT_LOCALIZED_CHART_ACTIONS.has(context.authoringActionName)) {
916
+ return;
917
+ }
918
+ const settingsPath = `${path}.settings`;
919
+ if (!_.isUndefined(block.settings) && !_.isPlainObject(block.settings)) {
920
+ pushAuthoringError(errors, {
921
+ path: settingsPath,
922
+ ruleId: "chart-localized-settings-invalid",
923
+ message: `flowSurfaces authoring ${settingsPath} must be an object for compose/addBlocks chart blocks`,
924
+ details: withChartRepairHint()
925
+ });
926
+ return;
927
+ }
928
+ const settings = _.isPlainObject(block.settings) ? block.settings : {};
929
+ if (hasOwn(settings, "configure")) {
930
+ if (["query", "visual", "events"].some((key) => hasOwn(settings, key))) {
931
+ pushAuthoringError(errors, {
932
+ path: settingsPath,
933
+ ruleId: "chart-localized-settings-mixed-configure",
934
+ message: `flowSurfaces authoring ${settingsPath} cannot mix legacy configure with query/visual/events`,
935
+ details: withChartRepairHint()
936
+ });
937
+ return;
938
+ }
939
+ collectLocalizedLegacyChartConfigureErrors(settings.configure, `${settingsPath}.configure`, errors);
940
+ return;
941
+ }
942
+ if (!hasOwn(settings, "query") && !hasOwn(settings, "visual")) {
943
+ return;
944
+ }
945
+ collectChartAssetQueryErrors(settings, settingsPath, context, errors);
946
+ collectChartAssetVisualErrors(settings, settingsPath, errors);
947
+ }
948
+ function collectLocalizedLegacyChartConfigureErrors(configure, path, errors) {
949
+ if (!_.isPlainObject(configure)) {
950
+ pushAuthoringError(errors, {
951
+ path,
952
+ ruleId: "chart-configure-invalid",
953
+ message: `flowSurfaces authoring ${path} must be an object`,
954
+ details: withChartRepairHint()
955
+ });
956
+ return;
957
+ }
958
+ collectLegacyChartQueryCompatibilityErrors(configure.query, `${path}.query`, errors);
959
+ }
960
+ function collectLegacyChartQueryCompatibilityErrors(query, path, errors) {
961
+ if (!_.isPlainObject(query)) {
962
+ return;
963
+ }
964
+ collectChartQueryFilterOperatorErrors(query, path, errors);
965
+ const hasResource = hasOwn(query, "resource");
966
+ const hasCollectionPath = hasOwn(query, "collectionPath");
967
+ if (!hasResource && !hasCollectionPath) {
968
+ return;
969
+ }
970
+ const resource = hasResource ? normalizeLegacyChartResourceForValidation(query.resource, `${path}.resource`, errors) : void 0;
971
+ const collectionPathResource = hasCollectionPath ? normalizeLegacyChartCollectionPathResourceForValidation(query.collectionPath, `${path}.collectionPath`, errors) : void 0;
972
+ if (hasResource && hasCollectionPath && resource && collectionPathResource && !_.isEqual(resource, collectionPathResource)) {
973
+ pushAuthoringError(errors, {
974
+ path,
975
+ ruleId: "chart-legacy-query-resource-conflict",
976
+ message: `flowSurfaces authoring ${path}.resource and ${path}.collectionPath must reference the same collection`,
977
+ details: withChartRepairHint({
978
+ resource,
979
+ collectionPathResource
980
+ })
981
+ });
982
+ }
983
+ }
984
+ function normalizeLegacyChartCollectionPathResource(collectionPath) {
985
+ if (!Array.isArray(collectionPath)) {
986
+ return void 0;
987
+ }
988
+ const collectionName = normalizeLegacyChartRequiredString(collectionPath[1]);
989
+ if (!collectionName) {
990
+ return void 0;
991
+ }
992
+ const dataSourceKey = normalizeLegacyChartCollectionPathDataSourceKey(collectionPath[0]);
993
+ if (!dataSourceKey) {
994
+ return void 0;
995
+ }
996
+ return {
997
+ dataSourceKey,
998
+ collectionName
999
+ };
1000
+ }
1001
+ function normalizeLegacyChartResourceForValidation(resource, path, errors) {
1002
+ if (!_.isPlainObject(resource)) {
1003
+ pushAuthoringError(errors, {
1004
+ path,
1005
+ ruleId: "chart-legacy-query-resource-invalid",
1006
+ message: `flowSurfaces authoring ${path} must be an object with string collectionName`,
1007
+ details: withChartRepairHint()
1008
+ });
1009
+ return void 0;
1010
+ }
1011
+ const collectionName = normalizeLegacyChartRequiredString(resource.collectionName);
1012
+ if (!collectionName) {
1013
+ pushAuthoringError(errors, {
1014
+ path: `${path}.collectionName`,
1015
+ ruleId: "chart-legacy-query-resource-invalid",
1016
+ message: `flowSurfaces authoring ${path}.collectionName must be a non-empty string`,
1017
+ details: withChartRepairHint()
1018
+ });
1019
+ return void 0;
1020
+ }
1021
+ const dataSourceKey = normalizeLegacyChartResourceDataSourceKey(resource.dataSourceKey);
1022
+ if (!dataSourceKey) {
1023
+ pushAuthoringError(errors, {
1024
+ path: `${path}.dataSourceKey`,
1025
+ ruleId: "chart-legacy-query-resource-invalid",
1026
+ message: `flowSurfaces authoring ${path}.dataSourceKey must be a non-empty string when provided`,
1027
+ details: withChartRepairHint()
1028
+ });
1029
+ return void 0;
1030
+ }
1031
+ return {
1032
+ dataSourceKey,
1033
+ collectionName
1034
+ };
1035
+ }
1036
+ function normalizeLegacyChartCollectionPathResourceForValidation(collectionPath, path, errors) {
1037
+ const resource = normalizeLegacyChartCollectionPathResource(collectionPath);
1038
+ if (!resource) {
1039
+ pushAuthoringError(errors, {
1040
+ path,
1041
+ ruleId: "chart-legacy-query-collection-path-invalid",
1042
+ message: `flowSurfaces authoring ${path} must be [dataSourceKey, collectionName] with string values and a non-empty collectionName`,
1043
+ details: withChartRepairHint()
1044
+ });
1045
+ }
1046
+ return resource;
1047
+ }
1048
+ function normalizeLegacyChartRequiredString(input) {
1049
+ if (typeof input !== "string") {
1050
+ return void 0;
1051
+ }
1052
+ return input.trim() || void 0;
1053
+ }
1054
+ function normalizeLegacyChartResourceDataSourceKey(input) {
1055
+ if (_.isUndefined(input) || _.isNull(input)) {
1056
+ return CHART_DEFAULT_DATA_SOURCE_KEY;
1057
+ }
1058
+ return normalizeLegacyChartRequiredString(input);
1059
+ }
1060
+ function normalizeLegacyChartCollectionPathDataSourceKey(input) {
1061
+ if (_.isUndefined(input) || _.isNull(input)) {
1062
+ return CHART_DEFAULT_DATA_SOURCE_KEY;
1063
+ }
1064
+ if (typeof input === "string" && !input.trim()) {
1065
+ return CHART_DEFAULT_DATA_SOURCE_KEY;
1066
+ }
1067
+ return normalizeLegacyChartRequiredString(input);
1068
+ }
497
1069
  function collectChartBlockAssetReferenceErrors(block, path, chartAssets, errors) {
498
1070
  if (!CHART_BLOCK_TYPES.has(String((block == null ? void 0 : block.type) || "").trim())) {
499
1071
  return;
@@ -502,7 +1074,8 @@ function collectChartBlockAssetReferenceErrors(block, path, chartAssets, errors)
502
1074
  pushAuthoringError(errors, {
503
1075
  path: `${path}.stepParams`,
504
1076
  ruleId: "chart-block-step-params-unsupported",
505
- message: `flowSurfaces authoring ${path}.stepParams is not accepted on public chart blocks; put chart configuration under assets.charts and reference it with block.chart`
1077
+ message: `flowSurfaces authoring ${path}.stepParams is not accepted on public chart blocks; put chart configuration under assets.charts and reference it with block.chart`,
1078
+ details: withChartRepairHint()
506
1079
  });
507
1080
  }
508
1081
  const chartKey = String(block.chart || "").trim();
@@ -510,7 +1083,8 @@ function collectChartBlockAssetReferenceErrors(block, path, chartAssets, errors)
510
1083
  pushAuthoringError(errors, {
511
1084
  path: `${path}.chart`,
512
1085
  ruleId: "chart-block-asset-reference-required",
513
- message: `flowSurfaces authoring ${path}.chart must reference one key from assets.charts`
1086
+ message: `flowSurfaces authoring ${path}.chart must reference one key from assets.charts`,
1087
+ details: withChartRepairHint()
514
1088
  });
515
1089
  return;
516
1090
  }
@@ -519,9 +1093,9 @@ function collectChartBlockAssetReferenceErrors(block, path, chartAssets, errors)
519
1093
  path: `${path}.chart`,
520
1094
  ruleId: "chart-block-asset-reference-missing",
521
1095
  message: `flowSurfaces authoring ${path}.chart references missing chart asset '${chartKey}'`,
522
- details: {
1096
+ details: withChartRepairHint({
523
1097
  chartKey
524
- }
1098
+ })
525
1099
  });
526
1100
  }
527
1101
  }
@@ -535,7 +1109,8 @@ function collectChartAssetRegistryErrors(charts, path, context, errors) {
535
1109
  pushAuthoringError(errors, {
536
1110
  path: assetPath,
537
1111
  ruleId: "chart-asset-invalid",
538
- message: `flowSurfaces authoring ${assetPath} must be an object`
1112
+ message: `flowSurfaces authoring ${assetPath} must be an object`,
1113
+ details: withChartRepairHint()
539
1114
  });
540
1115
  return;
541
1116
  }
@@ -549,7 +1124,8 @@ function collectChartAssetQueryErrors(asset, path, context, errors) {
549
1124
  pushAuthoringError(errors, {
550
1125
  path: `${path}.query`,
551
1126
  ruleId: "chart-query-missing",
552
- message: `flowSurfaces authoring ${path}.query is required`
1127
+ message: `flowSurfaces authoring ${path}.query is required`,
1128
+ details: withChartRepairHint()
553
1129
  });
554
1130
  return;
555
1131
  }
@@ -559,9 +1135,9 @@ function collectChartAssetQueryErrors(asset, path, context, errors) {
559
1135
  path: `${path}.query.mode`,
560
1136
  ruleId: "chart-query-mode-unsupported",
561
1137
  message: `flowSurfaces authoring ${path}.query.mode '${mode}' is not supported`,
562
- details: {
1138
+ details: withChartRepairHint({
563
1139
  mode
564
- }
1140
+ })
565
1141
  });
566
1142
  return;
567
1143
  }
@@ -577,14 +1153,16 @@ function collectBuilderChartAssetQueryErrors(query, path, context, errors) {
577
1153
  pushAuthoringError(errors, {
578
1154
  path: `${path}.query.resource`,
579
1155
  ruleId: "chart-builder-query-resource-missing",
580
- message: `flowSurfaces authoring ${path}.query.resource.collectionName is required for builder chart assets`
1156
+ message: `flowSurfaces authoring ${path}.query.resource.collectionName is required for builder chart assets`,
1157
+ details: withChartRepairHint()
581
1158
  });
582
1159
  }
583
1160
  if (!Array.isArray(query.measures) || !query.measures.length) {
584
1161
  pushAuthoringError(errors, {
585
1162
  path: `${path}.query.measures`,
586
1163
  ruleId: "chart-builder-query-measures-missing",
587
- message: `flowSurfaces authoring ${path}.query.measures must include at least one measure`
1164
+ message: `flowSurfaces authoring ${path}.query.measures must include at least one measure`,
1165
+ details: withChartRepairHint()
588
1166
  });
589
1167
  }
590
1168
  collectForbiddenObjectKeyErrors(
@@ -592,10 +1170,88 @@ function collectBuilderChartAssetQueryErrors(query, path, context, errors) {
592
1170
  `${path}.query`,
593
1171
  CHART_BUILDER_QUERY_FORBIDDEN_KEYS,
594
1172
  "chart-builder-query-forbidden-keys",
595
- errors
1173
+ errors,
1174
+ withChartRepairHint()
596
1175
  );
1176
+ collectChartQueryFilterOperatorErrors(query, `${path}.query`, errors);
597
1177
  collectBuilderChartAssetFieldErrors(query, path, context, errors);
598
1178
  }
1179
+ function collectChartQueryFilterOperatorErrors(query, path, errors) {
1180
+ if (!_.isPlainObject(query) || !hasOwn(query, "filter")) {
1181
+ return;
1182
+ }
1183
+ collectChartFilterOperatorErrors(query.filter, `${path}.filter`, errors);
1184
+ }
1185
+ function collectChartFilterOperatorErrors(filter, path, errors) {
1186
+ if (_.isUndefined(filter) || _.isNull(filter) || !_.isPlainObject(filter)) {
1187
+ return;
1188
+ }
1189
+ if (Array.isArray(filter.items)) {
1190
+ collectChartFilterGroupOperatorErrors(filter.items, `${path}.items`, errors);
1191
+ return;
1192
+ }
1193
+ collectBackendQueryFilterOperatorErrors(filter, path, errors);
1194
+ }
1195
+ function collectChartFilterGroupOperatorErrors(items, path, errors) {
1196
+ items.forEach((item, index) => {
1197
+ const itemPath = `${path}[${index}]`;
1198
+ if (!_.isPlainObject(item)) {
1199
+ return;
1200
+ }
1201
+ if (Array.isArray(item.items)) {
1202
+ collectChartFilterGroupOperatorErrors(item.items, `${itemPath}.items`, errors);
1203
+ return;
1204
+ }
1205
+ if (hasOwn(item, "operator")) {
1206
+ collectChartFilterOperatorError(item.operator, `${itemPath}.operator`, errors);
1207
+ collectChartFilterDateValueError(item.operator, item.value, `${itemPath}.value`, errors);
1208
+ }
1209
+ });
1210
+ }
1211
+ function collectBackendQueryFilterOperatorErrors(filter, path, errors) {
1212
+ Object.entries(filter).forEach(([field, condition]) => {
1213
+ const fieldPath = `${path}.${field}`;
1214
+ if ((field === "$and" || field === "$or") && Array.isArray(condition)) {
1215
+ condition.forEach(
1216
+ (operand, index) => collectChartFilterOperatorErrors(operand, `${fieldPath}[${index}]`, errors)
1217
+ );
1218
+ return;
1219
+ }
1220
+ if (!_.isPlainObject(condition)) {
1221
+ return;
1222
+ }
1223
+ Object.keys(condition).forEach((operator) => {
1224
+ if (operator === "$and" || operator === "$or") {
1225
+ collectChartFilterOperatorErrors({ [operator]: condition[operator] }, fieldPath, errors);
1226
+ return;
1227
+ }
1228
+ collectChartFilterOperatorError(operator, `${fieldPath}.${operator}`, errors);
1229
+ collectChartFilterDateValueError(operator, condition[operator], `${fieldPath}.${operator}`, errors);
1230
+ });
1231
+ });
1232
+ }
1233
+ function collectChartFilterOperatorError(operator, path, errors) {
1234
+ try {
1235
+ (0, import_filter_group.assertFlowSurfaceFilterOperator)(operator, path);
1236
+ } catch (error) {
1237
+ if (error instanceof import_errors.FlowSurfaceBadRequestError) {
1238
+ pushChartBadRequestAuthoringError(errors, error, path);
1239
+ return;
1240
+ }
1241
+ throw error;
1242
+ }
1243
+ }
1244
+ function collectChartFilterDateValueError(operator, value, path, errors) {
1245
+ try {
1246
+ (0, import_filter_group.normalizeFlowSurfaceStrictFilterDateValue)(operator, value, path);
1247
+ } catch (error) {
1248
+ if (error instanceof import_errors.FlowSurfaceBadRequestError) {
1249
+ pushChartBadRequestAuthoringError(errors, error, path);
1250
+ return;
1251
+ }
1252
+ throw error;
1253
+ }
1254
+ }
599
1255
  function normalizeChartAssetFieldPath(input) {
600
1256
  if (Array.isArray(input)) {
601
1257
  return input.map((item) => String(item || "").trim()).filter(Boolean).join(".");
@@ -603,6 +1259,7 @@ function normalizeChartAssetFieldPath(input) {
603
1259
  return String(input || "").trim();
604
1260
  }
605
1261
  function collectBuilderChartAssetFieldErrors(query, path, context, errors) {
1262
+ var _a, _b, _c, _d, _e;
606
1263
  const resource = _.isPlainObject(query.resource) ? query.resource : null;
607
1264
  const collectionName = String((resource == null ? void 0 : resource.collectionName) || "").trim();
608
1265
  if (!collectionName || typeof context.getCollection !== "function") {
@@ -616,10 +1273,12 @@ function collectBuilderChartAssetFieldErrors(query, path, context, errors) {
616
1273
  const selections = [
617
1274
  ..._.castArray(query.measures || []).map((selection, index) => ({
618
1275
  selection,
1276
+ kind: "measure",
619
1277
  fieldPath: `${path}.query.measures[${index}].field`
620
1278
  })),
621
1279
  ..._.castArray(query.dimensions || []).map((selection, index) => ({
622
1280
  selection,
1281
+ kind: "dimension",
623
1282
  fieldPath: `${path}.query.dimensions[${index}].field`
624
1283
  }))
625
1284
  ];
@@ -631,24 +1290,80 @@ function collectBuilderChartAssetFieldErrors(query, path, context, errors) {
631
1290
  if (!fieldPath) {
632
1291
  continue;
633
1292
  }
1293
+ const fieldPathParts = fieldPath.split(".").filter(Boolean);
1294
+ const isCountMeasureSelection = item.kind === "measure" && String(((_a = item.selection) == null ? void 0 : _a.aggregation) || "").trim() === "count" && !((_b = item.selection) == null ? void 0 : _b.distinct);
1295
+ if (fieldPathParts.length > 1 && !isCountMeasureSelection) {
1296
+ const directAssociationPath = fieldPathParts[0];
1297
+ const directAssociationField = (0, import_service_helpers.resolveFieldFromCollection)(collection, directAssociationPath);
1298
+ const directAssociationTargetCollection = directAssociationField && (0, import_service_helpers.isAssociationField)(directAssociationField) ? (0, import_service_helpers.resolveFieldTargetCollection)(
1299
+ directAssociationField,
1300
+ dataSourceKey,
1301
+ (resolvedDataSourceKey, targetCollection) => {
1302
+ var _a2;
1303
+ return (_a2 = context.getCollection) == null ? void 0 : _a2.call(context, resolvedDataSourceKey, targetCollection);
1304
+ }
1305
+ ) : null;
1306
+ const invalidDirectSubfield = directAssociationTargetCollection ? (0, import_service_helpers.getInvalidChartBuilderRelationDirectSubfieldDetails)({
1307
+ associationPathName: directAssociationPath,
1308
+ selectedSubfieldPath: fieldPathParts.slice(1).join("."),
1309
+ targetCollection: directAssociationTargetCollection
1310
+ }) : null;
1311
+ if (invalidDirectSubfield) {
1312
+ pushAuthoringError(errors, {
1313
+ path: item.fieldPath,
1314
+ ruleId: "chart-builder-query-relation-direct-subfield-required",
1315
+ message: `flowSurfaces authoring ${item.fieldPath} must reference a direct scalar child field under relation '${invalidDirectSubfield.associationPath}'. ${(0, import_service_helpers.formatChartBuilderSupportedRelationSubfields)(
1316
+ invalidDirectSubfield.associationPath,
1317
+ invalidDirectSubfield.supportedFields
1318
+ )}`,
1319
+ details: withChartRepairHint({
1320
+ fieldPath,
1321
+ dataSourceKey,
1322
+ collectionName,
1323
+ ...invalidDirectSubfield
1324
+ })
1325
+ });
1326
+ continue;
1327
+ }
1328
+ }
634
1329
  const field = (0, import_service_helpers.resolveFieldFromCollection)(collection, fieldPath);
1330
+ const associationPath = fieldPath.includes(".") ? fieldPath.split(".").slice(0, -1).join(".") : "";
1331
+ const leafFieldName = fieldPath.split(".").slice(-1)[0];
1332
+ const associationField = associationPath ? (0, import_service_helpers.resolveFieldFromCollection)(collection, associationPath) : null;
1333
+ const associationTargetCollection = associationField && (0, import_service_helpers.isAssociationField)(associationField) ? (0, import_service_helpers.resolveFieldTargetCollection)(
1334
+ associationField,
1335
+ dataSourceKey,
1336
+ (resolvedDataSourceKey, targetCollection) => {
1337
+ var _a2;
1338
+ return (_a2 = context.getCollection) == null ? void 0 : _a2.call(context, resolvedDataSourceKey, targetCollection);
1339
+ }
1340
+ ) : null;
1341
+ const leafModelAttributes = (0, import_service_helpers.getCollectionModelAttributes)(associationTargetCollection || collection);
1342
+ const hasLeafModelAttribute = Object.prototype.hasOwnProperty.call(leafModelAttributes, leafFieldName);
1343
+ const isCountMeasureRelationSubfield = item.kind === "measure" && String(((_c = item.selection) == null ? void 0 : _c.aggregation) || "").trim() === "count" && !((_d = item.selection) == null ? void 0 : _d.distinct) && associationField && (0, import_service_helpers.isAssociationField)(associationField);
1344
+ const unsupportedRelationSubfield = associationTargetCollection ? (0, import_service_helpers.getUnsupportedChartBuilderRelationSubfieldDetails)({
1345
+ associationPathName: associationPath,
1346
+ leafFieldName,
1347
+ leafField: field,
1348
+ targetCollection: associationTargetCollection
1349
+ }) : null;
635
1350
  if (!field) {
636
- if (collectionHasConcreteField(collection, fieldPath)) {
1351
+ const hasConcreteField = associationTargetCollection ? hasLeafModelAttribute || collectionHasConcreteField(associationTargetCollection, leafFieldName) : collectionHasConcreteField(collection, fieldPath);
1352
+ if (!hasConcreteField) {
1353
+ pushAuthoringError(errors, {
1354
+ path: item.fieldPath,
1355
+ ruleId: "chart-builder-query-field-unknown",
1356
+ message: `flowSurfaces authoring ${item.fieldPath} references unknown field '${fieldPath}' on collection '${dataSourceKey}.${collectionName}'`,
1357
+ details: withChartRepairHint({
1358
+ fieldPath,
1359
+ dataSourceKey,
1360
+ collectionName
1361
+ })
1362
+ });
637
1363
  continue;
638
1364
  }
639
- pushAuthoringError(errors, {
640
- path: item.fieldPath,
641
- ruleId: "chart-builder-query-field-unknown",
642
- message: `flowSurfaces authoring ${item.fieldPath} references unknown field '${fieldPath}' on collection '${dataSourceKey}.${collectionName}'`,
643
- details: {
644
- fieldPath,
645
- dataSourceKey,
646
- collectionName
647
- }
648
- });
649
- continue;
650
1365
  }
651
- if (!fieldPath.includes(".") && (0, import_service_helpers.isAssociationField)(field)) {
1366
+ if (!fieldPath.includes(".") && field && (0, import_service_helpers.isAssociationField)(field)) {
652
1367
  const suggestion = resolveChartBuilderAssociationSubfieldSuggestion(
653
1368
  fieldPath,
654
1369
  field,
@@ -659,12 +1374,49 @@ function collectBuilderChartAssetFieldErrors(query, path, context, errors) {
659
1374
  path: item.fieldPath,
660
1375
  ruleId: "chart-builder-query-association-field-requires-subfield",
661
1376
  message: `flowSurfaces authoring ${item.fieldPath} references association field '${fieldPath}' directly; use scalar subfield '${suggestion.suggestedFieldPath}' for builder charts`,
662
- details: {
1377
+ details: withChartRepairHint({
663
1378
  fieldPath,
664
1379
  dataSourceKey,
665
1380
  collectionName,
666
1381
  ...suggestion
667
- }
1382
+ })
1383
+ });
1384
+ }
1385
+ if (isCountMeasureRelationSubfield) {
1386
+ pushAuthoringError(errors, {
1387
+ path: item.fieldPath,
1388
+ ruleId: "chart-builder-query-count-measure-relation-subfield",
1389
+ message: `flowSurfaces authoring ${item.fieldPath} counts relation subfield '${fieldPath}'; count a scalar base field such as 'id' and keep '${fieldPath}' as a dimension`,
1390
+ details: withChartRepairHint({
1391
+ fieldPath,
1392
+ dataSourceKey,
1393
+ collectionName,
1394
+ suggestedMeasure: {
1395
+ field: "id",
1396
+ aggregation: "count",
1397
+ alias: String(((_e = item.selection) == null ? void 0 : _e.alias) || "").trim() || "recordCount"
1398
+ },
1399
+ suggestedDimension: {
1400
+ field: fieldPath
1401
+ }
1402
+ })
1403
+ });
1404
+ continue;
1405
+ }
1406
+ if (unsupportedRelationSubfield) {
1407
+ pushAuthoringError(errors, {
1408
+ path: item.fieldPath,
1409
+ ruleId: "chart-builder-query-relation-subfield-column-unsupported",
1410
+ message: `flowSurfaces authoring ${item.fieldPath} references relation subfield '${fieldPath}', but current chart builder SQL generation cannot query relation subfield '${unsupportedRelationSubfield.leafFieldName}' because its database column is '${unsupportedRelationSubfield.columnName}'. ${(0, import_service_helpers.formatChartBuilderSupportedRelationSubfields)(
1411
+ associationPath,
1412
+ unsupportedRelationSubfield.supportedFields
1413
+ )}`,
1414
+ details: withChartRepairHint({
1415
+ fieldPath,
1416
+ dataSourceKey,
1417
+ collectionName,
1418
+ ...unsupportedRelationSubfield
1419
+ })
668
1420
  });
669
1421
  }
670
1422
  }
@@ -691,7 +1443,8 @@ function collectSqlChartAssetQueryErrors(query, path, errors) {
691
1443
  pushAuthoringError(errors, {
692
1444
  path: `${path}.query.sql`,
693
1445
  ruleId: "chart-sql-query-text-missing",
694
- message: `flowSurfaces authoring ${path}.query.sql must be a non-empty string`
1446
+ message: `flowSurfaces authoring ${path}.query.sql must be a non-empty string`,
1447
+ details: withChartRepairHint()
695
1448
  });
696
1449
  }
697
1450
  collectForbiddenObjectKeyErrors(
@@ -699,7 +1452,8 @@ function collectSqlChartAssetQueryErrors(query, path, errors) {
699
1452
  `${path}.query`,
700
1453
  CHART_SQL_QUERY_FORBIDDEN_KEYS,
701
1454
  "chart-sql-query-forbidden-builder-keys",
702
- errors
1455
+ errors,
1456
+ withChartRepairHint()
703
1457
  );
704
1458
  }
705
1459
  function collectChartAssetVisualErrors(asset, path, errors) {
@@ -708,7 +1462,8 @@ function collectChartAssetVisualErrors(asset, path, errors) {
708
1462
  pushAuthoringError(errors, {
709
1463
  path: `${path}.visual`,
710
1464
  ruleId: "chart-visual-missing",
711
- message: `flowSurfaces authoring ${path}.visual is required`
1465
+ message: `flowSurfaces authoring ${path}.visual is required`,
1466
+ details: withChartRepairHint()
712
1467
  });
713
1468
  return;
714
1469
  }
@@ -717,7 +1472,8 @@ function collectChartAssetVisualErrors(asset, path, errors) {
717
1472
  `${path}.visual`,
718
1473
  CHART_VISUAL_LEGACY_BUILDER_KEYS,
719
1474
  "chart-visual-legacy-builder-keys-unsupported",
720
- errors
1475
+ errors,
1476
+ withChartRepairHint()
721
1477
  );
722
1478
  const mode = String(visual.mode || "basic").trim();
723
1479
  if (!CHART_VISUAL_MODE_SET.has(mode)) {
@@ -725,9 +1481,9 @@ function collectChartAssetVisualErrors(asset, path, errors) {
725
1481
  path: `${path}.visual.mode`,
726
1482
  ruleId: "chart-visual-mode-unsupported",
727
1483
  message: `flowSurfaces authoring ${path}.visual.mode '${mode}' is not supported`,
728
- details: {
1484
+ details: withChartRepairHint({
729
1485
  mode
730
- }
1486
+ })
731
1487
  });
732
1488
  return;
733
1489
  }
@@ -736,7 +1492,8 @@ function collectChartAssetVisualErrors(asset, path, errors) {
736
1492
  pushAuthoringError(errors, {
737
1493
  path: `${path}.visual.raw`,
738
1494
  ruleId: "chart-custom-visual-raw-missing",
739
- message: `flowSurfaces authoring ${path}.visual.raw is required for custom chart assets`
1495
+ message: `flowSurfaces authoring ${path}.visual.raw is required for custom chart assets`,
1496
+ details: withChartRepairHint()
740
1497
  });
741
1498
  }
742
1499
  collectForbiddenObjectKeyErrors(
@@ -744,7 +1501,8 @@ function collectChartAssetVisualErrors(asset, path, errors) {
744
1501
  `${path}.visual`,
745
1502
  CHART_CUSTOM_VISUAL_FORBIDDEN_KEYS,
746
1503
  "chart-custom-visual-public-keys-unsupported",
747
- errors
1504
+ errors,
1505
+ withChartRepairHint()
748
1506
  );
749
1507
  return;
750
1508
  }
@@ -753,23 +1511,25 @@ function collectChartAssetVisualErrors(asset, path, errors) {
753
1511
  pushAuthoringError(errors, {
754
1512
  path: `${path}.visual.type`,
755
1513
  ruleId: "chart-visual-type-missing",
756
- message: `flowSurfaces authoring ${path}.visual.type is required for basic chart assets`
1514
+ message: `flowSurfaces authoring ${path}.visual.type is required for basic chart assets`,
1515
+ details: withChartRepairHint()
757
1516
  });
758
1517
  } else if (!CHART_BASIC_VISUAL_TYPE_SET.has(type)) {
759
1518
  pushAuthoringError(errors, {
760
1519
  path: `${path}.visual.type`,
761
1520
  ruleId: "chart-visual-type-unsupported",
762
- message: `flowSurfaces authoring ${path}.visual.type '${type}' is not supported`,
763
- details: {
1521
+ message: `flowSurfaces authoring ${path}.visual.type '${type}' is not supported. Supported basic chart visual types: ${CHART_BASIC_VISUAL_TYPE_LIST}. If these types do not satisfy the requirement, use a jsBlock instead.`,
1522
+ details: withUnsupportedChartVisualTypeHint({
764
1523
  type
765
- }
1524
+ })
766
1525
  });
767
1526
  }
768
1527
  if (!_.isPlainObject(visual.mappings)) {
769
1528
  pushAuthoringError(errors, {
770
1529
  path: `${path}.visual.mappings`,
771
1530
  ruleId: "chart-visual-mappings-missing",
772
- message: `flowSurfaces authoring ${path}.visual.mappings is required for basic chart assets`
1531
+ message: `flowSurfaces authoring ${path}.visual.mappings is required for basic chart assets`,
1532
+ details: withChartRepairHint()
773
1533
  });
774
1534
  return;
775
1535
  }
@@ -781,14 +1541,14 @@ function collectChartAssetVisualErrors(asset, path, errors) {
781
1541
  path: `${path}.visual.mappings`,
782
1542
  ruleId: "chart-visual-required-mappings-missing",
783
1543
  message: `flowSurfaces authoring ${path}.visual.mappings is missing required keys: ${missingMappings.join(", ")}`,
784
- details: {
1544
+ details: withChartRepairHint({
785
1545
  type,
786
1546
  missingMappings
787
- }
1547
+ })
788
1548
  });
789
1549
  }
790
1550
  }
791
- function collectForbiddenObjectKeyErrors(value, path, forbiddenKeys, ruleId, errors) {
1551
+ function collectForbiddenObjectKeyErrors(value, path, forbiddenKeys, ruleId, errors, details = {}) {
792
1552
  if (!_.isPlainObject(value)) {
793
1553
  return;
794
1554
  }
@@ -801,6 +1561,7 @@ function collectForbiddenObjectKeyErrors(value, path, forbiddenKeys, ruleId, err
801
1561
  ruleId,
802
1562
  message: `flowSurfaces authoring ${path} does not accept keys: ${keys.join(", ")}`,
803
1563
  details: {
1564
+ ...details,
804
1565
  keys
805
1566
  }
806
1567
  });
@@ -3186,11 +3947,16 @@ function collectBlockErrors(block, path, errors, localKeys, context) {
3186
3947
  context
3187
3948
  );
3188
3949
  collectSemanticBindingErrors(block, blockType, path, errors, context);
3950
+ collectVisibleDataBlockFieldErrors(block, blockType, path, errors, context);
3189
3951
  collectCommentsBlockErrors(block, blockType, path, errors, context);
3190
3952
  collectRecordHistoryBlockErrors(block, blockType, path, errors, context);
3953
+ collectLocalizedChartSettingsErrors(block, blockType, path, errors, context);
3191
3954
  collectChartDisplayTitleErrors(block, blockType, path, errors);
3192
3955
  collectTreeTableExplicitFieldsErrors(block, blockType, path, errors, context);
3193
3956
  collectTreeConnectFieldsErrors((_a = block.settings) == null ? void 0 : _a.connectFields, `${path}.settings.connectFields`, errors);
3957
+ collectTableSettingsErrors(block, blockType, path, errors, {
3958
+ deferPublicDataScopeErrors: context.authoringActionName === "addBlocks"
3959
+ });
3194
3960
  collectGridCardSettingsErrors(block, blockType, path, errors);
3195
3961
  const descendantContext = getBlockDescendantValidationContext(block, context);
3196
3962
  collectActionListErrors(block.actions, `${path}.actions`, errors, block, descendantContext, "actions");
@@ -3214,7 +3980,8 @@ function collectJsBlockPublicContractErrors(block, path, errors, context) {
3214
3980
  pushAuthoringError(errors, {
3215
3981
  path: `${path}.type`,
3216
3982
  ruleId: "jsBlock-type-alias-unsupported",
3217
- message: `flowSurfaces authoring ${path}.type must be "jsBlock"; "js" is only an action type and is not a public JSBlock block alias. Use ${path}.settings.code for inline JSBlock code`
3983
+ message: `flowSurfaces authoring ${path}.type must be "jsBlock"; "js" is only an action type and is not a public JSBlock block alias. Use ${path}.settings.code for inline JSBlock code`,
3984
+ details: withJsBlockRepairHint()
3218
3985
  });
3219
3986
  return;
3220
3987
  }
@@ -3228,7 +3995,8 @@ function collectJsBlockPublicContractErrors(block, path, errors, context) {
3228
3995
  pushAuthoringError(errors, {
3229
3996
  path: `${path}.${key}`,
3230
3997
  ruleId: `jsBlock-top-level-${key}-unsupported`,
3231
- message: `flowSurfaces authoring ${path}.${key} is not accepted on public jsBlock blocks; use ${path}.settings.code and ${path}.settings.version for inline JS code`
3998
+ message: `flowSurfaces authoring ${path}.${key} is not accepted on public jsBlock blocks; use ${path}.settings.code and ${path}.settings.version for inline JS code`,
3999
+ details: withJsBlockRepairHint({ key })
3232
4000
  });
3233
4001
  });
3234
4002
  JS_BLOCK_INTERNAL_AUTHORING_KEYS.forEach((key) => {
@@ -3239,16 +4007,17 @@ function collectJsBlockPublicContractErrors(block, path, errors, context) {
3239
4007
  path: `${path}.${key}`,
3240
4008
  ruleId: key === "stepParams" ? "jsBlock-stepParams-unsupported" : "jsBlock-internal-field-unsupported",
3241
4009
  message: `flowSurfaces authoring ${path}.${key} is not accepted on public jsBlock blocks; use ${path}.settings.code and ${path}.settings.version instead of internal persisted fields`,
3242
- details: {
4010
+ details: withJsBlockRepairHint({
3243
4011
  key
3244
- }
4012
+ })
3245
4013
  });
3246
4014
  });
3247
4015
  if (hasOwn(block, "script") && context.authoringActionName !== "applyBlueprint") {
3248
4016
  pushAuthoringError(errors, {
3249
4017
  path: `${path}.script`,
3250
4018
  ruleId: "jsBlock-script-unsupported",
3251
- message: `flowSurfaces authoring ${path}.script is only supported by applyBlueprint assets.scripts; use ${path}.settings.code for localized jsBlock inline JS code`
4019
+ message: `flowSurfaces authoring ${path}.script is only supported by applyBlueprint assets.scripts; use ${path}.settings.code for localized jsBlock inline JS code`,
4020
+ details: withJsBlockRepairHint()
3252
4021
  });
3253
4022
  }
3254
4023
  const settings = _.isPlainObject(block.settings) ? block.settings : void 0;
@@ -3261,10 +4030,10 @@ function collectJsBlockPublicContractErrors(block, path, errors, context) {
3261
4030
  path: `${path}.settings.${key}`,
3262
4031
  ruleId: "jsBlock-settings-unsupported-key",
3263
4032
  message: `flowSurfaces authoring ${path}.settings.${key} is not part of the public jsBlock contract; use ${path}.settings.code and ${path}.settings.version for inline JS code`,
3264
- details: {
4033
+ details: withJsBlockRepairHint({
3265
4034
  key,
3266
4035
  allowedKeys: Array.from(JS_BLOCK_ALLOWED_SETTINGS_KEYS)
3267
- }
4036
+ })
3268
4037
  });
3269
4038
  });
3270
4039
  }
@@ -3274,9 +4043,9 @@ function collectJsBlockPublicContractErrors(block, path, errors, context) {
3274
4043
  path: `${path}.script`,
3275
4044
  ruleId: "jsBlock-mixed-inline-and-script",
3276
4045
  message: `flowSurfaces authoring ${path} cannot combine script asset references with ${inlineKeys.map((key) => `settings.${key}`).join(", ")}; use either applyBlueprint assets.scripts + block.script or inline ${path}.settings.code`,
3277
- details: {
4046
+ details: withJsBlockRepairHint({
3278
4047
  inlineKeys
3279
- }
4048
+ })
3280
4049
  });
3281
4050
  }
3282
4051
  const hasInlineCode = typeof (settings == null ? void 0 : settings.code) === "string" && !!settings.code.trim();
@@ -3286,7 +4055,8 @@ function collectJsBlockPublicContractErrors(block, path, errors, context) {
3286
4055
  pushAuthoringError(errors, {
3287
4056
  path,
3288
4057
  ruleId: "jsBlock-source-required",
3289
- message: `flowSurfaces authoring ${path} jsBlock must include inline ${path}.settings.code or, for applyBlueprint only, a block.script asset reference`
4058
+ message: `flowSurfaces authoring ${path} jsBlock must include inline ${path}.settings.code or, for applyBlueprint only, a block.script asset reference`,
4059
+ details: withJsBlockRepairHint()
3290
4060
  });
3291
4061
  }
3292
4062
  }
@@ -3302,16 +4072,17 @@ function collectJsBlockConfigurePublicContractErrors(changes, path, errors) {
3302
4072
  path: `${path}.${key}`,
3303
4073
  ruleId: key === "stepParams" ? "jsBlock-stepParams-unsupported" : "jsBlock-internal-field-unsupported",
3304
4074
  message: `flowSurfaces authoring ${path}.${key} is not accepted on public jsBlock configure changes; use ${path}.code and ${path}.version instead of internal persisted fields`,
3305
- details: {
4075
+ details: withJsBlockRepairHint({
3306
4076
  key
3307
- }
4077
+ })
3308
4078
  });
3309
4079
  });
3310
4080
  if (hasOwn(changes, "script")) {
3311
4081
  pushAuthoringError(errors, {
3312
4082
  path: `${path}.script`,
3313
4083
  ruleId: "jsBlock-script-unsupported",
3314
- message: `flowSurfaces authoring ${path}.script is only supported by applyBlueprint assets.scripts; use ${path}.code for localized jsBlock configure JS code`
4084
+ message: `flowSurfaces authoring ${path}.script is only supported by applyBlueprint assets.scripts; use ${path}.code for localized jsBlock configure JS code`,
4085
+ details: withJsBlockRepairHint()
3315
4086
  });
3316
4087
  }
3317
4088
  const inlineKeys = JS_BLOCK_TOP_LEVEL_JS_KEYS.filter((key) => hasOwn(changes, key));
@@ -3320,9 +4091,9 @@ function collectJsBlockConfigurePublicContractErrors(changes, path, errors) {
3320
4091
  path: `${path}.script`,
3321
4092
  ruleId: "jsBlock-mixed-inline-and-script",
3322
4093
  message: `flowSurfaces authoring ${path} cannot combine script asset references with ${inlineKeys.map((key) => `${path}.${key}`).join(", ")}; use either applyBlueprint assets.scripts + block.script or localized ${path}.code`,
3323
- details: {
4094
+ details: withJsBlockRepairHint({
3324
4095
  inlineKeys
3325
- }
4096
+ })
3326
4097
  });
3327
4098
  }
3328
4099
  if (!hasOwn(changes, "settings")) {
@@ -3333,7 +4104,8 @@ function collectJsBlockConfigurePublicContractErrors(changes, path, errors) {
3333
4104
  pushAuthoringError(errors, {
3334
4105
  path: `${path}.settings`,
3335
4106
  ruleId: "jsBlock-settings-unsupported-key",
3336
- message: `flowSurfaces authoring ${path}.settings is not part of the public jsBlock configure contract; use ${path}.code and ${path}.version`
4107
+ message: `flowSurfaces authoring ${path}.settings is not part of the public jsBlock configure contract; use ${path}.code and ${path}.version`,
4108
+ details: withJsBlockRepairHint()
3337
4109
  });
3338
4110
  return;
3339
4111
  }
@@ -3342,9 +4114,9 @@ function collectJsBlockConfigurePublicContractErrors(changes, path, errors) {
3342
4114
  path: `${path}.settings.${key}`,
3343
4115
  ruleId: "jsBlock-settings-unsupported-key",
3344
4116
  message: `flowSurfaces authoring ${path}.settings.${key} is not part of the public jsBlock configure contract; use ${path}.${key}`,
3345
- details: {
4117
+ details: withJsBlockRepairHint({
3346
4118
  key
3347
- }
4119
+ })
3348
4120
  });
3349
4121
  });
3350
4122
  }
@@ -3376,7 +4148,8 @@ function collectUnsupportedMainBlockSectionErrors(block, blockType, path, errors
3376
4148
  pushAuthoringError(errors, {
3377
4149
  path: `${path}.${section}`,
3378
4150
  ruleId: `${blockType}-main-block-unsupported-${section}`,
3379
- message: `flowSurfaces authoring ${path} ${blockType} main blocks do not support ${section}`
4151
+ message: `flowSurfaces authoring ${path} ${blockType} main blocks do not support ${section}`,
4152
+ details: blockType === "calendar" ? buildCalendarMainBlockRepairDetails(section) : blockType === "kanban" ? buildKanbanMainBlockRepairDetails(section) : void 0
3380
4153
  });
3381
4154
  });
3382
4155
  }
@@ -3393,7 +4166,8 @@ function collectApplyBlueprintKanbanFieldLimitErrors(block, blockType, path, err
3393
4166
  message: `flowSurfaces authoring ${path}.fields supports at most 2 fields for applyBlueprint kanban main blocks`,
3394
4167
  details: {
3395
4168
  max: 2,
3396
- count: block.fields.length
4169
+ count: block.fields.length,
4170
+ repairHint: "Kanban main block fields controls compact card display only. Keep at most 2 fields in applyBlueprint kanban fields, move richer card details to settings.cardPopup, and keep block type kanban."
3397
4171
  }
3398
4172
  });
3399
4173
  }
@@ -3440,6 +4214,7 @@ function collectFieldGroupsShapeErrors(fieldGroups, blockPath, errors, block, co
3440
4214
  if (fieldPath) {
3441
4215
  collectUnknownFieldPathError(fieldPath, itemPath, block, context, errors);
3442
4216
  }
4217
+ collectImplicitRelationTitleFieldErrors(field, itemPath, block, context, errors);
3443
4218
  if (!_.isPlainObject(field)) {
3444
4219
  return;
3445
4220
  }
@@ -3489,6 +4264,8 @@ async function collectConfigureErrors(values, errors, context) {
3489
4264
  collectCommentsBlockErrors(changesBlock, hostBlockType, "$.changes", errors, context);
3490
4265
  collectRecordHistoryBlockErrors(changesBlock, hostBlockType, "$.changes", errors, context);
3491
4266
  collectChartDisplayTitleErrors(changes, hostBlockType, "$.changes", errors);
4267
+ collectChartConfigureFilterOperatorErrors(changes, hostBlockType, "$.changes", errors);
4268
+ collectTableSettingsErrors(changes, hostBlockType, "$.changes", errors, { directSettings: true });
3492
4269
  collectGridCardSettingsErrors(changes, hostBlockType, "$.changes", errors, { directSettings: true });
3493
4270
  collectAssignValuesErrors(changes.assignValues, "$.changes.assignValues", errors, changesBlock, context);
3494
4271
  collectTriggerWorkflowsErrors(changes.triggerWorkflows, "$.changes.triggerWorkflows", errors);
@@ -3531,9 +4308,18 @@ function pushAuthoringError(errors, error) {
3531
4308
  type: "bad_request",
3532
4309
  code: "FLOW_SURFACE_AUTHORING_VALIDATION_ERROR",
3533
4310
  status: 400,
3534
- ...error
4311
+ ...error,
4312
+ message: appendRepairHintToAuthoringMessage(error)
3535
4313
  });
3536
4314
  }
4315
+ function appendRepairHintToAuthoringMessage(error) {
4316
+ var _a;
4317
+ const repairHint = typeof ((_a = error.details) == null ? void 0 : _a.repairHint) === "string" ? error.details.repairHint.trim() : "";
4318
+ if (!repairHint || error.message.includes(repairHint)) {
4319
+ return error.message;
4320
+ }
4321
+ return `${error.message}. ${repairHint}`;
4322
+ }
3537
4323
  function hasOwnDefined(value, key) {
3538
4324
  return _.isPlainObject(value) && Object.prototype.hasOwnProperty.call(value, key) && !_.isUndefined(value[key]);
3539
4325
  }
@@ -3567,6 +4353,23 @@ function collectUnsupportedDefaultFilterOperatorError(operator, path, errors) {
3567
4353
  }
3568
4354
  });
3569
4355
  }
4356
+ function collectDefaultFilterDateValueError(operator, value, path, errors) {
4357
+ var _a, _b, _c;
4358
+ try {
4359
+ (0, import_filter_group.normalizeFlowSurfaceStrictFilterDateValue)(operator, value, path);
4360
+ } catch (error) {
4361
+ if (!(error instanceof import_errors.FlowSurfaceBadRequestError)) {
4362
+ throw error;
4363
+ }
4364
+ const details = _.isPlainObject((_a = error.options) == null ? void 0 : _a.details) ? error.options.details : {};
4365
+ pushAuthoringError(errors, {
4366
+ path: typeof ((_b = error.options) == null ? void 0 : _b.path) === "string" && error.options.path ? error.options.path : path,
4367
+ ruleId: typeof ((_c = error.options) == null ? void 0 : _c.ruleId) === "string" && error.options.ruleId ? error.options.ruleId : "filter-group-date-value-invalid",
4368
+ message: error.message,
4369
+ details
4370
+ });
4371
+ }
4372
+ }
3570
4373
  function collectTopLevelLayoutErrors(actionName, values, errors) {
3571
4374
  if (actionName !== "applyBlueprint") {
3572
4375
  return;
@@ -3696,7 +4499,8 @@ function collectPublicLayoutErrors(layout, layoutPath, knownEntries, kind, error
3696
4499
  pushAuthoringError(errors, {
3697
4500
  path: `${layoutPath}.rows`,
3698
4501
  ruleId: "block-layout-single-column",
3699
- message: `flowSurfaces authoring ${layoutPath}.rows must not place every non-filter block on its own row`
4502
+ message: `flowSurfaces authoring ${layoutPath}.rows must not place every non-filter block on its own row`,
4503
+ details: buildTwoColumnLayoutRepairDetails()
3700
4504
  });
3701
4505
  }
3702
4506
  }
@@ -4064,81 +4868,274 @@ function collectTemplateBackedPublicDataSurfaceDefaultOverrideErrors(block, bloc
4064
4868
  if (!(0, import_public_data_surface_default_filter.isFlowSurfacePublicDataSurfaceBlockType)(blockType) || !(0, import_template_reference.hasFlowSurfaceTemplateDocument)(block == null ? void 0 : block.template)) {
4065
4869
  return;
4066
4870
  }
4067
- if (hasOwn(block, "defaultFilter")) {
4068
- pushAuthoringError(errors, {
4069
- path: `${path}.defaultFilter`,
4070
- ruleId: "data-surface-block-default-filter-template-unsupported",
4071
- message: "Template-backed table, list, gridCard, calendar, and kanban blocks do not support block-level defaultFilter; only direct blocks may define it."
4072
- });
4871
+ if (hasOwn(block, "defaultFilter")) {
4872
+ pushAuthoringError(errors, {
4873
+ path: `${path}.defaultFilter`,
4874
+ ruleId: "data-surface-block-default-filter-template-unsupported",
4875
+ message: "Template-backed table, list, gridCard, calendar, and kanban blocks do not support block-level defaultFilter; only direct blocks may define it."
4876
+ });
4877
+ }
4878
+ if (hasOwn(block, "defaultActionSettings")) {
4879
+ pushAuthoringError(errors, {
4880
+ path: `${path}.defaultActionSettings`,
4881
+ ruleId: "data-surface-block-default-action-settings-template-unsupported",
4882
+ message: "Template-backed table, list, gridCard, calendar, and kanban blocks do not support defaultActionSettings; use filter action settings on direct blocks instead."
4883
+ });
4884
+ }
4885
+ }
4886
+ function collectDefaultActionSettingsFilterErrors(defaultActionSettings, path, errors, block, context = {}) {
4887
+ if (_.isUndefined(defaultActionSettings)) {
4888
+ return;
4889
+ }
4890
+ if (!_.isPlainObject(defaultActionSettings)) {
4891
+ pushAuthoringError(errors, {
4892
+ path,
4893
+ ruleId: "defaultActionSettings-invalid-shape",
4894
+ message: `flowSurfaces authoring ${path} must be an object`
4895
+ });
4896
+ return;
4897
+ }
4898
+ if (!Object.prototype.hasOwnProperty.call(defaultActionSettings, "filter")) {
4899
+ return;
4900
+ }
4901
+ if (!doesBlockConsumeDefaultFilterAction(block)) {
4902
+ return;
4903
+ }
4904
+ const filterSettings = defaultActionSettings.filter;
4905
+ const filterSettingsPath = `${path}.filter`;
4906
+ if (!_.isPlainObject(filterSettings)) {
4907
+ pushAuthoringError(errors, {
4908
+ path: filterSettingsPath,
4909
+ ruleId: "defaultActionSettings-filter-invalid-shape",
4910
+ message: `flowSurfaces authoring ${filterSettingsPath} must be an object`
4911
+ });
4912
+ return;
4913
+ }
4914
+ collectDefaultFilterErrors(
4915
+ filterSettings.defaultFilter,
4916
+ `${filterSettingsPath}.defaultFilter`,
4917
+ errors,
4918
+ block,
4919
+ context
4920
+ );
4921
+ const filterableFieldNames = collectFilterableFieldNamesErrors(
4922
+ filterSettings.filterableFieldNames,
4923
+ `${filterSettingsPath}.filterableFieldNames`,
4924
+ errors,
4925
+ block,
4926
+ context
4927
+ );
4928
+ const blockPath = path.replace(/\.defaultActionSettings$/, "");
4929
+ const effectiveDefaultFilter = getEffectiveFilterSettingsDefaultFilter(
4930
+ block,
4931
+ filterSettings,
4932
+ filterSettingsPath,
4933
+ blockPath,
4934
+ context
4935
+ );
4936
+ collectDefaultFilterFilterableFieldErrors(
4937
+ effectiveDefaultFilter == null ? void 0 : effectiveDefaultFilter.value,
4938
+ (effectiveDefaultFilter == null ? void 0 : effectiveDefaultFilter.path) || `${filterSettingsPath}.defaultFilter`,
4939
+ filterableFieldNames,
4940
+ errors
4941
+ );
4942
+ }
4943
+ function doesBlockConsumeDefaultFilterAction(block) {
4944
+ const blockType = String((block == null ? void 0 : block.type) || "").trim();
4945
+ return (0, import_public_data_surface_default_filter.isFlowSurfacePublicDataSurfaceBlockType)(blockType) && !(0, import_template_reference.hasFlowSurfaceTemplateDocument)(block == null ? void 0 : block.template);
4946
+ }
4947
+ function collectVisibleDataBlockFieldErrors(block, blockType, path, errors, context) {
4948
+ if (!VISIBLE_FIELD_REQUIRED_DATA_BLOCK_TYPES.has(blockType) || (0, import_template_reference.hasFlowSurfaceTemplateReference)(block == null ? void 0 : block.template)) {
4949
+ return;
4950
+ }
4951
+ const fieldEntries = collectVisibleDataBlockFieldEntries(block, path);
4952
+ const validBusinessFieldNames = collectVisibleDataBlockValidBusinessFieldNames(block, context, fieldEntries);
4953
+ if (!fieldEntries.length || !validBusinessFieldNames.length) {
4954
+ const hasBlockFields2 = Array.isArray(block == null ? void 0 : block.fields);
4955
+ const hasBlockFieldGroups2 = Array.isArray(block == null ? void 0 : block.fieldGroups);
4956
+ const fieldConfigPath2 = !hasBlockFields2 && hasBlockFieldGroups2 ? `${path}.fieldGroups` : `${path}.fields`;
4957
+ const fieldConfigLabel2 = !hasBlockFields2 && hasBlockFieldGroups2 ? `${path}.fieldGroups[].fields` : `${path}.fields`;
4958
+ const suggestedFields = pickVisibleDataBlockFieldSuggestions(block, context);
4959
+ pushAuthoringError(errors, {
4960
+ path: fieldConfigPath2,
4961
+ ruleId: "data-block-visible-fields-required",
4962
+ message: `flowSurfaces authoring ${path} ${blockType} block has no valid business fields. Add collection field names to ${fieldConfigLabel2}; defaults.collections.*.fieldGroups only configures generated popups/forms and is not a substitute for visible block columns.`,
4963
+ details: {
4964
+ blockType,
4965
+ collection: getBlockCollectionName(block, context),
4966
+ fieldCount: fieldEntries.length,
4967
+ repairHint: VISIBLE_DATA_BLOCK_FIELDS_REPAIR_HINT,
4968
+ agentInstruction: REPAIR_ALL_ERRORS_AGENT_INSTRUCTION,
4969
+ ...suggestedFields.length ? { suggestion: { fields: suggestedFields } } : {}
4970
+ }
4971
+ });
4972
+ return;
4973
+ }
4974
+ if (!VISIBLE_FIELD_MINIMUM_DATA_BLOCK_TYPES.has(blockType)) {
4975
+ return;
4976
+ }
4977
+ if (hasUnknownVisibleDataBlockFieldPath(block, context, fieldEntries)) {
4978
+ return;
4979
+ }
4980
+ const eligibleBusinessFields = collectVisibleDataBlockEligibleBusinessFieldNames(block, context);
4981
+ if (eligibleBusinessFields.length < RICH_COLLECTION_VISIBLE_FIELD_THRESHOLD) {
4982
+ return;
4983
+ }
4984
+ const requiredFieldCount = Math.min(RICH_DATA_BLOCK_VISIBLE_FIELD_MINIMUM, eligibleBusinessFields.length);
4985
+ if (validBusinessFieldNames.length >= requiredFieldCount) {
4986
+ return;
4987
+ }
4988
+ const hasBlockFields = Array.isArray(block == null ? void 0 : block.fields);
4989
+ const hasBlockFieldGroups = Array.isArray(block == null ? void 0 : block.fieldGroups);
4990
+ const fieldConfigPath = !hasBlockFields && hasBlockFieldGroups ? `${path}.fieldGroups` : `${path}.fields`;
4991
+ const fieldConfigLabel = !hasBlockFields && hasBlockFieldGroups ? `${path}.fieldGroups[].fields` : `${path}.fields`;
4992
+ pushAuthoringError(errors, {
4993
+ path: fieldConfigPath,
4994
+ ruleId: "data-block-visible-fields-minimum",
4995
+ message: `flowSurfaces authoring ${path} ${blockType} block only has ${validBusinessFieldNames.length} valid business field(s). Add at least ${requiredFieldCount} collection field names to ${fieldConfigLabel}; defaults.collections.*.fieldGroups only configures generated popups/forms and is not a substitute for visible block columns.`,
4996
+ details: {
4997
+ blockType,
4998
+ collection: getBlockCollectionName(block, context),
4999
+ fieldCount: validBusinessFieldNames.length,
5000
+ requiredFieldCount,
5001
+ eligibleBusinessFieldCount: eligibleBusinessFields.length,
5002
+ repairHint: VISIBLE_DATA_BLOCK_FIELDS_REPAIR_HINT,
5003
+ agentInstruction: REPAIR_ALL_ERRORS_AGENT_INSTRUCTION,
5004
+ suggestion: {
5005
+ fields: eligibleBusinessFields.slice(0, requiredFieldCount)
5006
+ }
5007
+ }
5008
+ });
5009
+ }
5010
+ function collectVisibleDataBlockFieldEntries(block, path) {
5011
+ const entries = [];
5012
+ if (Array.isArray(block == null ? void 0 : block.fields)) {
5013
+ block.fields.forEach((field, index) => {
5014
+ entries.push({ field, path: `${path}.fields[${index}]` });
5015
+ });
5016
+ }
5017
+ if (Array.isArray(block == null ? void 0 : block.fieldGroups)) {
5018
+ block.fieldGroups.forEach((group, groupIndex) => {
5019
+ if (!Array.isArray(group == null ? void 0 : group.fields)) {
5020
+ return;
5021
+ }
5022
+ group.fields.forEach((field, fieldIndex) => {
5023
+ entries.push({
5024
+ field,
5025
+ path: `${path}.fieldGroups[${groupIndex}].fields[${fieldIndex}]`
5026
+ });
5027
+ });
5028
+ });
5029
+ }
5030
+ return entries;
5031
+ }
5032
+ function collectVisibleDataBlockValidBusinessFieldNames(block, context, fieldEntries) {
5033
+ const names = /* @__PURE__ */ new Set();
5034
+ fieldEntries.forEach((entry) => {
5035
+ const fieldPath = getAssociationAwareFieldPathInput(entry.field);
5036
+ if (!fieldPath || fieldPath.startsWith("$") || fieldPath.startsWith("{{")) {
5037
+ return;
5038
+ }
5039
+ if (!isVisibleDataBlockBusinessField(entry.field, block, context)) {
5040
+ return;
5041
+ }
5042
+ names.add((0, import_service_helpers.normalizeFieldPath)(fieldPath));
5043
+ });
5044
+ return Array.from(names);
5045
+ }
5046
+ function hasUnknownVisibleDataBlockFieldPath(block, context, fieldEntries) {
5047
+ const collection = getBlockCollection(block, context);
5048
+ if (!collection) {
5049
+ return false;
5050
+ }
5051
+ return fieldEntries.some((entry) => {
5052
+ const fieldPath = getAssociationAwareFieldPathInput(entry.field);
5053
+ if (!fieldPath || fieldPath.startsWith("$") || fieldPath.startsWith("{{")) {
5054
+ return false;
5055
+ }
5056
+ return !(0, import_service_helpers.resolveFieldFromCollection)(collection, (0, import_service_helpers.normalizeFieldPath)(fieldPath));
5057
+ });
5058
+ }
5059
+ function collectVisibleDataBlockEligibleBusinessFieldNames(block, context) {
5060
+ const collection = getBlockCollection(block, context);
5061
+ if (!collection) {
5062
+ return [];
5063
+ }
5064
+ return (0, import_service_helpers.getCollectionFields)(collection).map((field) => {
5065
+ const name = String((0, import_service_helpers.getFieldName)(field) || "").trim();
5066
+ if (!name || !isVisibleDataBlockMinimumCandidateResolvedField(field, name)) {
5067
+ return "";
5068
+ }
5069
+ return name;
5070
+ }).filter(Boolean);
5071
+ }
5072
+ function isVisibleDataBlockMinimumCandidateResolvedField(field, fieldName) {
5073
+ if (!isVisibleDataBlockBusinessResolvedField(field, fieldName)) {
5074
+ return false;
5075
+ }
5076
+ if ((0, import_service_helpers.isAssociationField)(field)) {
5077
+ return false;
4073
5078
  }
4074
- if (hasOwn(block, "defaultActionSettings")) {
4075
- pushAuthoringError(errors, {
4076
- path: `${path}.defaultActionSettings`,
4077
- ruleId: "data-surface-block-default-action-settings-template-unsupported",
4078
- message: "Template-backed table, list, gridCard, calendar, and kanban blocks do not support defaultActionSettings; use filter action settings on direct blocks instead."
4079
- });
5079
+ if (/Id$/.test(fieldName)) {
5080
+ return false;
4080
5081
  }
5082
+ return true;
4081
5083
  }
4082
- function collectDefaultActionSettingsFilterErrors(defaultActionSettings, path, errors, block, context = {}) {
4083
- if (_.isUndefined(defaultActionSettings)) {
4084
- return;
5084
+ function isVisibleDataBlockBusinessField(field, block, context) {
5085
+ const fieldPath = getAssociationAwareFieldPathInput(field);
5086
+ if (!fieldPath || fieldPath.startsWith("$") || fieldPath.startsWith("{{")) {
5087
+ return false;
4085
5088
  }
4086
- if (!_.isPlainObject(defaultActionSettings)) {
4087
- pushAuthoringError(errors, {
4088
- path,
4089
- ruleId: "defaultActionSettings-invalid-shape",
4090
- message: `flowSurfaces authoring ${path} must be an object`
4091
- });
4092
- return;
5089
+ if (_.isPlainObject(field)) {
5090
+ if (field.hidden === true || field.internal === true || field.synthetic === true || field.actionOnly === true) {
5091
+ return false;
5092
+ }
5093
+ const semanticType = String(field.type || field.fieldType || field.interface || "").trim();
5094
+ if (semanticType && NON_BUSINESS_VISIBLE_FIELD_TYPES.has(semanticType)) {
5095
+ return false;
5096
+ }
4093
5097
  }
4094
- if (!Object.prototype.hasOwnProperty.call(defaultActionSettings, "filter")) {
4095
- return;
5098
+ const collection = getBlockCollection(block, context);
5099
+ if (!collection) {
5100
+ return true;
4096
5101
  }
4097
- if (!doesBlockConsumeDefaultFilterAction(block)) {
4098
- return;
5102
+ const resolvedField = (0, import_service_helpers.resolveFieldFromCollection)(collection, (0, import_service_helpers.normalizeFieldPath)(fieldPath));
5103
+ if (!resolvedField) {
5104
+ return true;
4099
5105
  }
4100
- const filterSettings = defaultActionSettings.filter;
4101
- const filterSettingsPath = `${path}.filter`;
4102
- if (!_.isPlainObject(filterSettings)) {
4103
- pushAuthoringError(errors, {
4104
- path: filterSettingsPath,
4105
- ruleId: "defaultActionSettings-filter-invalid-shape",
4106
- message: `flowSurfaces authoring ${filterSettingsPath} must be an object`
4107
- });
4108
- return;
5106
+ const fieldName = (0, import_service_helpers.getFieldName)(resolvedField) || fieldPath;
5107
+ return isVisibleDataBlockBusinessResolvedField(resolvedField, fieldName);
5108
+ }
5109
+ function pickVisibleDataBlockFieldSuggestions(block, context) {
5110
+ const collection = getBlockCollection(block, context);
5111
+ if (!collection) {
5112
+ return [];
4109
5113
  }
4110
- collectDefaultFilterErrors(
4111
- filterSettings.defaultFilter,
4112
- `${filterSettingsPath}.defaultFilter`,
4113
- errors,
4114
- block,
4115
- context
4116
- );
4117
- const filterableFieldNames = collectFilterableFieldNamesErrors(
4118
- filterSettings.filterableFieldNames,
4119
- `${filterSettingsPath}.filterableFieldNames`,
4120
- errors,
4121
- block,
4122
- context
4123
- );
4124
- const blockPath = path.replace(/\.defaultActionSettings$/, "");
4125
- const effectiveDefaultFilter = getEffectiveFilterSettingsDefaultFilter(
4126
- block,
4127
- filterSettings,
4128
- filterSettingsPath,
4129
- blockPath,
4130
- context
4131
- );
4132
- collectDefaultFilterFilterableFieldErrors(
4133
- effectiveDefaultFilter == null ? void 0 : effectiveDefaultFilter.value,
4134
- (effectiveDefaultFilter == null ? void 0 : effectiveDefaultFilter.path) || `${filterSettingsPath}.defaultFilter`,
4135
- filterableFieldNames,
4136
- errors
4137
- );
5114
+ return (0, import_service_helpers.getCollectionFields)(collection).map((field) => {
5115
+ const name = String((0, import_service_helpers.getFieldName)(field) || "").trim();
5116
+ if (!name || !isVisibleDataBlockBusinessResolvedField(field, name)) {
5117
+ return "";
5118
+ }
5119
+ return name;
5120
+ }).filter(Boolean).slice(0, 3);
4138
5121
  }
4139
- function doesBlockConsumeDefaultFilterAction(block) {
4140
- const blockType = String((block == null ? void 0 : block.type) || "").trim();
4141
- return (0, import_public_data_surface_default_filter.isFlowSurfacePublicDataSurfaceBlockType)(blockType) && !(0, import_template_reference.hasFlowSurfaceTemplateDocument)(block == null ? void 0 : block.template);
5122
+ function isVisibleDataBlockBusinessResolvedField(field, fieldName) {
5123
+ var _a;
5124
+ if (NON_BUSINESS_VISIBLE_FIELD_NAMES.has(fieldName)) {
5125
+ return false;
5126
+ }
5127
+ const fieldInterface = String((0, import_service_helpers.getFieldInterface)(field) || "").trim();
5128
+ if (NON_BUSINESS_VISIBLE_FIELD_INTERFACES.has(fieldInterface)) {
5129
+ return false;
5130
+ }
5131
+ const fieldType = String((0, import_service_helpers.getFieldType)(field) || "").trim();
5132
+ if (NON_BUSINESS_VISIBLE_FIELD_TYPES.has(fieldType)) {
5133
+ return false;
5134
+ }
5135
+ if ((field == null ? void 0 : field.hidden) === true || ((_a = field == null ? void 0 : field.options) == null ? void 0 : _a.hidden) === true) {
5136
+ return false;
5137
+ }
5138
+ return true;
4142
5139
  }
4143
5140
  function hasConcreteFilterItem(value) {
4144
5141
  if (!_.isPlainObject(value)) {
@@ -4377,6 +5374,15 @@ function collectChartDisplayTitleErrors(block, blockType, blockPath, errors) {
4377
5374
  message: "Chart block settings do not support displayTitle in the current flowSurfaces runtime; keep settings.title and omit displayTitle."
4378
5375
  });
4379
5376
  }
5377
+ function collectChartConfigureFilterOperatorErrors(changes, hostBlockType, path, errors) {
5378
+ if (hostBlockType !== "chart" || !_.isPlainObject(changes)) {
5379
+ return;
5380
+ }
5381
+ collectChartQueryFilterOperatorErrors(changes.query, `${path}.query`, errors);
5382
+ if (_.isPlainObject(changes.configure)) {
5383
+ collectChartQueryFilterOperatorErrors(changes.configure.query, `${path}.configure.query`, errors);
5384
+ }
5385
+ }
4380
5386
  function visitFilterItems(value, path, errors, block, context = {}) {
4381
5387
  if (Array.isArray(value)) {
4382
5388
  value.forEach((item, index) => visitFilterItems(item, `${path}[${index}]`, errors, block, context));
@@ -4391,6 +5397,7 @@ function visitFilterItems(value, path, errors, block, context = {}) {
4391
5397
  }
4392
5398
  if (typeof value.operator === "string") {
4393
5399
  collectUnsupportedDefaultFilterOperatorError(value.operator, `${path}.operator`, errors);
5400
+ collectDefaultFilterDateValueError(value.operator, value.value, `${path}.value`, errors);
4394
5401
  }
4395
5402
  const filterItems = value.items;
4396
5403
  if (Array.isArray(filterItems)) {
@@ -4414,8 +5421,9 @@ function visitFilterItems(value, path, errors, block, context = {}) {
4414
5421
  }
4415
5422
  collectDefaultFilterFieldPathError(key, `${path}.${key}`, block, context, errors);
4416
5423
  if (_.isPlainObject(child)) {
4417
- Object.keys(child).forEach((operator) => {
5424
+ Object.entries(child).forEach(([operator, operatorValue]) => {
4418
5425
  collectUnsupportedDefaultFilterOperatorError(operator, `${path}.${key}.${operator}`, errors);
5426
+ collectDefaultFilterDateValueError(operator, operatorValue, `${path}.${key}.${operator}`, errors);
4419
5427
  });
4420
5428
  }
4421
5429
  });
@@ -4768,6 +5776,87 @@ function getCollectionFilterTargetKey(collection) {
4768
5776
  function normalizeDataSourceKey(value) {
4769
5777
  return String(value || "main").trim() || "main";
4770
5778
  }
5779
+ function collectTableSettingsErrors(block, blockType, blockPath, errors, options = {}) {
5780
+ if (blockType !== "table" || !_.isPlainObject(block)) {
5781
+ return;
5782
+ }
5783
+ TABLE_INTERNAL_AUTHORING_KEYS.forEach((key) => {
5784
+ if (Object.prototype.hasOwnProperty.call(block, key)) {
5785
+ pushTableSettingsUnsupportedError(errors, `${blockPath}.${key}`, key);
5786
+ }
5787
+ });
5788
+ const hasSettings = _.isPlainObject(block == null ? void 0 : block.settings);
5789
+ if (!hasSettings) {
5790
+ return;
5791
+ }
5792
+ const settings = block.settings;
5793
+ const settingsPath = `${blockPath}.settings`;
5794
+ Object.keys(settings).forEach((key) => {
5795
+ if (TABLE_ALLOWED_SETTINGS_KEYS.has(key) && options.directSettings !== true) {
5796
+ return;
5797
+ }
5798
+ if (options.directSettings === true && !TABLE_INTERNAL_AUTHORING_KEYS.includes(key)) {
5799
+ return;
5800
+ }
5801
+ pushTableSettingsUnsupportedError(errors, `${settingsPath}.${key}`, key);
5802
+ });
5803
+ if (!shouldDeferPublicDataScopeErrorsToBatchItem(blockPath, errors, options)) {
5804
+ collectPublicDataScopeErrors(settings.dataScope, `${settingsPath}.dataScope`, errors);
5805
+ }
5806
+ }
5807
+ function pushTableSettingsUnsupportedError(errors, path, key) {
5808
+ pushAuthoringError(errors, {
5809
+ path,
5810
+ ruleId: "table-settings-unsupported-key",
5811
+ message: `flowSurfaces authoring ${path} is not part of the public table settings contract`,
5812
+ details: {
5813
+ key,
5814
+ allowedKeys: Array.from(TABLE_ALLOWED_SETTINGS_KEYS),
5815
+ repairHint: TABLE_SETTINGS_REPAIR_HINT
5816
+ }
5817
+ });
5818
+ }
5819
+ function collectPublicDataScopeErrors(value, path, errors) {
5820
+ if (_.isUndefined(value)) {
5821
+ return;
5822
+ }
5823
+ if (value === null || _.isPlainObject(value) && !Object.keys(value).length) {
5824
+ return;
5825
+ }
5826
+ const validationValue = normalizePublicDataScopeValueForValidation(value);
5827
+ try {
5828
+ (0, import_filter_group.assertFlowSurfaceFilterGroupShape)(validationValue);
5829
+ } catch (error) {
5830
+ const reason = error instanceof Error ? error.message : String(error);
5831
+ pushAuthoringError(errors, {
5832
+ path,
5833
+ ruleId: "dataScope-filter-group-invalid-shape",
5834
+ message: `flowSurfaces authoring ${path} expects FilterGroup like ${import_filter_group.FLOW_SURFACE_FILTER_GROUP_EXAMPLE}: ${reason}`,
5835
+ details: {
5836
+ repairHint: 'Use settings.dataScope with logic/items, for example {"logic":"$and","items":[{"path":"status","operator":"$eq","value":"Active"}]}; do not use a field-name map.'
5837
+ }
5838
+ });
5839
+ }
5840
+ }
5841
+ function shouldDeferPublicDataScopeErrorsToBatchItem(blockPath, errors, options) {
5842
+ if (options.deferPublicDataScopeErrors !== true) {
5843
+ return false;
5844
+ }
5845
+ if (!/^\$\.blocks\[\d+\]$/.test(blockPath)) {
5846
+ return false;
5847
+ }
5848
+ return !errors.some((error) => error.path === `${blockPath}.settings.dataScope`);
5849
+ }
5850
+ function normalizePublicDataScopeValueForValidation(value) {
5851
+ if (!_.isPlainObject(value)) {
5852
+ return value;
5853
+ }
5854
+ const keys = Object.keys(value);
5855
+ if (keys.length === 1 && keys[0] === "filter") {
5856
+ return value.filter;
5857
+ }
5858
+ return value;
5859
+ }
4771
5860
  function collectGridCardSettingsErrors(block, blockType, blockPath, errors, options = {}) {
4772
5861
  const hasSettings = _.isPlainObject(block == null ? void 0 : block.settings);
4773
5862
  if (!hasSettings && options.directSettings !== true) {
@@ -4853,8 +5942,115 @@ function collectActionListErrors(actions, path, errors, block, context = {}, slo
4853
5942
  if (!Array.isArray(actions)) {
4854
5943
  return;
4855
5944
  }
5945
+ collectDuplicateAIEmployeeActionErrors(actions, path, errors, block);
4856
5946
  actions.forEach((action, index) => collectActionErrors(action, `${path}[${index}]`, errors, block, context, slot));
4857
5947
  }
5948
+ function collectDuplicateAIEmployeeActionErrors(actions, path, errors, block) {
5949
+ const seen = /* @__PURE__ */ new Map();
5950
+ actions.forEach((action, index) => {
5951
+ const actionType = resolveAuthoringActionType(action, block);
5952
+ if (actionType !== "aiEmployee" || !_.isPlainObject(action)) {
5953
+ return;
5954
+ }
5955
+ const identity = buildAuthoringAIEmployeeActionIdentity(action.settings);
5956
+ if (!identity) {
5957
+ return;
5958
+ }
5959
+ const currentPath = `${path}[${index}]`;
5960
+ const previousPath = seen.get(identity);
5961
+ if (previousPath) {
5962
+ pushAuthoringError(errors, {
5963
+ path: currentPath,
5964
+ ruleId: "duplicate-ai-employee-action",
5965
+ message: `flowSurfaces authoring ${currentPath} duplicates an existing AI employee action in the same action container; reuse or update the existing button instead of appending another identical AI employee action.`,
5966
+ details: {
5967
+ duplicateOf: previousPath,
5968
+ repairHint: "Remove the duplicate aiEmployee action, or change username, task title/key, or workContext if this is a genuinely different AI employee action."
5969
+ }
5970
+ });
5971
+ return;
5972
+ }
5973
+ seen.set(identity, currentPath);
5974
+ });
5975
+ }
5976
+ function buildAuthoringAIEmployeeActionIdentity(settings) {
5977
+ if (!_.isPlainObject(settings)) {
5978
+ return "";
5979
+ }
5980
+ const username = String(settings.username || "").trim();
5981
+ if (!username) {
5982
+ return "";
5983
+ }
5984
+ return stableSerializeAuthoringValue(normalizeAuthoringAIEmployeePublicSettingsForIdentity(settings));
5985
+ }
5986
+ function normalizeAuthoringAIEmployeePublicSettingsForIdentity(settings) {
5987
+ return {
5988
+ username: String(settings.username || "").trim(),
5989
+ auto: typeof settings.auto === "boolean" ? settings.auto : false,
5990
+ workContext: Object.prototype.hasOwnProperty.call(settings, "workContext") ? normalizeAuthoringAIEmployeeWorkContextForIdentity(settings.workContext) : [{ type: "flow-model", target: "self" }],
5991
+ tasks: normalizeAuthoringAIEmployeeTasksForIdentity(settings.tasks),
5992
+ style: {
5993
+ ...AUTHORING_AI_EMPLOYEE_DEFAULT_STYLE,
5994
+ ..._.isPlainObject(settings.style) ? _.pick(settings.style, AUTHORING_AI_EMPLOYEE_STYLE_PUBLIC_KEYS) : {}
5995
+ }
5996
+ };
5997
+ }
5998
+ function normalizeAuthoringAIEmployeeWorkContextForIdentity(value) {
5999
+ return _.castArray(value || []).map((item) => {
6000
+ if (!_.isPlainObject(item)) {
6001
+ return item;
6002
+ }
6003
+ const output = _.pick(item, AUTHORING_AI_EMPLOYEE_WORK_CONTEXT_PUBLIC_KEYS);
6004
+ if (!Object.prototype.hasOwnProperty.call(output, "type") || _.isUndefined(output.type) || output.type === null) {
6005
+ output.type = "flow-model";
6006
+ }
6007
+ return output;
6008
+ });
6009
+ }
6010
+ function normalizeAuthoringAIEmployeeTasksForIdentity(value) {
6011
+ return _.castArray(value || []).map((task) => {
6012
+ if (!_.isPlainObject(task)) {
6013
+ return task;
6014
+ }
6015
+ const output = _.pick(task, AUTHORING_AI_EMPLOYEE_TASK_PUBLIC_SETTING_KEYS);
6016
+ if (_.isPlainObject(output.message)) {
6017
+ output.message = _.pick(output.message, AUTHORING_AI_EMPLOYEE_TASK_MESSAGE_PUBLIC_KEYS);
6018
+ if (_.isPlainObject(output.message.workContext)) {
6019
+ output.message.workContext = normalizeAuthoringAIEmployeeWorkContextForIdentity(output.message.workContext);
6020
+ } else if (Array.isArray(output.message.workContext)) {
6021
+ output.message.workContext = normalizeAuthoringAIEmployeeWorkContextForIdentity(output.message.workContext);
6022
+ }
6023
+ }
6024
+ if (Object.prototype.hasOwnProperty.call(task, "prompt") && !Object.prototype.hasOwnProperty.call(output.message || {}, "user")) {
6025
+ output.message = {
6026
+ ..._.isPlainObject(output.message) ? output.message : {},
6027
+ user: task.prompt
6028
+ };
6029
+ }
6030
+ if (_.isPlainObject(output.model)) {
6031
+ output.model = _.pick(output.model, AUTHORING_AI_EMPLOYEE_TASK_MODEL_PUBLIC_KEYS);
6032
+ }
6033
+ if (_.isPlainObject(output.skillSettings)) {
6034
+ output.skillSettings = _.pick(output.skillSettings, AUTHORING_AI_EMPLOYEE_SKILL_SETTINGS_PUBLIC_KEYS);
6035
+ if (Array.isArray(output.skillSettings.skills) && !Object.prototype.hasOwnProperty.call(output.skillSettings, "skillsVersion")) {
6036
+ output.skillSettings.skillsVersion = 2;
6037
+ }
6038
+ if (Array.isArray(output.skillSettings.tools) && !Object.prototype.hasOwnProperty.call(output.skillSettings, "toolsVersion")) {
6039
+ output.skillSettings.toolsVersion = 2;
6040
+ }
6041
+ }
6042
+ return output;
6043
+ });
6044
+ }
6045
+ function stableSerializeAuthoringValue(value) {
6046
+ if (Array.isArray(value)) {
6047
+ return `[${value.map((item) => stableSerializeAuthoringValue(item)).join(",")}]`;
6048
+ }
6049
+ if (_.isPlainObject(value)) {
6050
+ return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${stableSerializeAuthoringValue(value[key])}`).join(",")}}`;
6051
+ }
6052
+ return JSON.stringify(value);
6053
+ }
4858
6054
  function resolveAuthoringActionType(action, block) {
4859
6055
  const rawType = typeof action === "string" ? action : _.isPlainObject(action) ? action.type : "";
4860
6056
  const normalized = String(rawType || "").trim().toLowerCase();
@@ -5301,6 +6497,7 @@ function collectFieldListErrors(fields, path, errors, localKeys, context, block)
5301
6497
  if (fieldPath) {
5302
6498
  collectUnknownFieldPathError(fieldPath, `${path}[${index}]`, block, context, errors);
5303
6499
  }
6500
+ collectImplicitRelationTitleFieldErrors(field, `${path}[${index}]`, block, context, errors);
5304
6501
  if (!_.isPlainObject(field)) {
5305
6502
  return;
5306
6503
  }
@@ -5388,7 +6585,8 @@ function collectApplyBlueprintScriptAssetReferenceErrors(spec, path, errors, con
5388
6585
  pushAuthoringError(errors, {
5389
6586
  path: `${path}.script`,
5390
6587
  ruleId: "apply-blueprint-script-asset-key-invalid",
5391
- message: `flowSurfaces applyBlueprint ${publicPath}.script must be a non-empty string asset key; use settings.code for inline JS code`
6588
+ message: `flowSurfaces applyBlueprint ${publicPath}.script must be a non-empty string asset key; use settings.code for inline JS code`,
6589
+ details: withJsBlockRepairHint()
5392
6590
  });
5393
6591
  return;
5394
6592
  }
@@ -5399,14 +6597,18 @@ function collectApplyBlueprintScriptAssetReferenceErrors(spec, path, errors, con
5399
6597
  pushAuthoringError(errors, {
5400
6598
  path: `${path}.script`,
5401
6599
  ruleId: "apply-blueprint-script-asset-code-required",
5402
- message: `flowSurfaces applyBlueprint ${publicPath}.script references script asset '${scriptKey}' without non-empty code; use settings.code for inline JS code`
6600
+ message: `flowSurfaces applyBlueprint ${publicPath}.script references script asset '${scriptKey}' without non-empty code; use settings.code for inline JS code`,
6601
+ details: withJsBlockRepairHint({
6602
+ scriptKey
6603
+ })
5403
6604
  });
5404
6605
  return;
5405
6606
  }
5406
6607
  pushAuthoringError(errors, {
5407
6608
  path: `${path}.script`,
5408
6609
  ruleId: "apply-blueprint-script-asset-key-invalid",
5409
- message: `flowSurfaces applyBlueprint ${publicPath}.script must be a string asset key; use settings.code for inline JS code`
6610
+ message: `flowSurfaces applyBlueprint ${publicPath}.script must be a string asset key; use settings.code for inline JS code`,
6611
+ details: withJsBlockRepairHint()
5410
6612
  });
5411
6613
  }
5412
6614
  function hasApplyBlueprintRunnableScriptAssetReference(script, context) {
@@ -5616,6 +6818,106 @@ function collectRelationTitleFieldErrors(fieldSpec, path, block, context, errors
5616
6818
  })
5617
6819
  });
5618
6820
  }
6821
+ function collectImplicitRelationTitleFieldErrors(fieldSpec, path, block, context, errors) {
6822
+ var _a;
6823
+ if (context.authoringActionName !== "applyBlueprint") {
6824
+ return;
6825
+ }
6826
+ const hostBlockType = String((block == null ? void 0 : block.type) || "").trim();
6827
+ if (!IMPLICIT_RELATION_TITLE_FIELD_DISPLAY_BLOCK_TYPES.has(hostBlockType)) {
6828
+ return;
6829
+ }
6830
+ if (_.isPlainObject(fieldSpec) && fieldSpec.__autoPopupForRelationField === true) {
6831
+ return;
6832
+ }
6833
+ if (_.isPlainObject(fieldSpec) && Object.prototype.hasOwnProperty.call(fieldSpec, "titleField")) {
6834
+ return;
6835
+ }
6836
+ const fieldPath = getFieldPathInput(fieldSpec);
6837
+ if (!fieldPath || fieldPath.includes(".")) {
6838
+ return;
6839
+ }
6840
+ const collection = getBlockCollection(block, context);
6841
+ if (!collection || !context.getCollection) {
6842
+ return;
6843
+ }
6844
+ const resolvedField = (0, import_service_helpers.resolveFieldFromCollection)(collection, (0, import_service_helpers.normalizeFieldPath)(fieldPath));
6845
+ if (!resolvedField || !(0, import_service_helpers.isAssociationField)(resolvedField)) {
6846
+ return;
6847
+ }
6848
+ const dataSourceKey = getBlockDataSourceKey(block, context);
6849
+ if (hasUsableDefaultFieldGroupRelationTitleField({
6850
+ fieldGroups: (_a = context.getDefaultFieldGroups) == null ? void 0 : _a.call(context, dataSourceKey, getBlockCollectionName(block, context)),
6851
+ fieldPath,
6852
+ field: resolvedField,
6853
+ dataSourceKey,
6854
+ context
6855
+ })) {
6856
+ return;
6857
+ }
6858
+ const registeredBinding = (0, import_field_binding_registry.resolveRegisteredFieldBinding)({
6859
+ containerUse: IMPLICIT_RELATION_TITLE_FIELD_CONTAINER_USE_BY_BLOCK_TYPE[hostBlockType],
6860
+ field: resolvedField,
6861
+ dataSourceKey,
6862
+ enabledPackages: context.enabledPackages,
6863
+ getCollection: (resolvedDataSourceKey, targetCollectionName) => {
6864
+ var _a2;
6865
+ return (_a2 = context.getCollection) == null ? void 0 : _a2.call(context, resolvedDataSourceKey, targetCollectionName);
6866
+ },
6867
+ useStrictOnly: true
6868
+ });
6869
+ if (registeredBinding == null ? void 0 : registeredBinding.modelClassName) {
6870
+ return;
6871
+ }
6872
+ try {
6873
+ const resolvedTitleField = (0, import_association_title_field.resolveAssociationSafeTitleField)(resolvedField, dataSourceKey, context.getCollection, {
6874
+ action: context.authoringActionName,
6875
+ path: `${path}.titleField`,
6876
+ fieldPath
6877
+ });
6878
+ if (!(resolvedTitleField == null ? void 0 : resolvedTitleField.fieldName)) {
6879
+ pushAuthoringError(errors, {
6880
+ path: `${path}.titleField`,
6881
+ ruleId: "relation-titleField-unavailable",
6882
+ message: `flowSurfaces authoring ${path} relation field '${fieldPath}' requires an explicit readable titleField`,
6883
+ details: {
6884
+ fieldPath,
6885
+ repairHint: `Use object field form such as {"field":"${fieldPath}","titleField":"<readable target field>"}.`
6886
+ }
6887
+ });
6888
+ }
6889
+ } catch (error) {
6890
+ if (!(error instanceof import_errors.FlowSurfaceBadRequestError)) {
6891
+ throw error;
6892
+ }
6893
+ pushAuthoringError(errors, {
6894
+ path: `${path}.titleField`,
6895
+ ruleId: error.options.ruleId || "relation-titleField-unavailable",
6896
+ message: `flowSurfaces authoring ${path} relation field '${fieldPath}' requires an explicit readable titleField`,
6897
+ details: {
6898
+ ...error.options.details || {},
6899
+ fieldPath,
6900
+ repairHint: `Use object field form such as {"field":"${fieldPath}","titleField":"<readable target field>"}.`
6901
+ }
6902
+ });
6903
+ }
6904
+ }
6905
+ function hasUsableDefaultFieldGroupRelationTitleField(input) {
6906
+ const titleField = (0, import_defaults.getFlowSurfaceDefaultFieldGroupRelationTitleFieldOverride)(input.fieldGroups, input.fieldPath);
6907
+ if (!titleField || titleField === "id" || !input.context.getCollection) {
6908
+ return false;
6909
+ }
6910
+ const targetCollection = (0, import_service_helpers.resolveFieldTargetCollection)(
6911
+ input.field,
6912
+ input.dataSourceKey,
6913
+ (dataSourceKey, collectionName) => {
6914
+ var _a, _b;
6915
+ return (_b = (_a = input.context).getCollection) == null ? void 0 : _b.call(_a, dataSourceKey, collectionName);
6916
+ }
6917
+ );
6918
+ const targetField = targetCollection ? (0, import_service_helpers.resolveFieldFromCollection)(targetCollection, titleField) : void 0;
6919
+ return !!targetField && !(0, import_service_helpers.isAssociationField)(targetField);
6920
+ }
5619
6921
  function getRelationTitleFieldInvalidReason(titleField, targetField) {
5620
6922
  if (titleField === "id") {
5621
6923
  return "id";
@@ -5649,18 +6951,18 @@ function getRecordHistoryDeclaredFilterTargetKey(collection) {
5649
6951
  return String(raw || "").trim();
5650
6952
  }
5651
6953
  function collectionHasConcreteField(collection, fieldName) {
5652
- var _a, _b, _c, _d, _e, _f;
6954
+ var _a, _b, _c;
5653
6955
  const normalized = String(fieldName || "").trim();
5654
6956
  if (!normalized) {
5655
6957
  return false;
5656
6958
  }
5657
- const modelAttributes = (typeof ((_a = collection == null ? void 0 : collection.model) == null ? void 0 : _a.getAttributes) === "function" ? collection.model.getAttributes() : null) || ((_b = collection == null ? void 0 : collection.model) == null ? void 0 : _b.rawAttributes) || ((_c = collection == null ? void 0 : collection.model) == null ? void 0 : _c.attributes) || {};
6959
+ const modelAttributes = (0, import_service_helpers.getCollectionModelAttributes)(collection);
5658
6960
  const primaryKeyAttributes = _.castArray(
5659
- ((_d = collection == null ? void 0 : collection.model) == null ? void 0 : _d.primaryKeyAttributes) || ((_e = collection == null ? void 0 : collection.model) == null ? void 0 : _e.primaryKeyAttribute) || []
6961
+ ((_a = collection == null ? void 0 : collection.model) == null ? void 0 : _a.primaryKeyAttributes) || ((_b = collection == null ? void 0 : collection.model) == null ? void 0 : _b.primaryKeyAttribute) || []
5660
6962
  );
5661
6963
  const modelAttribute = modelAttributes == null ? void 0 : modelAttributes[normalized];
5662
6964
  const isModelPrimaryKey = primaryKeyAttributes.includes(normalized) || !!(modelAttribute == null ? void 0 : modelAttribute.primaryKey);
5663
- return !!((0, import_service_helpers.resolveFieldFromCollection)(collection, normalized) || ((_f = collection == null ? void 0 : collection.getField) == null ? void 0 : _f.call(collection, normalized)) || (0, import_service_helpers.getCollectionFields)(collection).some((field) => (0, import_service_helpers.getFieldName)(field) === normalized) || isModelPrimaryKey);
6965
+ return !!((0, import_service_helpers.resolveFieldFromCollection)(collection, normalized) || ((_c = collection == null ? void 0 : collection.getField) == null ? void 0 : _c.call(collection, normalized)) || (0, import_service_helpers.getCollectionFields)(collection).some((field) => (0, import_service_helpers.getFieldName)(field) === normalized) || isModelPrimaryKey);
5664
6966
  }
5665
6967
  function collectDefaultFilterFieldPathError(rawFieldPath, path, block, context, errors) {
5666
6968
  const fieldPath = String(rawFieldPath || "").trim();