@nocobase/client-v2 2.1.0-alpha.40 → 2.1.0-alpha.46
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/Application.d.ts +7 -0
- package/es/BaseApplication.d.ts +13 -0
- package/es/RouterManager.d.ts +1 -0
- package/es/authRedirect.d.ts +12 -0
- package/es/collection-field-interface/CollectionFieldInterface.d.ts +51 -15
- package/es/collection-field-interface/CollectionFieldInterfaceManager.d.ts +82 -3
- package/es/collection-manager/field-configure.d.ts +80 -0
- package/es/collection-manager/field-validation.d.ts +43 -0
- package/es/collection-manager/filter-operators/index.d.ts +46 -0
- package/es/collection-manager/filter-operators/operators.d.ts +30 -0
- package/es/collection-manager/interfaces/checkbox.d.ts +1 -41
- package/es/collection-manager/interfaces/checkboxGroup.d.ts +12 -44
- package/es/collection-manager/interfaces/collection.d.ts +12 -51
- package/es/collection-manager/interfaces/color.d.ts +1 -16
- package/es/collection-manager/interfaces/createdAt.d.ts +1 -44
- package/es/collection-manager/interfaces/createdBy.d.ts +0 -4
- package/es/collection-manager/interfaces/dateOnly.d.ts +7 -44
- package/es/collection-manager/interfaces/datetime.d.ts +1 -44
- package/es/collection-manager/interfaces/datetimeNoTz.d.ts +1 -44
- package/es/collection-manager/interfaces/email.d.ts +1 -29
- package/es/collection-manager/interfaces/id.d.ts +1 -16
- package/es/collection-manager/interfaces/index.d.ts +2 -3
- package/es/collection-manager/interfaces/input.d.ts +1 -102
- package/es/collection-manager/interfaces/integer.d.ts +1 -95
- package/es/collection-manager/interfaces/json.d.ts +16 -7
- package/es/collection-manager/interfaces/m2m.d.ts +11 -19
- package/es/collection-manager/interfaces/m2o.d.ts +11 -19
- package/es/collection-manager/interfaces/markdown.d.ts +1 -63
- package/es/collection-manager/interfaces/multipleSelect.d.ts +12 -44
- package/es/collection-manager/interfaces/nanoid.d.ts +1 -34
- package/es/collection-manager/interfaces/number.d.ts +1 -87
- package/es/collection-manager/interfaces/o2m.d.ts +12 -24
- package/es/collection-manager/interfaces/obo.d.ts +207 -0
- package/es/collection-manager/interfaces/oho.d.ts +207 -0
- package/es/collection-manager/interfaces/password.d.ts +1 -56
- package/es/collection-manager/interfaces/percent.d.ts +1 -84
- package/es/collection-manager/interfaces/phone.d.ts +1 -25
- package/es/collection-manager/interfaces/properties/index.d.ts +0 -28
- package/es/collection-manager/interfaces/radioGroup.d.ts +1 -29
- package/es/collection-manager/interfaces/richText.d.ts +1 -63
- package/es/collection-manager/interfaces/select.d.ts +12 -44
- package/es/collection-manager/interfaces/snowflake-id.d.ts +1 -34
- package/es/collection-manager/interfaces/tableoid.d.ts +1 -10
- package/es/collection-manager/interfaces/textarea.d.ts +1 -51
- package/es/collection-manager/interfaces/time.d.ts +1 -16
- package/es/collection-manager/interfaces/types.d.ts +3 -12
- package/es/collection-manager/interfaces/unixTimestamp.d.ts +1 -44
- package/es/collection-manager/interfaces/updatedAt.d.ts +1 -44
- package/es/collection-manager/interfaces/updatedBy.d.ts +0 -4
- package/es/collection-manager/interfaces/url.d.ts +1 -20
- package/es/collection-manager/interfaces/uuid.d.ts +1 -34
- package/es/collection-manager/template-fields.d.ts +53 -0
- package/es/components/KeepAlive.d.ts +22 -0
- package/es/components/RouterBridge.d.ts +9 -0
- package/es/components/form/DialogFormLayout.d.ts +5 -29
- package/es/components/form/TypedVariableInput.d.ts +75 -0
- package/es/components/form/VariableInput.d.ts +53 -2
- package/es/components/form/filter/CollectionFilter.d.ts +49 -0
- package/es/components/form/filter/CollectionFilterItem.d.ts +49 -0
- package/es/components/form/filter/DateFilterDynamicComponent.d.ts +57 -0
- package/es/components/form/filter/FilterValueInput.d.ts +29 -0
- package/es/components/form/filter/index.d.ts +11 -0
- package/es/components/form/filter/useFilterActionProps.d.ts +96 -0
- package/es/components/form/index.d.ts +2 -0
- package/es/data-source/ExtendCollectionsProvider.d.ts +50 -0
- package/es/data-source/index.d.ts +9 -0
- package/es/flow/FlowPage.d.ts +2 -1
- package/es/flow/admin-shell/AdminLayoutRouteCoordinator.d.ts +8 -40
- package/es/flow/admin-shell/BaseLayoutModel.d.ts +89 -0
- package/es/flow/admin-shell/BaseLayoutRouteCoordinator.d.ts +74 -0
- package/es/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.d.ts +12 -0
- package/es/flow/admin-shell/admin-layout/AdminLayoutMenuModels.d.ts +1 -0
- package/es/flow/admin-shell/admin-layout/AdminLayoutModel.d.ts +7 -92
- package/es/flow/admin-shell/admin-layout/AppListRender.d.ts +11 -0
- package/es/flow/admin-shell/admin-layout/index.d.ts +3 -0
- package/es/flow/admin-shell/admin-layout/useApplications.d.ts +3 -2
- package/es/flow/admin-shell/useAdminLayoutRoutePage.d.ts +2 -2
- package/es/flow/admin-shell/useLayoutRoutePage.d.ts +23 -0
- package/es/flow/components/ConditionBuilder.d.ts +1 -0
- package/es/flow/components/FieldAssignRulesEditor.d.ts +3 -1
- package/es/flow/components/FieldAssignValueInput.d.ts +1 -0
- package/es/flow/components/FlowRoute.d.ts +10 -1
- package/es/flow/components/fieldAssignOptions.d.ts +10 -0
- package/es/flow/components/filter/LinkageFilterItem.d.ts +1 -0
- package/es/flow/components/filter/VariableFilterItem.d.ts +1 -0
- package/es/flow/components/filter/index.d.ts +2 -0
- package/es/flow/components/filter/metaTreeAssociationDepth.d.ts +13 -0
- package/es/flow/components/filter/useFilterOptions.d.ts +66 -0
- package/es/flow/index.d.ts +4 -0
- package/es/flow/models/base/AssociationFieldGroupModel.d.ts +2 -33
- package/es/flow/models/base/PageModel/PageModel.d.ts +3 -1
- package/es/flow/models/blocks/assign-form/assignFieldValuesFlow.d.ts +92 -0
- package/es/flow/models/blocks/assign-form/index.d.ts +1 -0
- package/es/flow/models/blocks/form/FormActionGroupModel.d.ts +1 -0
- package/es/flow/models/blocks/form/FormActionModel.d.ts +9 -2
- package/es/flow/models/blocks/table/TableBlockModel.d.ts +10 -0
- package/es/flow/models/blocks/table/TableColumnModel.d.ts +2 -0
- package/es/flow/models/fields/AssociationFieldModel/SubTableFieldModel/index.d.ts +1 -1
- package/es/flow-compat/passwordUtils.d.ts +1 -1
- package/es/index.d.ts +6 -0
- package/es/index.mjs +552 -459
- package/es/layout-manager/LayoutContentRoute.d.ts +14 -0
- package/es/layout-manager/LayoutManager.d.ts +22 -0
- package/es/layout-manager/LayoutRoute.d.ts +14 -0
- package/es/layout-manager/index.d.ts +13 -0
- package/es/layout-manager/types.d.ts +20 -0
- package/es/layout-manager/utils.d.ts +14 -0
- package/es/nocobase-buildin-plugin/index.d.ts +3 -10
- package/es/settings-center/index.d.ts +1 -1
- package/es/settings-center/plugin-manager/BulkEnableButton.d.ts +15 -0
- package/es/settings-center/plugin-manager/PluginCard.d.ts +15 -0
- package/es/settings-center/plugin-manager/PluginDetail.d.ts +16 -0
- package/es/settings-center/{PluginManagerPage.d.ts → plugin-manager/index.d.ts} +1 -7
- package/es/settings-center/plugin-manager/types.d.ts +34 -0
- package/lib/index.js +552 -459
- package/package.json +8 -7
- package/src/Application.tsx +51 -12
- package/src/BaseApplication.tsx +32 -0
- package/src/PluginSettingsManager.ts +1 -1
- package/src/RouterManager.tsx +17 -1
- package/src/__tests__/PluginSettingsManager.test.ts +41 -2
- package/src/__tests__/app.test.tsx +17 -1
- package/src/__tests__/globalDeps.test.ts +1 -0
- package/src/__tests__/nocobase-buildin-plugin-auth.test.tsx +50 -2
- package/src/__tests__/plugin-manager.test.tsx +177 -0
- package/src/__tests__/settings-center.test.tsx +24 -2
- package/src/authRedirect.ts +43 -0
- package/src/collection-field-interface/CollectionFieldInterface.ts +71 -77
- package/src/collection-field-interface/CollectionFieldInterfaceManager.ts +201 -4
- package/src/collection-manager/field-configure.ts +548 -0
- package/src/collection-manager/field-validation.ts +195 -0
- package/src/collection-manager/filter-operators/index.ts +176 -0
- package/src/collection-manager/{interfaces/properties → filter-operators}/operators.ts +24 -13
- package/src/collection-manager/interfaces/checkbox.ts +2 -9
- package/src/collection-manager/interfaces/checkboxGroup.ts +2 -10
- package/src/collection-manager/interfaces/collection.ts +2 -15
- package/src/collection-manager/interfaces/color.ts +2 -2
- package/src/collection-manager/interfaces/createdAt.ts +2 -2
- package/src/collection-manager/interfaces/createdBy.ts +1 -12
- package/src/collection-manager/interfaces/dateOnly.ts +8 -2
- package/src/collection-manager/interfaces/datetime.ts +2 -2
- package/src/collection-manager/interfaces/datetimeNoTz.ts +2 -2
- package/src/collection-manager/interfaces/email.ts +2 -9
- package/src/collection-manager/interfaces/id.ts +1 -2
- package/src/collection-manager/interfaces/index.ts +2 -3
- package/src/collection-manager/interfaces/input.ts +2 -133
- package/src/collection-manager/interfaces/integer.ts +2 -71
- package/src/collection-manager/interfaces/json.tsx +17 -11
- package/src/collection-manager/interfaces/m2m.tsx +0 -21
- package/src/collection-manager/interfaces/m2o.tsx +0 -22
- package/src/collection-manager/interfaces/markdown.ts +2 -51
- package/src/collection-manager/interfaces/multipleSelect.ts +2 -14
- package/src/collection-manager/interfaces/nanoid.ts +2 -2
- package/src/collection-manager/interfaces/number.ts +2 -85
- package/src/collection-manager/interfaces/o2m.tsx +1 -22
- package/src/collection-manager/interfaces/obo.tsx +145 -0
- package/src/collection-manager/interfaces/oho.tsx +145 -0
- package/src/collection-manager/interfaces/password.ts +2 -44
- package/src/collection-manager/interfaces/percent.ts +2 -74
- package/src/collection-manager/interfaces/phone.ts +2 -2
- package/src/collection-manager/interfaces/properties/index.ts +0 -133
- package/src/collection-manager/interfaces/radioGroup.ts +2 -2
- package/src/collection-manager/interfaces/richText.ts +2 -51
- package/src/collection-manager/interfaces/select.ts +2 -14
- package/src/collection-manager/interfaces/snowflake-id.ts +2 -2
- package/src/collection-manager/interfaces/tableoid.ts +1 -2
- package/src/collection-manager/interfaces/textarea.ts +2 -51
- package/src/collection-manager/interfaces/time.ts +2 -2
- package/src/collection-manager/interfaces/types.ts +4 -12
- package/src/collection-manager/interfaces/unixTimestamp.tsx +2 -2
- package/src/collection-manager/interfaces/updatedAt.ts +2 -2
- package/src/collection-manager/interfaces/updatedBy.ts +1 -12
- package/src/collection-manager/interfaces/url.ts +2 -4
- package/src/collection-manager/interfaces/uuid.ts +2 -2
- package/src/collection-manager/template-fields.ts +109 -0
- package/src/components/KeepAlive.tsx +131 -0
- package/src/components/README.md +138 -6
- package/src/components/README.zh-CN.md +138 -7
- package/src/components/RouterBridge.tsx +28 -4
- package/src/components/__tests__/KeepAlive.test.tsx +63 -0
- package/src/components/__tests__/RouterBridge.test.tsx +27 -0
- package/src/components/form/DialogFormLayout.tsx +5 -29
- package/src/components/form/TypedVariableInput.tsx +441 -0
- package/src/components/form/VariableInput.tsx +101 -28
- package/src/components/form/__tests__/TypedVariableInput.test.tsx +152 -0
- package/src/components/form/__tests__/VariableInput.test.ts +85 -0
- package/src/components/form/filter/CollectionFilter.tsx +111 -0
- package/src/components/form/filter/CollectionFilterItem.tsx +184 -0
- package/src/components/form/filter/DateFilterDynamicComponent.tsx +283 -0
- package/src/components/form/filter/FilterValueInput.tsx +198 -0
- package/src/components/form/filter/__tests__/CollectionFilterItem.test.tsx +247 -0
- package/src/components/form/filter/__tests__/DateFilterDynamicComponent.test.tsx +148 -0
- package/src/components/form/filter/__tests__/FilterValueInput.test.tsx +243 -0
- package/src/components/form/filter/__tests__/compileFilterGroup.test.ts +146 -0
- package/src/components/form/filter/index.ts +13 -0
- package/src/components/form/filter/useFilterActionProps.ts +203 -0
- package/src/components/form/index.tsx +2 -0
- package/src/data-source/ExtendCollectionsProvider.tsx +144 -0
- package/src/data-source/__tests__/ExtendCollectionsProvider.test.tsx +264 -0
- package/src/data-source/index.ts +10 -0
- package/src/flow/FlowPage.tsx +35 -7
- package/src/flow/__tests__/FlowPage.test.tsx +79 -0
- package/src/flow/__tests__/FlowRoute.test.tsx +537 -3
- package/src/flow/actions/__tests__/linkageRules.hiddenSync.restore.test.ts +100 -0
- package/src/flow/actions/__tests__/linkageRules.subFormSetFieldProps.test.ts +191 -0
- package/src/flow/actions/__tests__/linkageRulesRefresh.test.ts +23 -1
- package/src/flow/actions/__tests__/openView.subModelKey.test.tsx +33 -0
- package/src/flow/actions/aclCheck.tsx +4 -0
- package/src/flow/actions/aclCheckRefresh.tsx +4 -0
- package/src/flow/actions/dataScope.tsx +8 -1
- package/src/flow/actions/dateTimeFormat.tsx +12 -8
- package/src/flow/actions/linkageRules.tsx +127 -2
- package/src/flow/actions/linkageRulesRefresh.tsx +2 -3
- package/src/flow/actions/openView.tsx +28 -4
- package/src/flow/actions/setTargetDataScope.tsx +1 -1
- package/src/flow/admin-shell/AdminLayoutRouteCoordinator.ts +11 -329
- package/src/flow/admin-shell/BaseLayoutModel.tsx +455 -0
- package/src/flow/admin-shell/BaseLayoutRouteCoordinator.ts +502 -0
- package/src/flow/admin-shell/__tests__/AdminLayoutRouteCoordinator.test.ts +547 -3
- package/src/flow/admin-shell/admin-layout/AdminLayoutComponent.tsx +35 -7
- package/src/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.tsx +160 -0
- package/src/flow/admin-shell/admin-layout/AdminLayoutMenuModels.tsx +15 -13
- package/src/flow/admin-shell/admin-layout/AdminLayoutModel.tsx +28 -201
- package/src/flow/admin-shell/admin-layout/AdminLayoutSlotModels.tsx +11 -2
- package/src/flow/admin-shell/admin-layout/AppListRender.tsx +139 -0
- package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutMenuModels.test.ts +76 -27
- package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutModel.test.tsx +149 -27
- package/src/flow/admin-shell/admin-layout/index.ts +3 -0
- package/src/flow/admin-shell/admin-layout/resolveAdminRouteRuntimeTarget.test.ts +11 -0
- package/src/flow/admin-shell/admin-layout/resolveAdminRouteRuntimeTarget.ts +2 -4
- package/src/flow/admin-shell/admin-layout/useApplications.tsx +34 -1
- package/src/flow/admin-shell/useAdminLayoutRoutePage.ts +10 -26
- package/src/flow/admin-shell/useLayoutRoutePage.ts +61 -0
- package/src/flow/common/Markdown/Edit.tsx +32 -4
- package/src/flow/components/AdminLayout.tsx +4 -154
- package/src/flow/components/ConditionBuilder.tsx +12 -2
- package/src/flow/components/FieldAssignRulesEditor.tsx +37 -46
- package/src/flow/components/FieldAssignValueInput.tsx +8 -4
- package/src/flow/components/FlowRoute.tsx +105 -15
- package/src/flow/components/__tests__/FieldAssignRulesEditor.test.tsx +112 -1
- package/src/flow/components/__tests__/fieldAssignOptions.test.ts +71 -1
- package/src/flow/components/code-editor/__tests__/runjsCompletions.test.ts +272 -27
- package/src/flow/components/code-editor/runjsCompletions.ts +490 -9
- package/src/flow/components/fieldAssignOptions.ts +23 -6
- package/src/flow/components/filter/LinkageFilterItem.tsx +22 -9
- package/src/flow/components/filter/VariableFilterItem.tsx +27 -9
- package/src/flow/components/filter/__tests__/fieldsToOptions.test.ts +48 -0
- package/src/flow/components/filter/__tests__/metaTreeAssociationDepth.test.ts +60 -0
- package/src/flow/components/filter/fieldsToOptions.ts +9 -4
- package/src/flow/components/filter/index.ts +3 -0
- package/src/flow/components/filter/metaTreeAssociationDepth.ts +69 -0
- package/src/flow/components/filter/useFilterOptions.ts +102 -0
- package/src/flow/index.ts +4 -0
- package/src/flow/models/actions/FilterActionModel.tsx +15 -3
- package/src/flow/models/actions/UpdateRecordActionModel.tsx +14 -95
- package/src/flow/models/actions/UpdateRecordActionUtils.ts +4 -7
- package/src/flow/models/actions/__tests__/AssignFormRefill.test.ts +116 -1
- package/src/flow/models/base/ActionModel.tsx +8 -1
- package/src/flow/models/base/AssociationFieldGroupModel.tsx +20 -3
- package/src/flow/models/base/GridModel.tsx +1 -1
- package/src/flow/models/base/PageModel/ChildPageModel.tsx +5 -1
- package/src/flow/models/base/PageModel/PageModel.tsx +51 -18
- package/src/flow/models/base/PageModel/RootPageModel.tsx +6 -13
- package/src/flow/models/base/PageModel/__tests__/ChildPageModel.test.ts +12 -0
- package/src/flow/models/base/PageModel/__tests__/PageModel.test.ts +102 -1
- package/src/flow/models/base/RouteModel.tsx +1 -1
- package/src/flow/models/base/__tests__/AssociationFieldGroupModel.test.ts +86 -0
- package/src/flow/models/base/__tests__/GridModel.render.test.tsx +53 -0
- package/src/flow/models/blocks/assign-form/AssignFormGridModel.tsx +12 -3
- package/src/flow/models/blocks/assign-form/AssignFormItemModel.tsx +77 -6
- package/src/flow/models/blocks/assign-form/__tests__/assignFieldValuesFlow.editor.test.tsx +216 -0
- package/src/flow/models/blocks/assign-form/assignFieldValuesFlow.tsx +308 -0
- package/src/flow/models/blocks/assign-form/index.ts +1 -0
- package/src/flow/models/blocks/filter-form/FilterFormItemModel.tsx +1 -1
- package/src/flow/models/blocks/filter-form/__tests__/FilterFormItemModel.defineChildren.test.ts +6 -1
- package/src/flow/models/blocks/filter-manager/flow-actions/connectFields.tsx +48 -6
- package/src/flow/models/blocks/form/FormActionGroupModel.tsx +14 -0
- package/src/flow/models/blocks/form/FormActionModel.tsx +30 -3
- package/src/flow/models/blocks/form/FormAssociationItemModel.tsx +9 -0
- package/src/flow/models/blocks/form/FormItemModel.tsx +17 -1
- package/src/flow/models/blocks/form/__tests__/FormActionGroupModel.test.ts +46 -0
- package/src/flow/models/blocks/form/__tests__/FormBlockModel.test.tsx +17 -0
- package/src/flow/models/blocks/form/__tests__/FormItemModel.defineChildren.test.ts +27 -2
- package/src/flow/models/blocks/form/__tests__/submitHandler.test.ts +71 -0
- package/src/flow/models/blocks/form/submitHandler.ts +8 -1
- package/src/flow/models/blocks/form/submitValues.ts +4 -1
- package/src/flow/models/blocks/form/value-runtime/__tests__/runtime.test.ts +29 -0
- package/src/flow/models/blocks/form/value-runtime/runtime.ts +5 -1
- package/src/flow/models/blocks/table/TableBlockModel.tsx +118 -16
- package/src/flow/models/blocks/table/TableColumnModel.tsx +15 -5
- package/src/flow/models/blocks/table/TableCustomColumnModel.tsx +2 -2
- package/src/flow/models/blocks/table/__tests__/TableBlockModel.rowSelection.test.tsx +114 -0
- package/src/flow/models/blocks/table/__tests__/TableColumnModel.test.tsx +18 -0
- package/src/flow/models/fields/AssociationFieldModel/SubFormFieldModel.tsx +7 -1
- package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/SubTableColumnModel.tsx +6 -7
- package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/SubTableField.tsx +1 -1
- package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/index.tsx +6 -5
- package/src/flow/models/fields/ClickableFieldModel.tsx +9 -1
- package/src/flow/models/fields/CollectionSelectorFieldModel.tsx +8 -2
- package/src/flow/models/fields/DisplayEnumFieldModel.tsx +8 -2
- package/src/flow/models/fields/DisplayTimeFieldModel.tsx +1 -1
- package/src/flow/models/fields/TimeFieldModel.tsx +1 -1
- package/src/flow/models/fields/__tests__/TimeFieldModel.test.tsx +61 -0
- package/src/flow/models/fields/mobile-components/MobileDatePicker.tsx +19 -3
- package/src/flow/models/fields/mobile-components/MobileLazySelect.tsx +5 -3
- package/src/flow/models/fields/mobile-components/__tests__/MobileDatePicker.test.tsx +94 -0
- package/src/flow/models/fields/mobile-components/__tests__/MobileSelect.test.tsx +70 -0
- package/src/flow/models/topbar/TopbarActionModel.tsx +1 -1
- package/src/flow/utils/__tests__/dateTimeFormat.test.ts +91 -0
- package/src/index.ts +6 -0
- package/src/layout-manager/LayoutContentRoute.tsx +90 -0
- package/src/layout-manager/LayoutManager.tsx +185 -0
- package/src/layout-manager/LayoutRoute.tsx +138 -0
- package/src/layout-manager/__tests__/LayoutManager.test.tsx +335 -0
- package/src/layout-manager/__tests__/LayoutRoute.test.tsx +473 -0
- package/src/layout-manager/index.ts +14 -0
- package/src/layout-manager/types.ts +22 -0
- package/src/layout-manager/utils.ts +37 -0
- package/src/nocobase-buildin-plugin/index.tsx +69 -67
- package/src/nocobase-buildin-plugin/plugins/LocalePlugin.ts +1 -0
- package/src/settings-center/index.ts +1 -1
- package/src/settings-center/plugin-manager/BulkEnableButton.tsx +111 -0
- package/src/settings-center/plugin-manager/PluginCard.tsx +270 -0
- package/src/settings-center/plugin-manager/PluginDetail.tsx +195 -0
- package/src/settings-center/plugin-manager/index.tsx +254 -0
- package/src/settings-center/plugin-manager/types.ts +35 -0
- package/src/settings-center/utils.tsx +8 -1
- package/src/theme/__tests__/globalStyles.test.ts +24 -0
- package/src/theme/globalStyles.ts +10 -0
- package/src/utils/globalDeps.ts +2 -0
- package/es/collection-manager/interfaces/linkTo.d.ts +0 -90
- package/es/collection-manager/interfaces/o2o.d.ts +0 -621
- package/es/collection-manager/interfaces/properties/operators.d.ts +0 -294
- package/es/collection-manager/interfaces/subTable.d.ts +0 -172
- package/src/collection-manager/interfaces/linkTo.ts +0 -120
- package/src/collection-manager/interfaces/o2o.tsx +0 -561
- package/src/collection-manager/interfaces/subTable.ts +0 -218
- package/src/settings-center/PluginManagerPage.tsx +0 -162
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
import { describe, it, expect } from 'vitest';
|
|
11
11
|
import { FlowEngine, FlowModel } from '@nocobase/flow-engine';
|
|
12
|
-
import { UpdateRecordActionModel } from '../../..'; // 这样可以解决循环依赖问题
|
|
12
|
+
import { FormSubmitActionModel, UpdateRecordActionModel } from '../../..'; // 这样可以解决循环依赖问题
|
|
13
13
|
|
|
14
14
|
/**
|
|
15
15
|
* 精简版 AssignFormModel(仅用于单测):
|
|
@@ -52,4 +52,119 @@ describe('AssignForm value refill and save (beforeParamsSave)', () => {
|
|
|
52
52
|
const saved = action.getStepParams('assignSettings', 'assignFieldValues');
|
|
53
53
|
expect(saved?.assignedValues).toEqual({ nickname: 'Alice', score: 99 });
|
|
54
54
|
});
|
|
55
|
+
|
|
56
|
+
it('UpdateRecordActionModel: saves assignedValues from assignForm subModel when assignFormUid is not ready', async () => {
|
|
57
|
+
const root = new FlowEngine();
|
|
58
|
+
root.registerModels({ UpdateRecordActionModel, AssignFormModel: TestAssignFormModel });
|
|
59
|
+
|
|
60
|
+
const action = root.createModel<UpdateRecordActionModel>({ use: 'UpdateRecordActionModel', uid: 'act-u-sub' });
|
|
61
|
+
const form = root.createModel<TestAssignFormModel>({
|
|
62
|
+
use: 'AssignFormModel',
|
|
63
|
+
uid: 'form-u-sub',
|
|
64
|
+
parentId: action.uid,
|
|
65
|
+
subKey: 'assignForm',
|
|
66
|
+
});
|
|
67
|
+
form.setAssignedValues({ nickname: 'Bob' });
|
|
68
|
+
action.setSubModel('assignForm', form);
|
|
69
|
+
|
|
70
|
+
const flow = action.getFlow('assignSettings') as any;
|
|
71
|
+
const step = flow?.steps?.assignFieldValues;
|
|
72
|
+
|
|
73
|
+
await step.beforeParamsSave({ engine: root, model: action }, {}, {});
|
|
74
|
+
|
|
75
|
+
const saved = action.getStepParams('assignSettings', 'assignFieldValues');
|
|
76
|
+
expect(saved?.assignedValues).toEqual({ nickname: 'Bob' });
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('UpdateRecordActionModel: keeps previous assignedValues when AssignForm is unavailable during save', async () => {
|
|
80
|
+
const root = new FlowEngine();
|
|
81
|
+
root.registerModels({ UpdateRecordActionModel, AssignFormModel: TestAssignFormModel });
|
|
82
|
+
|
|
83
|
+
const action = root.createModel<UpdateRecordActionModel>({ use: 'UpdateRecordActionModel', uid: 'act-u-missing' });
|
|
84
|
+
action.setStepParams('assignSettings', 'assignFieldValues', {});
|
|
85
|
+
|
|
86
|
+
const flow = action.getFlow('assignSettings') as any;
|
|
87
|
+
const step = flow?.steps?.assignFieldValues;
|
|
88
|
+
|
|
89
|
+
await step.beforeParamsSave(
|
|
90
|
+
{ engine: root, model: action },
|
|
91
|
+
{},
|
|
92
|
+
{
|
|
93
|
+
assignedValues: { nickname: 'Previous' },
|
|
94
|
+
},
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
const saved = action.getStepParams('assignSettings', 'assignFieldValues');
|
|
98
|
+
expect(saved?.assignedValues).toEqual({ nickname: 'Previous' });
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('FormSubmitActionModel: reuses assignFieldValues step and saves assignedValues from AssignForm', async () => {
|
|
102
|
+
const root = new FlowEngine();
|
|
103
|
+
|
|
104
|
+
root.registerModels({ FormSubmitActionModel, AssignFormModel: TestAssignFormModel });
|
|
105
|
+
|
|
106
|
+
const action = root.createModel<FormSubmitActionModel>({ use: 'FormSubmitActionModel', uid: 'submit-u' });
|
|
107
|
+
const form = root.createModel<TestAssignFormModel>({
|
|
108
|
+
use: 'AssignFormModel',
|
|
109
|
+
uid: 'submit-form-u',
|
|
110
|
+
parentId: action.uid,
|
|
111
|
+
subKey: 'assignForm',
|
|
112
|
+
});
|
|
113
|
+
form.setAssignedValues({ status: 'published' });
|
|
114
|
+
action.assignFormUid = form.uid;
|
|
115
|
+
|
|
116
|
+
const flow = action.getFlow('submitSettings') as any;
|
|
117
|
+
const step = flow?.steps?.assignFieldValues;
|
|
118
|
+
expect(step?.beforeParamsSave).toBeTypeOf('function');
|
|
119
|
+
|
|
120
|
+
await step.beforeParamsSave({ engine: root, model: action });
|
|
121
|
+
|
|
122
|
+
const saved = action.getStepParams('submitSettings', 'assignFieldValues');
|
|
123
|
+
expect(saved?.assignedValues).toEqual({ status: 'published' });
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
it('FormSubmitActionModel: saves assignedValues from assignForm subModel when assignFormUid is not ready', async () => {
|
|
127
|
+
const root = new FlowEngine();
|
|
128
|
+
root.registerModels({ FormSubmitActionModel, AssignFormModel: TestAssignFormModel });
|
|
129
|
+
|
|
130
|
+
const action = root.createModel<FormSubmitActionModel>({ use: 'FormSubmitActionModel', uid: 'submit-u-sub' });
|
|
131
|
+
const form = root.createModel<TestAssignFormModel>({
|
|
132
|
+
use: 'AssignFormModel',
|
|
133
|
+
uid: 'submit-form-u-sub',
|
|
134
|
+
parentId: action.uid,
|
|
135
|
+
subKey: 'assignForm',
|
|
136
|
+
});
|
|
137
|
+
form.setAssignedValues({ status: 'draft' });
|
|
138
|
+
action.setSubModel('assignForm', form);
|
|
139
|
+
|
|
140
|
+
const flow = action.getFlow('submitSettings') as any;
|
|
141
|
+
const step = flow?.steps?.assignFieldValues;
|
|
142
|
+
|
|
143
|
+
await step.beforeParamsSave({ engine: root, model: action }, {}, {});
|
|
144
|
+
|
|
145
|
+
const saved = action.getStepParams('submitSettings', 'assignFieldValues');
|
|
146
|
+
expect(saved?.assignedValues).toEqual({ status: 'draft' });
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
it('FormSubmitActionModel: keeps previous assignedValues when AssignForm is unavailable during save', async () => {
|
|
150
|
+
const root = new FlowEngine();
|
|
151
|
+
root.registerModels({ FormSubmitActionModel, AssignFormModel: TestAssignFormModel });
|
|
152
|
+
|
|
153
|
+
const action = root.createModel<FormSubmitActionModel>({ use: 'FormSubmitActionModel', uid: 'submit-u-missing' });
|
|
154
|
+
action.setStepParams('submitSettings', 'assignFieldValues', {});
|
|
155
|
+
|
|
156
|
+
const flow = action.getFlow('submitSettings') as any;
|
|
157
|
+
const step = flow?.steps?.assignFieldValues;
|
|
158
|
+
|
|
159
|
+
await step.beforeParamsSave(
|
|
160
|
+
{ engine: root, model: action },
|
|
161
|
+
{},
|
|
162
|
+
{
|
|
163
|
+
assignedValues: { status: 'published' },
|
|
164
|
+
},
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
const saved = action.getStepParams('submitSettings', 'assignFieldValues');
|
|
168
|
+
expect(saved?.assignedValues).toEqual({ status: 'published' });
|
|
169
|
+
});
|
|
55
170
|
});
|
|
@@ -80,7 +80,14 @@ ActionModel.registerFlow({
|
|
|
80
80
|
};
|
|
81
81
|
},
|
|
82
82
|
defaultParams(ctx) {
|
|
83
|
-
|
|
83
|
+
const defaultProps = ctx.model.defaultProps || {};
|
|
84
|
+
if (!ctx.model.enableEditColor) {
|
|
85
|
+
return defaultProps;
|
|
86
|
+
}
|
|
87
|
+
return {
|
|
88
|
+
...defaultProps,
|
|
89
|
+
color: ctx.model.props?.color ?? defaultProps.color ?? ctx.themeToken?.colorPrimary,
|
|
90
|
+
};
|
|
84
91
|
},
|
|
85
92
|
handler(ctx, params) {
|
|
86
93
|
const { title, tooltip, ...rest } = params;
|
|
@@ -11,13 +11,20 @@ import { Collection, DisplayItemModel, FlowModel, FlowModelContext } from '@noco
|
|
|
11
11
|
|
|
12
12
|
export class AssociationFieldGroupModel extends FlowModel {
|
|
13
13
|
static itemModelName = 'DetailsItemModel';
|
|
14
|
+
static maxAssociationFieldDepth = 2;
|
|
14
15
|
static defineChildren(ctx: FlowModelContext) {
|
|
15
16
|
const itemModel = this.itemModelName;
|
|
16
|
-
const
|
|
17
|
+
const maxAssociationFieldDepth = this.maxAssociationFieldDepth ?? 2;
|
|
18
|
+
const displayAssociationFields = (targetCollection: Collection, fieldPath = '', associationDepth = 0) => {
|
|
19
|
+
if (associationDepth >= maxAssociationFieldDepth) {
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
|
|
17
23
|
return targetCollection
|
|
18
24
|
.getToOneAssociationFields()
|
|
19
25
|
.map((field) => {
|
|
20
26
|
const fPath = fieldPath ? `${fieldPath}.${field.name}` : field.name;
|
|
27
|
+
const nextAssociationDepth = associationDepth + 1;
|
|
21
28
|
if (!field.targetCollection) {
|
|
22
29
|
console.error(
|
|
23
30
|
`AssociationFieldGroupModel: target collection ${field.target} not found for field ${field.name}`,
|
|
@@ -37,6 +44,12 @@ export class AssociationFieldGroupModel extends FlowModel {
|
|
|
37
44
|
children: field.targetCollection
|
|
38
45
|
.getFields()
|
|
39
46
|
.map((f) => {
|
|
47
|
+
if (
|
|
48
|
+
nextAssociationDepth >= maxAssociationFieldDepth &&
|
|
49
|
+
(f.isAssociationField?.() || f.target || f.targetCollection)
|
|
50
|
+
) {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
40
53
|
const fp = `${fPath}.${f.name}`;
|
|
41
54
|
const binding = DisplayItemModel.getDefaultBindingByField(ctx, f, {
|
|
42
55
|
fallbackToTargetTitleField: true,
|
|
@@ -81,9 +94,13 @@ export class AssociationFieldGroupModel extends FlowModel {
|
|
|
81
94
|
key: `${fPath}-children-associationField`,
|
|
82
95
|
label: 'Display association fields',
|
|
83
96
|
type: 'group',
|
|
84
|
-
children: (
|
|
97
|
+
children: (
|
|
98
|
+
displayAssociationFields(field.targetCollection, fPath, nextAssociationDepth) || []
|
|
99
|
+
).filter(Boolean),
|
|
85
100
|
},
|
|
86
|
-
]
|
|
101
|
+
].filter((item) => {
|
|
102
|
+
return item.key !== `${fPath}-children-associationField` || (item.children as any[])?.length > 0;
|
|
103
|
+
});
|
|
87
104
|
},
|
|
88
105
|
};
|
|
89
106
|
})
|
|
@@ -1006,7 +1006,7 @@ export class GridModel<T extends { subModels: { items: FlowModel[] } } = Default
|
|
|
1006
1006
|
<Space
|
|
1007
1007
|
ref={this.gridContainerRef}
|
|
1008
1008
|
direction={'vertical'}
|
|
1009
|
-
style={{ width: '100%', marginBottom: this.props.rowGap }}
|
|
1009
|
+
style={{ width: '100%', marginBottom: this.props.rowGap, display: 'flex' }}
|
|
1010
1010
|
size={this.props.rowGap}
|
|
1011
1011
|
>
|
|
1012
1012
|
<DndProvider
|
|
@@ -49,7 +49,11 @@ export class ChildPageModel extends PageModel {
|
|
|
49
49
|
throw new Error('Invalid drag event');
|
|
50
50
|
}
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
if (event.active.id === event.over.id) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
await this.flowEngine.moveModel(event.active.id, event.over.id);
|
|
53
57
|
}
|
|
54
58
|
|
|
55
59
|
render() {
|
|
@@ -40,6 +40,15 @@ type PageModelStructure = {
|
|
|
40
40
|
};
|
|
41
41
|
};
|
|
42
42
|
|
|
43
|
+
type CurrentRouteWithTabs = {
|
|
44
|
+
id?: string | number | null;
|
|
45
|
+
enableTabs?: boolean;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
type PageModelContextWithRoute = {
|
|
49
|
+
currentRoute?: CurrentRouteWithTabs | null;
|
|
50
|
+
};
|
|
51
|
+
|
|
43
52
|
export class PageModel extends FlowModel<PageModelStructure> {
|
|
44
53
|
tabBarExtraContent: { left?: ReactNode; right?: ReactNode } = {};
|
|
45
54
|
private viewActivatedListener?: (_payload?: unknown) => void;
|
|
@@ -53,9 +62,15 @@ export class PageModel extends FlowModel<PageModelStructure> {
|
|
|
53
62
|
* 根页面标签页开关以路由表为准,避免 flow model 里的旧配置覆盖路由管理设置。
|
|
54
63
|
*/
|
|
55
64
|
private getEnableTabs(): boolean {
|
|
56
|
-
const
|
|
57
|
-
|
|
58
|
-
|
|
65
|
+
const currentRoute = (this.context as PageModelContextWithRoute).currentRoute;
|
|
66
|
+
const routeId = this.props.routeId;
|
|
67
|
+
if (
|
|
68
|
+
routeId != null &&
|
|
69
|
+
currentRoute?.id != null &&
|
|
70
|
+
String(currentRoute.id) === String(routeId) &&
|
|
71
|
+
typeof currentRoute.enableTabs === 'boolean'
|
|
72
|
+
) {
|
|
73
|
+
return currentRoute.enableTabs;
|
|
59
74
|
}
|
|
60
75
|
return !!this.props.enableTabs;
|
|
61
76
|
}
|
|
@@ -77,16 +92,27 @@ export class PageModel extends FlowModel<PageModelStructure> {
|
|
|
77
92
|
if (this.unmounted) return;
|
|
78
93
|
// Only skip when explicitly inactive; treat "unknown" (undefined) as active for backward compatibility.
|
|
79
94
|
if (getPageActive(this.context) === false) return;
|
|
80
|
-
|
|
81
|
-
if (activeKey) {
|
|
82
|
-
this.invokeTabModelLifecycleMethod(activeKey, 'onActive', forceRefresh);
|
|
83
|
-
}
|
|
95
|
+
this.activateCurrentTab(forceRefresh);
|
|
84
96
|
})
|
|
85
97
|
.catch(() => {
|
|
86
98
|
// ignore
|
|
87
99
|
});
|
|
88
100
|
}
|
|
89
101
|
|
|
102
|
+
activateCurrentTab(forceRefresh = false) {
|
|
103
|
+
const activeKey = this.getActiveTabKey();
|
|
104
|
+
if (activeKey) {
|
|
105
|
+
this.invokeTabModelLifecycleMethod(activeKey, 'onActive', forceRefresh);
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
deactivateCurrentTab() {
|
|
110
|
+
const activeKey = this.props.tabActiveKey || this.getFirstTab()?.uid;
|
|
111
|
+
if (activeKey) {
|
|
112
|
+
this.invokeTabModelLifecycleMethod(activeKey, 'onInactive');
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
|
|
90
116
|
onMount(): void {
|
|
91
117
|
super.onMount();
|
|
92
118
|
this.unmounted = false;
|
|
@@ -98,10 +124,7 @@ export class PageModel extends FlowModel<PageModelStructure> {
|
|
|
98
124
|
// We align this with the existing tab lifecycle by invoking `onActive` for the current tab blocks.
|
|
99
125
|
if (!this.viewActivatedListener) {
|
|
100
126
|
this.viewActivatedListener = (_payload?: unknown) => {
|
|
101
|
-
|
|
102
|
-
if (activeKey) {
|
|
103
|
-
this.invokeTabModelLifecycleMethod(activeKey, 'onActive');
|
|
104
|
-
}
|
|
127
|
+
this.activateCurrentTab();
|
|
105
128
|
};
|
|
106
129
|
this.flowEngine?.emitter?.on?.(VIEW_ACTIVATED_EVENT, this.viewActivatedListener);
|
|
107
130
|
}
|
|
@@ -113,10 +136,7 @@ export class PageModel extends FlowModel<PageModelStructure> {
|
|
|
113
136
|
emitterActivatedVersion > 0 && emitterActivatedVersion !== this.lastSeenEmitterViewActivatedVersion;
|
|
114
137
|
this.lastSeenEmitterViewActivatedVersion = emitterActivatedVersion;
|
|
115
138
|
if (shouldCatchUp && getPageActive(this.context) !== false) {
|
|
116
|
-
|
|
117
|
-
if (activeKey) {
|
|
118
|
-
this.invokeTabModelLifecycleMethod(activeKey, 'onActive');
|
|
119
|
-
}
|
|
139
|
+
this.activateCurrentTab();
|
|
120
140
|
}
|
|
121
141
|
|
|
122
142
|
// When data is written within the same view, trigger an "active" lifecycle pass so blocks can refresh based on dirty.
|
|
@@ -141,11 +161,21 @@ export class PageModel extends FlowModel<PageModelStructure> {
|
|
|
141
161
|
super.onUnmount();
|
|
142
162
|
}
|
|
143
163
|
|
|
144
|
-
invokeTabModelLifecycleMethod(
|
|
164
|
+
invokeTabModelLifecycleMethod(
|
|
165
|
+
tabActiveKey: string | undefined,
|
|
166
|
+
method: 'onActive' | 'onInactive',
|
|
167
|
+
forceRefresh = false,
|
|
168
|
+
) {
|
|
169
|
+
if (!tabActiveKey) {
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
|
|
145
173
|
if (method === 'onActive' && this.context?.pageInfo) {
|
|
146
174
|
this.context.pageInfo.version = 'v2';
|
|
147
175
|
}
|
|
148
|
-
const tabModel =
|
|
176
|
+
const tabModel =
|
|
177
|
+
this.findSubModel('tabs', (model) => model.uid === tabActiveKey) ||
|
|
178
|
+
(this.flowEngine.getModel(tabActiveKey) as BasePageTabModel | undefined);
|
|
149
179
|
|
|
150
180
|
if (tabModel) {
|
|
151
181
|
if (tabModel.context.tabActive) {
|
|
@@ -183,7 +213,10 @@ export class PageModel extends FlowModel<PageModelStructure> {
|
|
|
183
213
|
const routePathname = this.flowEngine?.context?.route?.pathname;
|
|
184
214
|
// In route-managed multi-view mode, only the top view in URL should mutate document.title.
|
|
185
215
|
if (hasRouteNavigation && currentViewUid && typeof routePathname === 'string') {
|
|
186
|
-
const
|
|
216
|
+
const layoutRoutePath = this.context?.layout?.routePath;
|
|
217
|
+
const topViewUid = parsePathnameToViewParams(routePathname, {
|
|
218
|
+
basePath: this.context?.layoutRoute?.basePathname || (layoutRoutePath?.startsWith('/') ? layoutRoutePath : ''),
|
|
219
|
+
}).at(-1)?.viewUid;
|
|
187
220
|
if (topViewUid && topViewUid !== currentViewUid) {
|
|
188
221
|
return;
|
|
189
222
|
}
|
|
@@ -68,22 +68,15 @@ export class RootPageModel extends PageModel {
|
|
|
68
68
|
reaction(
|
|
69
69
|
() => this.context.pageActive.value,
|
|
70
70
|
() => {
|
|
71
|
+
if (this.context.view?.inputArgs?.activationControlledByLayout) {
|
|
72
|
+
this.mounted = true;
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
71
75
|
if (this.context.pageActive.value && this.mounted) {
|
|
72
|
-
|
|
73
|
-
if (firstTab) {
|
|
74
|
-
this.setProps('tabActiveKey', firstTab.uid);
|
|
75
|
-
this.invokeTabModelLifecycleMethod(firstTab.uid, 'onActive', true);
|
|
76
|
-
}
|
|
76
|
+
this.activateCurrentTab(true);
|
|
77
77
|
}
|
|
78
78
|
if (this.context.pageActive.value === false) {
|
|
79
|
-
|
|
80
|
-
this.invokeTabModelLifecycleMethod(this.props.tabActiveKey, 'onInactive');
|
|
81
|
-
} else {
|
|
82
|
-
const firstTab = this.subModels.tabs?.[0];
|
|
83
|
-
if (firstTab) {
|
|
84
|
-
this.invokeTabModelLifecycleMethod(firstTab.uid, 'onInactive');
|
|
85
|
-
}
|
|
86
|
-
}
|
|
79
|
+
this.deactivateCurrentTab();
|
|
87
80
|
}
|
|
88
81
|
this.mounted = true;
|
|
89
82
|
},
|
|
@@ -107,6 +107,18 @@ describe('ChildPageModel', () => {
|
|
|
107
107
|
expect(mockFlowEngine.moveModel).toHaveBeenCalledWith('active-model-id', 'over-model-id');
|
|
108
108
|
});
|
|
109
109
|
|
|
110
|
+
it('should ignore self-drop', async () => {
|
|
111
|
+
await childPageModel.handleDragEnd({
|
|
112
|
+
...mockDragEndEvent,
|
|
113
|
+
over: {
|
|
114
|
+
...(mockDragEndEvent.over as NonNullable<DragEndEvent['over']>),
|
|
115
|
+
id: 'active-model-id',
|
|
116
|
+
},
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
expect(mockFlowEngine.moveModel).not.toHaveBeenCalled();
|
|
120
|
+
});
|
|
121
|
+
|
|
110
122
|
it('should handle case when over is null', async () => {
|
|
111
123
|
const eventWithNullOver = {
|
|
112
124
|
...mockDragEndEvent,
|
|
@@ -47,6 +47,13 @@ vi.mock('@nocobase/flow-engine', () => {
|
|
|
47
47
|
return [];
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
findSubModel(key: string, callback: any) {
|
|
51
|
+
if (this.subModels[key]) {
|
|
52
|
+
return this.subModels[key].find(callback) || null;
|
|
53
|
+
}
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
|
|
50
57
|
addSubModel() {}
|
|
51
58
|
setSubModel() {}
|
|
52
59
|
|
|
@@ -260,6 +267,44 @@ describe('PageModel', () => {
|
|
|
260
267
|
});
|
|
261
268
|
});
|
|
262
269
|
|
|
270
|
+
describe('tab lifecycle', () => {
|
|
271
|
+
it('should invoke tab lifecycle on PageModel subModels before engine lookup', () => {
|
|
272
|
+
const blockOnActive = vi.fn();
|
|
273
|
+
const blockOnInactive = vi.fn();
|
|
274
|
+
const tabModel = {
|
|
275
|
+
uid: 'tab1',
|
|
276
|
+
context: {
|
|
277
|
+
tabActive: { value: false },
|
|
278
|
+
},
|
|
279
|
+
subModels: {
|
|
280
|
+
grid: {
|
|
281
|
+
mapSubModels: vi.fn((_key, callback) => {
|
|
282
|
+
callback({ onActive: blockOnActive, onInactive: blockOnInactive });
|
|
283
|
+
}),
|
|
284
|
+
},
|
|
285
|
+
},
|
|
286
|
+
};
|
|
287
|
+
(pageModel as any).subModels = { tabs: [tabModel] };
|
|
288
|
+
(pageModel as any).flowEngine = {
|
|
289
|
+
getModel: vi.fn(() => undefined),
|
|
290
|
+
};
|
|
291
|
+
(pageModel as any).context = {
|
|
292
|
+
pageInfo: {},
|
|
293
|
+
view: {
|
|
294
|
+
inputArgs: { pageActive: true },
|
|
295
|
+
},
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
pageModel.invokeTabModelLifecycleMethod('tab1', 'onActive', true);
|
|
299
|
+
pageModel.invokeTabModelLifecycleMethod('tab1', 'onInactive');
|
|
300
|
+
|
|
301
|
+
expect((pageModel as any).flowEngine.getModel).not.toHaveBeenCalled();
|
|
302
|
+
expect(tabModel.context.tabActive.value).toBe(false);
|
|
303
|
+
expect(blockOnActive).toHaveBeenCalledWith(true);
|
|
304
|
+
expect(blockOnInactive).toHaveBeenCalledWith(false);
|
|
305
|
+
});
|
|
306
|
+
});
|
|
307
|
+
|
|
263
308
|
describe('renderTabs activeKey logic', () => {
|
|
264
309
|
beforeEach(() => {
|
|
265
310
|
// Mock mapTabs to avoid complex rendering logic inside it
|
|
@@ -455,6 +500,7 @@ describe('PageModel', () => {
|
|
|
455
500
|
} as any;
|
|
456
501
|
(pageModel as any).context = {
|
|
457
502
|
currentRoute: {
|
|
503
|
+
id: 'route-1',
|
|
458
504
|
enableTabs: false,
|
|
459
505
|
},
|
|
460
506
|
};
|
|
@@ -479,6 +525,7 @@ describe('PageModel', () => {
|
|
|
479
525
|
} as any;
|
|
480
526
|
(pageModel as any).context = {
|
|
481
527
|
currentRoute: {
|
|
528
|
+
id: 'route-1',
|
|
482
529
|
enableTabs: true,
|
|
483
530
|
},
|
|
484
531
|
};
|
|
@@ -495,6 +542,59 @@ describe('PageModel', () => {
|
|
|
495
542
|
paddingBottom: 0,
|
|
496
543
|
});
|
|
497
544
|
});
|
|
545
|
+
|
|
546
|
+
it('should ignore stale desktop route enableTabs=false from another route', () => {
|
|
547
|
+
pageModel.props = {
|
|
548
|
+
routeId: 'route-1',
|
|
549
|
+
displayTitle: true,
|
|
550
|
+
enableTabs: true,
|
|
551
|
+
title: 'Title',
|
|
552
|
+
headerStyle: { backgroundColor: 'var(--colorBgLayout)' },
|
|
553
|
+
} as any;
|
|
554
|
+
(pageModel as any).context = {
|
|
555
|
+
currentRoute: {
|
|
556
|
+
id: 'route-2',
|
|
557
|
+
enableTabs: false,
|
|
558
|
+
},
|
|
559
|
+
};
|
|
560
|
+
pageModel.renderTabs = vi.fn(() => null);
|
|
561
|
+
pageModel.renderFirstTab = vi.fn(() => null);
|
|
562
|
+
|
|
563
|
+
const result = pageModel.render() as any;
|
|
564
|
+
const header = result.props.children[0];
|
|
565
|
+
|
|
566
|
+
expect(pageModel.renderTabs).toHaveBeenCalled();
|
|
567
|
+
expect(pageModel.renderFirstTab).not.toHaveBeenCalled();
|
|
568
|
+
expect(header.props.style).toMatchObject({
|
|
569
|
+
backgroundColor: 'var(--colorBgLayout)',
|
|
570
|
+
paddingBottom: 0,
|
|
571
|
+
});
|
|
572
|
+
});
|
|
573
|
+
|
|
574
|
+
it('should ignore stale desktop route enableTabs=true from another route', () => {
|
|
575
|
+
pageModel.props = {
|
|
576
|
+
routeId: 'route-1',
|
|
577
|
+
displayTitle: true,
|
|
578
|
+
enableTabs: false,
|
|
579
|
+
title: 'Title',
|
|
580
|
+
headerStyle: { backgroundColor: 'var(--colorBgLayout)' },
|
|
581
|
+
} as any;
|
|
582
|
+
(pageModel as any).context = {
|
|
583
|
+
currentRoute: {
|
|
584
|
+
id: 'route-2',
|
|
585
|
+
enableTabs: true,
|
|
586
|
+
},
|
|
587
|
+
};
|
|
588
|
+
pageModel.renderTabs = vi.fn(() => null);
|
|
589
|
+
pageModel.renderFirstTab = vi.fn(() => null);
|
|
590
|
+
|
|
591
|
+
const result = pageModel.render() as any;
|
|
592
|
+
const header = result.props.children[0];
|
|
593
|
+
|
|
594
|
+
expect(pageModel.renderTabs).not.toHaveBeenCalled();
|
|
595
|
+
expect(pageModel.renderFirstTab).toHaveBeenCalled();
|
|
596
|
+
expect(header.props.style).toEqual({ backgroundColor: 'var(--colorBgLayout)' });
|
|
597
|
+
});
|
|
498
598
|
});
|
|
499
599
|
|
|
500
600
|
describe('dirty refresh signal', () => {
|
|
@@ -554,7 +654,7 @@ describe('PageModel', () => {
|
|
|
554
654
|
pageModel.onMount();
|
|
555
655
|
|
|
556
656
|
expect(typeof listeners['view:activated']).toBe('function');
|
|
557
|
-
expect(invokeSpy).toHaveBeenCalledWith('tab1', 'onActive');
|
|
657
|
+
expect(invokeSpy).toHaveBeenCalledWith('tab1', 'onActive', false);
|
|
558
658
|
});
|
|
559
659
|
});
|
|
560
660
|
|
|
@@ -630,6 +730,7 @@ describe('PageModel', () => {
|
|
|
630
730
|
it('should use page documentTitle when desktop route disables tabs even if flow model enables tabs', async () => {
|
|
631
731
|
pageModel.props = { routeId: 'route-1', enableTabs: true, title: 'Route page title' } as any;
|
|
632
732
|
(pageModel as any).context.currentRoute = {
|
|
733
|
+
id: 'route-1',
|
|
633
734
|
enableTabs: false,
|
|
634
735
|
};
|
|
635
736
|
(pageModel as any).stepParams = {
|
|
@@ -0,0 +1,86 @@
|
|
|
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 { afterEach, describe, expect, it, vi } from 'vitest';
|
|
11
|
+
import { DisplayItemModel } from '@nocobase/flow-engine';
|
|
12
|
+
import { AssociationFieldGroupModel } from '../AssociationFieldGroupModel';
|
|
13
|
+
|
|
14
|
+
function createCollection(name: string, fields: any[]) {
|
|
15
|
+
return {
|
|
16
|
+
name,
|
|
17
|
+
dataSourceKey: 'main',
|
|
18
|
+
getFields: () => fields,
|
|
19
|
+
getToOneAssociationFields: () => fields.filter((field) => field?.type === 'belongsTo' || field?.type === 'hasOne'),
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
describe('AssociationFieldGroupModel', () => {
|
|
24
|
+
afterEach(() => {
|
|
25
|
+
vi.restoreAllMocks();
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
it('limits display association fields to relation / relation / field', () => {
|
|
29
|
+
vi.spyOn(DisplayItemModel, 'getDefaultBindingByField').mockReturnValue({ modelName: 'InputFieldModel' } as any);
|
|
30
|
+
|
|
31
|
+
const companies = createCollection('companies', [
|
|
32
|
+
{ name: 'title', title: 'Company title', interface: 'input', type: 'string' },
|
|
33
|
+
]);
|
|
34
|
+
const departments = createCollection('departments', [
|
|
35
|
+
{ name: 'name', title: 'Department name', interface: 'input', type: 'string' },
|
|
36
|
+
{
|
|
37
|
+
name: 'company',
|
|
38
|
+
title: 'Company',
|
|
39
|
+
interface: 'm2o',
|
|
40
|
+
type: 'belongsTo',
|
|
41
|
+
target: 'companies',
|
|
42
|
+
targetCollection: companies,
|
|
43
|
+
isAssociationField: () => true,
|
|
44
|
+
},
|
|
45
|
+
]);
|
|
46
|
+
const users = createCollection('users', [
|
|
47
|
+
{
|
|
48
|
+
name: 'department',
|
|
49
|
+
title: 'Department',
|
|
50
|
+
interface: 'm2o',
|
|
51
|
+
type: 'belongsTo',
|
|
52
|
+
target: 'departments',
|
|
53
|
+
targetCollection: departments,
|
|
54
|
+
isAssociationField: () => true,
|
|
55
|
+
},
|
|
56
|
+
]);
|
|
57
|
+
const posts = createCollection('posts', [
|
|
58
|
+
{
|
|
59
|
+
name: 'user',
|
|
60
|
+
title: 'User',
|
|
61
|
+
interface: 'm2o',
|
|
62
|
+
type: 'belongsTo',
|
|
63
|
+
target: 'users',
|
|
64
|
+
targetCollection: users,
|
|
65
|
+
isAssociationField: () => true,
|
|
66
|
+
},
|
|
67
|
+
]);
|
|
68
|
+
|
|
69
|
+
const ctx = {
|
|
70
|
+
collection: posts,
|
|
71
|
+
t: (key: string) => key,
|
|
72
|
+
} as any;
|
|
73
|
+
|
|
74
|
+
const firstLevel = AssociationFieldGroupModel.defineChildren(ctx) as any[];
|
|
75
|
+
const firstChildren = firstLevel[0].children();
|
|
76
|
+
const firstAssociationGroup = firstChildren.find((item) => item.key === 'user-children-associationField');
|
|
77
|
+
const secondLevel = firstAssociationGroup.children;
|
|
78
|
+
const secondChildren = secondLevel[0].children();
|
|
79
|
+
const secondFieldsGroup = secondChildren.find((item) => item.key === 'user.department-children-collectionField');
|
|
80
|
+
|
|
81
|
+
expect(secondChildren.map((item) => item.key)).toContain('user.department-children-collectionField');
|
|
82
|
+
expect(secondChildren.map((item) => item.key)).not.toContain('user.department-children-associationField');
|
|
83
|
+
expect(secondFieldsGroup.children.map((item) => item.key)).toContain('c-user.department.name');
|
|
84
|
+
expect(secondFieldsGroup.children.map((item) => item.key)).not.toContain('c-user.department.company');
|
|
85
|
+
});
|
|
86
|
+
});
|