@nocobase/client-v2 2.2.0-beta.9 → 2.2.0
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 +13 -3
- package/es/BaseApplication.d.ts +1 -0
- package/es/collection-field-interface/CollectionFieldInterface.d.ts +1 -0
- package/es/collection-field-interface/CollectionFieldInterfaceManager.d.ts +1 -0
- package/es/components/category-tabs/SortableCategoryTabs.d.ts +55 -0
- package/es/components/category-tabs/index.d.ts +9 -0
- package/es/components/form/ScanInput/useCodeScanner.d.ts +3 -2
- package/es/components/form/TypedVariableInput.d.ts +31 -5
- package/es/components/form/filter/CollectionFilter.d.ts +2 -0
- package/es/components/form/filter/CollectionFilterItem.d.ts +11 -1
- package/es/components/form/filter/CollectionFilterPanel.d.ts +2 -0
- package/es/components/form/filter/index.d.ts +2 -0
- package/es/components/form/filter/useFilterActionProps.d.ts +2 -0
- package/es/components/index.d.ts +1 -0
- package/es/flow/actions/index.d.ts +1 -1
- package/es/flow/actions/linkageRules.d.ts +27 -0
- package/es/flow/admin-shell/admin-layout/AdminLayoutMenuModels.d.ts +1 -0
- package/es/flow/components/FieldAssignExactDatePicker.d.ts +1 -0
- package/es/flow/components/FieldAssignValueInput.d.ts +7 -24
- package/es/flow/components/FlowRoute.d.ts +2 -2
- package/es/flow/components/RunJSValueEditor.d.ts +1 -0
- package/es/flow/components/field-value-variable/DateVariableEditor.d.ts +24 -0
- package/es/flow/components/field-value-variable/FieldValueVariableInput.d.ts +31 -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/FilterGroup.d.ts +1 -0
- package/es/flow/components/filter/VariableFilterItem.d.ts +6 -1
- package/es/flow/components/placeholders/BlockPlaceholder.d.ts +1 -0
- package/es/flow/index.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/base/PageModel/PageModel.d.ts +12 -0
- package/es/flow/models/base/PageModel/PageModelTabBar.d.ts +22 -0
- package/es/flow/models/base/PageModel/PageTabModel.d.ts +12 -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/QuickEditFormModel.d.ts +17 -2
- 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/fieldValidationConstants.d.ts +1 -1
- package/es/flow-compat/passwordUtils.d.ts +1 -1
- package/es/flow-compat/routeTypes.d.ts +1 -0
- package/es/index.d.ts +5 -0
- package/es/index.mjs +199 -161
- package/es/ui-operation/index.d.ts +15 -0
- package/es/ui-operation/ui-operation-codec.d.ts +10 -0
- package/es/utils/getRouteRuntimeVersion.d.ts +23 -0
- package/es/utils/index.d.ts +1 -0
- package/lib/index.js +215 -177
- package/lib/locale/languageCodes.js +3 -1
- package/package.json +9 -7
- package/src/APIClient.ts +90 -7
- package/src/Application.tsx +7 -1
- package/src/BaseApplication.tsx +11 -6
- package/src/__tests__/APIClient.test.tsx +58 -0
- package/src/__tests__/app.test.tsx +73 -0
- package/src/__tests__/browserChecker.test.ts +61 -0
- package/src/__tests__/getRouteRuntimeVersion.test.ts +68 -0
- package/src/__tests__/nocobase-buildin-plugin-auth.test.tsx +35 -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-field-interface/CollectionFieldInterface.ts +1 -0
- package/src/collection-field-interface/CollectionFieldInterfaceManager.ts +1 -0
- package/src/collection-manager/field-validation.ts +1 -1
- package/src/components/README.md +7 -1
- package/src/components/README.zh-CN.md +6 -1
- package/src/components/category-tabs/SortableCategoryTabs.tsx +210 -0
- package/src/components/category-tabs/index.ts +10 -0
- package/src/components/form/JsonTextArea.tsx +4 -0
- package/src/components/form/ScanInput/CodeScanner.tsx +79 -35
- package/src/components/form/ScanInput/__tests__/CodeScanner.test.tsx +101 -0
- package/src/components/form/ScanInput/__tests__/useCodeScanner.test.tsx +284 -11
- package/src/components/form/ScanInput/useCodeScanner.ts +332 -24
- package/src/components/form/TypedVariableInput.tsx +452 -101
- package/src/components/form/__tests__/TypedVariableInput.test.tsx +364 -12
- package/src/components/form/filter/CollectionFilter.tsx +4 -0
- package/src/components/form/filter/CollectionFilterItem.tsx +36 -9
- package/src/components/form/filter/CollectionFilterPanel.tsx +4 -0
- package/src/components/form/filter/__tests__/CollectionFilterItem.test.tsx +55 -0
- package/src/components/form/filter/__tests__/useFilterActionProps.test.tsx +95 -0
- package/src/components/form/filter/index.ts +2 -0
- package/src/components/form/filter/useFilterActionProps.ts +37 -6
- package/src/components/form/table/Table.tsx +81 -6
- package/src/components/form/table/__tests__/Table.columnWidth.test.tsx +433 -0
- package/src/components/index.ts +1 -0
- package/src/flow/FlowPage.tsx +9 -1
- package/src/flow/__tests__/FlowPage.test.tsx +50 -3
- package/src/flow/__tests__/FlowRoute.test.tsx +128 -10
- 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__/linkageRules.tab.test.ts +171 -0
- package/src/flow/actions/__tests__/linkageRulesRefresh.test.ts +7 -3
- package/src/flow/actions/index.ts +2 -0
- package/src/flow/actions/linkageRules.tsx +144 -26
- package/src/flow/actions/linkageRulesRefresh.tsx +2 -6
- package/src/flow/admin-shell/admin-layout/AdminLayoutComponent.tsx +0 -1
- package/src/flow/admin-shell/admin-layout/AdminLayoutMenuUtils.tsx +78 -59
- package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutComponent.test.tsx +253 -6
- package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutMenuModels.test.ts +228 -0
- package/src/flow/common/Markdown/style.ts +4 -0
- package/src/flow/components/BlockItemCard.tsx +2 -2
- package/src/flow/components/FieldAssignExactDatePicker.tsx +25 -11
- package/src/flow/components/FieldAssignValueInput.tsx +72 -584
- package/src/flow/components/FlowRoute.tsx +78 -32
- package/src/flow/components/RunJSValueEditor.tsx +9 -1
- package/src/flow/components/__tests__/FieldAssignValueInput.context.test.tsx +216 -0
- package/src/flow/components/field-value-variable/DateVariableEditor.tsx +181 -0
- package/src/flow/components/field-value-variable/FieldValueVariableInput.tsx +326 -0
- package/src/flow/components/field-value-variable/__tests__/FieldValueVariableInput.test.tsx +380 -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/FilterGroup.tsx +33 -5
- package/src/flow/components/filter/VariableFilterItem.tsx +170 -13
- package/src/flow/components/filter/__tests__/FilterGroup.test.tsx +45 -0
- package/src/flow/components/filter/__tests__/VariableFilterItem.leftMetaTree.test.tsx +9 -0
- package/src/flow/components/filter/__tests__/VariableFilterItem.test.tsx +195 -1
- 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 +3 -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/PageModel/PageModel.tsx +387 -53
- package/src/flow/models/base/PageModel/PageModelTabBar.tsx +114 -0
- package/src/flow/models/base/PageModel/PageTabModel.tsx +249 -18
- package/src/flow/models/base/PageModel/__tests__/PageModel.test.ts +790 -10
- package/src/flow/models/base/PageModel/__tests__/PageModelTabBar.module-isolation.test.tsx +130 -0
- package/src/flow/models/base/PageModel/__tests__/PageModelTabBar.test.tsx +118 -0
- package/src/flow/models/base/PageModel/__tests__/PageTabModel.test.ts +1075 -7
- 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/AssignFormItemModel.tsx +28 -53
- 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 +28 -3
- package/src/flow/models/blocks/filter-form/FilterFormGridModel.tsx +36 -5
- package/src/flow/models/blocks/filter-form/FilterFormItemModel.tsx +155 -25
- 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__/FilterFormItemModel.defineChildren.test.ts +395 -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 +66 -4
- 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 +47 -0
- package/src/flow/models/blocks/form/FormGridModel.tsx +4 -0
- package/src/flow/models/blocks/form/QuickEditFormModel.tsx +189 -36
- package/src/flow/models/blocks/form/__tests__/FormBlockModel.test.tsx +8 -2
- package/src/flow/models/blocks/form/__tests__/QuickEditFormModel.quickEdit.test.ts +350 -2
- 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/TableActionsColumnModel.tsx +2 -1
- package/src/flow/models/blocks/table/TableBlockModel.tsx +29 -3
- 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 +10 -1
- 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 +24 -1
- package/src/flow/models/fields/AssociationFieldModel/RecordSelectFieldModel.tsx +9 -136
- package/src/flow/models/fields/AssociationFieldModel/__tests__/RecordPickerFieldModel.itemContext.test.ts +167 -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/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/VariableFieldFormModel.tsx +3 -3
- 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/__tests__/VariableFieldFormModel.test.tsx +51 -0
- package/src/flow/models/fields/mobile-components/MobileLazySelect.tsx +26 -10
- package/src/flow/models/fields/mobile-components/MobileSelect.tsx +51 -14
- package/src/flow/models/fields/mobile-components/__tests__/MobileSelect.test.tsx +139 -13
- package/src/flow/utils/dataScopeFormValueClear.ts +4 -3
- package/src/flow-compat/fieldValidationConstants.ts +1 -1
- package/src/flow-compat/routeTypes.ts +1 -0
- package/src/index.ts +5 -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 +3 -1
- package/src/nocobase-buildin-plugin/index.tsx +12 -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
- package/src/utils/getRouteRuntimeVersion.ts +185 -0
- package/src/utils/index.tsx +1 -0
|
@@ -15,8 +15,10 @@ import {
|
|
|
15
15
|
DndProvider,
|
|
16
16
|
DragHandler,
|
|
17
17
|
Droppable,
|
|
18
|
+
isCtxDateExpression,
|
|
18
19
|
isRunJSValue,
|
|
19
20
|
normalizeRunJSValue,
|
|
21
|
+
parseCtxDateExpression,
|
|
20
22
|
tExpr,
|
|
21
23
|
FlowModelRenderer,
|
|
22
24
|
FlowSettingsButton,
|
|
@@ -44,6 +46,15 @@ import { normalizeFilterValueByOperator } from './valueNormalization';
|
|
|
44
46
|
|
|
45
47
|
const RELATION_FIELD_TYPES = ['belongsTo', 'hasOne', 'hasMany', 'belongsToMany', 'belongsToArray'];
|
|
46
48
|
const NUMERIC_FIELD_TYPES = ['integer', 'float', 'double', 'decimal'];
|
|
49
|
+
const DATE_FILTER_OPERATORS = new Set([
|
|
50
|
+
'$dateOn',
|
|
51
|
+
'$dateNotOn',
|
|
52
|
+
'$dateBefore',
|
|
53
|
+
'$dateAfter',
|
|
54
|
+
'$dateNotBefore',
|
|
55
|
+
'$dateNotAfter',
|
|
56
|
+
'$dateBetween',
|
|
57
|
+
]);
|
|
47
58
|
|
|
48
59
|
function getFilterFormFieldMetaType(field: CollectionField) {
|
|
49
60
|
if (RELATION_FIELD_TYPES.includes(field.type)) {
|
|
@@ -66,6 +77,14 @@ function getFilterFormFieldMetaType(field: CollectionField) {
|
|
|
66
77
|
}
|
|
67
78
|
}
|
|
68
79
|
|
|
80
|
+
function parseDateFilterDefaultValue(operator: string | undefined, rawValue: unknown) {
|
|
81
|
+
if (!operator || !DATE_FILTER_OPERATORS.has(operator) || !isCtxDateExpression(rawValue)) {
|
|
82
|
+
return undefined;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return parseCtxDateExpression(rawValue);
|
|
86
|
+
}
|
|
87
|
+
|
|
69
88
|
function shouldShowFilterFormFieldMeta(field: CollectionField) {
|
|
70
89
|
return Boolean(field?.interface);
|
|
71
90
|
}
|
|
@@ -431,6 +450,7 @@ export class FilterFormBlockModel extends FilterBlockModel<{
|
|
|
431
450
|
|
|
432
451
|
private canApplyFormDefaultValue(name: string, current: any, force?: boolean) {
|
|
433
452
|
if (force) return true;
|
|
453
|
+
if (this.userEditedFieldNames.has(name)) return false;
|
|
434
454
|
if (isEmptyValue(current)) return true;
|
|
435
455
|
if (!this.lastDefaultValueByFieldName.has(name)) return false;
|
|
436
456
|
return isEqual(current, this.lastDefaultValueByFieldName.get(name));
|
|
@@ -488,7 +508,7 @@ export class FilterFormBlockModel extends FilterBlockModel<{
|
|
|
488
508
|
const rules = (params?.value || []) as any[];
|
|
489
509
|
if (!Array.isArray(rules) || rules.length === 0) return appliedValues;
|
|
490
510
|
|
|
491
|
-
const resolveValue = async (raw: any) => {
|
|
511
|
+
const resolveValue = async (raw: any, operator?: string) => {
|
|
492
512
|
// RunJS support
|
|
493
513
|
if (isRunJSValue(raw)) {
|
|
494
514
|
const { code, version } = normalizeRunJSValue(raw);
|
|
@@ -496,6 +516,11 @@ export class FilterFormBlockModel extends FilterBlockModel<{
|
|
|
496
516
|
return ret?.success ? ret.value : undefined;
|
|
497
517
|
}
|
|
498
518
|
|
|
519
|
+
const parsedDateFilterValue = parseDateFilterDefaultValue(operator, raw);
|
|
520
|
+
if (typeof parsedDateFilterValue !== 'undefined') {
|
|
521
|
+
return parsedDateFilterValue;
|
|
522
|
+
}
|
|
523
|
+
|
|
499
524
|
return await (this.context as any).resolveJsonTemplate?.(raw);
|
|
500
525
|
};
|
|
501
526
|
|
|
@@ -519,11 +544,11 @@ export class FilterFormBlockModel extends FilterBlockModel<{
|
|
|
519
544
|
|
|
520
545
|
const current = (form as any).getFieldValue?.(name);
|
|
521
546
|
|
|
522
|
-
const
|
|
547
|
+
const operator = getDefaultOperator(itemModel as any);
|
|
548
|
+
const resolved = await resolveValue(rule.value, operator);
|
|
523
549
|
if (options?.refreshSeq && options.refreshSeq !== this.defaultValuesRefreshSeq) return appliedValues;
|
|
524
550
|
if (typeof resolved === 'undefined') continue;
|
|
525
551
|
|
|
526
|
-
const operator = getDefaultOperator(itemModel as any);
|
|
527
552
|
const normalized = normalizeFilterValueByOperator(operator, resolved);
|
|
528
553
|
const mode = this.normalizeFieldValueMode(rule.mode);
|
|
529
554
|
if (mode === 'default' && !this.canApplyFormDefaultValue(String(name), current, force)) continue;
|
|
@@ -59,11 +59,42 @@ export class FilterFormGridModel extends GridModel {
|
|
|
59
59
|
|
|
60
60
|
readonly loading = observable.ref(false);
|
|
61
61
|
|
|
62
|
-
private
|
|
63
|
-
const
|
|
62
|
+
private isRecordSelectFilterField(subModel: FilterFormItemModel) {
|
|
63
|
+
const fieldModel = subModel.subModels?.field;
|
|
64
|
+
if (!fieldModel) {
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const RecordSelectModel = this.flowEngine.getModelClass('FilterFormRecordSelectFieldModel');
|
|
69
|
+
if (!RecordSelectModel) {
|
|
70
|
+
return fieldModel.constructor?.name === 'FilterFormRecordSelectFieldModel';
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return fieldModel instanceof RecordSelectModel;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
private getAssociationFilterTargetKey(field: any, subModel: FilterFormItemModel) {
|
|
77
|
+
const normalizeKey = (key: any) => {
|
|
78
|
+
if (Array.isArray(key)) {
|
|
79
|
+
return key[0];
|
|
80
|
+
}
|
|
81
|
+
return key;
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const fieldModelValueKey = normalizeKey(subModel.subModels?.field?.props?.fieldNames?.value);
|
|
85
|
+
if (fieldModelValueKey) {
|
|
86
|
+
return fieldModelValueKey;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
const filterTargetKey = normalizeKey(field?.targetCollection?.filterTargetKey);
|
|
90
|
+
const fieldTargetKey = normalizeKey(field?.targetKey);
|
|
91
|
+
|
|
92
|
+
if (filterTargetKey && filterTargetKey !== 'id') {
|
|
93
|
+
return filterTargetKey;
|
|
94
|
+
}
|
|
64
95
|
|
|
65
|
-
if (
|
|
66
|
-
return
|
|
96
|
+
if (!this.isRecordSelectFilterField(subModel) && fieldTargetKey) {
|
|
97
|
+
return fieldTargetKey;
|
|
67
98
|
}
|
|
68
99
|
|
|
69
100
|
return filterTargetKey || 'id';
|
|
@@ -370,7 +401,7 @@ export class FilterFormGridModel extends GridModel {
|
|
|
370
401
|
if (field?.target) {
|
|
371
402
|
return {
|
|
372
403
|
targetId: model.uid,
|
|
373
|
-
filterPaths: [`${fieldPath}.${this.getAssociationFilterTargetKey(field)}`],
|
|
404
|
+
filterPaths: [`${fieldPath}.${this.getAssociationFilterTargetKey(field, subModel)}`],
|
|
374
405
|
};
|
|
375
406
|
}
|
|
376
407
|
}
|
|
@@ -31,6 +31,12 @@ import {
|
|
|
31
31
|
import { FilterFormFieldModel } from './fields';
|
|
32
32
|
import { normalizeFilterValueByOperator } from './valueNormalization';
|
|
33
33
|
|
|
34
|
+
type CollectionWithManager = Collection & {
|
|
35
|
+
collectionManager?: {
|
|
36
|
+
getCollection?: (name: string) => Collection | undefined;
|
|
37
|
+
};
|
|
38
|
+
};
|
|
39
|
+
|
|
34
40
|
const getAssociationTargetCollection = (field: any, collection?: Collection, model?: CollectionBlockModel) => {
|
|
35
41
|
if (field?.targetCollection) {
|
|
36
42
|
return field.targetCollection;
|
|
@@ -42,6 +48,10 @@ const getAssociationTargetCollection = (field: any, collection?: Collection, mod
|
|
|
42
48
|
if (collection?.dataSource?.getCollection) {
|
|
43
49
|
return collection.dataSource.getCollection(targetName);
|
|
44
50
|
}
|
|
51
|
+
const collectionManager = (collection as CollectionWithManager | undefined)?.collectionManager;
|
|
52
|
+
if (collectionManager?.getCollection) {
|
|
53
|
+
return collectionManager.getCollection(targetName);
|
|
54
|
+
}
|
|
45
55
|
const dataSourceKey = collection?.dataSourceKey;
|
|
46
56
|
if (dataSourceKey && model?.context?.dataSourceManager?.getCollection) {
|
|
47
57
|
return model.context.dataSourceManager.getCollection(dataSourceKey, targetName);
|
|
@@ -62,9 +72,25 @@ function isRecord(value: unknown): value is Record<string, unknown> {
|
|
|
62
72
|
return !!value && typeof value === 'object' && !Array.isArray(value);
|
|
63
73
|
}
|
|
64
74
|
|
|
75
|
+
interface CollectionFieldWithAssociationMarker {
|
|
76
|
+
isAssociationField?: () => boolean;
|
|
77
|
+
target?: unknown;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function hasAssociationMarker(value: unknown): value is CollectionFieldWithAssociationMarker {
|
|
81
|
+
return isRecord(value) && (typeof value.isAssociationField === 'function' || 'target' in value);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const isAssociationCollectionField = (collectionField: unknown) => {
|
|
85
|
+
if (!hasAssociationMarker(collectionField)) {
|
|
86
|
+
return false;
|
|
87
|
+
}
|
|
88
|
+
return collectionField.isAssociationField ? collectionField.isAssociationField() : Boolean(collectionField.target);
|
|
89
|
+
};
|
|
90
|
+
|
|
65
91
|
const normalizeAssociationDefaultFilterValue = (value: any, fieldModel: any) => {
|
|
66
92
|
const collectionField = fieldModel?.context?.collectionField;
|
|
67
|
-
if (!collectionField
|
|
93
|
+
if (!isAssociationCollectionField(collectionField)) {
|
|
68
94
|
return value;
|
|
69
95
|
}
|
|
70
96
|
|
|
@@ -152,6 +178,74 @@ const buildVirtualFilterCollectionField = (ctx: FlowModelContext, filterField: a
|
|
|
152
178
|
return result;
|
|
153
179
|
};
|
|
154
180
|
|
|
181
|
+
const getFilterableChildren = (field: any) => {
|
|
182
|
+
const children = field?.filterable?.children;
|
|
183
|
+
return Array.isArray(children) ? children : [];
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
const hasAssociationChildren = (field: any, collection?: Collection, model?: CollectionBlockModel) => {
|
|
187
|
+
return (
|
|
188
|
+
isAssociationCollectionField(field) &&
|
|
189
|
+
(getFilterableChildren(field).length > 0 || !!getAssociationTargetCollection(field, collection, model))
|
|
190
|
+
);
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
const inferFilterableChildInterface = (child: any) => {
|
|
194
|
+
if (child?.interface) {
|
|
195
|
+
return child.interface;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
const schema = child?.schema || child?.uiSchema;
|
|
199
|
+
const component = schema?.['x-component'];
|
|
200
|
+
if (component === 'Select') {
|
|
201
|
+
return 'select';
|
|
202
|
+
}
|
|
203
|
+
if (component === 'Checkbox.Group') {
|
|
204
|
+
return 'checkboxGroup';
|
|
205
|
+
}
|
|
206
|
+
if (component === 'Checkbox') {
|
|
207
|
+
return 'checkbox';
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const type = child?.type || schema?.type;
|
|
211
|
+
if (type === 'number' || type === 'integer') {
|
|
212
|
+
return 'number';
|
|
213
|
+
}
|
|
214
|
+
return 'input';
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
const translateFilterableChildTitle = (title: unknown, t: (value: string) => string) => {
|
|
218
|
+
return typeof title === 'string' ? t(title) : title;
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
const buildFilterableChildField = (child: any, t: (value: string) => string) => {
|
|
222
|
+
const name = child?.name || child?.value;
|
|
223
|
+
if (!name) {
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const schema = child?.schema || child?.uiSchema || {};
|
|
228
|
+
const rawTitle = child?.title || child?.label || schema?.title || name;
|
|
229
|
+
const title = translateFilterableChildTitle(rawTitle, t);
|
|
230
|
+
const filterable = child?.filterable || (child?.operators ? { operators: child.operators } : undefined);
|
|
231
|
+
|
|
232
|
+
return {
|
|
233
|
+
...child,
|
|
234
|
+
name,
|
|
235
|
+
title,
|
|
236
|
+
type: child?.type || schema?.type || 'string',
|
|
237
|
+
interface: inferFilterableChildInterface(child),
|
|
238
|
+
uiSchema: {
|
|
239
|
+
...schema,
|
|
240
|
+
title: translateFilterableChildTitle(schema?.title || title, t),
|
|
241
|
+
},
|
|
242
|
+
filterable,
|
|
243
|
+
__filterFormVirtual: true,
|
|
244
|
+
isAssociationField: () => false,
|
|
245
|
+
getComponentProps: () => schema?.['x-component-props'] || {},
|
|
246
|
+
};
|
|
247
|
+
};
|
|
248
|
+
|
|
155
249
|
const buildFilterFormFieldItem = ({
|
|
156
250
|
model,
|
|
157
251
|
collection,
|
|
@@ -171,12 +265,7 @@ const buildFilterFormFieldItem = ({
|
|
|
171
265
|
if (!binding) {
|
|
172
266
|
return;
|
|
173
267
|
}
|
|
174
|
-
const
|
|
175
|
-
typeof field?.isAssociationField === 'function' ? field.isAssociationField() : Boolean(field?.target);
|
|
176
|
-
const fieldModel =
|
|
177
|
-
isAssociation && ctxWithFlags.engine?.getModelClass?.('FilterFormRecordSelectFieldModel')
|
|
178
|
-
? 'FilterFormRecordSelectFieldModel'
|
|
179
|
-
: binding.modelName;
|
|
268
|
+
const fieldModel = binding.modelName;
|
|
180
269
|
const label = field.title || field.name;
|
|
181
270
|
const displayLabel = labelPrefix ? `${labelPrefix} / ${label}` : label;
|
|
182
271
|
return {
|
|
@@ -196,7 +285,10 @@ const buildFilterFormFieldItem = ({
|
|
|
196
285
|
},
|
|
197
286
|
filterFormItemSettings: {
|
|
198
287
|
init: {
|
|
199
|
-
filterField:
|
|
288
|
+
filterField: {
|
|
289
|
+
..._.pick(field, ['name', 'title', 'interface', 'type', 'filterable', 'uiSchema', '__filterFormVirtual']),
|
|
290
|
+
title: displayLabel,
|
|
291
|
+
},
|
|
200
292
|
defaultTargetUid: model.uid,
|
|
201
293
|
},
|
|
202
294
|
},
|
|
@@ -230,7 +322,8 @@ const buildAssociationFieldMenuItem = ({
|
|
|
230
322
|
depth: number;
|
|
231
323
|
}) => {
|
|
232
324
|
const targetCollection = getAssociationTargetCollection(field, collection, model);
|
|
233
|
-
|
|
325
|
+
const filterableChildren = getFilterableChildren(field);
|
|
326
|
+
if (!targetCollection && !filterableChildren.length) {
|
|
234
327
|
return;
|
|
235
328
|
}
|
|
236
329
|
if (depth > MAX_ASSOCIATION_DEPTH) {
|
|
@@ -247,10 +340,35 @@ const buildAssociationFieldMenuItem = ({
|
|
|
247
340
|
const targetFields = getTargetFilterableFields(field, collection, model);
|
|
248
341
|
const fieldItems: any[] = [];
|
|
249
342
|
const associationItems: any[] = [];
|
|
343
|
+
const addedFieldPaths = new Set<string>();
|
|
344
|
+
|
|
345
|
+
filterableChildren.forEach((child: any) => {
|
|
346
|
+
const virtualChildField = buildFilterableChildField(child, t);
|
|
347
|
+
if (!virtualChildField) {
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
const childFieldPath = `${fieldPath}.${virtualChildField.name}`;
|
|
352
|
+
const childItem = buildFilterFormFieldItem({
|
|
353
|
+
model,
|
|
354
|
+
collection,
|
|
355
|
+
ctxWithFlags,
|
|
356
|
+
field: virtualChildField,
|
|
357
|
+
fieldPath: childFieldPath,
|
|
358
|
+
labelPrefix: label,
|
|
359
|
+
});
|
|
360
|
+
if (childItem) {
|
|
361
|
+
addedFieldPaths.add(childFieldPath);
|
|
362
|
+
fieldItems.push(childItem);
|
|
363
|
+
}
|
|
364
|
+
});
|
|
250
365
|
|
|
251
366
|
targetFields.forEach((targetField: any) => {
|
|
252
367
|
const targetFieldPath = `${fieldPath}.${targetField.name}`;
|
|
253
|
-
if (
|
|
368
|
+
if (addedFieldPaths.has(targetFieldPath)) {
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
if (hasAssociationChildren(targetField, collection, model)) {
|
|
254
372
|
const associationItem = buildAssociationFieldMenuItem({
|
|
255
373
|
model,
|
|
256
374
|
collection,
|
|
@@ -343,7 +461,7 @@ const getModelFieldGroups = async (model: CollectionBlockModel) => {
|
|
|
343
461
|
baseItems.push(baseItem);
|
|
344
462
|
}
|
|
345
463
|
|
|
346
|
-
if (field
|
|
464
|
+
if (hasAssociationChildren(field, collection, model)) {
|
|
347
465
|
const associationItem = buildAssociationFieldMenuItem({
|
|
348
466
|
model,
|
|
349
467
|
collection,
|
|
@@ -474,6 +592,14 @@ export class FilterFormItemModel extends FilterableItemModel<{
|
|
|
474
592
|
title: initFilterField?.title || initFilterField?.name,
|
|
475
593
|
},
|
|
476
594
|
});
|
|
595
|
+
if (initFilterField?.__filterFormVirtual) {
|
|
596
|
+
const virtualField = buildVirtualFilterCollectionField(this.context, initFilterField);
|
|
597
|
+
if (virtualField) {
|
|
598
|
+
this.context.defineProperty('collectionField', {
|
|
599
|
+
value: virtualField,
|
|
600
|
+
});
|
|
601
|
+
}
|
|
602
|
+
}
|
|
477
603
|
}
|
|
478
604
|
}
|
|
479
605
|
|
|
@@ -507,10 +633,7 @@ export class FilterFormItemModel extends FilterableItemModel<{
|
|
|
507
633
|
const formValue = this.context.form?.getFieldValue(this.props.name);
|
|
508
634
|
const modelValue = fieldModel.getFilterValue ? fieldModel.getFilterValue() : formValue;
|
|
509
635
|
const collectionField = (fieldModel as any)?.context?.collectionField;
|
|
510
|
-
const isAssociationField =
|
|
511
|
-
typeof collectionField?.isAssociationField === 'function'
|
|
512
|
-
? collectionField.isAssociationField()
|
|
513
|
-
: !!collectionField?.target;
|
|
636
|
+
const isAssociationField = isAssociationCollectionField(collectionField);
|
|
514
637
|
const shouldUseFormValue =
|
|
515
638
|
isAssociationField &&
|
|
516
639
|
!this.mounted &&
|
|
@@ -547,11 +670,7 @@ export class FilterFormItemModel extends FilterableItemModel<{
|
|
|
547
670
|
return value;
|
|
548
671
|
}
|
|
549
672
|
const collectionField = (fieldModel as any)?.context?.collectionField;
|
|
550
|
-
|
|
551
|
-
typeof collectionField?.isAssociationField === 'function'
|
|
552
|
-
? collectionField.isAssociationField()
|
|
553
|
-
: !!collectionField?.target;
|
|
554
|
-
if (!isAssociation) {
|
|
673
|
+
if (!isAssociationCollectionField(collectionField)) {
|
|
555
674
|
return value;
|
|
556
675
|
}
|
|
557
676
|
const normalizedFieldNames = normalizeAssociationFieldNames(
|
|
@@ -684,7 +803,8 @@ FilterFormItemModel.registerFlow({
|
|
|
684
803
|
// @ts-ignore
|
|
685
804
|
(fieldSettingsInitParams?.dataSourceKey && fieldSettingsInitParams?.collectionName)
|
|
686
805
|
);
|
|
687
|
-
|
|
806
|
+
const shouldUseVirtualFilterField = !!normalizedFilterField?.__filterFormVirtual;
|
|
807
|
+
if ((shouldUseVirtualFilterField || (!hasCollectionContext && !collectionField)) && normalizedFilterField) {
|
|
688
808
|
const virtualField = buildVirtualFilterCollectionField(ctx, normalizedFilterField);
|
|
689
809
|
if (virtualField) {
|
|
690
810
|
ctx.model.context.defineProperty('collectionField', {
|
|
@@ -779,10 +899,13 @@ FilterFormItemModel.registerFlow({
|
|
|
779
899
|
type: 'select',
|
|
780
900
|
key: 'use',
|
|
781
901
|
props: {
|
|
782
|
-
options: classes.map((model) =>
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
902
|
+
options: classes.map((model) => {
|
|
903
|
+
const ModelClass = ctx.engine.getModelClass(model.modelName);
|
|
904
|
+
return {
|
|
905
|
+
label: t(ModelClass?.meta?.label || model.modelName),
|
|
906
|
+
value: model.modelName,
|
|
907
|
+
};
|
|
908
|
+
}),
|
|
786
909
|
},
|
|
787
910
|
};
|
|
788
911
|
},
|
|
@@ -798,6 +921,13 @@ FilterFormItemModel.registerFlow({
|
|
|
798
921
|
},
|
|
799
922
|
defaultOperator: {
|
|
800
923
|
use: 'defaultOperator',
|
|
924
|
+
hideInSettings(ctx) {
|
|
925
|
+
const collectionField =
|
|
926
|
+
ctx.collectionField ||
|
|
927
|
+
ctx.model?.context?.collectionField ||
|
|
928
|
+
ctx.model?.subModels?.field?.context?.collectionField;
|
|
929
|
+
return isAssociationCollectionField(collectionField);
|
|
930
|
+
},
|
|
801
931
|
},
|
|
802
932
|
operatorComponentProps: {
|
|
803
933
|
use: 'operatorComponentProps',
|
|
@@ -8,23 +8,76 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import type { ButtonProps } from 'antd/es/button';
|
|
11
|
+
import { reaction } from '@formily/reactive';
|
|
11
12
|
import { tExpr } from '@nocobase/flow-engine';
|
|
12
13
|
import { FilterFormActionModel } from './FilterFormActionModel';
|
|
13
14
|
|
|
15
|
+
type FilterFormBlockState = {
|
|
16
|
+
autoTriggerFilter: boolean;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const mountedSubmitActions = new WeakSet<object>();
|
|
20
|
+
const visibleSubmitActionsByBlock = new WeakMap<FilterFormBlockState, Set<object>>();
|
|
21
|
+
const hiddenReactionDisposers = new WeakMap<object, () => void>();
|
|
22
|
+
|
|
23
|
+
const syncAutoTriggerFilter = (blockModel: FilterFormBlockState, lifecycleAction: object & { hidden?: boolean }) => {
|
|
24
|
+
let visibleSubmitActions = visibleSubmitActionsByBlock.get(blockModel);
|
|
25
|
+
|
|
26
|
+
if (mountedSubmitActions.has(lifecycleAction) && !lifecycleAction.hidden) {
|
|
27
|
+
if (!visibleSubmitActions) {
|
|
28
|
+
visibleSubmitActions = new Set<object>();
|
|
29
|
+
visibleSubmitActionsByBlock.set(blockModel, visibleSubmitActions);
|
|
30
|
+
}
|
|
31
|
+
visibleSubmitActions.add(lifecycleAction);
|
|
32
|
+
} else {
|
|
33
|
+
visibleSubmitActions?.delete(lifecycleAction);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
blockModel.autoTriggerFilter = Boolean(!visibleSubmitActions?.size);
|
|
37
|
+
if (!visibleSubmitActions?.size) {
|
|
38
|
+
visibleSubmitActionsByBlock.delete(blockModel);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
|
|
14
42
|
export class FilterFormSubmitActionModel extends FilterFormActionModel {
|
|
15
43
|
defaultProps: ButtonProps = {
|
|
16
44
|
title: tExpr('Filter'),
|
|
17
45
|
type: 'primary',
|
|
18
46
|
};
|
|
19
47
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
48
|
+
private getLifecycleAction(): object & { hidden?: boolean } {
|
|
49
|
+
return this.context.model || this;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
private syncAutoTriggerFilter(): void {
|
|
53
|
+
const blockModel = this.context.blockModel as FilterFormBlockState;
|
|
54
|
+
const lifecycleAction = this.getLifecycleAction();
|
|
55
|
+
syncAutoTriggerFilter(blockModel, lifecycleAction);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
onMount(): void {
|
|
59
|
+
super.onMount();
|
|
60
|
+
const blockModel = this.context.blockModel as FilterFormBlockState;
|
|
61
|
+
const lifecycleAction = this.getLifecycleAction();
|
|
62
|
+
mountedSubmitActions.add(lifecycleAction);
|
|
63
|
+
hiddenReactionDisposers.get(lifecycleAction)?.();
|
|
64
|
+
hiddenReactionDisposers.set(
|
|
65
|
+
lifecycleAction,
|
|
66
|
+
reaction(
|
|
67
|
+
() => lifecycleAction.hidden,
|
|
68
|
+
() => syncAutoTriggerFilter(blockModel, lifecycleAction),
|
|
69
|
+
),
|
|
70
|
+
);
|
|
71
|
+
this.syncAutoTriggerFilter();
|
|
23
72
|
}
|
|
24
73
|
|
|
25
74
|
onUnmount(): void {
|
|
26
75
|
super.onUnmount();
|
|
27
|
-
|
|
76
|
+
const lifecycleAction = this.getLifecycleAction();
|
|
77
|
+
hiddenReactionDisposers.get(lifecycleAction)?.();
|
|
78
|
+
hiddenReactionDisposers.delete(lifecycleAction);
|
|
79
|
+
mountedSubmitActions.delete(lifecycleAction);
|
|
80
|
+
this.syncAutoTriggerFilter();
|
|
28
81
|
}
|
|
29
82
|
}
|
|
30
83
|
|