@nocobase/flow-engine 2.1.0-alpha.30 → 2.1.0-alpha.31

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.
@@ -14,5 +14,11 @@ interface ExtendedFormItemProps extends FormItemProps {
14
14
  labelWrap?: boolean;
15
15
  showLabel?: boolean;
16
16
  }
17
+ export declare const verticalFormItemLabelStyle: {
18
+ paddingBottom: number;
19
+ };
20
+ export declare const formItemStyle: {
21
+ marginBottom: number;
22
+ };
17
23
  export declare const FormItem: ({ children, showLabel, labelWidth, ...rest }: ExtendedFormItemProps & ChildExtraProps) => React.JSX.Element;
18
24
  export {};
@@ -37,11 +37,15 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
37
37
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
38
38
  var FormItem_exports = {};
39
39
  __export(FormItem_exports, {
40
- FormItem: () => FormItem
40
+ FormItem: () => FormItem,
41
+ formItemStyle: () => formItemStyle,
42
+ verticalFormItemLabelStyle: () => verticalFormItemLabelStyle
41
43
  });
42
44
  module.exports = __toCommonJS(FormItem_exports);
43
45
  var import_react = __toESM(require("react"));
44
46
  var import_antd = require("antd");
47
+ const verticalFormItemLabelStyle = { paddingBottom: 0 };
48
+ const formItemStyle = { marginBottom: 12 };
45
49
  const formItemPropKeys = [
46
50
  "colon",
47
51
  "dependencies",
@@ -90,6 +94,7 @@ const FormItem = /* @__PURE__ */ __name(({
90
94
  });
91
95
  const { label, labelWrap, colon = true, layout } = rest;
92
96
  const effectiveLabelWrap = !layout || layout === "vertical" ? true : labelWrap;
97
+ const labelColStyle = layout === "vertical" ? { width: labelWidth, ...verticalFormItemLabelStyle } : { width: labelWidth };
93
98
  const renderLabel = /* @__PURE__ */ __name(() => {
94
99
  if (!showLabel) return null;
95
100
  if (effectiveLabelWrap) {
@@ -132,7 +137,8 @@ const FormItem = /* @__PURE__ */ __name(({
132
137
  import_antd.Form.Item,
133
138
  {
134
139
  ...rest,
135
- labelCol: { style: { width: labelWidth } },
140
+ style: { ...formItemStyle, ...rest.style },
141
+ labelCol: { style: labelColStyle },
136
142
  layout,
137
143
  label: renderLabel(),
138
144
  colon: false,
@@ -147,5 +153,7 @@ const FormItem = /* @__PURE__ */ __name(({
147
153
  }, "FormItem");
148
154
  // Annotate the CommonJS export names for ESM import in node:
149
155
  0 && (module.exports = {
150
- FormItem
156
+ FormItem,
157
+ formItemStyle,
158
+ verticalFormItemLabelStyle
151
159
  });
@@ -851,6 +851,18 @@ const findCellByPath = /* @__PURE__ */ __name((layout, path) => {
851
851
  }
852
852
  return null;
853
853
  }, "findCellByPath");
854
+ const findCellByPathOrClosestAncestor = /* @__PURE__ */ __name((layout, path) => {
855
+ if (!(path == null ? void 0 : path.length)) {
856
+ return null;
857
+ }
858
+ for (let length = path.length; length > 0; length -= 1) {
859
+ const target = findCellByPath(layout, path.slice(0, length));
860
+ if (target) {
861
+ return target;
862
+ }
863
+ }
864
+ return null;
865
+ }, "findCellByPathOrClosestAncestor");
854
866
  const removeItemFromGridLayout = /* @__PURE__ */ __name((layout, sourceUid) => {
855
867
  const removeFromRows = /* @__PURE__ */ __name((rows) => rows.map((row) => {
856
868
  const cellsWithSizes = row.cells.map((cell, index) => {
@@ -918,7 +930,7 @@ const simulateGridLayoutForSlot = /* @__PURE__ */ __name(({
918
930
  removeItemFromGridLayout(cloned, sourceUid);
919
931
  switch (slot.type) {
920
932
  case "column": {
921
- const target = findCellByPath(cloned, targetPath);
933
+ const target = findCellByPathOrClosestAncestor(cloned, targetPath);
922
934
  if (!target) {
923
935
  break;
924
936
  }
@@ -934,7 +946,7 @@ const simulateGridLayoutForSlot = /* @__PURE__ */ __name(({
934
946
  break;
935
947
  }
936
948
  case "empty-column": {
937
- const target = findCellByPath(cloned, targetPath);
949
+ const target = findCellByPathOrClosestAncestor(cloned, targetPath);
938
950
  if (target) {
939
951
  delete target.cell.rows;
940
952
  target.cell.items = [sourceUid];
@@ -942,7 +954,7 @@ const simulateGridLayoutForSlot = /* @__PURE__ */ __name(({
942
954
  break;
943
955
  }
944
956
  case "column-edge": {
945
- const target = findCellByPath(cloned, targetPath);
957
+ const target = findCellByPathOrClosestAncestor(cloned, targetPath);
946
958
  if (!target) {
947
959
  break;
948
960
  }
@@ -969,7 +981,7 @@ const simulateGridLayoutForSlot = /* @__PURE__ */ __name(({
969
981
  if (!targetItemUid) {
970
982
  break;
971
983
  }
972
- const target = findCellByPath(cloned, targetPath);
984
+ const target = findCellByPathOrClosestAncestor(cloned, targetPath);
973
985
  if (!(target == null ? void 0 : target.cell.items)) {
974
986
  break;
975
987
  }
@@ -90,6 +90,8 @@ export declare class DataSourceManager {
90
90
  force: boolean;
91
91
  }): Promise<void>;
92
92
  }
93
+ export type CollectionFieldInterfaceDataSourceManager = Pick<DataSourceManager, 'collectionFieldInterfaceManager'>;
94
+ export declare function getCollectionFieldInterface(interfaceName: string | undefined, ...dataSourceManagers: Array<CollectionFieldInterfaceDataSourceManager | null | undefined>): any;
93
95
  export declare class DataSource {
94
96
  dataSourceManager: DataSourceManager;
95
97
  collectionManager: CollectionManager;
@@ -42,6 +42,7 @@ __export(data_source_exports, {
42
42
  CollectionManager: () => CollectionManager,
43
43
  DataSource: () => DataSource,
44
44
  DataSourceManager: () => DataSourceManager,
45
+ getCollectionFieldInterface: () => getCollectionFieldInterface,
45
46
  isFieldInterfaceMatch: () => isFieldInterfaceMatch,
46
47
  jioToJoiSchema: () => import_jioToJoiSchema.jioToJoiSchema
47
48
  });
@@ -279,6 +280,20 @@ const _DataSourceManager = class _DataSourceManager {
279
280
  };
280
281
  __name(_DataSourceManager, "DataSourceManager");
281
282
  let DataSourceManager = _DataSourceManager;
283
+ function getCollectionFieldInterface(interfaceName, ...dataSourceManagers) {
284
+ if (!interfaceName) {
285
+ return void 0;
286
+ }
287
+ for (const dataSourceManager of dataSourceManagers) {
288
+ const collectionFieldInterfaceManager = dataSourceManager == null ? void 0 : dataSourceManager.collectionFieldInterfaceManager;
289
+ const getFieldInterface = collectionFieldInterfaceManager == null ? void 0 : collectionFieldInterfaceManager.getFieldInterface;
290
+ if (typeof getFieldInterface === "function") {
291
+ return getFieldInterface.call(collectionFieldInterfaceManager, interfaceName);
292
+ }
293
+ }
294
+ return void 0;
295
+ }
296
+ __name(getCollectionFieldInterface, "getCollectionFieldInterface");
282
297
  const _DataSource = class _DataSource {
283
298
  dataSourceManager;
284
299
  collectionManager;
@@ -982,7 +997,17 @@ const _CollectionField = class _CollectionField {
982
997
  abortEarly: false
983
998
  });
984
999
  if (error) {
985
- const message = error.details.map((d) => d.message.replace(/"value"/g, `"${label}"`)).join(", ");
1000
+ const message = error.details.map((d) => {
1001
+ const translated = this.flowEngine.translate(d.type, {
1002
+ ...d.context,
1003
+ ns: "data-source-main",
1004
+ label
1005
+ });
1006
+ if (translated && translated !== d.type) {
1007
+ return translated;
1008
+ }
1009
+ return d.message.replace(/"value"/g, `"${label}"`);
1010
+ }).join(", ");
986
1011
  return Promise.reject(message);
987
1012
  }
988
1013
  return Promise.resolve();
@@ -1002,8 +1027,14 @@ const _CollectionField = class _CollectionField {
1002
1027
  return this.targetCollection.getFields();
1003
1028
  }
1004
1029
  getInterfaceOptions() {
1005
- const app = this.flowEngine.context.app;
1006
- return app.dataSourceManager.collectionFieldInterfaceManager.getFieldInterface(this.interface);
1030
+ var _a, _b, _c;
1031
+ const ctx = this.flowEngine.context;
1032
+ return getCollectionFieldInterface(
1033
+ this.interface,
1034
+ (_b = (_a = this.collection) == null ? void 0 : _a.dataSource) == null ? void 0 : _b.dataSourceManager,
1035
+ ctx.dataSourceManager,
1036
+ (_c = ctx.app) == null ? void 0 : _c.dataSourceManager
1037
+ );
1007
1038
  }
1008
1039
  getFilterOperators() {
1009
1040
  var _a;
@@ -1068,6 +1099,7 @@ __name(isFieldInterfaceMatch, "isFieldInterfaceMatch");
1068
1099
  CollectionManager,
1069
1100
  DataSource,
1070
1101
  DataSourceManager,
1102
+ getCollectionFieldInterface,
1071
1103
  isFieldInterfaceMatch,
1072
1104
  jioToJoiSchema
1073
1105
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nocobase/flow-engine",
3
- "version": "2.1.0-alpha.30",
3
+ "version": "2.1.0-alpha.31",
4
4
  "private": false,
5
5
  "description": "A standalone flow engine for NocoBase, managing workflows, models, and actions.",
6
6
  "main": "lib/index.js",
@@ -8,8 +8,8 @@
8
8
  "dependencies": {
9
9
  "@formily/antd-v5": "1.x",
10
10
  "@formily/reactive": "2.x",
11
- "@nocobase/sdk": "2.1.0-alpha.30",
12
- "@nocobase/shared": "2.1.0-alpha.30",
11
+ "@nocobase/sdk": "2.1.0-alpha.31",
12
+ "@nocobase/shared": "2.1.0-alpha.31",
13
13
  "ahooks": "^3.7.2",
14
14
  "axios": "^1.7.0",
15
15
  "dayjs": "^1.11.9",
@@ -37,5 +37,5 @@
37
37
  ],
38
38
  "author": "NocoBase Team",
39
39
  "license": "Apache-2.0",
40
- "gitHead": "292ae0ad87f195ed201b274902d21ecd96f5ddd0"
40
+ "gitHead": "e2bc6b461a9bfd336043069c3211c9c5b01ebcc3"
41
41
  }
@@ -19,6 +19,9 @@ interface ExtendedFormItemProps extends FormItemProps {
19
19
  showLabel?: boolean;
20
20
  }
21
21
 
22
+ export const verticalFormItemLabelStyle = { paddingBottom: 0 };
23
+ export const formItemStyle = { marginBottom: 12 };
24
+
22
25
  const formItemPropKeys: (keyof ExtendedFormItemProps)[] = [
23
26
  'colon',
24
27
  'dependencies',
@@ -73,6 +76,8 @@ export const FormItem = ({
73
76
  });
74
77
  const { label, labelWrap, colon = true, layout } = rest;
75
78
  const effectiveLabelWrap = !layout || layout === 'vertical' ? true : labelWrap;
79
+ const labelColStyle =
80
+ layout === 'vertical' ? { width: labelWidth, ...verticalFormItemLabelStyle } : { width: labelWidth };
76
81
  const renderLabel = () => {
77
82
  if (!showLabel) return null;
78
83
  if (effectiveLabelWrap) {
@@ -118,7 +123,8 @@ export const FormItem = ({
118
123
  return (
119
124
  <Form.Item
120
125
  {...rest}
121
- labelCol={{ style: { width: labelWidth } }}
126
+ style={{ ...formItemStyle, ...rest.style }}
127
+ labelCol={{ style: labelColStyle }}
122
128
  layout={layout}
123
129
  label={renderLabel()}
124
130
  colon={false}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * This file is part of the NocoBase (R) project.
3
+ * Copyright (c) 2020-2024 NocoBase Co., Ltd.
4
+ * Authors: NocoBase Team.
5
+ *
6
+ * This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
7
+ * For more information, please refer to: https://www.nocobase.com/agreement.
8
+ */
9
+
10
+ import { describe, expect, it } from 'vitest';
11
+ import { formItemStyle, verticalFormItemLabelStyle } from '../FormItem';
12
+
13
+ describe('FormItem', () => {
14
+ it('keeps vertical label-to-value spacing consistent with v1', () => {
15
+ expect(verticalFormItemLabelStyle).toEqual({
16
+ paddingBottom: 0,
17
+ });
18
+ });
19
+
20
+ it('keeps spacing between form items consistent with v1', () => {
21
+ expect(formItemStyle).toEqual({
22
+ marginBottom: 12,
23
+ });
24
+ });
25
+ });
@@ -829,6 +829,52 @@ describe('simulateLayoutForSlot', () => {
829
829
  expect(nestedRows[1].sizes).toEqual([12, 12]);
830
830
  });
831
831
 
832
+ it('keeps nested column insertion target when removing a sibling collapses the original path', () => {
833
+ const layout = createLayout(
834
+ {
835
+ vyvfw2jw071: [['6ad3ccaabd5', 'ff8b4b57f65']],
836
+ ablhoqw51gb: [['21b422021b8']],
837
+ },
838
+ {
839
+ vyvfw2jw071: [24],
840
+ ablhoqw51gb: [24],
841
+ },
842
+ ['vyvfw2jw071', 'ablhoqw51gb'],
843
+ );
844
+ layout.layout = normalizeGridLayout({
845
+ rows: layout.rows,
846
+ sizes: layout.sizes,
847
+ rowOrder: layout.rowOrder,
848
+ itemUids: ['6ad3ccaabd5', 'ff8b4b57f65', '21b422021b8'],
849
+ });
850
+
851
+ const slot: LayoutSlot = {
852
+ type: 'column',
853
+ rowId: 'll5vo5pzj3u',
854
+ columnIndex: 0,
855
+ insertIndex: 1,
856
+ position: 'after',
857
+ path: [
858
+ { rowId: 'vyvfw2jw071', cellId: 'vyvfw2jw071:cell:0' },
859
+ { rowId: 'll5vo5pzj3u', cellId: 'ghy612j5zzg' },
860
+ ],
861
+ rect,
862
+ };
863
+
864
+ const result = simulateLayoutForSlot({ slot, sourceUid: 'ff8b4b57f65', layout });
865
+
866
+ expect(result.layout!.rows).toMatchObject([
867
+ {
868
+ id: 'vyvfw2jw071',
869
+ cells: [{ items: ['6ad3ccaabd5', 'ff8b4b57f65'] }],
870
+ },
871
+ {
872
+ id: 'ablhoqw51gb',
873
+ cells: [{ items: ['21b422021b8'] }],
874
+ },
875
+ ]);
876
+ });
877
+
832
878
  it('treats dragging an item to its own item-edge as no-op', () => {
833
879
  const layout = createLayout(
834
880
  {
@@ -1146,6 +1146,21 @@ const findCellByPath = (layout: GridLayoutV2, path?: GridLayoutPath) => {
1146
1146
  return null;
1147
1147
  };
1148
1148
 
1149
+ const findCellByPathOrClosestAncestor = (layout: GridLayoutV2, path?: GridLayoutPath) => {
1150
+ if (!path?.length) {
1151
+ return null;
1152
+ }
1153
+
1154
+ for (let length = path.length; length > 0; length -= 1) {
1155
+ const target = findCellByPath(layout, path.slice(0, length));
1156
+ if (target) {
1157
+ return target;
1158
+ }
1159
+ }
1160
+
1161
+ return null;
1162
+ };
1163
+
1149
1164
  const removeItemFromGridLayout = (layout: GridLayoutV2, sourceUid: string) => {
1150
1165
  const removeFromRows = (rows: GridRowV2[]): GridRowV2[] =>
1151
1166
  rows
@@ -1231,7 +1246,7 @@ const simulateGridLayoutForSlot = ({
1231
1246
 
1232
1247
  switch (slot.type) {
1233
1248
  case 'column': {
1234
- const target = findCellByPath(cloned, targetPath);
1249
+ const target = findCellByPathOrClosestAncestor(cloned, targetPath);
1235
1250
  if (!target) {
1236
1251
  break;
1237
1252
  }
@@ -1247,7 +1262,7 @@ const simulateGridLayoutForSlot = ({
1247
1262
  break;
1248
1263
  }
1249
1264
  case 'empty-column': {
1250
- const target = findCellByPath(cloned, targetPath);
1265
+ const target = findCellByPathOrClosestAncestor(cloned, targetPath);
1251
1266
  if (target) {
1252
1267
  delete target.cell.rows;
1253
1268
  target.cell.items = [sourceUid];
@@ -1255,7 +1270,7 @@ const simulateGridLayoutForSlot = ({
1255
1270
  break;
1256
1271
  }
1257
1272
  case 'column-edge': {
1258
- const target = findCellByPath(cloned, targetPath);
1273
+ const target = findCellByPathOrClosestAncestor(cloned, targetPath);
1259
1274
  if (!target) {
1260
1275
  break;
1261
1276
  }
@@ -1282,7 +1297,7 @@ const simulateGridLayoutForSlot = ({
1282
1297
  if (!targetItemUid) {
1283
1298
  break;
1284
1299
  }
1285
- const target = findCellByPath(cloned, targetPath);
1300
+ const target = findCellByPathOrClosestAncestor(cloned, targetPath);
1286
1301
  if (!target?.cell.items) {
1287
1302
  break;
1288
1303
  }
@@ -7,8 +7,8 @@
7
7
  * For more information, please refer to: https://www.nocobase.com/agreement.
8
8
  */
9
9
 
10
- import { describe, expect, it } from 'vitest';
11
- import { DataSource, DataSourceManager, isFieldInterfaceMatch } from '../index';
10
+ import { describe, expect, it, vi } from 'vitest';
11
+ import { DataSource, DataSourceManager, getCollectionFieldInterface, isFieldInterfaceMatch } from '../index';
12
12
  import { FlowEngine } from '../../flowEngine';
13
13
 
14
14
  describe('Collection/Field helpers', () => {
@@ -55,4 +55,43 @@ describe('Collection/Field helpers', () => {
55
55
  const field = posts.getFieldByPath('category.name');
56
56
  expect(field?.name).toBe('name');
57
57
  });
58
+
59
+ it('resolves collection field interfaces from the first available manager', () => {
60
+ const first = { collectionFieldInterfaceManager: { getFieldInterface: vi.fn((name) => ({ name })) } };
61
+ const second = { collectionFieldInterfaceManager: { getFieldInterface: vi.fn((name) => ({ name })) } };
62
+
63
+ expect(getCollectionFieldInterface('input', {}, first, second)).toEqual({ name: 'input' });
64
+ expect(first.collectionFieldInterfaceManager.getFieldInterface).toHaveBeenCalledWith('input');
65
+ expect(second.collectionFieldInterfaceManager.getFieldInterface).not.toHaveBeenCalled();
66
+ expect(getCollectionFieldInterface(undefined, first)).toBeUndefined();
67
+ expect(getCollectionFieldInterface('input', {})).toBeUndefined();
68
+ });
69
+
70
+ it('uses collection field interface resolver from getInterfaceOptions', () => {
71
+ const { ds, m } = setup();
72
+ const ctx = m.flowEngine.context;
73
+ const getOwnerFieldInterface = vi.fn((name: string) => ({ name, source: 'owner' }));
74
+ const getLegacyFieldInterface = vi.fn((name: string) => ({ name, source: 'legacy' }));
75
+
76
+ ctx.defineProperty('app', {
77
+ value: {
78
+ dataSourceManager: {
79
+ collectionFieldInterfaceManager: {
80
+ getFieldInterface: getLegacyFieldInterface,
81
+ },
82
+ },
83
+ },
84
+ });
85
+ ds.addCollection({
86
+ name: 'posts',
87
+ fields: [{ name: 'title', type: 'string', interface: 'input' }],
88
+ });
89
+
90
+ const field = ds.getCollection('posts')!.getField('title')!;
91
+ expect(field.getInterfaceOptions()).toEqual({ name: 'input', source: 'legacy' });
92
+
93
+ m.setCollectionFieldInterfaceManager({ getFieldInterface: getOwnerFieldInterface });
94
+ expect(field.getInterfaceOptions()).toEqual({ name: 'input', source: 'owner' });
95
+ expect(getLegacyFieldInterface).toHaveBeenCalledTimes(1);
96
+ });
58
97
  });
@@ -80,6 +80,40 @@ describe('DataSource & Collection APIs', () => {
80
80
  ).toThrow(/circular/);
81
81
  });
82
82
 
83
+ it('translates validation messages from data-source-main in component rules', async () => {
84
+ const { m, engine } = makeManager();
85
+ engine.context.i18n = {
86
+ t: (key: string, options?: Record<string, any>) => {
87
+ if (key === 'string.length' && options?.ns === 'data-source-main') {
88
+ return `${options.label} 长度必须为 ${options.limit} 个字符`;
89
+ }
90
+ return key;
91
+ },
92
+ } as any;
93
+
94
+ const ds = new DataSource({ key: 'main' });
95
+ m.addDataSource(ds);
96
+ ds.addCollection({
97
+ name: 'posts',
98
+ fields: [
99
+ {
100
+ name: 'title',
101
+ type: 'string',
102
+ interface: 'text',
103
+ title: '单行文本',
104
+ validation: {
105
+ type: 'string',
106
+ rules: [{ name: 'length', args: { limit: 18 } }],
107
+ },
108
+ },
109
+ ],
110
+ });
111
+
112
+ const rules = ds.getCollection('posts')!.getField('title')!.getComponentProps().rules;
113
+
114
+ await expect(rules[0].validator({}, '123')).rejects.toBe('单行文本 长度必须为 18 个字符');
115
+ });
116
+
83
117
  it('ensureLoaded, reload and data source events work for main loader', async () => {
84
118
  const { m, engine } = makeManager();
85
119
  const loadedListener = vi.fn();
@@ -295,6 +295,29 @@ export class DataSourceManager {
295
295
  }
296
296
  }
297
297
 
298
+ export type CollectionFieldInterfaceDataSourceManager = Pick<DataSourceManager, 'collectionFieldInterfaceManager'>;
299
+
300
+ export function getCollectionFieldInterface(
301
+ interfaceName: string | undefined,
302
+ ...dataSourceManagers: Array<CollectionFieldInterfaceDataSourceManager | null | undefined>
303
+ ) {
304
+ if (!interfaceName) {
305
+ return undefined;
306
+ }
307
+
308
+ // TODO: Once legacy client is removed and all runtimes share the client-v2 flow-engine
309
+ // DataSourceManager, callers should only pass the flow-engine context DataSourceManager.
310
+ for (const dataSourceManager of dataSourceManagers) {
311
+ const collectionFieldInterfaceManager = dataSourceManager?.collectionFieldInterfaceManager;
312
+ const getFieldInterface = collectionFieldInterfaceManager?.getFieldInterface;
313
+ if (typeof getFieldInterface === 'function') {
314
+ return getFieldInterface.call(collectionFieldInterfaceManager, interfaceName);
315
+ }
316
+ }
317
+
318
+ return undefined;
319
+ }
320
+
298
321
  export class DataSource {
299
322
  dataSourceManager: DataSourceManager;
300
323
  collectionManager: CollectionManager;
@@ -1112,7 +1135,21 @@ export class CollectionField {
1112
1135
  });
1113
1136
 
1114
1137
  if (error) {
1115
- const message = error.details.map((d: any) => d.message.replace(/"value"/g, `"${label}"`)).join(', ');
1138
+ const message = error.details
1139
+ .map((d: any) => {
1140
+ const translated = this.flowEngine.translate(d.type, {
1141
+ ...d.context,
1142
+ ns: 'data-source-main',
1143
+ label,
1144
+ });
1145
+
1146
+ if (translated && translated !== d.type) {
1147
+ return translated;
1148
+ }
1149
+
1150
+ return d.message.replace(/"value"/g, `"${label}"`);
1151
+ })
1152
+ .join(', ');
1116
1153
  return Promise.reject(message);
1117
1154
  }
1118
1155
 
@@ -1135,8 +1172,13 @@ export class CollectionField {
1135
1172
  }
1136
1173
 
1137
1174
  getInterfaceOptions() {
1138
- const app = this.flowEngine.context.app;
1139
- return app.dataSourceManager.collectionFieldInterfaceManager.getFieldInterface(this.interface);
1175
+ const ctx = this.flowEngine.context;
1176
+ return getCollectionFieldInterface(
1177
+ this.interface,
1178
+ this.collection?.dataSource?.dataSourceManager,
1179
+ ctx.dataSourceManager,
1180
+ ctx.app?.dataSourceManager,
1181
+ );
1140
1182
  }
1141
1183
 
1142
1184
  getFilterOperators() {