@nocobase/client-v2 2.3.0-alpha.1 → 2.3.0-beta.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/es/APIClient.d.ts +12 -0
- package/es/components/form/ScanInput/useCodeScanner.d.ts +12 -2
- package/es/components/form/ScanInput/zxingWasmDecoder.d.ts +9 -0
- package/es/flow/actions/linkageRules.d.ts +25 -0
- package/es/flow/components/FieldAssignValueInput.d.ts +6 -30
- package/es/flow/components/FlowRoute.d.ts +2 -2
- package/es/flow/components/field-value-variable/DateVariableEditor.d.ts +24 -0
- package/es/flow/components/field-value-variable/FieldValueVariableInput.d.ts +32 -0
- package/es/flow/components/field-value-variable/dateValue.d.ts +36 -0
- package/es/flow/components/field-value-variable/index.d.ts +11 -0
- package/es/flow/components/filter/VariableFilterItem.d.ts +7 -0
- package/es/flow/components/placeholders/BlockPlaceholder.d.ts +1 -0
- package/es/flow/internal/registerDeviceTypeContext.d.ts +10 -0
- package/es/flow/internal/utils/operatorSchemaHelper.d.ts +2 -2
- package/es/flow/models/actions/UpdateRecordActionUtils.d.ts +8 -2
- package/es/flow/models/base/ActionModelCore.d.ts +4 -2
- package/es/flow/models/base/BlockGridModel.d.ts +3 -0
- package/es/flow/models/base/CollectionBlockModel.d.ts +3 -0
- package/es/flow/models/blocks/details/DetailsBlockModel.d.ts +3 -0
- package/es/flow/models/blocks/filter-form/FilterFormGridModel.d.ts +1 -0
- package/es/flow/models/blocks/filter-form/FilterFormSubmitActionModel.d.ts +3 -1
- package/es/flow/models/blocks/form/FormBlockModel.d.ts +7 -0
- package/es/flow/models/blocks/form/FormGridModel.d.ts +6 -0
- package/es/flow/models/blocks/form/value-runtime/rules.d.ts +1 -0
- package/es/flow/models/blocks/table/JSColumnModel.d.ts +2 -0
- package/es/flow/models/blocks/table/TableBlockModel.d.ts +1 -0
- package/es/flow/models/blocks/table/TableColumnModel.d.ts +12 -0
- package/es/flow/models/blocks/table/utils.d.ts +1 -0
- package/es/flow/models/fields/AssociationFieldModel/RecordPickerFieldModel.d.ts +2 -1
- package/es/flow/models/fields/AssociationFieldModel/RecordSelectFieldModel.d.ts +0 -17
- package/es/flow/models/fields/AssociationFieldModel/recordSelectShared.d.ts +41 -0
- package/es/flow/models/fields/DateTimeFieldModel/dateLimit.d.ts +15 -7
- package/es/flow-compat/passwordUtils.d.ts +1 -1
- package/es/index.d.ts +1 -0
- package/es/index.mjs +148 -145
- package/es/ui-operation/index.d.ts +15 -0
- package/es/ui-operation/ui-operation-codec.d.ts +10 -0
- package/lib/index.js +170 -167
- package/lib/locale/languageCodes.js +1 -0
- package/package.json +10 -8
- package/src/APIClient.ts +92 -0
- package/src/Application.tsx +3 -1
- package/src/__tests__/APIClient.test.tsx +58 -0
- package/src/__tests__/nocobase-buildin-plugin-auth.test.tsx +7 -2
- package/src/__tests__/settings-center.test.tsx +270 -6
- package/src/acl/ACLProvider.tsx +2 -0
- package/src/acl/__tests__/ACLProvider.test.tsx +92 -0
- package/src/collection-manager/__tests__/field-configure.test.ts +52 -0
- package/src/collection-manager/field-configure.ts +2 -2
- package/src/components/form/ScanInput/CodeScanner.tsx +64 -35
- package/src/components/form/ScanInput/__tests__/CodeScanner.test.tsx +107 -0
- package/src/components/form/ScanInput/__tests__/useCodeScanner.test.tsx +294 -24
- package/src/components/form/ScanInput/__tests__/zxingWasmDecoder.test.ts +78 -0
- package/src/components/form/ScanInput/useCodeScanner.ts +281 -23
- package/src/components/form/ScanInput/zxingWasmDecoder.ts +64 -0
- package/src/components/form/filter/CollectionFilterItem.tsx +4 -2
- package/src/components/form/filter/__tests__/CollectionFilterItem.test.tsx +17 -0
- package/src/components/form/table/Table.tsx +81 -6
- package/src/components/form/table/__tests__/Table.columnWidth.test.tsx +433 -0
- package/src/flow/__tests__/FlowRoute.test.tsx +126 -8
- package/src/flow/__tests__/PluginFlowEngine.test.ts +58 -0
- package/src/flow/actions/__tests__/actionLinkageRules.forkProps.test.ts +314 -0
- package/src/flow/actions/__tests__/dataScopeFormValueClear.test.ts +102 -0
- package/src/flow/actions/__tests__/linkageRules.actionStates.test.ts +33 -0
- package/src/flow/actions/__tests__/linkageRules.subFormSetFieldProps.test.ts +72 -0
- package/src/flow/actions/__tests__/validation.test.ts +48 -0
- package/src/flow/actions/linkageRules.tsx +59 -16
- package/src/flow/admin-shell/admin-layout/AdminLayoutMenuUtils.tsx +78 -59
- package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutMenuModels.test.ts +228 -0
- package/src/flow/admin-shell/admin-layout/__tests__/TopbarActionsBar.test.tsx +42 -23
- package/src/flow/common/Markdown/style.ts +4 -0
- package/src/flow/components/BlockItemCard.tsx +2 -2
- package/src/flow/components/FieldAssignValueInput.tsx +42 -621
- package/src/flow/components/FlowRoute.tsx +71 -29
- package/src/flow/components/field-value-variable/DateVariableEditor.tsx +181 -0
- package/src/flow/components/field-value-variable/FieldValueVariableInput.tsx +335 -0
- package/src/flow/components/field-value-variable/__tests__/FieldValueVariableInput.test.tsx +389 -0
- package/src/flow/components/field-value-variable/dateValue.ts +223 -0
- package/src/flow/components/field-value-variable/index.ts +12 -0
- package/src/flow/components/filter/VariableFilterItem.tsx +23 -6
- package/src/flow/components/filter/__tests__/VariableFilterItem.rightMetaTree.test.tsx +158 -0
- package/src/flow/components/filter/__tests__/VariableFilterItem.test.tsx +125 -0
- package/src/flow/components/placeholders/BlockPlaceholder.tsx +70 -23
- package/src/flow/components/placeholders/__tests__/BlockPlaceholder.test.tsx +57 -7
- package/src/flow/index.ts +2 -0
- package/src/flow/internal/components/Markdown/DisplayMarkdown.tsx +14 -9
- package/src/flow/internal/components/Markdown/__tests__/DisplayMarkdown.test.tsx +46 -0
- package/src/flow/internal/registerDeviceTypeContext.ts +39 -0
- package/src/flow/internal/utils/operatorSchemaHelper.ts +3 -2
- package/src/flow/models/actions/UpdateRecordActionModel.tsx +18 -1
- package/src/flow/models/actions/UpdateRecordActionUtils.ts +18 -6
- package/src/flow/models/actions/__tests__/UpdateRecordActionModel.test.ts +76 -4
- package/src/flow/models/base/ActionModelCore.tsx +11 -2
- package/src/flow/models/base/BlockGridModel.tsx +26 -0
- package/src/flow/models/base/CollectionBlockModel.tsx +38 -3
- package/src/flow/models/base/GridModel.tsx +0 -1
- package/src/flow/models/base/PageModel/PageTabModel.tsx +67 -17
- package/src/flow/models/base/PageModel/__tests__/PageTabModel.test.ts +509 -12
- package/src/flow/models/base/__tests__/ActionModelCore.render.test.tsx +49 -0
- package/src/flow/models/base/__tests__/BlockGridModel.selectSceneActivation.test.ts +124 -0
- package/src/flow/models/base/__tests__/CollectionBlockModel.addAppends.test.ts +41 -0
- package/src/flow/models/base/__tests__/CollectionBlockModel.initialBeforeRenderRefresh.test.ts +125 -9
- package/src/flow/models/blocks/assign-form/AssignFormGridModel.tsx +22 -1
- package/src/flow/models/blocks/assign-form/AssignFormItemModel.tsx +36 -50
- package/src/flow/models/blocks/assign-form/__tests__/assignFieldValuesFlow.editor.test.tsx +140 -0
- package/src/flow/models/blocks/details/DetailsBlockModel.tsx +8 -3
- package/src/flow/models/blocks/details/__tests__/DetailsBlockModel.initialPaginationChangeRefresh.test.ts +32 -1
- package/src/flow/models/blocks/filter-form/FilterFormBlockModel.tsx +27 -3
- package/src/flow/models/blocks/filter-form/FilterFormGridModel.tsx +36 -5
- package/src/flow/models/blocks/filter-form/FilterFormItemModel.tsx +129 -14
- package/src/flow/models/blocks/filter-form/FilterFormSubmitActionModel.tsx +57 -4
- package/src/flow/models/blocks/filter-form/__tests__/FilterFormGridModel.onModelCreated.test.ts +174 -1
- package/src/flow/models/blocks/filter-form/__tests__/FilterFormGridModel.toggleFormFieldsCollapse.test.ts +29 -0
- package/src/flow/models/blocks/filter-form/__tests__/FilterFormItemModel.defineChildren.test.ts +359 -1
- package/src/flow/models/blocks/filter-form/__tests__/FilterFormItemModel.getFilterValue.test.ts +72 -0
- package/src/flow/models/blocks/filter-form/__tests__/FilterFormSubmitActionModel.lifecycle.test.ts +90 -0
- package/src/flow/models/blocks/filter-form/__tests__/defaultValues.wiring.test.ts +32 -4
- package/src/flow/models/blocks/filter-form/fields/FieldComponentProps.tsx +1 -1
- package/src/flow/models/blocks/filter-form/fields/__tests__/FieldComponentProps.options.test.tsx +61 -0
- package/src/flow/models/blocks/filter-manager/FilterManager.ts +5 -0
- package/src/flow/models/blocks/filter-manager/__tests__/FilterManager.test.ts +40 -0
- package/src/flow/models/blocks/form/FormBlockModel.tsx +73 -5
- package/src/flow/models/blocks/form/FormGridModel.tsx +4 -0
- package/src/flow/models/blocks/form/__tests__/FormBlockModel.test.tsx +153 -2
- package/src/flow/models/blocks/form/__tests__/popupLinkage.test.tsx +175 -0
- package/src/flow/models/blocks/form/__tests__/runJsFormSubmit.test.ts +131 -0
- package/src/flow/models/blocks/form/value-runtime/__tests__/runtime.test.ts +435 -0
- package/src/flow/models/blocks/form/value-runtime/rules.ts +67 -14
- package/src/flow/models/blocks/form/value-runtime/runtime.ts +43 -19
- package/src/flow/models/blocks/js-block/JSBlock.tsx +1 -1
- package/src/flow/models/blocks/table/JSColumnModel.tsx +10 -1
- package/src/flow/models/blocks/table/TableBlockModel.tsx +28 -2
- package/src/flow/models/blocks/table/TableColumnModel.tsx +48 -9
- package/src/flow/models/blocks/table/__tests__/JSColumnModel.test.tsx +52 -5
- package/src/flow/models/blocks/table/__tests__/TableBlockModel.filterReset.test.ts +78 -0
- package/src/flow/models/blocks/table/__tests__/TableBlockModel.quickEditRefresh.test.ts +12 -0
- package/src/flow/models/blocks/table/__tests__/TableColumnModel.test.tsx +33 -0
- package/src/flow/models/blocks/table/utils.ts +7 -0
- package/src/flow/models/fields/AssociationFieldModel/CascadeSelectFieldModel.tsx +33 -1
- package/src/flow/models/fields/AssociationFieldModel/PopupSubTableFieldModel/PopupSubTableFieldModel.tsx +12 -3
- package/src/flow/models/fields/AssociationFieldModel/PopupSubTableFieldModel/__tests__/popupContext.test.ts +120 -0
- package/src/flow/models/fields/AssociationFieldModel/PopupSubTableFieldModel/actions/PopupSubTableEditActionModel.tsx +10 -2
- package/src/flow/models/fields/AssociationFieldModel/RecordPickerFieldModel.tsx +29 -3
- package/src/flow/models/fields/AssociationFieldModel/RecordSelectFieldModel.tsx +9 -136
- package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/SubTableField.tsx +5 -1
- package/src/flow/models/fields/AssociationFieldModel/__tests__/RecordPickerFieldModel.itemContext.test.ts +191 -3
- package/src/flow/models/fields/AssociationFieldModel/recordSelectShared.tsx +156 -0
- package/src/flow/models/fields/DateTimeFieldModel/__tests__/DateTimeNoTzFieldModel.dateLimit.test.tsx +149 -0
- package/src/flow/models/fields/DateTimeFieldModel/dateLimit.ts +149 -113
- package/src/flow/models/fields/DisplayAssociationField/DisplaySubTableFieldModel.tsx +42 -7
- package/src/flow/models/fields/DisplayAssociationField/__tests__/DisplaySubTableFieldModel.test.tsx +351 -0
- package/src/flow/models/fields/DisplayHtmlFieldModel.tsx +2 -1
- package/src/flow/models/fields/DisplayNumberFieldModel.tsx +1 -1
- package/src/flow/models/fields/JsonFieldModel.tsx +31 -8
- package/src/flow/models/fields/NumberFieldModel.tsx +1 -1
- package/src/flow/models/fields/RichTextFieldModel/__tests__/RichTextFieldModel.test.tsx +74 -0
- package/src/flow/models/fields/RichTextFieldModel/index.tsx +27 -6
- package/src/flow/models/fields/__tests__/DisplayNumberFieldModel.test.ts +33 -0
- package/src/flow/models/fields/__tests__/JsonFieldModel.test.ts +82 -0
- package/src/flow/models/fields/__tests__/NumberFieldModel.test.tsx +47 -0
- package/src/flow/models/fields/mobile-components/MobileLazySelect.tsx +6 -0
- package/src/flow/models/fields/mobile-components/MobileSelect.tsx +27 -2
- package/src/flow/models/fields/mobile-components/__tests__/MobileSelect.test.tsx +139 -13
- package/src/flow/models/topbar/TopbarActionModel.tsx +5 -5
- package/src/flow/utils/dataScopeFormValueClear.ts +4 -3
- package/src/index.ts +1 -0
- package/src/layout-manager/LayoutContentRoute.tsx +2 -1
- package/src/layout-manager/LayoutRoute.tsx +2 -1
- package/src/layout-manager/__tests__/LayoutRoute.test.tsx +87 -1
- package/src/locale/languageCodes.ts +1 -0
- package/src/settings-center/AdminSettingsLayout.tsx +23 -2
- package/src/ui-operation/index.ts +33 -0
- package/src/ui-operation/ui-operation-codec.ts +54 -0
|
@@ -86,6 +86,10 @@ export class FormValueRuntime {
|
|
|
86
86
|
|
|
87
87
|
this.ruleEngine = new RuleEngine({
|
|
88
88
|
getBlockModelUid: () => String(this.model?.uid),
|
|
89
|
+
getAssignRulesModelUid: () => {
|
|
90
|
+
const grid = this.model?.subModels?.grid;
|
|
91
|
+
return !Array.isArray(grid) && grid?.uid ? String(grid.uid) : undefined;
|
|
92
|
+
},
|
|
89
93
|
getActionName: () => this.model?.getAclActionName?.() ?? this.model?.context?.actionName,
|
|
90
94
|
getBlockContext: () => this.model?.context,
|
|
91
95
|
getEngine: () => this.model?.context?.engine,
|
|
@@ -190,13 +194,32 @@ export class FormValueRuntime {
|
|
|
190
194
|
return values;
|
|
191
195
|
}
|
|
192
196
|
|
|
193
|
-
private toMirrorSnapshot(value:
|
|
194
|
-
const
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
197
|
+
private toMirrorSnapshot<T>(value: T): T {
|
|
198
|
+
const cloneValue = (input: unknown): unknown =>
|
|
199
|
+
_.cloneDeepWith(input, (item: unknown) => {
|
|
200
|
+
if (isObservable(item)) {
|
|
201
|
+
const plainItem = toJS(item);
|
|
202
|
+
if (plainItem !== item) return cloneValue(plainItem);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
// Tracking form-value array proxies hide `constructor`, while Lodash's array
|
|
206
|
+
// clone relies on it being callable.
|
|
207
|
+
if (Array.isArray(item) && typeof item.constructor !== 'function') {
|
|
208
|
+
const plainArray = new Array(item.length);
|
|
209
|
+
for (let index = 0; index < item.length; index++) {
|
|
210
|
+
if (Object.hasOwn(item, index)) {
|
|
211
|
+
plainArray[index] = cloneValue(item[index]);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
return plainArray;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
if (!item || typeof item !== 'object') return undefined;
|
|
218
|
+
if (Array.isArray(item) || _.isPlainObject(item)) return undefined;
|
|
219
|
+
return item;
|
|
220
|
+
});
|
|
221
|
+
|
|
222
|
+
return cloneValue(value) as T;
|
|
200
223
|
}
|
|
201
224
|
|
|
202
225
|
canApplyDefaultValuePatch(namePath: NamePath, resolved: any) {
|
|
@@ -940,11 +963,12 @@ export class FormValueRuntime {
|
|
|
940
963
|
const changedPaths: NamePath[] = [];
|
|
941
964
|
|
|
942
965
|
if (!Array.isArray(patch)) {
|
|
943
|
-
const patchEntries = Object.entries(patch || {})
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
966
|
+
const patchEntries = Object.entries(patch || {})
|
|
967
|
+
.map(([pathKey, rawValue]) => [pathKey, this.toMirrorSnapshot(rawValue)] as const)
|
|
968
|
+
.filter(([pathKey, value]) => {
|
|
969
|
+
if (shouldSkipByLinkageScope(pathKey)) return false;
|
|
970
|
+
return !_.isEqual(this.getFormValueAtPath([pathKey]), value);
|
|
971
|
+
});
|
|
948
972
|
const patchToApply = Object.fromEntries(patchEntries);
|
|
949
973
|
const patchKeys = patchEntries.map(([pathKey]) => pathKey);
|
|
950
974
|
if (!patchKeys.length) {
|
|
@@ -955,8 +979,7 @@ export class FormValueRuntime {
|
|
|
955
979
|
}
|
|
956
980
|
this.suppressFormCallbackDepth++;
|
|
957
981
|
try {
|
|
958
|
-
for (const [pathKey,
|
|
959
|
-
const value = isObservable(rawValue) ? toJS(rawValue) : rawValue;
|
|
982
|
+
for (const [pathKey, value] of patchEntries) {
|
|
960
983
|
if (typeof form.setFieldValue === 'function') {
|
|
961
984
|
form.setFieldValue(pathKey, value);
|
|
962
985
|
} else if (typeof (form as any).setFields === 'function') {
|
|
@@ -1017,7 +1040,7 @@ export class FormValueRuntime {
|
|
|
1017
1040
|
const namePath = this.resolveNamePath(callerCtx, item.path);
|
|
1018
1041
|
const pathKey = namePathToPathKey(namePath);
|
|
1019
1042
|
const rawValue = item.value;
|
|
1020
|
-
const value =
|
|
1043
|
+
const value = this.toMirrorSnapshot(rawValue);
|
|
1021
1044
|
|
|
1022
1045
|
if (shouldSkipByLinkageScope(pathKey)) continue;
|
|
1023
1046
|
|
|
@@ -1156,17 +1179,18 @@ export class FormValueRuntime {
|
|
|
1156
1179
|
if (!form) return;
|
|
1157
1180
|
if (source === 'override' && this.findUserEditedHit(pathKey)) return;
|
|
1158
1181
|
|
|
1182
|
+
const value = this.toMirrorSnapshot(nextValue);
|
|
1159
1183
|
const prevValue = _.get(this.valuesMirror, namePath);
|
|
1160
|
-
if (_.isEqual(prevValue,
|
|
1184
|
+
if (_.isEqual(prevValue, value)) return;
|
|
1161
1185
|
|
|
1162
1186
|
this.writeSeq += 1;
|
|
1163
1187
|
const writeSeq = this.writeSeq;
|
|
1164
1188
|
|
|
1165
1189
|
this.suppressFormCallbackDepth++;
|
|
1166
1190
|
try {
|
|
1167
|
-
form.setFieldValue?.(namePath,
|
|
1168
|
-
_.set(this.valuesMirror, namePath, this.toMirrorSnapshot(
|
|
1169
|
-
this.syncMountedFieldModelValue(namePath,
|
|
1191
|
+
form.setFieldValue?.(namePath, value);
|
|
1192
|
+
_.set(this.valuesMirror, namePath, this.toMirrorSnapshot(value));
|
|
1193
|
+
this.syncMountedFieldModelValue(namePath, value);
|
|
1170
1194
|
this.bumpChangeTick();
|
|
1171
1195
|
} finally {
|
|
1172
1196
|
this.suppressFormCallbackDepth--;
|
|
@@ -235,7 +235,7 @@ export class JSBlockModel extends BlockModel {
|
|
|
235
235
|
const cardProps = {
|
|
236
236
|
...rest,
|
|
237
237
|
height,
|
|
238
|
-
style,
|
|
238
|
+
...(style === undefined ? {} : { style }),
|
|
239
239
|
...(beforeContent === undefined ? {} : { beforeContent }),
|
|
240
240
|
...(afterContent === undefined ? {} : { afterContent }),
|
|
241
241
|
};
|
|
@@ -9,13 +9,14 @@
|
|
|
9
9
|
|
|
10
10
|
import { LockOutlined, QuestionCircleOutlined } from '@ant-design/icons';
|
|
11
11
|
import { css } from '@emotion/css';
|
|
12
|
-
import type { PropertyMetaFactory } from '@nocobase/flow-engine';
|
|
12
|
+
import type { FlowModelOptions, PropertyMetaFactory } from '@nocobase/flow-engine';
|
|
13
13
|
import {
|
|
14
14
|
Droppable,
|
|
15
15
|
tExpr,
|
|
16
16
|
FlowsFloatContextMenu,
|
|
17
17
|
DragHandler,
|
|
18
18
|
MemoFlowModelRenderer,
|
|
19
|
+
createCurrentRecordMetaFactory,
|
|
19
20
|
createRecordMetaFactory,
|
|
20
21
|
createRecordResolveOnServerWithLocal,
|
|
21
22
|
ElementProxy,
|
|
@@ -51,6 +52,14 @@ function getRecordRenderSignature(record: any) {
|
|
|
51
52
|
export class JSColumnModel extends TableCustomColumnModel {
|
|
52
53
|
// Stable per‑instance render component to avoid remounts across re-renders
|
|
53
54
|
private _RenderComponent?: React.ComponentType;
|
|
55
|
+
|
|
56
|
+
onInit(options: FlowModelOptions): void {
|
|
57
|
+
super.onInit(options);
|
|
58
|
+
this.context.defineProperty('record', {
|
|
59
|
+
meta: createCurrentRecordMetaFactory(this.context, () => this.context.collection),
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
|
|
54
63
|
renderHiddenInConfig() {
|
|
55
64
|
return (
|
|
56
65
|
<Tooltip
|
|
@@ -36,7 +36,15 @@ import { BlockSceneEnum } from '../../base/BlockModel';
|
|
|
36
36
|
import { CollectionBlockModel } from '../../base/CollectionBlockModel';
|
|
37
37
|
import { QuickEditFormModel } from '../form/QuickEditFormModel';
|
|
38
38
|
import { TableColumnModel } from './TableColumnModel';
|
|
39
|
-
import {
|
|
39
|
+
import {
|
|
40
|
+
extractIndex,
|
|
41
|
+
adjustColumnOrder,
|
|
42
|
+
setNestedValue,
|
|
43
|
+
extractIds,
|
|
44
|
+
extractRowKeys,
|
|
45
|
+
getRowKey,
|
|
46
|
+
useBlockHeight,
|
|
47
|
+
} from './utils';
|
|
40
48
|
import { resolveTableSorterField } from './sortUtils';
|
|
41
49
|
import { commonConditionHandler, ConditionBuilder } from '../../../components/ConditionBuilder';
|
|
42
50
|
import { BulkDeleteActionModel } from '../../actions/BulkDeleteActionModel';
|
|
@@ -222,6 +230,22 @@ export class TableBlockModel extends CollectionBlockModel<TableBlockModelStructu
|
|
|
222
230
|
return super.resource as MultiRecordResource;
|
|
223
231
|
}
|
|
224
232
|
|
|
233
|
+
resetAfterFilterChange() {
|
|
234
|
+
if (!this.props.treeTable) {
|
|
235
|
+
return;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
const expandAll = !!this.props.defaultExpandAllRows;
|
|
239
|
+
const expandedRowKeys = expandAll ? extractRowKeys(this.resource.getData(), this.collection.filterTargetKey) : [];
|
|
240
|
+
|
|
241
|
+
this.setProps('expandedRowKeys', expandedRowKeys);
|
|
242
|
+
this.mapSubModels('actions', (action) => {
|
|
243
|
+
if ('setExpandFlag' in action && typeof action.setExpandFlag === 'function') {
|
|
244
|
+
action.setExpandFlag(expandAll);
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
}
|
|
248
|
+
|
|
225
249
|
private readonly columns = observable.ref([]);
|
|
226
250
|
private disposeAutorun: () => void;
|
|
227
251
|
|
|
@@ -244,7 +268,9 @@ export class TableBlockModel extends CollectionBlockModel<TableBlockModelStructu
|
|
|
244
268
|
}
|
|
245
269
|
|
|
246
270
|
createResource(ctx, params) {
|
|
247
|
-
|
|
271
|
+
const resource = this.context.createResource(MultiRecordResource);
|
|
272
|
+
resource.addRequestHeader('X-With-ACL-Meta', 'true');
|
|
273
|
+
return resource;
|
|
248
274
|
}
|
|
249
275
|
|
|
250
276
|
/**
|
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
ModelRenderMode,
|
|
28
28
|
useFlowModel,
|
|
29
29
|
} from '@nocobase/flow-engine';
|
|
30
|
+
import type { FlowModel } from '@nocobase/flow-engine';
|
|
30
31
|
import { useTranslation } from 'react-i18next';
|
|
31
32
|
import { TableColumnProps, Tooltip, Space, InputNumber, Button, Divider } from 'antd';
|
|
32
33
|
import { get, omit, capitalize } from 'lodash';
|
|
@@ -61,19 +62,28 @@ export function FieldDeletePlaceholder(props: any) {
|
|
|
61
62
|
);
|
|
62
63
|
}
|
|
63
64
|
|
|
64
|
-
|
|
65
|
+
type FieldPermissionPlaceholderModel = FlowModel & {
|
|
66
|
+
fieldPath?: string;
|
|
67
|
+
forbidden?: { actionName?: string } | null;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
export function FieldWithoutPermissionPlaceholder({
|
|
71
|
+
targetModel,
|
|
72
|
+
}: {
|
|
73
|
+
targetModel?: FieldPermissionPlaceholderModel;
|
|
74
|
+
} = {}) {
|
|
65
75
|
const { t } = useTranslation();
|
|
66
|
-
const
|
|
67
|
-
const
|
|
68
|
-
const collection = model.context.collectionField?.collection || blockModel
|
|
69
|
-
const dataSource = collection
|
|
76
|
+
const contextModel = useFlowModel<FieldPermissionPlaceholderModel>();
|
|
77
|
+
const model = targetModel || contextModel;
|
|
78
|
+
const collection = model.context.collectionField?.collection || model.context.blockModel?.collection;
|
|
79
|
+
const dataSource = collection?.dataSource;
|
|
70
80
|
const name = model.context.collectionField?.name || model.fieldPath;
|
|
71
81
|
const nameValue = useMemo(() => {
|
|
72
|
-
const dataSourcePrefix = `${t(dataSource.displayName || dataSource.key)} >
|
|
82
|
+
const dataSourcePrefix = dataSource ? `${t(dataSource.displayName || dataSource.key)} > ` : '';
|
|
73
83
|
const collectionPrefix = collection ? `${t(collection.title) || collection.name || collection.tableName} > ` : '';
|
|
74
84
|
return `${dataSourcePrefix}${collectionPrefix}${name}`;
|
|
75
|
-
}, [collection, dataSource
|
|
76
|
-
const
|
|
85
|
+
}, [collection, dataSource, name, t]);
|
|
86
|
+
const actionName = model.forbidden?.actionName || 'view';
|
|
77
87
|
const messageValue = useMemo(() => {
|
|
78
88
|
return t(
|
|
79
89
|
`The current user only has the UI configuration permission, but don't have "{{actionName}}" permission for field "{{name}}"`,
|
|
@@ -194,6 +204,35 @@ export class TableColumnModel extends DisplayItemModel {
|
|
|
194
204
|
.filter(Boolean);
|
|
195
205
|
}
|
|
196
206
|
|
|
207
|
+
canQuickEdit(record: Record<string, unknown>): boolean {
|
|
208
|
+
if (!this.props.editable) {
|
|
209
|
+
return false;
|
|
210
|
+
}
|
|
211
|
+
if (this.context.skipAclCheck) {
|
|
212
|
+
return true;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const blockModel = this.context.blockModel;
|
|
216
|
+
const collection = blockModel?.collection;
|
|
217
|
+
const resource = blockModel?.resource;
|
|
218
|
+
const collectionField = this.collectionField;
|
|
219
|
+
if (!collection || !resource || !collectionField) {
|
|
220
|
+
return false;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
const filterByTk = collection.getFilterByTK(record);
|
|
224
|
+
const recordPkValue = typeof filterByTk === 'string' || typeof filterByTk === 'number' ? filterByTk : undefined;
|
|
225
|
+
|
|
226
|
+
return this.context.acl.can({
|
|
227
|
+
dataSourceKey: collection.dataSourceKey,
|
|
228
|
+
resourceName: resource.getResourceName() || collection.name,
|
|
229
|
+
actionName: 'update',
|
|
230
|
+
recordPkValue,
|
|
231
|
+
allowedActions: resource.getMeta('allowedActions'),
|
|
232
|
+
fields: [collectionField.name],
|
|
233
|
+
});
|
|
234
|
+
}
|
|
235
|
+
|
|
197
236
|
getColumnProps(): TableColumnProps & { sortField?: string } {
|
|
198
237
|
if (!this.props.width) {
|
|
199
238
|
return;
|
|
@@ -250,7 +289,7 @@ export class TableColumnModel extends DisplayItemModel {
|
|
|
250
289
|
record,
|
|
251
290
|
recordIndex: record?.__index || recordIndex,
|
|
252
291
|
width: this.props.width - 16,
|
|
253
|
-
editable: this.
|
|
292
|
+
editable: this.canQuickEdit(record),
|
|
254
293
|
dataIndex: this.props.dataIndex,
|
|
255
294
|
title: this.props.title,
|
|
256
295
|
overflowMode: this.props.overflowMode,
|
|
@@ -11,17 +11,62 @@ import { FlowEngine } from '@nocobase/flow-engine';
|
|
|
11
11
|
import { describe, expect, it, vi } from 'vitest';
|
|
12
12
|
import { JSColumnModel } from '../JSColumnModel';
|
|
13
13
|
|
|
14
|
-
describe('JSColumnModel
|
|
14
|
+
describe('JSColumnModel', () => {
|
|
15
|
+
it('declares current record metadata before rendering any row', async () => {
|
|
16
|
+
const engine = new FlowEngine();
|
|
17
|
+
engine.registerModels({ JSColumnModel });
|
|
18
|
+
const model = engine.createModel<JSColumnModel>({
|
|
19
|
+
use: 'JSColumnModel',
|
|
20
|
+
uid: 'js-column-record-meta',
|
|
21
|
+
props: {
|
|
22
|
+
width: 200,
|
|
23
|
+
title: 'JS column',
|
|
24
|
+
},
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
engine.context.dataSourceManager.getDataSource('main').addCollection({
|
|
28
|
+
name: 'users',
|
|
29
|
+
filterTargetKey: 'id',
|
|
30
|
+
fields: [
|
|
31
|
+
{ name: 'id', type: 'integer', interface: 'number' },
|
|
32
|
+
{ name: 'age', type: 'integer', interface: 'integer' },
|
|
33
|
+
],
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const collection = engine.context.dataSourceManager.getCollection('main', 'users');
|
|
37
|
+
model.context.defineProperty('collection', {
|
|
38
|
+
value: collection,
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
const recordNode = model.context.getPropertyMetaTree().find((node) => node.name === 'record');
|
|
42
|
+
const recordFields =
|
|
43
|
+
typeof recordNode?.children === 'function' ? await recordNode.children() : recordNode?.children || [];
|
|
44
|
+
|
|
45
|
+
expect(model.context.record).toBeUndefined();
|
|
46
|
+
expect(recordNode).toMatchObject({
|
|
47
|
+
name: 'record',
|
|
48
|
+
title: 'Current record',
|
|
49
|
+
paths: ['record'],
|
|
50
|
+
});
|
|
51
|
+
expect(recordFields).toEqual(
|
|
52
|
+
expect.arrayContaining([
|
|
53
|
+
expect.objectContaining({ name: 'id', paths: ['record', 'id'] }),
|
|
54
|
+
expect.objectContaining({ name: 'age', paths: ['record', 'age'] }),
|
|
55
|
+
]),
|
|
56
|
+
);
|
|
57
|
+
});
|
|
58
|
+
|
|
15
59
|
it('changes renderer key and invalidates beforeRender cache when row content changes', () => {
|
|
16
60
|
const engine = new FlowEngine();
|
|
17
|
-
|
|
61
|
+
engine.registerModels({ JSColumnModel });
|
|
62
|
+
const model = engine.createModel<JSColumnModel>({
|
|
63
|
+
use: 'JSColumnModel',
|
|
18
64
|
uid: 'js-column-row-refresh',
|
|
19
|
-
flowEngine: engine,
|
|
20
65
|
props: {
|
|
21
66
|
width: 200,
|
|
22
67
|
title: 'JS column',
|
|
23
68
|
},
|
|
24
|
-
}
|
|
69
|
+
});
|
|
25
70
|
|
|
26
71
|
engine.context.dataSourceManager.getDataSource('main').addCollection({
|
|
27
72
|
name: 'users',
|
|
@@ -39,12 +84,14 @@ describe('JSColumnModel row refresh', () => {
|
|
|
39
84
|
});
|
|
40
85
|
|
|
41
86
|
const column = model.getColumnProps();
|
|
42
|
-
const
|
|
87
|
+
const firstRecord = { id: 1, age: 3, workyears: 39.2 };
|
|
88
|
+
const first = column.render(null, firstRecord, 0) as any;
|
|
43
89
|
const fork = model.getFork('1') as any;
|
|
44
90
|
const invalidateFlowCache = vi.fn();
|
|
45
91
|
fork.invalidateFlowCache = invalidateFlowCache;
|
|
46
92
|
const second = column.render(null, { id: 1, age: 37, workyears: 39.2 }, 0) as any;
|
|
47
93
|
|
|
94
|
+
expect(fork.context.record).toEqual({ id: 1, age: 37, workyears: 39.2 });
|
|
48
95
|
expect(first.key).not.toBe(second.key);
|
|
49
96
|
expect(invalidateFlowCache).toHaveBeenCalledWith('beforeRender');
|
|
50
97
|
});
|
|
@@ -0,0 +1,78 @@
|
|
|
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, vi } from 'vitest';
|
|
11
|
+
import { TableBlockModel } from '../TableBlockModel';
|
|
12
|
+
|
|
13
|
+
describe('TableBlockModel filter reset', () => {
|
|
14
|
+
it('collapses the filtered tree when rows are not expanded by default', () => {
|
|
15
|
+
const setExpandFlag = vi.fn();
|
|
16
|
+
const setProps = vi.fn();
|
|
17
|
+
const model = {
|
|
18
|
+
props: { treeTable: true, defaultExpandAllRows: false, expandedRowKeys: [1, 2] },
|
|
19
|
+
resource: { getData: () => [{ id: 3, children: [{ id: 4 }] }] },
|
|
20
|
+
setProps,
|
|
21
|
+
mapSubModels: (_key, callback) => callback({ setExpandFlag }),
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
TableBlockModel.prototype.resetAfterFilterChange.call(model);
|
|
25
|
+
|
|
26
|
+
expect(setProps).toHaveBeenCalledWith('expandedRowKeys', []);
|
|
27
|
+
expect(setExpandFlag).toHaveBeenCalledWith(false);
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('expands the filtered tree when rows are expanded by default', () => {
|
|
31
|
+
const setExpandFlag = vi.fn();
|
|
32
|
+
const setProps = vi.fn();
|
|
33
|
+
const model = {
|
|
34
|
+
props: { treeTable: true, defaultExpandAllRows: true, expandedRowKeys: [1, 2] },
|
|
35
|
+
collection: { filterTargetKey: 'id' },
|
|
36
|
+
resource: { getData: () => [{ id: 3, children: [{ id: 4 }] }] },
|
|
37
|
+
setProps,
|
|
38
|
+
mapSubModels: (_key, callback) => callback({ setExpandFlag }),
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
TableBlockModel.prototype.resetAfterFilterChange.call(model);
|
|
42
|
+
|
|
43
|
+
expect(setProps).toHaveBeenCalledWith('expandedRowKeys', [3, 4]);
|
|
44
|
+
expect(setExpandFlag).toHaveBeenCalledWith(true);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('uses the collection filter target key when expanding the filtered tree', () => {
|
|
48
|
+
const setProps = vi.fn();
|
|
49
|
+
const model = {
|
|
50
|
+
props: { treeTable: true, defaultExpandAllRows: true },
|
|
51
|
+
collection: { filterTargetKey: ['tenant', 'slug'] },
|
|
52
|
+
resource: {
|
|
53
|
+
getData: () => [{ tenant: 'acme', slug: 'root', children: [{ tenant: 'acme', slug: 'child' }] }],
|
|
54
|
+
},
|
|
55
|
+
setProps,
|
|
56
|
+
mapSubModels: vi.fn(),
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
TableBlockModel.prototype.resetAfterFilterChange.call(model);
|
|
60
|
+
|
|
61
|
+
expect(setProps).toHaveBeenCalledWith('expandedRowKeys', ['acme-root', 'acme-child']);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('does not change expansion state for a regular table', () => {
|
|
65
|
+
const setProps = vi.fn();
|
|
66
|
+
const mapSubModels = vi.fn();
|
|
67
|
+
const model = {
|
|
68
|
+
props: { treeTable: false },
|
|
69
|
+
setProps,
|
|
70
|
+
mapSubModels,
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
TableBlockModel.prototype.resetAfterFilterChange.call(model);
|
|
74
|
+
|
|
75
|
+
expect(setProps).not.toHaveBeenCalled();
|
|
76
|
+
expect(mapSubModels).not.toHaveBeenCalled();
|
|
77
|
+
});
|
|
78
|
+
});
|
|
@@ -9,8 +9,20 @@
|
|
|
9
9
|
|
|
10
10
|
import { FlowEngine, MultiRecordResource } from '@nocobase/flow-engine';
|
|
11
11
|
import { describe, expect, it } from 'vitest';
|
|
12
|
+
import { TableBlockModel } from '../TableBlockModel';
|
|
12
13
|
|
|
13
14
|
describe('TableBlockModel quick edit refresh', () => {
|
|
15
|
+
it('requests record-level ACL metadata for table data', () => {
|
|
16
|
+
const engine = new FlowEngine();
|
|
17
|
+
const model = {
|
|
18
|
+
context: engine.context,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const resource = TableBlockModel.prototype.createResource.call(model, {}, {});
|
|
22
|
+
|
|
23
|
+
expect(resource.getRequestOptions().headers['X-With-ACL-Meta']).toBe('true');
|
|
24
|
+
});
|
|
25
|
+
|
|
14
26
|
it('updates table data through a new array reference after quick editing a flat row', () => {
|
|
15
27
|
const engine = new FlowEngine();
|
|
16
28
|
const resource = engine.context.createResource(MultiRecordResource);
|
|
@@ -66,6 +66,39 @@ describe('TableColumnModel sorter settings', () => {
|
|
|
66
66
|
expect(setProps).toHaveBeenCalledWith('editable', false);
|
|
67
67
|
});
|
|
68
68
|
|
|
69
|
+
it('checks record update scope and field permission before enabling quick edit', () => {
|
|
70
|
+
const can = vi.fn(() => false);
|
|
71
|
+
const model = {
|
|
72
|
+
props: { editable: true },
|
|
73
|
+
collectionField: { name: 'title' },
|
|
74
|
+
context: {
|
|
75
|
+
skipAclCheck: false,
|
|
76
|
+
acl: { can },
|
|
77
|
+
blockModel: {
|
|
78
|
+
collection: {
|
|
79
|
+
dataSourceKey: 'main',
|
|
80
|
+
name: 'posts',
|
|
81
|
+
getFilterByTK: () => 2,
|
|
82
|
+
},
|
|
83
|
+
resource: {
|
|
84
|
+
getResourceName: () => 'posts',
|
|
85
|
+
getMeta: () => ({ update: [1] }),
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
|
|
91
|
+
expect(TableColumnModel.prototype.canQuickEdit.call(model, { id: 2 })).toBe(false);
|
|
92
|
+
expect(can).toHaveBeenCalledWith({
|
|
93
|
+
dataSourceKey: 'main',
|
|
94
|
+
resourceName: 'posts',
|
|
95
|
+
actionName: 'update',
|
|
96
|
+
recordPkValue: 2,
|
|
97
|
+
allowedActions: { update: [1] },
|
|
98
|
+
fields: ['title'],
|
|
99
|
+
});
|
|
100
|
+
});
|
|
101
|
+
|
|
69
102
|
it('hides sortable setting for association fields', async () => {
|
|
70
103
|
const engine = new FlowEngine();
|
|
71
104
|
const model = new TableColumnModel({ uid: 'table-column-association-sorter', flowEngine: engine } as any);
|
|
@@ -67,6 +67,13 @@ export function extractIds(data) {
|
|
|
67
67
|
return ids;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
+
export function extractRowKeys(data: Record<string, unknown>[], key: string | string[]) {
|
|
71
|
+
return data.flatMap((item) => {
|
|
72
|
+
const children = Array.isArray(item.children) ? extractRowKeys(item.children, key) : [];
|
|
73
|
+
return [getRowKey(item, key), ...children];
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
70
77
|
/**
|
|
71
78
|
* 生成表格行唯一 key
|
|
72
79
|
* @param record 当前行数据
|
|
@@ -8,7 +8,13 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import { Cascader, Space, Button } from 'antd';
|
|
11
|
-
import {
|
|
11
|
+
import {
|
|
12
|
+
CollectionField,
|
|
13
|
+
EditableItemModel,
|
|
14
|
+
FilterableItemModel,
|
|
15
|
+
MultiRecordResource,
|
|
16
|
+
tExpr,
|
|
17
|
+
} from '@nocobase/flow-engine';
|
|
12
18
|
import { DeleteOutlined } from '@ant-design/icons';
|
|
13
19
|
import { css, cx } from '@emotion/css';
|
|
14
20
|
import { debounce, castArray, omit, last, isEqual } from 'lodash';
|
|
@@ -31,6 +37,23 @@ function normalizeLabelKeys(labelKeyOrKeys?: string | string[]): string[] {
|
|
|
31
37
|
return Array.from(new Set(list.filter((item): item is string => !!item && typeof item === 'string')));
|
|
32
38
|
}
|
|
33
39
|
|
|
40
|
+
function normalizeCascadeFieldKey(key: unknown): string | undefined {
|
|
41
|
+
if (typeof key === 'string' && key) {
|
|
42
|
+
return key;
|
|
43
|
+
}
|
|
44
|
+
if (Array.isArray(key) && key.length === 1 && typeof key[0] === 'string') {
|
|
45
|
+
return key[0];
|
|
46
|
+
}
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function getDefaultCascadeFieldNames(field: CollectionField) {
|
|
51
|
+
const targetCollection = field?.targetCollection;
|
|
52
|
+
const value = normalizeCascadeFieldKey(targetCollection?.filterTargetKey) || 'id';
|
|
53
|
+
const label = targetCollection?.titleCollectionField?.name || value;
|
|
54
|
+
return { label, value };
|
|
55
|
+
}
|
|
56
|
+
|
|
34
57
|
function getRecordDisplayLabel(item: any, labelKeyOrKeys?: string | string[]): string | null {
|
|
35
58
|
if (!isPlainRecord(item)) return null;
|
|
36
59
|
const labelKeys = normalizeLabelKeys(labelKeyOrKeys);
|
|
@@ -815,6 +838,15 @@ EditableItemModel.bindModelToInterface('CascadeSelectFieldModel', ['m2o', 'o2o',
|
|
|
815
838
|
order: 60,
|
|
816
839
|
});
|
|
817
840
|
|
|
841
|
+
FilterableItemModel.bindModelToInterface('CascadeSelectFieldModel', ['m2o', 'o2o', 'oho', 'obo'], {
|
|
842
|
+
when: (ctx, field) => field.targetCollection?.template === 'tree',
|
|
843
|
+
isDefault: true,
|
|
844
|
+
order: 60,
|
|
845
|
+
defaultProps: (ctx, field) => ({
|
|
846
|
+
fieldNames: getDefaultCascadeFieldNames(field),
|
|
847
|
+
}),
|
|
848
|
+
});
|
|
849
|
+
|
|
818
850
|
EditableItemModel.bindModelToInterface('CascadeSelectListFieldModel', ['m2m', 'o2m', 'mbm'], {
|
|
819
851
|
when: (ctx, field) => field.targetCollection?.template === 'tree',
|
|
820
852
|
isDefault: true,
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
createCurrentRecordMetaFactory,
|
|
20
20
|
useFlowModel,
|
|
21
21
|
} from '@nocobase/flow-engine';
|
|
22
|
-
import { Table, Button, Space } from 'antd';
|
|
22
|
+
import { Table, Button, Space, theme } from 'antd';
|
|
23
23
|
import { uid } from '@formily/shared';
|
|
24
24
|
import classNames from 'classnames';
|
|
25
25
|
import { DragEndEvent } from '@dnd-kit/core';
|
|
@@ -28,6 +28,7 @@ import { observer } from '@formily/reactive-react';
|
|
|
28
28
|
import React, { useEffect, useMemo, useState, useRef } from 'react';
|
|
29
29
|
import { useTranslation } from 'react-i18next';
|
|
30
30
|
import { buildRecordPickerPopupContextInputArgs, RecordPickerContent } from '../RecordPickerFieldModel';
|
|
31
|
+
import { buildOpenerUids } from '../recordSelectShared';
|
|
31
32
|
import { AssociationFieldModel } from '../AssociationFieldModel';
|
|
32
33
|
import { adjustColumnOrder } from '../../../blocks/table/utils';
|
|
33
34
|
import { isSubTableColumnFieldComponentContext } from '../SubTableFieldModel/SubTableColumnModel';
|
|
@@ -189,6 +190,7 @@ const AddFieldColumn = ({ model }) => {
|
|
|
189
190
|
};
|
|
190
191
|
|
|
191
192
|
const DisplayTable = (props) => {
|
|
193
|
+
const { token } = theme.useToken();
|
|
192
194
|
const {
|
|
193
195
|
pageSize,
|
|
194
196
|
value,
|
|
@@ -268,7 +270,7 @@ const DisplayTable = (props) => {
|
|
|
268
270
|
},
|
|
269
271
|
},
|
|
270
272
|
...baseColumns,
|
|
271
|
-
{ key: 'empty' },
|
|
273
|
+
{ key: 'empty', render: () => <div style={{ minHeight: token.controlHeight }} /> },
|
|
272
274
|
].filter(Boolean),
|
|
273
275
|
) as any[];
|
|
274
276
|
|
|
@@ -282,7 +284,7 @@ const DisplayTable = (props) => {
|
|
|
282
284
|
}
|
|
283
285
|
|
|
284
286
|
return cols;
|
|
285
|
-
}, [baseColumns, enableIndexColumn, currentPage, currentPageSize, isConfigMode, model]);
|
|
287
|
+
}, [baseColumns, enableIndexColumn, currentPage, currentPageSize, isConfigMode, model, token.controlHeight]);
|
|
286
288
|
return (
|
|
287
289
|
<Table
|
|
288
290
|
tableLayout="fixed"
|
|
@@ -653,6 +655,11 @@ PopupSubTableFieldModel.registerFlow({
|
|
|
653
655
|
const parentItemOptions = ctx?.getPropertyOptions?.('item');
|
|
654
656
|
const itemIndex = Array.isArray(ctx.model?.props?.value) ? ctx.model.props.value.length : 0;
|
|
655
657
|
const itemLength = itemIndex + 1;
|
|
658
|
+
const associationName = ctx.collectionField?.resourceName;
|
|
659
|
+
const sourceId = parentItem?.value
|
|
660
|
+
? ctx.collectionField?.collection?.getFilterByTK?.(parentItem.value)
|
|
661
|
+
: undefined;
|
|
662
|
+
const openerUids = buildOpenerUids(ctx, ctx.inputArgs);
|
|
656
663
|
ctx.viewer.open({
|
|
657
664
|
type: openMode,
|
|
658
665
|
width: sizeToWidthMap[openMode][size],
|
|
@@ -663,12 +670,14 @@ PopupSubTableFieldModel.registerFlow({
|
|
|
663
670
|
scene: 'subForm',
|
|
664
671
|
dataSourceKey: ctx.collection.dataSourceKey,
|
|
665
672
|
collectionName: ctx.collectionField?.target,
|
|
673
|
+
...(associationName && sourceId != null ? { associationName, sourceId } : {}),
|
|
666
674
|
collectionField: ctx.collectionField,
|
|
667
675
|
parentItem,
|
|
668
676
|
parentItemMeta: parentItemOptions?.meta,
|
|
669
677
|
parentItemResolver: parentItemOptions?.resolveOnServer,
|
|
670
678
|
itemIndex,
|
|
671
679
|
itemLength,
|
|
680
|
+
openerUids,
|
|
672
681
|
},
|
|
673
682
|
content: () => <EditFormContent model={ctx.model} scene="create" />,
|
|
674
683
|
styles: {
|