@nocobase/client-v2 2.2.0-alpha.1 → 2.2.0-alpha.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 +1 -3
- package/es/BaseApplication.d.ts +3 -0
- package/es/PluginSettingsManager.d.ts +33 -0
- package/es/RouteRepository.d.ts +29 -6
- package/es/RouterManager.d.ts +15 -0
- package/es/authRedirect.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/JsonTextArea.d.ts +2 -1
- package/es/components/form/ScanInput/useCodeScanner.d.ts +3 -2
- package/es/components/form/TypedVariableInput.d.ts +31 -5
- package/es/components/form/VariableJsonTextArea.d.ts +19 -0
- 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/form/index.d.ts +1 -0
- package/es/components/index.d.ts +2 -0
- package/es/entry-actions/EntryActionManager.d.ts +24 -0
- package/es/entry-actions/index.d.ts +9 -0
- package/es/flow/actions/afterSuccess.d.ts +8 -1
- package/es/flow/actions/index.d.ts +2 -2
- package/es/flow/actions/linkageRules.d.ts +2 -0
- package/es/flow/admin-shell/BaseLayoutModel.d.ts +6 -0
- package/es/flow/admin-shell/BaseLayoutRouteCoordinator.d.ts +7 -0
- package/es/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.d.ts +2 -0
- package/es/flow/admin-shell/admin-layout/AdminLayoutMenuFlowUtils.d.ts +2 -1
- package/es/flow/admin-shell/admin-layout/AdminLayoutMenuModels.d.ts +3 -0
- package/es/flow/admin-shell/admin-layout/AdminLayoutMenuUtils.d.ts +3 -2
- package/es/flow/admin-shell/admin-layout/AdminLayoutSlotModels.d.ts +5 -0
- package/es/flow/admin-shell/admin-layout/AppListRender.d.ts +2 -1
- package/es/flow/admin-shell/admin-layout/AppSwitcherActionPanelModel.d.ts +24 -0
- package/es/flow/admin-shell/admin-layout/index.d.ts +1 -0
- package/es/flow/admin-shell/admin-layout/resolveAdminRouteRuntimeTarget.d.ts +6 -0
- package/es/flow/admin-shell/admin-layout/useApplications.d.ts +7 -2
- package/es/flow/components/FieldAssignExactDatePicker.d.ts +1 -0
- package/es/flow/components/FieldAssignRulesEditor.d.ts +3 -1
- package/es/flow/components/FieldAssignValueInput.d.ts +9 -0
- package/es/flow/components/FlowRoute.d.ts +2 -2
- package/es/flow/components/RunJSValueEditor.d.ts +1 -0
- package/es/flow/components/filter/FilterGroup.d.ts +1 -0
- package/es/flow/components/filter/VariableFilterItem.d.ts +6 -1
- package/es/flow/index.d.ts +1 -0
- package/es/flow/internal/registerDeviceTypeContext.d.ts +10 -0
- package/es/flow/models/base/ActionModelCore.d.ts +2 -0
- package/es/flow/models/base/BlockGridModel.d.ts +3 -0
- package/es/flow/models/base/GridModel.d.ts +1 -1
- 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/filter-form/FilterFormBlockModel.d.ts +5 -0
- package/es/flow/models/blocks/form/FormBlockModel.d.ts +4 -0
- package/es/flow/models/blocks/form/QuickEditFormModel.d.ts +17 -2
- package/es/flow/models/blocks/form/submitHandler.d.ts +1 -1
- package/es/flow/models/blocks/form/value-runtime/rules.d.ts +21 -0
- package/es/flow/models/blocks/form/value-runtime/runtime.d.ts +30 -0
- package/es/flow/models/blocks/form/value-runtime/types.d.ts +2 -2
- package/es/flow/models/blocks/js-block/JSBlock.d.ts +1 -0
- package/es/flow/models/blocks/table/TableActionsColumnModel.d.ts +1 -0
- package/es/flow/models/blocks/table/TableBlockModel.d.ts +1 -0
- package/es/flow/models/blocks/table/TableColumnModel.d.ts +1 -0
- package/es/flow/models/blocks/table/dragSort/dragSortHooks.d.ts +1 -1
- package/es/flow/models/blocks/table/dragSort/dragSortSettings.d.ts +2 -1
- package/es/flow/models/blocks/table/dragSort/dragSortUtils.d.ts +6 -4
- package/es/flow/models/fields/AssociationFieldModel/RecordSelectFieldModel.d.ts +2 -0
- package/es/flow/models/fields/AssociationFieldModel/SubTableFieldModel/SubTableColumnModel.d.ts +6 -0
- package/es/flow/models/fields/DateTimeFieldModel/dateLimit.d.ts +15 -7
- package/es/flow/resolveViewParamsToViewList.d.ts +1 -1
- package/es/flow/routeTransientInputArgs.d.ts +14 -0
- package/es/flow/utils/dataScopeRowSnapshot.d.ts +59 -0
- package/es/flow/utils/dateTimeDisplayProps.d.ts +49 -0
- package/es/flow/utils/formValueDeps.d.ts +32 -0
- package/es/flow-compat/FieldValidation.d.ts +2 -1
- package/es/flow-compat/fieldValidationConstants.d.ts +1 -1
- package/es/flow-compat/routeTypes.d.ts +1 -0
- package/es/index.d.ts +8 -1
- package/es/index.mjs +367 -181
- package/es/utils/getRouteRuntimeVersion.d.ts +23 -0
- package/es/utils/index.d.ts +1 -0
- package/es/utils/markdownSanitize.d.ts +11 -0
- package/lib/index.js +367 -181
- package/lib/locale/languageCodes.js +3 -1
- package/package.json +9 -7
- package/src/APIClient.ts +1 -10
- package/src/Application.tsx +4 -0
- package/src/BaseApplication.tsx +13 -6
- package/src/PluginSettingsManager.ts +53 -0
- package/src/RouteRepository.ts +151 -24
- package/src/RouterManager.tsx +142 -1
- package/src/__tests__/PluginSettingsManager.test.ts +13 -0
- package/src/__tests__/RouteRepository.test.ts +239 -0
- package/src/__tests__/RouterManager.test.ts +125 -0
- package/src/__tests__/app.test.tsx +73 -0
- package/src/__tests__/authRedirect.test.ts +17 -0
- package/src/__tests__/browserChecker.test.ts +61 -0
- package/src/__tests__/exports.test.ts +16 -0
- package/src/__tests__/getRouteRuntimeVersion.test.ts +68 -0
- package/src/__tests__/nocobase-buildin-plugin-auth.test.tsx +234 -2
- package/src/__tests__/plugin-manager.test.tsx +44 -2
- package/src/__tests__/settings-center.test.tsx +40 -1
- package/src/authRedirect.ts +38 -0
- package/src/collection-field-interface/CollectionFieldInterface.ts +1 -0
- package/src/collection-field-interface/CollectionFieldInterfaceManager.ts +1 -0
- package/src/collection-manager/field-configure.ts +1 -1
- package/src/collection-manager/field-validation.ts +1 -1
- package/src/collection-manager/interfaces/id.ts +1 -1
- package/src/collection-manager/interfaces/m2m.tsx +2 -2
- package/src/collection-manager/interfaces/m2o.tsx +2 -2
- package/src/collection-manager/interfaces/nanoid.ts +1 -1
- package/src/collection-manager/interfaces/o2m.tsx +2 -2
- package/src/collection-manager/interfaces/obo.tsx +2 -2
- package/src/collection-manager/interfaces/oho.tsx +2 -2
- package/src/collection-manager/interfaces/properties/index.ts +2 -2
- package/src/collection-manager/interfaces/uuid.ts +1 -1
- package/src/components/AppComponents.tsx +19 -3
- 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 +25 -11
- 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/VariableJsonTextArea.tsx +175 -0
- package/src/components/form/__tests__/JsonTextArea.test.tsx +43 -0
- package/src/components/form/__tests__/TypedVariableInput.test.tsx +364 -12
- package/src/components/form/__tests__/VariableJsonTextArea.test.tsx +86 -0
- package/src/components/form/filter/CollectionFilter.tsx +4 -0
- package/src/components/form/filter/CollectionFilterItem.tsx +32 -7
- package/src/components/form/filter/CollectionFilterPanel.tsx +4 -0
- package/src/components/form/filter/__tests__/CollectionFilterItem.test.tsx +38 -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/index.tsx +1 -0
- package/src/components/index.ts +2 -0
- package/src/entry-actions/EntryActionManager.ts +76 -0
- package/src/entry-actions/index.ts +10 -0
- package/src/flow/FlowPage.tsx +38 -3
- package/src/flow/__tests__/FlowPage.test.tsx +201 -27
- package/src/flow/__tests__/FlowRoute.test.tsx +1181 -80
- package/src/flow/__tests__/PluginFlowEngine.test.ts +58 -0
- package/src/flow/__tests__/getKey.test.ts +7 -0
- package/src/flow/__tests__/resolveViewParamsToViewList.test.ts +34 -0
- package/src/flow/actions/__tests__/actionLinkageRules.forkProps.test.ts +115 -0
- package/src/flow/actions/__tests__/afterSuccess.test.ts +73 -0
- package/src/flow/actions/__tests__/dataScopeFilter.test.ts +120 -0
- package/src/flow/actions/__tests__/dataScopeFormValueClear.test.ts +1124 -0
- package/src/flow/actions/__tests__/fieldLinkageRules.scopeDepth.test.ts +150 -1
- package/src/flow/actions/__tests__/linkageAssignField.legacy.test.ts +135 -0
- package/src/flow/actions/__tests__/linkageRules.hiddenSync.restore.test.ts +19 -5
- package/src/flow/actions/__tests__/linkageRules.subFormSetFieldProps.test.ts +92 -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/__tests__/openView.defineProps.route.test.tsx +164 -0
- package/src/flow/actions/__tests__/subFormFieldLinkageRules.inputArgs.test.ts +2 -2
- package/src/flow/actions/afterSuccess.tsx +142 -3
- package/src/flow/actions/customVariable.tsx +1 -2
- package/src/flow/actions/dataScopeFilter.ts +20 -1
- package/src/flow/actions/dateTimeFormat.tsx +42 -28
- package/src/flow/actions/index.ts +3 -1
- package/src/flow/actions/linkageRules.tsx +209 -47
- package/src/flow/actions/linkageRulesFormValueRefresh.ts +22 -130
- package/src/flow/actions/linkageRulesRefresh.tsx +2 -6
- package/src/flow/actions/openView.tsx +59 -5
- package/src/flow/actions/runjs.tsx +2 -14
- package/src/flow/actions/validation.tsx +62 -30
- package/src/flow/admin-shell/BaseLayoutModel.tsx +149 -3
- package/src/flow/admin-shell/BaseLayoutRouteCoordinator.ts +187 -42
- package/src/flow/admin-shell/__tests__/AdminLayoutRouteCoordinator.test.ts +1020 -110
- package/src/flow/admin-shell/admin-layout/AdminLayoutComponent.tsx +74 -14
- package/src/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.test.tsx +486 -0
- package/src/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.tsx +64 -8
- package/src/flow/admin-shell/admin-layout/AdminLayoutMenuFlowUtils.ts +5 -3
- package/src/flow/admin-shell/admin-layout/AdminLayoutMenuModels.tsx +61 -9
- package/src/flow/admin-shell/admin-layout/AdminLayoutMenuUtils.tsx +71 -8
- package/src/flow/admin-shell/admin-layout/AdminLayoutModel.tsx +1 -1
- package/src/flow/admin-shell/admin-layout/AdminLayoutSlotModels.tsx +23 -9
- package/src/flow/admin-shell/admin-layout/AppListRender.tsx +13 -2
- package/src/flow/admin-shell/admin-layout/AppSwitcherActionPanelModel.tsx +289 -0
- package/src/flow/admin-shell/admin-layout/HelpLite.tsx +1 -3
- package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutComponent.test.tsx +435 -0
- package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutMenuModels.test.ts +99 -0
- package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutModel.test.tsx +518 -2
- package/src/flow/admin-shell/admin-layout/__tests__/TopbarActionsBar.test.tsx +214 -2
- package/src/flow/admin-shell/admin-layout/index.ts +1 -0
- package/src/flow/admin-shell/admin-layout/resolveAdminRouteRuntimeTarget.test.ts +20 -0
- package/src/flow/admin-shell/admin-layout/resolveAdminRouteRuntimeTarget.ts +33 -5
- package/src/flow/admin-shell/admin-layout/useApplications.tsx +81 -12
- package/src/flow/common/Markdown/Display.tsx +14 -3
- package/src/flow/common/Markdown/Edit.tsx +19 -7
- package/src/flow/common/Markdown/style.ts +4 -0
- package/src/flow/components/BlockItemCard.tsx +2 -2
- package/src/flow/components/DefaultValue.tsx +1 -2
- package/src/flow/components/DynamicFlowsIcon.tsx +447 -126
- package/src/flow/components/FieldAssignExactDatePicker.tsx +25 -11
- package/src/flow/components/FieldAssignRulesEditor.tsx +128 -21
- package/src/flow/components/FieldAssignValueInput.tsx +91 -20
- package/src/flow/components/FlowRoute.tsx +256 -53
- package/src/flow/components/RunJSValueEditor.tsx +9 -1
- package/src/flow/components/__tests__/DynamicFlowsIcon.test.tsx +148 -2
- package/src/flow/components/__tests__/FieldAssignRulesEditor.test.tsx +508 -4
- package/src/flow/components/__tests__/FieldAssignValueInput.context.test.tsx +216 -0
- package/src/flow/components/__tests__/fieldAssignOptions.test.ts +151 -3
- package/src/flow/components/code-editor/__tests__/useCodeRunner.test.tsx +2 -17
- package/src/flow/components/code-editor/hooks/useCodeRunner.ts +2 -14
- package/src/flow/components/code-editor/runjsDiagnostics.ts +8 -45
- package/src/flow/components/fieldAssignOptions.ts +155 -27
- package/src/flow/components/filter/FilterGroup.tsx +33 -5
- package/src/flow/components/filter/VariableFilterItem.tsx +158 -10
- 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 +70 -1
- package/src/flow/flows/editMarkdownFlow.tsx +1 -1
- package/src/flow/getViewDiffAndUpdateHidden.tsx +1 -0
- package/src/flow/index.ts +4 -1
- package/src/flow/internal/components/Markdown/util.ts +2 -1
- package/src/flow/internal/registerDeviceTypeContext.ts +39 -0
- package/src/flow/internal/utils/operatorSchemaHelper.ts +15 -1
- package/src/flow/models/actions/JSActionModel.tsx +2 -7
- package/src/flow/models/actions/JSCollectionActionModel.tsx +2 -7
- package/src/flow/models/actions/JSItemActionModel.tsx +2 -7
- package/src/flow/models/actions/JSRecordActionModel.tsx +2 -7
- package/src/flow/models/base/ActionModel.tsx +21 -8
- package/src/flow/models/base/ActionModelCore.tsx +11 -4
- package/src/flow/models/base/BlockGridModel.tsx +26 -0
- package/src/flow/models/base/CollectionBlockModel.tsx +6 -2
- package/src/flow/models/base/GridModel.tsx +38 -7
- package/src/flow/models/base/PageModel/PageModel.tsx +387 -50
- 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 +817 -13
- 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__/ActionModel.test.ts +83 -0
- package/src/flow/models/base/__tests__/ActionModelCore.render.test.tsx +37 -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__/GridModel.dragSnapshotContainer.test.ts +239 -1
- package/src/flow/models/base/__tests__/transformRowsToSingleColumn.test.ts +48 -0
- package/src/flow/models/blocks/filter-form/FilterFormBlockModel.tsx +59 -6
- package/src/flow/models/blocks/filter-form/FilterFormItemModel.tsx +27 -12
- package/src/flow/models/blocks/filter-form/FilterFormJSActionModel.tsx +2 -7
- package/src/flow/models/blocks/filter-form/__tests__/FilterFormItemModel.defineChildren.test.ts +36 -0
- package/src/flow/models/blocks/filter-form/__tests__/defaultValues.wiring.test.ts +143 -4
- package/src/flow/models/blocks/filter-form/fields/FilterFormCustomFieldModel.tsx +1 -1
- package/src/flow/models/blocks/filter-manager/flow-actions/__tests__/customizeFilterRender.test.tsx +56 -1
- package/src/flow/models/blocks/form/EditFormModel.tsx +1 -0
- package/src/flow/models/blocks/form/FormActionModel.tsx +1 -1
- package/src/flow/models/blocks/form/FormBlockModel.tsx +7 -0
- package/src/flow/models/blocks/form/JSFormActionModel.tsx +2 -7
- package/src/flow/models/blocks/form/QuickEditFormModel.tsx +189 -36
- package/src/flow/models/blocks/form/__tests__/FormBlockModel.test.tsx +17 -0
- package/src/flow/models/blocks/form/__tests__/QuickEditFormModel.quickEdit.test.ts +350 -2
- package/src/flow/models/blocks/form/__tests__/submitHandler.test.ts +54 -1
- package/src/flow/models/blocks/form/submitHandler.ts +17 -3
- package/src/flow/models/blocks/form/value-runtime/__tests__/runtime.test.ts +940 -75
- package/src/flow/models/blocks/form/value-runtime/rules.ts +445 -13
- package/src/flow/models/blocks/form/value-runtime/runtime.ts +348 -13
- package/src/flow/models/blocks/form/value-runtime/types.ts +2 -2
- package/src/flow/models/blocks/js-block/JSBlock.tsx +225 -9
- package/src/flow/models/blocks/js-block/__tests__/JSBlockModel.test.tsx +150 -0
- package/src/flow/models/blocks/table/JSColumnModel.tsx +1 -9
- package/src/flow/models/blocks/table/TableActionsColumnModel.tsx +38 -14
- package/src/flow/models/blocks/table/TableBlockModel.tsx +42 -19
- package/src/flow/models/blocks/table/TableColumnModel.tsx +72 -6
- package/src/flow/models/blocks/table/__tests__/TableActionsColumnModel.test.tsx +111 -1
- package/src/flow/models/blocks/table/__tests__/TableBlockModel.dragSort.test.ts +127 -0
- package/src/flow/models/blocks/table/__tests__/TableBlockModel.mobileSettingsButtons.test.tsx +78 -0
- package/src/flow/models/blocks/table/__tests__/TableBlockModel.quickEditRefresh.test.ts +12 -0
- package/src/flow/models/blocks/table/__tests__/TableBlockModel.rowSelection.test.tsx +1 -0
- package/src/flow/models/blocks/table/__tests__/TableColumnModel.test.tsx +243 -1
- package/src/flow/models/blocks/table/dragSort/dragSortHooks.tsx +28 -17
- package/src/flow/models/blocks/table/dragSort/dragSortSettings.ts +13 -6
- package/src/flow/models/blocks/table/dragSort/dragSortUtils.ts +15 -2
- package/src/flow/models/fields/AssociationFieldModel/AssociationFieldModel.tsx +1 -1
- package/src/flow/models/fields/AssociationFieldModel/PopupSubTableFieldModel/PopupSubTableFieldModel.tsx +31 -7
- package/src/flow/models/fields/AssociationFieldModel/RecordSelectFieldModel.tsx +61 -17
- package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/SubTableColumnModel.tsx +141 -19
- package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/SubTableField.tsx +13 -1
- package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/__tests__/SubTableColumnModel.rowRecord.test.ts +197 -0
- package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/__tests__/SubTableFieldModel.reset.test.ts +180 -0
- package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/index.tsx +6 -4
- package/src/flow/models/fields/AssociationFieldModel/__tests__/AssociationFieldModel.updateAssociation.test.ts +72 -0
- package/src/flow/models/fields/AssociationFieldModel/__tests__/RecordPickerFieldModel.itemContext.test.ts +23 -0
- package/src/flow/models/fields/ClickableFieldModel.tsx +5 -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/DisplayDateTimeFieldModel.tsx +29 -1
- package/src/flow/models/fields/InputFieldModel.tsx +40 -2
- package/src/flow/models/fields/JSEditableFieldModel.tsx +2 -11
- package/src/flow/models/fields/JSFieldModel.tsx +2 -7
- package/src/flow/models/fields/JSItemModel.tsx +2 -14
- package/src/flow/models/fields/SelectFieldModel.tsx +6 -4
- package/src/flow/models/fields/TextareaFieldModel.tsx +72 -3
- package/src/flow/models/fields/VariableFieldFormModel.tsx +3 -3
- package/src/flow/models/fields/__tests__/DisplayDateTimeFieldModel.test.tsx +96 -0
- package/src/flow/models/fields/__tests__/InputFieldModel.test.tsx +117 -1
- package/src/flow/models/fields/__tests__/SelectFieldModel.test.tsx +43 -0
- package/src/flow/models/fields/__tests__/TextareaFieldModel.test.tsx +131 -0
- package/src/flow/models/fields/__tests__/VariableFieldFormModel.test.tsx +51 -0
- package/src/flow/models/fields/mobile-components/MobileLazySelect.tsx +20 -10
- package/src/flow/models/fields/mobile-components/MobileSelect.tsx +24 -12
- package/src/flow/models/topbar/TopbarActionModel.tsx +168 -10
- package/src/flow/resolveViewParamsToViewList.tsx +11 -3
- package/src/flow/routeTransientInputArgs.ts +27 -0
- package/src/flow/utils/__tests__/dateTimeFormat.test.ts +300 -0
- package/src/flow/utils/dataScopeFormValueClear.ts +219 -81
- package/src/flow/utils/dataScopeRowSnapshot.ts +616 -0
- package/src/flow/utils/dateTimeDisplayProps.ts +135 -0
- package/src/flow/utils/formValueDeps.ts +170 -0
- package/src/flow-compat/FieldValidation.tsx +122 -60
- package/src/flow-compat/Popover.tsx +43 -4
- package/src/flow-compat/__tests__/Popover.test.tsx +34 -0
- package/src/flow-compat/fieldValidationConstants.ts +1 -1
- package/src/flow-compat/routeTypes.ts +1 -0
- package/src/index.ts +14 -1
- package/src/layout-manager/__tests__/LayoutRoute.test.tsx +41 -1
- package/src/locale/languageCodes.ts +3 -1
- package/src/nocobase-buildin-plugin/index.tsx +63 -15
- package/src/settings-center/AdminSettingsLayout.tsx +10 -2
- package/src/settings-center/SystemSettingsPage.tsx +1 -2
- package/src/settings-center/plugin-manager/PluginCard.tsx +2 -2
- package/src/settings-center/plugin-manager/index.tsx +3 -0
- package/src/settings-center/utils.tsx +0 -6
- package/src/utils/getRouteRuntimeVersion.ts +185 -0
- package/src/utils/index.tsx +1 -0
- package/src/utils/markdownSanitize.ts +88 -0
|
@@ -15,9 +15,10 @@ import {
|
|
|
15
15
|
DndProvider,
|
|
16
16
|
DragHandler,
|
|
17
17
|
Droppable,
|
|
18
|
+
isCtxDateExpression,
|
|
18
19
|
isRunJSValue,
|
|
19
20
|
normalizeRunJSValue,
|
|
20
|
-
|
|
21
|
+
parseCtxDateExpression,
|
|
21
22
|
tExpr,
|
|
22
23
|
FlowModelRenderer,
|
|
23
24
|
FlowSettingsButton,
|
|
@@ -45,6 +46,15 @@ import { normalizeFilterValueByOperator } from './valueNormalization';
|
|
|
45
46
|
|
|
46
47
|
const RELATION_FIELD_TYPES = ['belongsTo', 'hasOne', 'hasMany', 'belongsToMany', 'belongsToArray'];
|
|
47
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
|
+
]);
|
|
48
58
|
|
|
49
59
|
function getFilterFormFieldMetaType(field: CollectionField) {
|
|
50
60
|
if (RELATION_FIELD_TYPES.includes(field.type)) {
|
|
@@ -67,6 +77,14 @@ function getFilterFormFieldMetaType(field: CollectionField) {
|
|
|
67
77
|
}
|
|
68
78
|
}
|
|
69
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
|
+
|
|
70
88
|
function shouldShowFilterFormFieldMeta(field: CollectionField) {
|
|
71
89
|
return Boolean(field?.interface);
|
|
72
90
|
}
|
|
@@ -231,6 +249,7 @@ export class FilterFormBlockModel extends FilterBlockModel<{
|
|
|
231
249
|
private initialDefaultsPromise?: Promise<void>;
|
|
232
250
|
private initialRefreshHandledTargetIds = new Set<string>();
|
|
233
251
|
private lastDefaultValueByFieldName = new Map<string, any>();
|
|
252
|
+
private userEditedFieldNames = new Set<string>();
|
|
234
253
|
private defaultValuesRefreshSeq = 0;
|
|
235
254
|
|
|
236
255
|
get form() {
|
|
@@ -431,11 +450,34 @@ 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));
|
|
437
457
|
}
|
|
438
458
|
|
|
459
|
+
private canApplyFormOverrideValue(name: string, force?: boolean) {
|
|
460
|
+
if (force) return true;
|
|
461
|
+
return !this.userEditedFieldNames.has(name);
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
private normalizeFieldValueMode(mode: unknown): 'default' | 'assign' | 'override' {
|
|
465
|
+
if (mode === 'assign') return 'assign';
|
|
466
|
+
if (mode === 'override') return 'override';
|
|
467
|
+
return 'default';
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
private markFilterFormUserEditedFields(changedValues: any) {
|
|
471
|
+
if (!changedValues || typeof changedValues !== 'object' || Array.isArray(changedValues)) return;
|
|
472
|
+
for (const name of Object.keys(changedValues)) {
|
|
473
|
+
this.userEditedFieldNames.add(String(name));
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
private resetFilterFormUserEditedFields() {
|
|
478
|
+
this.userEditedFieldNames.clear();
|
|
479
|
+
}
|
|
480
|
+
|
|
439
481
|
private async matchDefaultValueCondition(condition: any) {
|
|
440
482
|
if (!condition) return true;
|
|
441
483
|
|
|
@@ -458,18 +500,27 @@ export class FilterFormBlockModel extends FilterBlockModel<{
|
|
|
458
500
|
if (!form) return appliedValues;
|
|
459
501
|
|
|
460
502
|
const force = options?.force === true;
|
|
503
|
+
if (force) {
|
|
504
|
+
this.resetFilterFormUserEditedFields();
|
|
505
|
+
}
|
|
506
|
+
|
|
461
507
|
const params = this.getStepParams?.('formFilterBlockModelSettings', 'defaultValues');
|
|
462
508
|
const rules = (params?.value || []) as any[];
|
|
463
509
|
if (!Array.isArray(rules) || rules.length === 0) return appliedValues;
|
|
464
510
|
|
|
465
|
-
const resolveValue = async (raw: any) => {
|
|
511
|
+
const resolveValue = async (raw: any, operator?: string) => {
|
|
466
512
|
// RunJS support
|
|
467
513
|
if (isRunJSValue(raw)) {
|
|
468
514
|
const { code, version } = normalizeRunJSValue(raw);
|
|
469
|
-
const ret = await
|
|
515
|
+
const ret = await this.context.runjs(code, undefined, { version });
|
|
470
516
|
return ret?.success ? ret.value : undefined;
|
|
471
517
|
}
|
|
472
518
|
|
|
519
|
+
const parsedDateFilterValue = parseDateFilterDefaultValue(operator, raw);
|
|
520
|
+
if (typeof parsedDateFilterValue !== 'undefined') {
|
|
521
|
+
return parsedDateFilterValue;
|
|
522
|
+
}
|
|
523
|
+
|
|
473
524
|
return await (this.context as any).resolveJsonTemplate?.(raw);
|
|
474
525
|
};
|
|
475
526
|
|
|
@@ -493,14 +544,15 @@ export class FilterFormBlockModel extends FilterBlockModel<{
|
|
|
493
544
|
|
|
494
545
|
const current = (form as any).getFieldValue?.(name);
|
|
495
546
|
|
|
496
|
-
const
|
|
547
|
+
const operator = getDefaultOperator(itemModel as any);
|
|
548
|
+
const resolved = await resolveValue(rule.value, operator);
|
|
497
549
|
if (options?.refreshSeq && options.refreshSeq !== this.defaultValuesRefreshSeq) return appliedValues;
|
|
498
550
|
if (typeof resolved === 'undefined') continue;
|
|
499
551
|
|
|
500
|
-
const operator = getDefaultOperator(itemModel as any);
|
|
501
552
|
const normalized = normalizeFilterValueByOperator(operator, resolved);
|
|
502
|
-
const mode =
|
|
553
|
+
const mode = this.normalizeFieldValueMode(rule.mode);
|
|
503
554
|
if (mode === 'default' && !this.canApplyFormDefaultValue(String(name), current, force)) continue;
|
|
555
|
+
if (mode === 'override' && !this.canApplyFormOverrideValue(String(name), force)) continue;
|
|
504
556
|
if (isEqual(current, normalized)) {
|
|
505
557
|
if (mode === 'default') {
|
|
506
558
|
this.lastDefaultValueByFieldName.set(String(name), normalized);
|
|
@@ -527,6 +579,7 @@ export class FilterFormBlockModel extends FilterBlockModel<{
|
|
|
527
579
|
}
|
|
528
580
|
|
|
529
581
|
private handleFilterFormValuesChange(changedValues: any, allValues: any) {
|
|
582
|
+
this.markFilterFormUserEditedFields(changedValues);
|
|
530
583
|
const refreshSeq = ++this.defaultValuesRefreshSeq;
|
|
531
584
|
void (async () => {
|
|
532
585
|
const appliedValues = await this.applyFormDefaultValues({ refreshSeq });
|
|
@@ -62,9 +62,25 @@ function isRecord(value: unknown): value is Record<string, unknown> {
|
|
|
62
62
|
return !!value && typeof value === 'object' && !Array.isArray(value);
|
|
63
63
|
}
|
|
64
64
|
|
|
65
|
+
interface CollectionFieldWithAssociationMarker {
|
|
66
|
+
isAssociationField?: () => boolean;
|
|
67
|
+
target?: unknown;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function hasAssociationMarker(value: unknown): value is CollectionFieldWithAssociationMarker {
|
|
71
|
+
return isRecord(value) && (typeof value.isAssociationField === 'function' || 'target' in value);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const isAssociationCollectionField = (collectionField: unknown) => {
|
|
75
|
+
if (!hasAssociationMarker(collectionField)) {
|
|
76
|
+
return false;
|
|
77
|
+
}
|
|
78
|
+
return collectionField.isAssociationField ? collectionField.isAssociationField() : Boolean(collectionField.target);
|
|
79
|
+
};
|
|
80
|
+
|
|
65
81
|
const normalizeAssociationDefaultFilterValue = (value: any, fieldModel: any) => {
|
|
66
82
|
const collectionField = fieldModel?.context?.collectionField;
|
|
67
|
-
if (!collectionField
|
|
83
|
+
if (!isAssociationCollectionField(collectionField)) {
|
|
68
84
|
return value;
|
|
69
85
|
}
|
|
70
86
|
|
|
@@ -171,8 +187,7 @@ const buildFilterFormFieldItem = ({
|
|
|
171
187
|
if (!binding) {
|
|
172
188
|
return;
|
|
173
189
|
}
|
|
174
|
-
const isAssociation =
|
|
175
|
-
typeof field?.isAssociationField === 'function' ? field.isAssociationField() : Boolean(field?.target);
|
|
190
|
+
const isAssociation = isAssociationCollectionField(field);
|
|
176
191
|
const fieldModel =
|
|
177
192
|
isAssociation && ctxWithFlags.engine?.getModelClass?.('FilterFormRecordSelectFieldModel')
|
|
178
193
|
? 'FilterFormRecordSelectFieldModel'
|
|
@@ -507,10 +522,7 @@ export class FilterFormItemModel extends FilterableItemModel<{
|
|
|
507
522
|
const formValue = this.context.form?.getFieldValue(this.props.name);
|
|
508
523
|
const modelValue = fieldModel.getFilterValue ? fieldModel.getFilterValue() : formValue;
|
|
509
524
|
const collectionField = (fieldModel as any)?.context?.collectionField;
|
|
510
|
-
const isAssociationField =
|
|
511
|
-
typeof collectionField?.isAssociationField === 'function'
|
|
512
|
-
? collectionField.isAssociationField()
|
|
513
|
-
: !!collectionField?.target;
|
|
525
|
+
const isAssociationField = isAssociationCollectionField(collectionField);
|
|
514
526
|
const shouldUseFormValue =
|
|
515
527
|
isAssociationField &&
|
|
516
528
|
!this.mounted &&
|
|
@@ -547,11 +559,7 @@ export class FilterFormItemModel extends FilterableItemModel<{
|
|
|
547
559
|
return value;
|
|
548
560
|
}
|
|
549
561
|
const collectionField = (fieldModel as any)?.context?.collectionField;
|
|
550
|
-
|
|
551
|
-
typeof collectionField?.isAssociationField === 'function'
|
|
552
|
-
? collectionField.isAssociationField()
|
|
553
|
-
: !!collectionField?.target;
|
|
554
|
-
if (!isAssociation) {
|
|
562
|
+
if (!isAssociationCollectionField(collectionField)) {
|
|
555
563
|
return value;
|
|
556
564
|
}
|
|
557
565
|
const normalizedFieldNames = normalizeAssociationFieldNames(
|
|
@@ -798,6 +806,13 @@ FilterFormItemModel.registerFlow({
|
|
|
798
806
|
},
|
|
799
807
|
defaultOperator: {
|
|
800
808
|
use: 'defaultOperator',
|
|
809
|
+
hideInSettings(ctx) {
|
|
810
|
+
const collectionField =
|
|
811
|
+
ctx.collectionField ||
|
|
812
|
+
ctx.model?.context?.collectionField ||
|
|
813
|
+
ctx.model?.subModels?.field?.context?.collectionField;
|
|
814
|
+
return isAssociationCollectionField(collectionField);
|
|
815
|
+
},
|
|
801
816
|
},
|
|
802
817
|
operatorComponentProps: {
|
|
803
818
|
use: 'operatorComponentProps',
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import { tExpr } from '@nocobase/flow-engine';
|
|
11
11
|
import { CodeEditor } from '../../../components/code-editor';
|
|
12
12
|
import { FilterFormActionModel } from './FilterFormActionModel';
|
|
13
13
|
import { resolveRunJsParams } from '../../utils/resolveRunJsParams';
|
|
@@ -60,12 +60,7 @@ FilterFormJSActionModel.registerFlow({
|
|
|
60
60
|
},
|
|
61
61
|
async handler(ctx, params) {
|
|
62
62
|
const { code, version } = resolveRunJsParams(ctx, params);
|
|
63
|
-
|
|
64
|
-
await ctx.runjs(
|
|
65
|
-
code,
|
|
66
|
-
{ window: createSafeWindow({ navigator }), document: createSafeDocument(), navigator },
|
|
67
|
-
{ version },
|
|
68
|
-
);
|
|
63
|
+
await ctx.runjs(code, undefined, { version });
|
|
69
64
|
},
|
|
70
65
|
},
|
|
71
66
|
},
|
package/src/flow/models/blocks/filter-form/__tests__/FilterFormItemModel.defineChildren.test.ts
CHANGED
|
@@ -33,6 +33,42 @@ class DummyCollectionBlockModel extends CollectionBlockModel {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
describe('FilterFormItemModel defineChildren association fields', () => {
|
|
36
|
+
it('hides default operator setting for association filter fields', () => {
|
|
37
|
+
const engine = new FlowEngine();
|
|
38
|
+
engine.registerModels({
|
|
39
|
+
FilterFormItemModel,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
const filterItem = engine.createModel<FilterFormItemModel>({
|
|
43
|
+
uid: 'association-filter-item-settings',
|
|
44
|
+
use: 'FilterFormItemModel',
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
const defaultOperatorStep = filterItem.getFlow('filterFormItemSettings')?.steps?.defaultOperator as {
|
|
48
|
+
hideInSettings?: (ctx: {
|
|
49
|
+
collectionField?: unknown;
|
|
50
|
+
model?: {
|
|
51
|
+
subModels?: {
|
|
52
|
+
field?: {
|
|
53
|
+
context?: {
|
|
54
|
+
collectionField?: unknown;
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
};
|
|
59
|
+
}) => boolean;
|
|
60
|
+
};
|
|
61
|
+
expect(defaultOperatorStep?.hideInSettings?.({ collectionField: { isAssociationField: () => true } })).toBe(true);
|
|
62
|
+
expect(
|
|
63
|
+
defaultOperatorStep?.hideInSettings?.({
|
|
64
|
+
model: { subModels: { field: { context: { collectionField: { target: 'departments' } } } } },
|
|
65
|
+
}),
|
|
66
|
+
).toBe(true);
|
|
67
|
+
expect(defaultOperatorStep?.hideInSettings?.({ collectionField: { interface: 'input', type: 'string' } })).toBe(
|
|
68
|
+
false,
|
|
69
|
+
);
|
|
70
|
+
});
|
|
71
|
+
|
|
36
72
|
it('groups association target fields and supports recursive paths', async () => {
|
|
37
73
|
const engine = new FlowEngine();
|
|
38
74
|
engine.registerModels({
|
|
@@ -17,7 +17,15 @@ import { FilterFormBlockModel } from '../FilterFormBlockModel';
|
|
|
17
17
|
function resolveTemplateValue(raw: any, values: Record<string, any>): any {
|
|
18
18
|
if (typeof raw === 'string') {
|
|
19
19
|
const matched = raw.match(/^\{\{\s*ctx\.formValues\.([^}]+?)\s*\}\}$/);
|
|
20
|
-
|
|
20
|
+
if (matched) {
|
|
21
|
+
return values[matched[1]];
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (/^\{\{\s*ctx\.date\.relative\.past\.day\.n7\s*\}\}$/.test(raw)) {
|
|
25
|
+
return '2026-06-15';
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
return raw;
|
|
21
29
|
}
|
|
22
30
|
if (Array.isArray(raw)) {
|
|
23
31
|
return raw.map((item) => resolveTemplateValue(item, values));
|
|
@@ -30,7 +38,7 @@ function resolveTemplateValue(raw: any, values: Record<string, any>): any {
|
|
|
30
38
|
|
|
31
39
|
function createFilterFormDefaultValuesModel(rules: any[], initialValues: Record<string, any> = {}) {
|
|
32
40
|
const values = { ...initialValues };
|
|
33
|
-
const createItem = (fieldPath: string, uid: string) => ({
|
|
41
|
+
const createItem = (fieldPath: string, uid: string, operator?: string) => ({
|
|
34
42
|
uid,
|
|
35
43
|
fieldPath,
|
|
36
44
|
props: { name: `${fieldPath}_${uid}` },
|
|
@@ -44,12 +52,13 @@ function createFilterFormDefaultValuesModel(rules: any[], initialValues: Record<
|
|
|
44
52
|
return undefined;
|
|
45
53
|
},
|
|
46
54
|
subModels: {
|
|
47
|
-
field: {},
|
|
55
|
+
field: operator ? { operator } : {},
|
|
48
56
|
},
|
|
49
57
|
});
|
|
50
58
|
const model = {
|
|
51
59
|
defaultValuesRefreshSeq: 0,
|
|
52
60
|
lastDefaultValueByFieldName: new Map<string, any>(),
|
|
61
|
+
userEditedFieldNames: new Set<string>(),
|
|
53
62
|
form: {
|
|
54
63
|
getFieldsValue: () => ({ ...values }),
|
|
55
64
|
getFieldValue: (name: string) => values[name],
|
|
@@ -75,7 +84,11 @@ function createFilterFormDefaultValuesModel(rules: any[], initialValues: Record<
|
|
|
75
84
|
subModels: {
|
|
76
85
|
grid: {
|
|
77
86
|
subModels: {
|
|
78
|
-
items: [
|
|
87
|
+
items: [
|
|
88
|
+
createItem('nickname', 'nick'),
|
|
89
|
+
createItem('username', 'user'),
|
|
90
|
+
createItem('birthdate_tz', 'birthdate', '$dateOn'),
|
|
91
|
+
],
|
|
79
92
|
},
|
|
80
93
|
},
|
|
81
94
|
},
|
|
@@ -86,6 +99,10 @@ function createFilterFormDefaultValuesModel(rules: any[], initialValues: Record<
|
|
|
86
99
|
return undefined;
|
|
87
100
|
}),
|
|
88
101
|
canApplyFormDefaultValue: (FilterFormBlockModel.prototype as any).canApplyFormDefaultValue,
|
|
102
|
+
canApplyFormOverrideValue: (FilterFormBlockModel.prototype as any).canApplyFormOverrideValue,
|
|
103
|
+
normalizeFieldValueMode: (FilterFormBlockModel.prototype as any).normalizeFieldValueMode,
|
|
104
|
+
markFilterFormUserEditedFields: (FilterFormBlockModel.prototype as any).markFilterFormUserEditedFields,
|
|
105
|
+
resetFilterFormUserEditedFields: (FilterFormBlockModel.prototype as any).resetFilterFormUserEditedFields,
|
|
89
106
|
matchDefaultValueCondition: (FilterFormBlockModel.prototype as any).matchDefaultValueCondition,
|
|
90
107
|
applyFormDefaultValues: FilterFormBlockModel.prototype.applyFormDefaultValues,
|
|
91
108
|
handleFilterFormValuesChange: (FilterFormBlockModel.prototype as any).handleFilterFormValuesChange,
|
|
@@ -296,6 +313,40 @@ describe('filter-form defaultValues wiring', () => {
|
|
|
296
313
|
expect(values.username_user).toBe('Manual');
|
|
297
314
|
});
|
|
298
315
|
|
|
316
|
+
it('does not reapply a filter form default value after user clears the field', async () => {
|
|
317
|
+
const { model, values } = createFilterFormDefaultValuesModel([
|
|
318
|
+
{
|
|
319
|
+
key: 'username-default',
|
|
320
|
+
enable: true,
|
|
321
|
+
targetPath: 'username',
|
|
322
|
+
mode: 'default',
|
|
323
|
+
value: 'admin',
|
|
324
|
+
},
|
|
325
|
+
]);
|
|
326
|
+
|
|
327
|
+
await FilterFormBlockModel.prototype.applyFormDefaultValues.call(model as any);
|
|
328
|
+
expect(values.username_user).toBe('admin');
|
|
329
|
+
|
|
330
|
+
values.username_user = undefined;
|
|
331
|
+
(model as any).handleFilterFormValuesChange({ username_user: undefined }, { username_user: undefined });
|
|
332
|
+
|
|
333
|
+
await waitFor(() => {
|
|
334
|
+
expect(model.dispatchEvent).toHaveBeenCalledWith(
|
|
335
|
+
'formValuesChange',
|
|
336
|
+
{
|
|
337
|
+
changedValues: {
|
|
338
|
+
username_user: undefined,
|
|
339
|
+
},
|
|
340
|
+
allValues: {
|
|
341
|
+
username_user: undefined,
|
|
342
|
+
},
|
|
343
|
+
},
|
|
344
|
+
{ debounce: true },
|
|
345
|
+
);
|
|
346
|
+
});
|
|
347
|
+
expect(values.username_user).toBeUndefined();
|
|
348
|
+
});
|
|
349
|
+
|
|
299
350
|
it('applies fixed values even when the target filter field already has a value', async () => {
|
|
300
351
|
const { model, values } = createFilterFormDefaultValuesModel(
|
|
301
352
|
[
|
|
@@ -315,6 +366,94 @@ describe('filter-form defaultValues wiring', () => {
|
|
|
315
366
|
expect(values.username_user).toBe('Bob');
|
|
316
367
|
});
|
|
317
368
|
|
|
369
|
+
it('preserves relative date descriptors for date filter default values', async () => {
|
|
370
|
+
const { model, values } = createFilterFormDefaultValuesModel([
|
|
371
|
+
{
|
|
372
|
+
key: 'birthdate-default',
|
|
373
|
+
enable: true,
|
|
374
|
+
targetPath: 'birthdate_tz',
|
|
375
|
+
mode: 'assign',
|
|
376
|
+
value: '{{ ctx.date.relative.past.day.n7 }}',
|
|
377
|
+
},
|
|
378
|
+
]);
|
|
379
|
+
|
|
380
|
+
await FilterFormBlockModel.prototype.applyFormDefaultValues.call(model as any);
|
|
381
|
+
|
|
382
|
+
expect(values.birthdate_tz_birthdate).toEqual({ type: 'past', unit: 'day', number: 7 });
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
it('applies override values until the target filter field is changed by user', async () => {
|
|
386
|
+
const { model, values } = createFilterFormDefaultValuesModel(
|
|
387
|
+
[
|
|
388
|
+
{
|
|
389
|
+
key: 'username-override',
|
|
390
|
+
enable: true,
|
|
391
|
+
targetPath: 'username',
|
|
392
|
+
mode: 'override',
|
|
393
|
+
value: '{{ ctx.formValues.nickname_nick }}',
|
|
394
|
+
},
|
|
395
|
+
],
|
|
396
|
+
{ nickname_nick: 'Bob', username_user: 'Manual' },
|
|
397
|
+
);
|
|
398
|
+
|
|
399
|
+
await FilterFormBlockModel.prototype.applyFormDefaultValues.call(model as any);
|
|
400
|
+
expect(values.username_user).toBe('Bob');
|
|
401
|
+
|
|
402
|
+
values.nickname_nick = 'Carol';
|
|
403
|
+
model.defaultValuesRefreshSeq += 1;
|
|
404
|
+
await FilterFormBlockModel.prototype.applyFormDefaultValues.call(model as any, {
|
|
405
|
+
refreshSeq: model.defaultValuesRefreshSeq,
|
|
406
|
+
});
|
|
407
|
+
expect(values.username_user).toBe('Carol');
|
|
408
|
+
|
|
409
|
+
values.username_user = 'User value';
|
|
410
|
+
(model as any).handleFilterFormValuesChange(
|
|
411
|
+
{ username_user: 'User value' },
|
|
412
|
+
{ nickname_nick: 'Carol', username_user: 'User value' },
|
|
413
|
+
);
|
|
414
|
+
|
|
415
|
+
await waitFor(() => {
|
|
416
|
+
expect(values.username_user).toBe('User value');
|
|
417
|
+
});
|
|
418
|
+
|
|
419
|
+
values.nickname_nick = 'Dora';
|
|
420
|
+
model.defaultValuesRefreshSeq += 1;
|
|
421
|
+
await FilterFormBlockModel.prototype.applyFormDefaultValues.call(model as any, {
|
|
422
|
+
refreshSeq: model.defaultValuesRefreshSeq,
|
|
423
|
+
});
|
|
424
|
+
expect(values.username_user).toBe('User value');
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
it('clears filter form user-edited override state on forced apply', async () => {
|
|
428
|
+
const { model, values } = createFilterFormDefaultValuesModel(
|
|
429
|
+
[
|
|
430
|
+
{
|
|
431
|
+
key: 'username-override',
|
|
432
|
+
enable: true,
|
|
433
|
+
targetPath: 'username',
|
|
434
|
+
mode: 'override',
|
|
435
|
+
condition: {
|
|
436
|
+
logic: '$and',
|
|
437
|
+
items: [{ path: '{{ ctx.formValues.nickname_nick }}', operator: '$eq', value: 'allow' }],
|
|
438
|
+
},
|
|
439
|
+
value: '{{ ctx.formValues.nickname_nick }}',
|
|
440
|
+
},
|
|
441
|
+
],
|
|
442
|
+
{ nickname_nick: 'deny', username_user: 'User value' },
|
|
443
|
+
);
|
|
444
|
+
|
|
445
|
+
model.userEditedFieldNames.add('username_user');
|
|
446
|
+
|
|
447
|
+
await FilterFormBlockModel.prototype.applyFormDefaultValues.call(model as any, { force: true });
|
|
448
|
+
expect(values.username_user).toBe('User value');
|
|
449
|
+
expect(model.userEditedFieldNames.has('username_user')).toBe(false);
|
|
450
|
+
|
|
451
|
+
values.nickname_nick = 'allow';
|
|
452
|
+
await FilterFormBlockModel.prototype.applyFormDefaultValues.call(model as any);
|
|
453
|
+
|
|
454
|
+
expect(values.username_user).toBe('allow');
|
|
455
|
+
});
|
|
456
|
+
|
|
318
457
|
it('skips filter form field values when the rule condition does not match', async () => {
|
|
319
458
|
const { model, values } = createFilterFormDefaultValuesModel(
|
|
320
459
|
[
|
|
@@ -210,7 +210,7 @@ FilterFormCustomFieldModel.registerFlow({
|
|
|
210
210
|
'x-decorator': 'FormItem',
|
|
211
211
|
required: true,
|
|
212
212
|
description:
|
|
213
|
-
'{{t("Randomly generated and can be modified. Support letters, numbers and underscores, must start with
|
|
213
|
+
'{{t("Randomly generated and can be modified. Support letters, numbers and underscores, must start with a letter.")}}',
|
|
214
214
|
},
|
|
215
215
|
source: {
|
|
216
216
|
type: 'array',
|
package/src/flow/models/blocks/filter-manager/flow-actions/__tests__/customizeFilterRender.test.tsx
CHANGED
|
@@ -18,12 +18,23 @@ type TestFieldModel = {
|
|
|
18
18
|
setupReactiveRender: ReturnType<typeof vi.fn>;
|
|
19
19
|
_reactiveWrapperCache?: unknown;
|
|
20
20
|
__originalRender?: () => React.ReactNode;
|
|
21
|
+
translate?: (text: string) => string;
|
|
21
22
|
};
|
|
22
23
|
|
|
23
24
|
const MultipleKeywordsInput = (props: Record<string, unknown>) => {
|
|
24
25
|
return <div data-testid="multiple-keywords-input" {...props} />;
|
|
25
26
|
};
|
|
26
27
|
|
|
28
|
+
const Select = (props: Record<string, unknown>) => {
|
|
29
|
+
return <div data-testid="select" {...props} />;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
function mockT(text: string) {
|
|
33
|
+
if (text === '{{t("Yes")}}') return '是';
|
|
34
|
+
if (text === '{{t("No")}}') return '否';
|
|
35
|
+
return text;
|
|
36
|
+
}
|
|
37
|
+
|
|
27
38
|
function createFieldModel() {
|
|
28
39
|
return {
|
|
29
40
|
props: {
|
|
@@ -52,7 +63,10 @@ function createFilterItemModel({
|
|
|
52
63
|
collectionField,
|
|
53
64
|
context: {
|
|
54
65
|
app: {
|
|
55
|
-
getComponent: (name: string) =>
|
|
66
|
+
getComponent: (name: string) => {
|
|
67
|
+
if (name === 'MultipleKeywordsInput') return MultipleKeywordsInput;
|
|
68
|
+
if (name === 'Select') return Select;
|
|
69
|
+
},
|
|
56
70
|
},
|
|
57
71
|
collectionField,
|
|
58
72
|
},
|
|
@@ -112,6 +126,47 @@ describe('customizeFilterRender action', () => {
|
|
|
112
126
|
expect((rerenderedElement as React.ReactElement).props.placeholder).toBe('updated runtime placeholder');
|
|
113
127
|
});
|
|
114
128
|
|
|
129
|
+
it('translates operator schema select options', () => {
|
|
130
|
+
const fieldModel = {
|
|
131
|
+
...createFieldModel(),
|
|
132
|
+
translate: mockT,
|
|
133
|
+
};
|
|
134
|
+
const model = createFilterItemModel({
|
|
135
|
+
fieldModel,
|
|
136
|
+
operator: '$isTruly',
|
|
137
|
+
collectionField: {
|
|
138
|
+
interface: 'checkbox',
|
|
139
|
+
type: 'boolean',
|
|
140
|
+
filterable: {
|
|
141
|
+
operators: [
|
|
142
|
+
{
|
|
143
|
+
label: '{{t("Yes")}}',
|
|
144
|
+
value: '$isTruly',
|
|
145
|
+
schema: {
|
|
146
|
+
'x-component': 'Select',
|
|
147
|
+
'x-component-props': {
|
|
148
|
+
options: [
|
|
149
|
+
{ label: '{{t("Yes")}}', value: true },
|
|
150
|
+
{ label: '{{t("No")}}', value: false },
|
|
151
|
+
],
|
|
152
|
+
},
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
],
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
customizeFilterRender.handler?.({ model } as any);
|
|
161
|
+
|
|
162
|
+
const element = fieldModel.render();
|
|
163
|
+
expect((element as React.ReactElement).type).toBe(Select);
|
|
164
|
+
expect((element as React.ReactElement).props.options).toEqual([
|
|
165
|
+
{ label: '是', value: true },
|
|
166
|
+
{ label: '否', value: false },
|
|
167
|
+
]);
|
|
168
|
+
});
|
|
169
|
+
|
|
115
170
|
it('restores original render when switching to an operator without a schema component', () => {
|
|
116
171
|
const fieldModel = createFieldModel();
|
|
117
172
|
const originalRender = fieldModel.render;
|
|
@@ -117,7 +117,7 @@ FormSubmitActionModel.registerFlow({
|
|
|
117
117
|
try {
|
|
118
118
|
ctx.model.setProps('loading', true);
|
|
119
119
|
const { submitHandler } = await import('./submitHandler');
|
|
120
|
-
await submitHandler(ctx, params);
|
|
120
|
+
return await submitHandler(ctx, params);
|
|
121
121
|
} catch (error) {
|
|
122
122
|
ctx.model.setProps('loading', false);
|
|
123
123
|
if (error instanceof FlowExitAllException) {
|
|
@@ -166,6 +166,13 @@ export class FormBlockModel<
|
|
|
166
166
|
this.userModifiedTopLevelFields.clear();
|
|
167
167
|
}
|
|
168
168
|
|
|
169
|
+
/**
|
|
170
|
+
* @internal
|
|
171
|
+
*/
|
|
172
|
+
resetRuntimeUserEditedState(): void {
|
|
173
|
+
this.formValueRuntime?.resetUserEditedState?.();
|
|
174
|
+
}
|
|
175
|
+
|
|
169
176
|
public async onDispatchEventStart(eventName: string, options?: any, inputArgs?: Record<string, any>): Promise<void> {
|
|
170
177
|
if (eventName === 'beforeRender') {
|
|
171
178
|
const grid = this.subModels.grid;
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
/**
|
|
11
11
|
* JS Form Action:表单工具栏按钮点击执行 JS。
|
|
12
12
|
*/
|
|
13
|
-
import { tExpr
|
|
13
|
+
import { tExpr } from '@nocobase/flow-engine';
|
|
14
14
|
import { CodeEditor } from '../../../components/code-editor';
|
|
15
15
|
import { FormActionModel } from './FormActionModel';
|
|
16
16
|
import { resolveRunJsParams } from '../../utils/resolveRunJsParams';
|
|
@@ -73,12 +73,7 @@ ctx.message.success('Current form values: ' + JSON.stringify(values));
|
|
|
73
73
|
await ctx.resource.refresh();
|
|
74
74
|
}
|
|
75
75
|
});
|
|
76
|
-
|
|
77
|
-
await ctx.runjs(
|
|
78
|
-
code,
|
|
79
|
-
{ window: createSafeWindow({ navigator }), document: createSafeDocument(), navigator },
|
|
80
|
-
{ version },
|
|
81
|
-
);
|
|
76
|
+
await ctx.runjs(code, undefined, { version });
|
|
82
77
|
},
|
|
83
78
|
},
|
|
84
79
|
},
|