@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.
- package/dist/client/index.js +1 -1
- package/dist/externalVersion.js +9 -9
- package/dist/node_modules/@ant-design/icons-svg/package.json +1 -1
- package/dist/node_modules/acorn/package.json +1 -1
- package/dist/node_modules/acorn-jsx/package.json +1 -1
- package/dist/node_modules/acorn-walk/package.json +1 -1
- package/dist/node_modules/ses/package.json +1 -1
- package/dist/node_modules/zod/package.json +1 -1
- package/dist/server/flow-surfaces/apply/compiler.js +28 -14
- package/dist/server/flow-surfaces/apply/matching.js +2 -0
- package/dist/server/flow-surfaces/authoring-validation.d.ts +1 -0
- package/dist/server/flow-surfaces/authoring-validation.js +1453 -151
- package/dist/server/flow-surfaces/blueprint/compile-blocks.js +21 -3
- package/dist/server/flow-surfaces/blueprint/compile-plan.js +9 -9
- package/dist/server/flow-surfaces/blueprint/normalize-document.js +5 -1
- package/dist/server/flow-surfaces/catalog.js +26 -9
- package/dist/server/flow-surfaces/chart-config.js +231 -14
- package/dist/server/flow-surfaces/compose-compiler.d.ts +2 -0
- package/dist/server/flow-surfaces/compose-compiler.js +2 -0
- package/dist/server/flow-surfaces/compose-runtime.js +4 -7
- package/dist/server/flow-surfaces/configure-options.js +19 -8
- package/dist/server/flow-surfaces/contract-guard.js +40 -6
- package/dist/server/flow-surfaces/default-block-actions.js +2 -0
- package/dist/server/flow-surfaces/errors.d.ts +15 -0
- package/dist/server/flow-surfaces/errors.js +49 -3
- package/dist/server/flow-surfaces/event-flow-normalizer.d.ts +19 -0
- package/dist/server/flow-surfaces/event-flow-normalizer.js +128 -0
- package/dist/server/flow-surfaces/filter-group.d.ts +9 -1
- package/dist/server/flow-surfaces/filter-group.js +402 -3
- package/dist/server/flow-surfaces/locator.js +16 -2
- package/dist/server/flow-surfaces/public-data-surface-default-filter.js +2 -1
- package/dist/server/flow-surfaces/route-sync.js +19 -2
- package/dist/server/flow-surfaces/runjs-authoring/ast/bindings.d.ts +66 -0
- package/dist/server/flow-surfaces/runjs-authoring/ast/bindings.js +661 -0
- package/dist/server/flow-surfaces/runjs-authoring/ast/execution.d.ts +20 -0
- package/dist/server/flow-surfaces/runjs-authoring/ast/execution.js +275 -0
- package/dist/server/flow-surfaces/runjs-authoring/ast/parser.d.ts +16 -0
- package/dist/server/flow-surfaces/runjs-authoring/ast/parser.js +130 -0
- package/dist/server/flow-surfaces/runjs-authoring/ast/react-values.d.ts +20 -0
- package/dist/server/flow-surfaces/runjs-authoring/ast/react-values.js +401 -0
- package/dist/server/flow-surfaces/runjs-authoring/ast/request-config.d.ts +21 -0
- package/dist/server/flow-surfaces/runjs-authoring/ast/request-config.js +199 -0
- package/dist/server/flow-surfaces/runjs-authoring/ast/source.d.ts +70 -0
- package/dist/server/flow-surfaces/runjs-authoring/ast/source.js +895 -0
- package/dist/server/flow-surfaces/runjs-authoring/ast/static-bindings.d.ts +23 -0
- package/dist/server/flow-surfaces/runjs-authoring/ast/static-bindings.js +618 -0
- package/dist/server/flow-surfaces/runjs-authoring/ast/static-values.d.ts +196 -0
- package/dist/server/flow-surfaces/runjs-authoring/ast/static-values.js +1777 -0
- package/dist/server/flow-surfaces/runjs-authoring/ast/walk.d.ts +10 -0
- package/dist/server/flow-surfaces/runjs-authoring/ast/walk.js +55 -0
- package/dist/server/flow-surfaces/runjs-authoring/collectors.d.ts +12 -0
- package/dist/server/flow-surfaces/runjs-authoring/collectors.js +589 -0
- package/dist/server/flow-surfaces/runjs-authoring/ctx-libs-member-mismatch-stop/index.js +1 -1
- package/dist/server/flow-surfaces/runjs-authoring/index.d.ts +2 -25
- package/dist/server/flow-surfaces/runjs-authoring/index.js +5 -7033
- package/dist/server/flow-surfaces/runjs-authoring/inspect.d.ts +13 -0
- package/dist/server/flow-surfaces/runjs-authoring/inspect.js +149 -0
- package/dist/server/flow-surfaces/runjs-authoring/internal-types.d.ts +333 -0
- package/dist/server/flow-surfaces/runjs-authoring/internal-types.js +36 -0
- package/dist/server/flow-surfaces/runjs-authoring/rules.js +2 -0
- package/dist/server/flow-surfaces/runjs-authoring/runtime/constants.d.ts +67 -0
- package/dist/server/flow-surfaces/runjs-authoring/runtime/constants.js +757 -0
- package/dist/server/flow-surfaces/runjs-authoring/runtime/errors.d.ts +22 -0
- package/dist/server/flow-surfaces/runjs-authoring/runtime/errors.js +91 -0
- package/dist/server/flow-surfaces/runjs-authoring/runtime/source-budget.d.ts +16 -0
- package/dist/server/flow-surfaces/runjs-authoring/runtime/source-budget.js +115 -0
- package/dist/server/flow-surfaces/runjs-authoring/runtime/surface.d.ts +19 -0
- package/dist/server/flow-surfaces/runjs-authoring/runtime/surface.js +140 -0
- package/dist/server/flow-surfaces/runjs-authoring/runtime/types.d.ts +91 -0
- package/dist/server/flow-surfaces/runjs-authoring/runtime/types.js +24 -0
- package/dist/server/flow-surfaces/runjs-authoring/scan/ctx-api.d.ts +138 -0
- package/dist/server/flow-surfaces/runjs-authoring/scan/ctx-api.js +1779 -0
- package/dist/server/flow-surfaces/runjs-authoring/scan/filter.d.ts +10 -0
- package/dist/server/flow-surfaces/runjs-authoring/scan/filter.js +1583 -0
- package/dist/server/flow-surfaces/runjs-authoring/scan/index.d.ts +195 -0
- package/dist/server/flow-surfaces/runjs-authoring/scan/index.js +463 -0
- package/dist/server/flow-surfaces/runjs-authoring/scan/react-render.d.ts +48 -0
- package/dist/server/flow-surfaces/runjs-authoring/scan/react-render.js +379 -0
- package/dist/server/flow-surfaces/runjs-authoring/scan/react.d.ts +26 -0
- package/dist/server/flow-surfaces/runjs-authoring/scan/react.js +1441 -0
- package/dist/server/flow-surfaces/runjs-authoring/scan/resource.d.ts +23 -0
- package/dist/server/flow-surfaces/runjs-authoring/scan/resource.js +1427 -0
- package/dist/server/flow-surfaces/runjs-authoring/scan/source-patterns.d.ts +91 -0
- package/dist/server/flow-surfaces/runjs-authoring/scan/source-patterns.js +889 -0
- package/dist/server/flow-surfaces/runjs-authoring/types.d.ts +1 -1
- package/dist/server/flow-surfaces/runjs-authoring/unknown-global-stop/index.d.ts +10 -0
- package/dist/server/flow-surfaces/runjs-authoring/unknown-global-stop/index.js +40 -0
- package/dist/server/flow-surfaces/runjs-authoring/validators/index.d.ts +12 -0
- package/dist/server/flow-surfaces/runjs-authoring/validators/index.js +887 -0
- package/dist/server/flow-surfaces/service-helpers.d.ts +29 -0
- package/dist/server/flow-surfaces/service-helpers.js +105 -0
- package/dist/server/flow-surfaces/service-utils.d.ts +17 -3
- package/dist/server/flow-surfaces/service-utils.js +14 -5
- package/dist/server/flow-surfaces/service.d.ts +74 -15
- package/dist/server/flow-surfaces/service.js +1781 -193
- package/dist/server/flow-surfaces/template-service-utils.d.ts +1 -0
- package/dist/server/flow-surfaces/types.d.ts +3 -0
- package/dist/server/repository.d.ts +12 -1
- package/dist/server/repository.js +195 -23
- package/dist/swagger/flow-surfaces.d.ts +180 -2
- package/dist/swagger/flow-surfaces.examples.d.ts +11 -37
- package/dist/swagger/flow-surfaces.examples.js +6 -6
- package/dist/swagger/flow-surfaces.js +136 -54
- package/dist/swagger/index.d.ts +180 -2
- 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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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 ${
|
|
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
|
-
|
|
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: "
|
|
358
|
-
message: "flowSurfaces authoring $.navigation.group.icon is required when creating a
|
|
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: "
|
|
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: "
|
|
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: "
|
|
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
|
-
|
|
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 (
|
|
4075
|
-
|
|
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
|
|
4083
|
-
|
|
4084
|
-
|
|
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 (
|
|
4087
|
-
|
|
4088
|
-
|
|
4089
|
-
|
|
4090
|
-
|
|
4091
|
-
|
|
4092
|
-
|
|
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
|
-
|
|
4095
|
-
|
|
5098
|
+
const collection = getBlockCollection(block, context);
|
|
5099
|
+
if (!collection) {
|
|
5100
|
+
return true;
|
|
4096
5101
|
}
|
|
4097
|
-
|
|
4098
|
-
|
|
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
|
|
4101
|
-
|
|
4102
|
-
|
|
4103
|
-
|
|
4104
|
-
|
|
4105
|
-
|
|
4106
|
-
|
|
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
|
-
|
|
4111
|
-
|
|
4112
|
-
|
|
4113
|
-
|
|
4114
|
-
|
|
4115
|
-
|
|
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
|
|
4140
|
-
|
|
4141
|
-
|
|
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.
|
|
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
|
|
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 = (
|
|
6959
|
+
const modelAttributes = (0, import_service_helpers.getCollectionModelAttributes)(collection);
|
|
5658
6960
|
const primaryKeyAttributes = _.castArray(
|
|
5659
|
-
((
|
|
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) || ((
|
|
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();
|