@nocobase/plugin-flow-engine 2.1.0-beta.41 → 2.1.0-beta.43

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.
@@ -60,6 +60,7 @@ 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
62
  var import_configure_options = require("./configure-options");
63
+ var import_filter_group = require("./filter-group");
63
64
  const MAIN_BLOCK_UNSUPPORTED_SECTIONS = {
64
65
  calendar: ["fields", "fieldGroups", "recordActions", "fieldsLayout"],
65
66
  kanban: ["fieldGroups", "recordActions", "fieldsLayout"],
@@ -83,6 +84,13 @@ const VISIBLE_FIELD_REQUIRED_DATA_BLOCK_TYPES = /* @__PURE__ */ new Set([
83
84
  "kanban"
84
85
  ]);
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
+ };
86
94
  const RICH_COLLECTION_VISIBLE_FIELD_THRESHOLD = import_public_data_surface_default_filter.FLOW_SURFACE_DEFAULT_FILTER_REQUIRED_FIELD_COUNT * 2;
87
95
  const RICH_DATA_BLOCK_VISIBLE_FIELD_MINIMUM = 3;
88
96
  const NON_BUSINESS_VISIBLE_FIELD_NAMES = /* @__PURE__ */ new Set([
@@ -163,10 +171,31 @@ const JS_BLOCK_ALLOWED_SETTINGS_KEYS = /* @__PURE__ */ new Set(["title", "descri
163
171
  const JS_BLOCK_TOP_LEVEL_JS_KEYS = ["code", "version"];
164
172
  const JS_BLOCK_INTERNAL_AUTHORING_KEYS = ["props", "decoratorProps", "flowRegistry", "stepParams"];
165
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.";
166
- const CHART_REPAIR_HINT = "This is a chart payload shape problem. 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.";
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 JS_BLOCK_FORBIDDEN_FALLBACKS = [
176
+ "table",
177
+ "list",
178
+ "chart",
179
+ "actionPanel",
180
+ "gridCard",
181
+ "markdown",
182
+ "drop jsBlock",
183
+ "defer jsBlock"
184
+ ];
185
+ const CHART_FORBIDDEN_FALLBACKS = [
186
+ "table",
187
+ "list",
188
+ "jsBlock",
189
+ "actionPanel",
190
+ "gridCard",
191
+ "markdown",
192
+ "drop chart",
193
+ "defer chart"
194
+ ];
167
195
  const CHART_QUERY_MODE_SET = new Set(import_chart_config.CHART_QUERY_MODES);
168
196
  const CHART_VISUAL_MODE_SET = new Set(import_chart_config.CHART_VISUAL_MODES);
169
197
  const CHART_BASIC_VISUAL_TYPE_SET = new Set(import_chart_config.CHART_BASIC_VISUAL_TYPES);
198
+ const STRICT_LOCALIZED_CHART_ACTIONS = /* @__PURE__ */ new Set(["compose", "addBlocks"]);
170
199
  const CHART_VISUAL_LEGACY_BUILDER_KEYS = /* @__PURE__ */ new Set([
171
200
  "xField",
172
201
  "yField",
@@ -201,6 +230,7 @@ const CHART_SQL_QUERY_FORBIDDEN_KEYS = /* @__PURE__ */ new Set([
201
230
  "offset"
202
231
  ]);
203
232
  const CHART_CUSTOM_VISUAL_FORBIDDEN_KEYS = /* @__PURE__ */ new Set(["type", "mappings", "style"]);
233
+ const CHART_DEFAULT_DATA_SOURCE_KEY = "main";
204
234
  const JS_ITEM_COLLECTION_ACTION_HOST_BLOCK_TYPES = /* @__PURE__ */ new Set(["table", "list", "gridCard", "calendar", "kanban"]);
205
235
  const JS_ITEM_RECORD_ACTION_HOST_BLOCK_TYPES = /* @__PURE__ */ new Set(["table", "details", "list", "gridCard"]);
206
236
  const JS_ITEM_FORM_ACTION_HOST_BLOCK_TYPES = /* @__PURE__ */ new Set(["createForm", "editForm"]);
@@ -396,6 +426,14 @@ async function collectFlowSurfaceAuthoringErrors(actionName, values, context = {
396
426
  if (!_.isPlainObject(values)) {
397
427
  return errors;
398
428
  }
429
+ validationContext.getDefaultFieldGroups = validationContext.getDefaultFieldGroups || ((dataSourceKey, collectionName) => {
430
+ var _a2;
431
+ return (_a2 = (0, import_defaults.resolveFlowSurfaceApplyBlueprintDefaultCollection)({
432
+ metadata: values == null ? void 0 : values.defaults,
433
+ dataSourceKey,
434
+ collectionName
435
+ }).collectionDefaults) == null ? void 0 : _a2.fieldGroups;
436
+ });
399
437
  if (actionName === "applyBlueprint" && _.isPlainObject((_a = values == null ? void 0 : values.assets) == null ? void 0 : _a.scripts)) {
400
438
  validationContext.applyBlueprintScriptAssets = values.assets.scripts;
401
439
  }
@@ -408,7 +446,7 @@ async function collectFlowSurfaceAuthoringErrors(actionName, values, context = {
408
446
  collectApplyBlueprintChartAssetErrors(actionName, values, validationContext, errors);
409
447
  if (actionName === "configure") {
410
448
  await collectConfigureErrors(values, errors, validationContext);
411
- errors.push(...(0, import_runjs_authoring.collectRunJsAuthoringErrors)(actionName, values, validationContext));
449
+ appendRunJsAuthoringErrors(actionName, values, validationContext, errors);
412
450
  if (!validationContext.skipGeneratedPopupDefaultFieldGroups) {
413
451
  collectGeneratedPopupDefaultFieldGroupErrors(actionName, values, validationContext, errors);
414
452
  }
@@ -429,9 +467,42 @@ async function collectFlowSurfaceAuthoringErrors(actionName, values, context = {
429
467
  if (!validationContext.skipGeneratedPopupDefaultFieldGroups) {
430
468
  collectGeneratedPopupDefaultFieldGroupErrors(actionName, values, validationContext, errors);
431
469
  }
432
- errors.push(...(0, import_runjs_authoring.collectRunJsAuthoringErrors)(actionName, values, validationContext));
470
+ appendRunJsAuthoringErrors(actionName, values, validationContext, errors);
433
471
  return errors;
434
472
  }
473
+ function appendRunJsAuthoringErrors(actionName, values, context, errors) {
474
+ try {
475
+ errors.push(...(0, import_runjs_authoring.collectRunJsAuthoringErrors)(actionName, values, context));
476
+ } catch (error) {
477
+ if (shouldKeepExistingChartAuthoringErrors(error, errors)) {
478
+ return;
479
+ }
480
+ if (isChartBadRequestError(error)) {
481
+ pushChartBadRequestAuthoringError(errors, error, actionName === "configure" ? "$.changes" : "$");
482
+ return;
483
+ }
484
+ throw error;
485
+ }
486
+ }
487
+ function isChartBadRequestError(error) {
488
+ return error instanceof import_errors.FlowSurfaceBadRequestError && String(error.message || "").startsWith("chart ");
489
+ }
490
+ function shouldKeepExistingChartAuthoringErrors(error, errors) {
491
+ return isChartBadRequestError(error) && errors.some((item) => {
492
+ var _a;
493
+ return ((_a = item.details) == null ? void 0 : _a.repairHint) === CHART_REPAIR_HINT;
494
+ });
495
+ }
496
+ function pushChartBadRequestAuthoringError(errors, error, fallbackPath) {
497
+ var _a, _b, _c;
498
+ const details = _.isPlainObject((_a = error.options) == null ? void 0 : _a.details) ? error.options.details : {};
499
+ pushAuthoringError(errors, {
500
+ path: typeof ((_b = error.options) == null ? void 0 : _b.path) === "string" && error.options.path ? error.options.path : fallbackPath,
501
+ ruleId: typeof ((_c = error.options) == null ? void 0 : _c.ruleId) === "string" && error.options.ruleId ? error.options.ruleId : "chart-configure-invalid",
502
+ message: error.message,
503
+ details: withChartRepairHint(details)
504
+ });
505
+ }
435
506
  async function collectNavigationGroupErrors(actionName, values, context, errors) {
436
507
  var _a;
437
508
  if (actionName !== "applyBlueprint" || (values == null ? void 0 : values.mode) !== "create" || !_.isPlainObject((_a = values == null ? void 0 : values.navigation) == null ? void 0 : _a.group)) {
@@ -644,12 +715,38 @@ function collectChartAssetBlockTreeErrors(block, path, chartAssets, errors) {
644
715
  function withJsBlockRepairHint(details = {}) {
645
716
  return {
646
717
  ...details,
647
- repairHint: JS_BLOCK_REPAIR_HINT
718
+ requiredBlockType: "jsBlock",
719
+ fixStrategy: "repair_same_block_type",
720
+ repairHint: JS_BLOCK_REPAIR_HINT,
721
+ repairExample: {
722
+ inlineBlock: {
723
+ type: "jsBlock",
724
+ settings: {
725
+ code: 'ctx.render("Replace this with the required rendered UI");'
726
+ }
727
+ },
728
+ assetBlock: {
729
+ assets: {
730
+ scripts: {
731
+ scriptKey: {
732
+ code: 'ctx.render("Replace this with the required rendered UI");'
733
+ }
734
+ }
735
+ },
736
+ block: {
737
+ type: "jsBlock",
738
+ script: "scriptKey"
739
+ }
740
+ }
741
+ },
742
+ forbiddenFallbacks: JS_BLOCK_FORBIDDEN_FALLBACKS
648
743
  };
649
744
  }
650
745
  function withChartRepairHint(details = {}) {
651
746
  return {
652
747
  ...details,
748
+ requiredBlockType: "chart",
749
+ fixStrategy: "repair_same_block_type",
653
750
  repairHint: CHART_REPAIR_HINT,
654
751
  repairSteps: [
655
752
  "Keep the block type as chart.",
@@ -658,6 +755,58 @@ function withChartRepairHint(details = {}) {
658
755
  "Retry the chart payload instead of replacing the chart with another block type or omitting it."
659
756
  ],
660
757
  expectedShape: {
758
+ settings: {
759
+ query: {
760
+ mode: "builder",
761
+ resource: {
762
+ dataSourceKey: "main",
763
+ collectionName: "employees"
764
+ },
765
+ measures: [
766
+ {
767
+ field: "id",
768
+ aggregation: "count",
769
+ alias: "employeeCount"
770
+ }
771
+ ]
772
+ },
773
+ visual: {
774
+ mode: "basic",
775
+ type: "bar",
776
+ mappings: {
777
+ x: "status",
778
+ y: "employeeCount"
779
+ }
780
+ }
781
+ },
782
+ legacySettings: {
783
+ configure: {
784
+ query: {
785
+ mode: "builder",
786
+ resource: {
787
+ dataSourceKey: "main",
788
+ collectionName: "employees"
789
+ },
790
+ measures: [
791
+ {
792
+ field: "id",
793
+ aggregation: "count",
794
+ alias: "employeeCount"
795
+ }
796
+ ]
797
+ },
798
+ chart: {
799
+ option: {
800
+ mode: "basic",
801
+ builder: {
802
+ type: "bar",
803
+ xField: "status",
804
+ yField: "employeeCount"
805
+ }
806
+ }
807
+ }
808
+ }
809
+ },
661
810
  assets: {
662
811
  charts: {
663
812
  chartKey: {
@@ -671,9 +820,232 @@ function withChartRepairHint(details = {}) {
671
820
  chart: "chartKey"
672
821
  }
673
822
  },
674
- forbiddenFallbacks: ["table", "jsBlock", "actionPanel", "gridCard", "drop chart", "defer chart"]
823
+ repairExample: {
824
+ settings: {
825
+ query: {
826
+ mode: "builder",
827
+ resource: {
828
+ dataSourceKey: "main",
829
+ collectionName: "<collectionName>"
830
+ },
831
+ measures: [
832
+ {
833
+ field: "id",
834
+ aggregation: "count",
835
+ alias: "recordCount"
836
+ }
837
+ ],
838
+ dimensions: [
839
+ {
840
+ field: "<dimensionField>"
841
+ }
842
+ ]
843
+ },
844
+ visual: {
845
+ mode: "basic",
846
+ type: "bar",
847
+ mappings: {
848
+ x: "<dimensionField>",
849
+ y: "recordCount"
850
+ }
851
+ }
852
+ },
853
+ assets: {
854
+ charts: {
855
+ chartKey: {
856
+ query: {
857
+ mode: "builder",
858
+ resource: {
859
+ dataSourceKey: "main",
860
+ collectionName: "<collectionName>"
861
+ },
862
+ measures: [
863
+ {
864
+ field: "id",
865
+ aggregation: "count",
866
+ alias: "recordCount"
867
+ }
868
+ ],
869
+ dimensions: [
870
+ {
871
+ field: "<dimensionField>"
872
+ }
873
+ ]
874
+ },
875
+ visual: {
876
+ mode: "basic",
877
+ type: "bar",
878
+ mappings: {
879
+ x: "<dimensionField>",
880
+ y: "recordCount"
881
+ }
882
+ }
883
+ }
884
+ }
885
+ },
886
+ block: {
887
+ type: "chart",
888
+ chart: "chartKey"
889
+ }
890
+ },
891
+ forbiddenFallbacks: CHART_FORBIDDEN_FALLBACKS
892
+ };
893
+ }
894
+ function collectLocalizedChartSettingsErrors(block, blockType, path, errors, context) {
895
+ if (blockType !== "chart" || !STRICT_LOCALIZED_CHART_ACTIONS.has(context.authoringActionName)) {
896
+ return;
897
+ }
898
+ const settingsPath = `${path}.settings`;
899
+ if (!_.isUndefined(block.settings) && !_.isPlainObject(block.settings)) {
900
+ pushAuthoringError(errors, {
901
+ path: settingsPath,
902
+ ruleId: "chart-localized-settings-invalid",
903
+ message: `flowSurfaces authoring ${settingsPath} must be an object for compose/addBlocks chart blocks`,
904
+ details: withChartRepairHint()
905
+ });
906
+ return;
907
+ }
908
+ const settings = _.isPlainObject(block.settings) ? block.settings : {};
909
+ if (hasOwn(settings, "configure")) {
910
+ if (["query", "visual", "events"].some((key) => hasOwn(settings, key))) {
911
+ pushAuthoringError(errors, {
912
+ path: settingsPath,
913
+ ruleId: "chart-localized-settings-mixed-configure",
914
+ message: `flowSurfaces authoring ${settingsPath} cannot mix legacy configure with query/visual/events`,
915
+ details: withChartRepairHint()
916
+ });
917
+ return;
918
+ }
919
+ collectLocalizedLegacyChartConfigureErrors(settings.configure, `${settingsPath}.configure`, errors);
920
+ return;
921
+ }
922
+ if (!hasOwn(settings, "query") && !hasOwn(settings, "visual")) {
923
+ return;
924
+ }
925
+ collectChartAssetQueryErrors(settings, settingsPath, context, errors);
926
+ collectChartAssetVisualErrors(settings, settingsPath, errors);
927
+ }
928
+ function collectLocalizedLegacyChartConfigureErrors(configure, path, errors) {
929
+ if (!_.isPlainObject(configure)) {
930
+ pushAuthoringError(errors, {
931
+ path,
932
+ ruleId: "chart-configure-invalid",
933
+ message: `flowSurfaces authoring ${path} must be an object`,
934
+ details: withChartRepairHint()
935
+ });
936
+ return;
937
+ }
938
+ collectLegacyChartQueryCompatibilityErrors(configure.query, `${path}.query`, errors);
939
+ }
940
+ function collectLegacyChartQueryCompatibilityErrors(query, path, errors) {
941
+ if (!_.isPlainObject(query)) {
942
+ return;
943
+ }
944
+ collectChartQueryFilterOperatorErrors(query, path, errors);
945
+ const hasResource = hasOwn(query, "resource");
946
+ const hasCollectionPath = hasOwn(query, "collectionPath");
947
+ if (!hasResource && !hasCollectionPath) {
948
+ return;
949
+ }
950
+ const resource = hasResource ? normalizeLegacyChartResourceForValidation(query.resource, `${path}.resource`, errors) : void 0;
951
+ const collectionPathResource = hasCollectionPath ? normalizeLegacyChartCollectionPathResourceForValidation(query.collectionPath, `${path}.collectionPath`, errors) : void 0;
952
+ if (hasResource && hasCollectionPath && resource && collectionPathResource && !_.isEqual(resource, collectionPathResource)) {
953
+ pushAuthoringError(errors, {
954
+ path,
955
+ ruleId: "chart-legacy-query-resource-conflict",
956
+ message: `flowSurfaces authoring ${path}.resource and ${path}.collectionPath must reference the same collection`,
957
+ details: withChartRepairHint({
958
+ resource,
959
+ collectionPathResource
960
+ })
961
+ });
962
+ }
963
+ }
964
+ function normalizeLegacyChartCollectionPathResource(collectionPath) {
965
+ if (!Array.isArray(collectionPath)) {
966
+ return void 0;
967
+ }
968
+ const collectionName = normalizeLegacyChartRequiredString(collectionPath[1]);
969
+ if (!collectionName) {
970
+ return void 0;
971
+ }
972
+ const dataSourceKey = normalizeLegacyChartCollectionPathDataSourceKey(collectionPath[0]);
973
+ if (!dataSourceKey) {
974
+ return void 0;
975
+ }
976
+ return {
977
+ dataSourceKey,
978
+ collectionName
675
979
  };
676
980
  }
981
+ function normalizeLegacyChartResourceForValidation(resource, path, errors) {
982
+ if (!_.isPlainObject(resource)) {
983
+ pushAuthoringError(errors, {
984
+ path,
985
+ ruleId: "chart-legacy-query-resource-invalid",
986
+ message: `flowSurfaces authoring ${path} must be an object with string collectionName`,
987
+ details: withChartRepairHint()
988
+ });
989
+ return void 0;
990
+ }
991
+ const collectionName = normalizeLegacyChartRequiredString(resource.collectionName);
992
+ if (!collectionName) {
993
+ pushAuthoringError(errors, {
994
+ path: `${path}.collectionName`,
995
+ ruleId: "chart-legacy-query-resource-invalid",
996
+ message: `flowSurfaces authoring ${path}.collectionName must be a non-empty string`,
997
+ details: withChartRepairHint()
998
+ });
999
+ return void 0;
1000
+ }
1001
+ const dataSourceKey = normalizeLegacyChartResourceDataSourceKey(resource.dataSourceKey);
1002
+ if (!dataSourceKey) {
1003
+ pushAuthoringError(errors, {
1004
+ path: `${path}.dataSourceKey`,
1005
+ ruleId: "chart-legacy-query-resource-invalid",
1006
+ message: `flowSurfaces authoring ${path}.dataSourceKey must be a non-empty string when provided`,
1007
+ details: withChartRepairHint()
1008
+ });
1009
+ return void 0;
1010
+ }
1011
+ return {
1012
+ dataSourceKey,
1013
+ collectionName
1014
+ };
1015
+ }
1016
+ function normalizeLegacyChartCollectionPathResourceForValidation(collectionPath, path, errors) {
1017
+ const resource = normalizeLegacyChartCollectionPathResource(collectionPath);
1018
+ if (!resource) {
1019
+ pushAuthoringError(errors, {
1020
+ path,
1021
+ ruleId: "chart-legacy-query-collection-path-invalid",
1022
+ message: `flowSurfaces authoring ${path} must be [dataSourceKey, collectionName] with string values and a non-empty collectionName`,
1023
+ details: withChartRepairHint()
1024
+ });
1025
+ }
1026
+ return resource;
1027
+ }
1028
+ function normalizeLegacyChartRequiredString(input) {
1029
+ if (typeof input !== "string") {
1030
+ return void 0;
1031
+ }
1032
+ return input.trim() || void 0;
1033
+ }
1034
+ function normalizeLegacyChartResourceDataSourceKey(input) {
1035
+ if (_.isUndefined(input) || _.isNull(input)) {
1036
+ return CHART_DEFAULT_DATA_SOURCE_KEY;
1037
+ }
1038
+ return normalizeLegacyChartRequiredString(input);
1039
+ }
1040
+ function normalizeLegacyChartCollectionPathDataSourceKey(input) {
1041
+ if (_.isUndefined(input) || _.isNull(input)) {
1042
+ return CHART_DEFAULT_DATA_SOURCE_KEY;
1043
+ }
1044
+ if (typeof input === "string" && !input.trim()) {
1045
+ return CHART_DEFAULT_DATA_SOURCE_KEY;
1046
+ }
1047
+ return normalizeLegacyChartRequiredString(input);
1048
+ }
677
1049
  function collectChartBlockAssetReferenceErrors(block, path, chartAssets, errors) {
678
1050
  if (!CHART_BLOCK_TYPES.has(String((block == null ? void 0 : block.type) || "").trim())) {
679
1051
  return;
@@ -781,8 +1153,85 @@ function collectBuilderChartAssetQueryErrors(query, path, context, errors) {
781
1153
  errors,
782
1154
  withChartRepairHint()
783
1155
  );
1156
+ collectChartQueryFilterOperatorErrors(query, `${path}.query`, errors);
784
1157
  collectBuilderChartAssetFieldErrors(query, path, context, errors);
785
1158
  }
1159
+ function collectChartQueryFilterOperatorErrors(query, path, errors) {
1160
+ if (!_.isPlainObject(query) || !hasOwn(query, "filter")) {
1161
+ return;
1162
+ }
1163
+ collectChartFilterOperatorErrors(query.filter, `${path}.filter`, errors);
1164
+ }
1165
+ function collectChartFilterOperatorErrors(filter, path, errors) {
1166
+ if (_.isUndefined(filter) || _.isNull(filter) || !_.isPlainObject(filter)) {
1167
+ return;
1168
+ }
1169
+ if (Array.isArray(filter.items)) {
1170
+ collectChartFilterGroupOperatorErrors(filter.items, `${path}.items`, errors);
1171
+ return;
1172
+ }
1173
+ collectBackendQueryFilterOperatorErrors(filter, path, errors);
1174
+ }
1175
+ function collectChartFilterGroupOperatorErrors(items, path, errors) {
1176
+ items.forEach((item, index) => {
1177
+ const itemPath = `${path}[${index}]`;
1178
+ if (!_.isPlainObject(item)) {
1179
+ return;
1180
+ }
1181
+ if (Array.isArray(item.items)) {
1182
+ collectChartFilterGroupOperatorErrors(item.items, `${itemPath}.items`, errors);
1183
+ return;
1184
+ }
1185
+ if (hasOwn(item, "operator")) {
1186
+ collectChartFilterOperatorError(item.operator, `${itemPath}.operator`, errors);
1187
+ collectChartFilterDateValueError(item.operator, item.value, `${itemPath}.value`, errors);
1188
+ }
1189
+ });
1190
+ }
1191
+ function collectBackendQueryFilterOperatorErrors(filter, path, errors) {
1192
+ Object.entries(filter).forEach(([field, condition]) => {
1193
+ const fieldPath = `${path}.${field}`;
1194
+ if ((field === "$and" || field === "$or") && Array.isArray(condition)) {
1195
+ condition.forEach(
1196
+ (operand, index) => collectChartFilterOperatorErrors(operand, `${fieldPath}[${index}]`, errors)
1197
+ );
1198
+ return;
1199
+ }
1200
+ if (!_.isPlainObject(condition)) {
1201
+ return;
1202
+ }
1203
+ Object.keys(condition).forEach((operator) => {
1204
+ if (operator === "$and" || operator === "$or") {
1205
+ collectChartFilterOperatorErrors({ [operator]: condition[operator] }, fieldPath, errors);
1206
+ return;
1207
+ }
1208
+ collectChartFilterOperatorError(operator, `${fieldPath}.${operator}`, errors);
1209
+ collectChartFilterDateValueError(operator, condition[operator], `${fieldPath}.${operator}`, errors);
1210
+ });
1211
+ });
1212
+ }
1213
+ function collectChartFilterOperatorError(operator, path, errors) {
1214
+ try {
1215
+ (0, import_filter_group.assertFlowSurfaceFilterOperator)(operator, path);
1216
+ } catch (error) {
1217
+ if (error instanceof import_errors.FlowSurfaceBadRequestError) {
1218
+ pushChartBadRequestAuthoringError(errors, error, path);
1219
+ return;
1220
+ }
1221
+ throw error;
1222
+ }
1223
+ }
1224
+ function collectChartFilterDateValueError(operator, value, path, errors) {
1225
+ try {
1226
+ (0, import_filter_group.normalizeFlowSurfaceFilterDateValue)(operator, value, path);
1227
+ } catch (error) {
1228
+ if (error instanceof import_errors.FlowSurfaceBadRequestError) {
1229
+ pushChartBadRequestAuthoringError(errors, error, path);
1230
+ return;
1231
+ }
1232
+ throw error;
1233
+ }
1234
+ }
786
1235
  function normalizeChartAssetFieldPath(input) {
787
1236
  if (Array.isArray(input)) {
788
1237
  return input.map((item) => String(item || "").trim()).filter(Boolean).join(".");
@@ -3385,10 +3834,13 @@ function collectBlockErrors(block, path, errors, localKeys, context) {
3385
3834
  collectVisibleDataBlockFieldErrors(block, blockType, path, errors, context);
3386
3835
  collectCommentsBlockErrors(block, blockType, path, errors, context);
3387
3836
  collectRecordHistoryBlockErrors(block, blockType, path, errors, context);
3837
+ collectLocalizedChartSettingsErrors(block, blockType, path, errors, context);
3388
3838
  collectChartDisplayTitleErrors(block, blockType, path, errors);
3389
3839
  collectTreeTableExplicitFieldsErrors(block, blockType, path, errors, context);
3390
3840
  collectTreeConnectFieldsErrors((_a = block.settings) == null ? void 0 : _a.connectFields, `${path}.settings.connectFields`, errors);
3391
- collectTableSettingsErrors(block, blockType, path, errors);
3841
+ collectTableSettingsErrors(block, blockType, path, errors, {
3842
+ deferPublicDataScopeErrors: context.authoringActionName === "addBlocks"
3843
+ });
3392
3844
  collectGridCardSettingsErrors(block, blockType, path, errors);
3393
3845
  const descendantContext = getBlockDescendantValidationContext(block, context);
3394
3846
  collectActionListErrors(block.actions, `${path}.actions`, errors, block, descendantContext, "actions");
@@ -3646,6 +4098,7 @@ function collectFieldGroupsShapeErrors(fieldGroups, blockPath, errors, block, co
3646
4098
  if (fieldPath) {
3647
4099
  collectUnknownFieldPathError(fieldPath, itemPath, block, context, errors);
3648
4100
  }
4101
+ collectImplicitRelationTitleFieldErrors(field, itemPath, block, context, errors);
3649
4102
  if (!_.isPlainObject(field)) {
3650
4103
  return;
3651
4104
  }
@@ -3695,6 +4148,7 @@ async function collectConfigureErrors(values, errors, context) {
3695
4148
  collectCommentsBlockErrors(changesBlock, hostBlockType, "$.changes", errors, context);
3696
4149
  collectRecordHistoryBlockErrors(changesBlock, hostBlockType, "$.changes", errors, context);
3697
4150
  collectChartDisplayTitleErrors(changes, hostBlockType, "$.changes", errors);
4151
+ collectChartConfigureFilterOperatorErrors(changes, hostBlockType, "$.changes", errors);
3698
4152
  collectTableSettingsErrors(changes, hostBlockType, "$.changes", errors, { directSettings: true });
3699
4153
  collectGridCardSettingsErrors(changes, hostBlockType, "$.changes", errors, { directSettings: true });
3700
4154
  collectAssignValuesErrors(changes.assignValues, "$.changes.assignValues", errors, changesBlock, context);
@@ -4783,6 +5237,15 @@ function collectChartDisplayTitleErrors(block, blockType, blockPath, errors) {
4783
5237
  message: "Chart block settings do not support displayTitle in the current flowSurfaces runtime; keep settings.title and omit displayTitle."
4784
5238
  });
4785
5239
  }
5240
+ function collectChartConfigureFilterOperatorErrors(changes, hostBlockType, path, errors) {
5241
+ if (hostBlockType !== "chart" || !_.isPlainObject(changes)) {
5242
+ return;
5243
+ }
5244
+ collectChartQueryFilterOperatorErrors(changes.query, `${path}.query`, errors);
5245
+ if (_.isPlainObject(changes.configure)) {
5246
+ collectChartQueryFilterOperatorErrors(changes.configure.query, `${path}.configure.query`, errors);
5247
+ }
5248
+ }
4786
5249
  function visitFilterItems(value, path, errors, block, context = {}) {
4787
5250
  if (Array.isArray(value)) {
4788
5251
  value.forEach((item, index) => visitFilterItems(item, `${path}[${index}]`, errors, block, context));
@@ -5198,6 +5661,9 @@ function collectTableSettingsErrors(block, blockType, blockPath, errors, options
5198
5661
  }
5199
5662
  pushTableSettingsUnsupportedError(errors, `${settingsPath}.${key}`, key);
5200
5663
  });
5664
+ if (!shouldDeferPublicDataScopeErrorsToBatchItem(blockPath, errors, options)) {
5665
+ collectPublicDataScopeErrors(settings.dataScope, `${settingsPath}.dataScope`, errors);
5666
+ }
5201
5667
  }
5202
5668
  function pushTableSettingsUnsupportedError(errors, path, key) {
5203
5669
  pushAuthoringError(errors, {
@@ -5211,6 +5677,47 @@ function pushTableSettingsUnsupportedError(errors, path, key) {
5211
5677
  }
5212
5678
  });
5213
5679
  }
5680
+ function collectPublicDataScopeErrors(value, path, errors) {
5681
+ if (_.isUndefined(value)) {
5682
+ return;
5683
+ }
5684
+ if (value === null || _.isPlainObject(value) && !Object.keys(value).length) {
5685
+ return;
5686
+ }
5687
+ const validationValue = normalizePublicDataScopeValueForValidation(value);
5688
+ try {
5689
+ (0, import_filter_group.assertFlowSurfaceFilterGroupShape)(validationValue);
5690
+ } catch (error) {
5691
+ const reason = error instanceof Error ? error.message : String(error);
5692
+ pushAuthoringError(errors, {
5693
+ path,
5694
+ ruleId: "dataScope-filter-group-invalid-shape",
5695
+ message: `flowSurfaces authoring ${path} expects FilterGroup like ${import_filter_group.FLOW_SURFACE_FILTER_GROUP_EXAMPLE}: ${reason}`,
5696
+ details: {
5697
+ 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.'
5698
+ }
5699
+ });
5700
+ }
5701
+ }
5702
+ function shouldDeferPublicDataScopeErrorsToBatchItem(blockPath, errors, options) {
5703
+ if (options.deferPublicDataScopeErrors !== true) {
5704
+ return false;
5705
+ }
5706
+ if (!/^\$\.blocks\[\d+\]$/.test(blockPath)) {
5707
+ return false;
5708
+ }
5709
+ return !errors.some((error) => error.path === `${blockPath}.settings.dataScope`);
5710
+ }
5711
+ function normalizePublicDataScopeValueForValidation(value) {
5712
+ if (!_.isPlainObject(value)) {
5713
+ return value;
5714
+ }
5715
+ const keys = Object.keys(value);
5716
+ if (keys.length === 1 && keys[0] === "filter") {
5717
+ return value.filter;
5718
+ }
5719
+ return value;
5720
+ }
5214
5721
  function collectGridCardSettingsErrors(block, blockType, blockPath, errors, options = {}) {
5215
5722
  const hasSettings = _.isPlainObject(block == null ? void 0 : block.settings);
5216
5723
  if (!hasSettings && options.directSettings !== true) {
@@ -5851,6 +6358,7 @@ function collectFieldListErrors(fields, path, errors, localKeys, context, block)
5851
6358
  if (fieldPath) {
5852
6359
  collectUnknownFieldPathError(fieldPath, `${path}[${index}]`, block, context, errors);
5853
6360
  }
6361
+ collectImplicitRelationTitleFieldErrors(field, `${path}[${index}]`, block, context, errors);
5854
6362
  if (!_.isPlainObject(field)) {
5855
6363
  return;
5856
6364
  }
@@ -6171,6 +6679,106 @@ function collectRelationTitleFieldErrors(fieldSpec, path, block, context, errors
6171
6679
  })
6172
6680
  });
6173
6681
  }
6682
+ function collectImplicitRelationTitleFieldErrors(fieldSpec, path, block, context, errors) {
6683
+ var _a;
6684
+ if (context.authoringActionName !== "applyBlueprint") {
6685
+ return;
6686
+ }
6687
+ const hostBlockType = String((block == null ? void 0 : block.type) || "").trim();
6688
+ if (!IMPLICIT_RELATION_TITLE_FIELD_DISPLAY_BLOCK_TYPES.has(hostBlockType)) {
6689
+ return;
6690
+ }
6691
+ if (_.isPlainObject(fieldSpec) && fieldSpec.__autoPopupForRelationField === true) {
6692
+ return;
6693
+ }
6694
+ if (_.isPlainObject(fieldSpec) && Object.prototype.hasOwnProperty.call(fieldSpec, "titleField")) {
6695
+ return;
6696
+ }
6697
+ const fieldPath = getFieldPathInput(fieldSpec);
6698
+ if (!fieldPath || fieldPath.includes(".")) {
6699
+ return;
6700
+ }
6701
+ const collection = getBlockCollection(block, context);
6702
+ if (!collection || !context.getCollection) {
6703
+ return;
6704
+ }
6705
+ const resolvedField = (0, import_service_helpers.resolveFieldFromCollection)(collection, (0, import_service_helpers.normalizeFieldPath)(fieldPath));
6706
+ if (!resolvedField || !(0, import_service_helpers.isAssociationField)(resolvedField)) {
6707
+ return;
6708
+ }
6709
+ const dataSourceKey = getBlockDataSourceKey(block, context);
6710
+ if (hasUsableDefaultFieldGroupRelationTitleField({
6711
+ fieldGroups: (_a = context.getDefaultFieldGroups) == null ? void 0 : _a.call(context, dataSourceKey, getBlockCollectionName(block, context)),
6712
+ fieldPath,
6713
+ field: resolvedField,
6714
+ dataSourceKey,
6715
+ context
6716
+ })) {
6717
+ return;
6718
+ }
6719
+ const registeredBinding = (0, import_field_binding_registry.resolveRegisteredFieldBinding)({
6720
+ containerUse: IMPLICIT_RELATION_TITLE_FIELD_CONTAINER_USE_BY_BLOCK_TYPE[hostBlockType],
6721
+ field: resolvedField,
6722
+ dataSourceKey,
6723
+ enabledPackages: context.enabledPackages,
6724
+ getCollection: (resolvedDataSourceKey, targetCollectionName) => {
6725
+ var _a2;
6726
+ return (_a2 = context.getCollection) == null ? void 0 : _a2.call(context, resolvedDataSourceKey, targetCollectionName);
6727
+ },
6728
+ useStrictOnly: true
6729
+ });
6730
+ if (registeredBinding == null ? void 0 : registeredBinding.modelClassName) {
6731
+ return;
6732
+ }
6733
+ try {
6734
+ const resolvedTitleField = (0, import_association_title_field.resolveAssociationSafeTitleField)(resolvedField, dataSourceKey, context.getCollection, {
6735
+ action: context.authoringActionName,
6736
+ path: `${path}.titleField`,
6737
+ fieldPath
6738
+ });
6739
+ if (!(resolvedTitleField == null ? void 0 : resolvedTitleField.fieldName)) {
6740
+ pushAuthoringError(errors, {
6741
+ path: `${path}.titleField`,
6742
+ ruleId: "relation-titleField-unavailable",
6743
+ message: `flowSurfaces authoring ${path} relation field '${fieldPath}' requires an explicit readable titleField`,
6744
+ details: {
6745
+ fieldPath,
6746
+ repairHint: `Use object field form such as {"field":"${fieldPath}","titleField":"<readable target field>"}.`
6747
+ }
6748
+ });
6749
+ }
6750
+ } catch (error) {
6751
+ if (!(error instanceof import_errors.FlowSurfaceBadRequestError)) {
6752
+ throw error;
6753
+ }
6754
+ pushAuthoringError(errors, {
6755
+ path: `${path}.titleField`,
6756
+ ruleId: error.options.ruleId || "relation-titleField-unavailable",
6757
+ message: `flowSurfaces authoring ${path} relation field '${fieldPath}' requires an explicit readable titleField`,
6758
+ details: {
6759
+ ...error.options.details || {},
6760
+ fieldPath,
6761
+ repairHint: `Use object field form such as {"field":"${fieldPath}","titleField":"<readable target field>"}.`
6762
+ }
6763
+ });
6764
+ }
6765
+ }
6766
+ function hasUsableDefaultFieldGroupRelationTitleField(input) {
6767
+ const titleField = (0, import_defaults.getFlowSurfaceDefaultFieldGroupRelationTitleFieldOverride)(input.fieldGroups, input.fieldPath);
6768
+ if (!titleField || titleField === "id" || !input.context.getCollection) {
6769
+ return false;
6770
+ }
6771
+ const targetCollection = (0, import_service_helpers.resolveFieldTargetCollection)(
6772
+ input.field,
6773
+ input.dataSourceKey,
6774
+ (dataSourceKey, collectionName) => {
6775
+ var _a, _b;
6776
+ return (_b = (_a = input.context).getCollection) == null ? void 0 : _b.call(_a, dataSourceKey, collectionName);
6777
+ }
6778
+ );
6779
+ const targetField = targetCollection ? (0, import_service_helpers.resolveFieldFromCollection)(targetCollection, titleField) : void 0;
6780
+ return !!targetField && !(0, import_service_helpers.isAssociationField)(targetField);
6781
+ }
6174
6782
  function getRelationTitleFieldInvalidReason(titleField, targetField) {
6175
6783
  if (titleField === "id") {
6176
6784
  return "id";