@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
|
@@ -213,6 +213,7 @@ const ArrayNester = ({
|
|
|
213
213
|
const isConfigMode = !!model.context.flowSettingsEnabled;
|
|
214
214
|
const { t } = useTranslation();
|
|
215
215
|
const rowIndex = model.context.fieldIndex || [];
|
|
216
|
+
const parentFieldPathArray = (model?.parent as any)?.context?.fieldPathArray || [];
|
|
216
217
|
// 用来缓存每行的 fork,保证每行只创建一次
|
|
217
218
|
const forksRef = useRef<Record<string, any>>({});
|
|
218
219
|
const collectionName = model.context.collectionField.name;
|
|
@@ -251,7 +252,7 @@ const ArrayNester = ({
|
|
|
251
252
|
{displayFields.map((field: any, index) => {
|
|
252
253
|
const { key, name: fieldName, isDefault } = field;
|
|
253
254
|
const fieldIndex = [...rowIndex, `${collectionName}:${index}`];
|
|
254
|
-
|
|
255
|
+
const fieldPathArray = parentFieldPathArray;
|
|
255
256
|
// 每行只创建一次 fork
|
|
256
257
|
if (!forksRef.current[key]) {
|
|
257
258
|
const fork = gridModel.createFork({ disabled });
|
|
@@ -268,6 +269,11 @@ const ArrayNester = ({
|
|
|
268
269
|
get: () => fieldIndex,
|
|
269
270
|
cache: false,
|
|
270
271
|
});
|
|
272
|
+
console.log(fieldPathArray);
|
|
273
|
+
currentFork.context.defineProperty('fieldPathArray', {
|
|
274
|
+
get: () => fieldPathArray,
|
|
275
|
+
cache: false,
|
|
276
|
+
});
|
|
271
277
|
|
|
272
278
|
const getRowItem = createItemChainGetter({
|
|
273
279
|
valueAccessor: () => currentFork.context.form.getFieldValue([name, fieldName]),
|
package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/SubTableColumnModel.tsx
CHANGED
|
@@ -33,7 +33,7 @@ import React, { useRef, useMemo, useEffect } from 'react';
|
|
|
33
33
|
import { SubTableFieldModel } from '.';
|
|
34
34
|
import { FieldModel } from '../../../base/FieldModel';
|
|
35
35
|
import { DetailsItemModel } from '../../../blocks/details/DetailsItemModel';
|
|
36
|
-
import { FieldDeletePlaceholder, CustomWidth } from '../../../blocks/table/TableColumnModel';
|
|
36
|
+
import { FieldDeletePlaceholder, CustomWidth, normalizeTableColumnWidth } from '../../../blocks/table/TableColumnModel';
|
|
37
37
|
import { buildDynamicNamePath } from '../../../blocks/form/dynamicNamePath';
|
|
38
38
|
import { getSubTableRowIdentity } from './rowIdentity';
|
|
39
39
|
import { getFieldBindingUse, rebuildFieldSubModel } from '../../../../internal/utils/rebuildFieldSubModel';
|
|
@@ -67,7 +67,7 @@ export function FieldWithoutPermissionPlaceholder({ targetModel }) {
|
|
|
67
67
|
const dataSourcePrefix = `${t(dataSource.displayName || dataSource.key)} > `;
|
|
68
68
|
const collectionPrefix = collection ? `${t(collection.title) || collection.name || collection.tableName} > ` : '';
|
|
69
69
|
return `${dataSourcePrefix}${collectionPrefix}${name}`;
|
|
70
|
-
}, []);
|
|
70
|
+
}, [collection, dataSource.displayName, dataSource.key, name, t]);
|
|
71
71
|
const { actionName } = fieldModel.forbidden || {};
|
|
72
72
|
const messageValue = useMemo(() => {
|
|
73
73
|
return t(
|
|
@@ -77,7 +77,7 @@ export function FieldWithoutPermissionPlaceholder({ targetModel }) {
|
|
|
77
77
|
actionName: t(capitalize(actionName)),
|
|
78
78
|
},
|
|
79
79
|
).replaceAll('>', '>');
|
|
80
|
-
}, [nameValue, t]);
|
|
80
|
+
}, [actionName, nameValue, t]);
|
|
81
81
|
return (
|
|
82
82
|
<Tooltip title={messageValue}>
|
|
83
83
|
<LockOutlined style={{ opacity: '0.3' }} />
|
|
@@ -100,10 +100,9 @@ const LargeFieldEdit = observer(({ model, params: { fieldPath, index }, defaultV
|
|
|
100
100
|
const handleChange = useMemo(
|
|
101
101
|
() =>
|
|
102
102
|
debounce((val) => {
|
|
103
|
-
if (props.onChange) props.onChange(val);
|
|
104
103
|
if (onChange) onChange(val);
|
|
105
104
|
}, 200),
|
|
106
|
-
[
|
|
105
|
+
[onChange],
|
|
107
106
|
);
|
|
108
107
|
|
|
109
108
|
return <FieldModelRenderer model={model} {...rest} onChange={handleChange} />;
|
|
@@ -149,7 +148,7 @@ const LargeFieldEdit = observer(({ model, params: { fieldPath, index }, defaultV
|
|
|
149
148
|
</Space>
|
|
150
149
|
);
|
|
151
150
|
}
|
|
152
|
-
}, [collectionField.interface, defaultValue, fieldModel]);
|
|
151
|
+
}, [collectionField.interface, defaultValue, disabled, fieldModel]);
|
|
153
152
|
return (
|
|
154
153
|
<div
|
|
155
154
|
ref={ref}
|
|
@@ -830,7 +829,7 @@ SubTableColumnModel.registerFlow({
|
|
|
830
829
|
width: 200,
|
|
831
830
|
},
|
|
832
831
|
handler(ctx, params) {
|
|
833
|
-
ctx.model.setProps('width', params.width);
|
|
832
|
+
ctx.model.setProps('width', normalizeTableColumnWidth(params.width));
|
|
834
833
|
},
|
|
835
834
|
},
|
|
836
835
|
aclCheck: {
|
|
@@ -60,13 +60,13 @@ export class SubTableFieldModel extends AssociationFieldModel {
|
|
|
60
60
|
setCurrentPage;
|
|
61
61
|
currentPageSize;
|
|
62
62
|
|
|
63
|
-
getCurrentValue
|
|
63
|
+
getCurrentValue() {
|
|
64
64
|
const fallback = Array.isArray(this.props.value) ? this.props.value : [];
|
|
65
|
-
const fieldPathArray = this.parent?.context?.fieldPathArray;
|
|
65
|
+
const fieldPathArray = this.context.fieldPathArray ?? this.parent?.context?.fieldPathArray;
|
|
66
66
|
if (!Array.isArray(fieldPathArray) || !fieldPathArray.length) return fallback;
|
|
67
67
|
const latest = this.context.blockModel?.context?.form?.getFieldValue?.(fieldPathArray as any);
|
|
68
68
|
return Array.isArray(latest) ? latest : fallback;
|
|
69
|
-
}
|
|
69
|
+
}
|
|
70
70
|
|
|
71
71
|
get collection() {
|
|
72
72
|
return this.context.collection;
|
|
@@ -111,6 +111,7 @@ export class SubTableFieldModel extends AssociationFieldModel {
|
|
|
111
111
|
},
|
|
112
112
|
};
|
|
113
113
|
const isConfigMode = !!this.context.flowSettingsEnabled;
|
|
114
|
+
const fieldPathArray = this.context.fieldPathArray ?? this.parent?.context?.fieldPathArray;
|
|
114
115
|
return (
|
|
115
116
|
<SubTableField
|
|
116
117
|
{...this.props}
|
|
@@ -121,8 +122,8 @@ export class SubTableFieldModel extends AssociationFieldModel {
|
|
|
121
122
|
parentItem={this.context.item}
|
|
122
123
|
filterTargetKey={this.collection.filterTargetKey}
|
|
123
124
|
formValuesChangeEmitter={this.context.blockModel?.emitter}
|
|
124
|
-
fieldPathArray={
|
|
125
|
-
getCurrentValue={this.getCurrentValue}
|
|
125
|
+
fieldPathArray={fieldPathArray}
|
|
126
|
+
getCurrentValue={() => this.getCurrentValue()}
|
|
126
127
|
/>
|
|
127
128
|
);
|
|
128
129
|
}
|
|
@@ -191,7 +191,15 @@ export class ClickableFieldModel extends FieldModel {
|
|
|
191
191
|
}
|
|
192
192
|
|
|
193
193
|
renderInDisplayStyle(value, record?, isToMany?, wrap?) {
|
|
194
|
-
const {
|
|
194
|
+
const {
|
|
195
|
+
clickToOpen = false,
|
|
196
|
+
displayStyle,
|
|
197
|
+
titleField,
|
|
198
|
+
overflowMode,
|
|
199
|
+
disabled,
|
|
200
|
+
timeFormat,
|
|
201
|
+
...restProps
|
|
202
|
+
} = this.props;
|
|
195
203
|
const titleCollectionField = titleField
|
|
196
204
|
? this.context.collectionField?.targetCollection?.getField?.(titleField) || this.context.collectionField
|
|
197
205
|
: this.context.collectionField;
|
|
@@ -38,6 +38,12 @@ const CollectionSelector = (props) => {
|
|
|
38
38
|
);
|
|
39
39
|
};
|
|
40
40
|
|
|
41
|
+
function getConfiguredCollectionNames(collectionField) {
|
|
42
|
+
return (collectionField?.uiSchema?.enum || collectionField?.enum || [])
|
|
43
|
+
.map((item) => (item && typeof item === 'object' ? item.value : item))
|
|
44
|
+
.filter((value) => value !== null && typeof value !== 'undefined');
|
|
45
|
+
}
|
|
46
|
+
|
|
41
47
|
export class CollectionSelectorFieldModel extends FieldModel {
|
|
42
48
|
render() {
|
|
43
49
|
return <CollectionSelector {...this.props} />;
|
|
@@ -66,12 +72,12 @@ CollectionSelectorFieldModel.registerFlow({
|
|
|
66
72
|
});
|
|
67
73
|
} else {
|
|
68
74
|
const collections = ctx.dataSourceManager.getDataSource('main').getCollections();
|
|
69
|
-
const defaultOptions = ctx.model.context.collectionField
|
|
75
|
+
const defaultOptions = getConfiguredCollectionNames(ctx.model.context.collectionField);
|
|
70
76
|
const options = collections
|
|
71
77
|
.filter((item: any) => !item.options.hidden)
|
|
72
78
|
.filter((v) => {
|
|
73
79
|
if (defaultOptions.length) {
|
|
74
|
-
return defaultOptions.
|
|
80
|
+
return defaultOptions.includes(v.name);
|
|
75
81
|
}
|
|
76
82
|
return true;
|
|
77
83
|
})
|
|
@@ -43,6 +43,12 @@ const fieldNames = {
|
|
|
43
43
|
color: 'color',
|
|
44
44
|
};
|
|
45
45
|
|
|
46
|
+
function getConfiguredCollectionNames(collectionField) {
|
|
47
|
+
return (collectionField?.uiSchema?.enum || collectionField?.enum || [])
|
|
48
|
+
.map((item) => (item && typeof item === 'object' ? item.value : item))
|
|
49
|
+
.filter((value) => value !== null && typeof value !== 'undefined');
|
|
50
|
+
}
|
|
51
|
+
|
|
46
52
|
export class DisplayEnumFieldModel extends ClickableFieldModel {
|
|
47
53
|
isEmpty(value: any) {
|
|
48
54
|
return value === null || value === undefined || value === '';
|
|
@@ -134,12 +140,12 @@ DisplayEnumFieldModel.registerFlow({
|
|
|
134
140
|
});
|
|
135
141
|
} else {
|
|
136
142
|
const collections = ctx.dataSourceManager.getDataSource('main').getCollections();
|
|
137
|
-
const defaultOptions = ctx.model.context.collectionField
|
|
143
|
+
const defaultOptions = getConfiguredCollectionNames(ctx.model.context.collectionField);
|
|
138
144
|
const options = collections
|
|
139
145
|
.filter((item: any) => !item.options.hidden)
|
|
140
146
|
.filter((v) => {
|
|
141
147
|
if (defaultOptions.length) {
|
|
142
|
-
return defaultOptions.
|
|
148
|
+
return defaultOptions.includes(v.name);
|
|
143
149
|
}
|
|
144
150
|
return true;
|
|
145
151
|
})
|
|
@@ -15,7 +15,7 @@ import { ClickableFieldModel } from './ClickableFieldModel';
|
|
|
15
15
|
export class DisplayTimeFieldModel extends ClickableFieldModel {
|
|
16
16
|
public renderComponent(value) {
|
|
17
17
|
const { prefix, suffix, style, className } = this.props;
|
|
18
|
-
const format = this.props['format'] || 'HH:mm:ss';
|
|
18
|
+
const format = this.props['timeFormat'] || this.props['format'] || 'HH:mm:ss';
|
|
19
19
|
const result = value && dayjs(value, 'HH:mm:ss').format(format);
|
|
20
20
|
return (
|
|
21
21
|
<span className={className} style={style}>
|
|
@@ -15,7 +15,7 @@ import { FieldModel } from '../base/FieldModel';
|
|
|
15
15
|
import { MobileTimePicker } from './mobile-components/MobileTimePicker';
|
|
16
16
|
|
|
17
17
|
const TimePickerCom = (props) => {
|
|
18
|
-
const format = props['format'] || 'HH:mm:ss';
|
|
18
|
+
const format = props['timeFormat'] || props['format'] || 'HH:mm:ss';
|
|
19
19
|
const onChange = props.onChange;
|
|
20
20
|
const ctx = useFlowModelContext();
|
|
21
21
|
const componentProps = {
|
|
@@ -0,0 +1,61 @@
|
|
|
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 { FlowEngine, FlowModelProvider } from '@nocobase/flow-engine';
|
|
11
|
+
import { render, screen } from '@testing-library/react';
|
|
12
|
+
import { describe, expect, it } from 'vitest';
|
|
13
|
+
import React from 'react';
|
|
14
|
+
import { DisplayTimeFieldModel } from '../DisplayTimeFieldModel';
|
|
15
|
+
import { TimeFieldModel } from '../TimeFieldModel';
|
|
16
|
+
|
|
17
|
+
describe('TimeFieldModel', () => {
|
|
18
|
+
it('uses timeFormat before format when rendering the editable time picker', () => {
|
|
19
|
+
const engine = new FlowEngine();
|
|
20
|
+
engine.registerModels({ TimeFieldModel });
|
|
21
|
+
|
|
22
|
+
const model = engine.createModel<TimeFieldModel>({
|
|
23
|
+
use: TimeFieldModel,
|
|
24
|
+
uid: 'time-field-format',
|
|
25
|
+
props: {
|
|
26
|
+
value: '13:05:06',
|
|
27
|
+
format: 'HH:mm:ss',
|
|
28
|
+
timeFormat: 'hh:mm:ss a',
|
|
29
|
+
},
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
render(
|
|
33
|
+
<FlowModelProvider model={model}>
|
|
34
|
+
<>{model.render()}</>
|
|
35
|
+
</FlowModelProvider>,
|
|
36
|
+
);
|
|
37
|
+
|
|
38
|
+
expect(screen.getByDisplayValue('01:05:06 pm')).toBeInTheDocument();
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
describe('DisplayTimeFieldModel', () => {
|
|
43
|
+
it('uses timeFormat before format when rendering read pretty time text', () => {
|
|
44
|
+
const engine = new FlowEngine();
|
|
45
|
+
engine.registerModels({ DisplayTimeFieldModel });
|
|
46
|
+
|
|
47
|
+
const model = engine.createModel<DisplayTimeFieldModel>({
|
|
48
|
+
use: DisplayTimeFieldModel,
|
|
49
|
+
uid: 'display-time-field-format',
|
|
50
|
+
props: {
|
|
51
|
+
value: '13:05:06',
|
|
52
|
+
format: 'HH:mm:ss',
|
|
53
|
+
timeFormat: 'hh:mm:ss a',
|
|
54
|
+
},
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
render(model.render());
|
|
58
|
+
|
|
59
|
+
expect(screen.getByText('01:05:06 pm')).toBeInTheDocument();
|
|
60
|
+
});
|
|
61
|
+
});
|
|
@@ -9,11 +9,26 @@
|
|
|
9
9
|
|
|
10
10
|
import { useFlowModelContext } from '@nocobase/flow-engine';
|
|
11
11
|
import { dayjs } from '@nocobase/utils/client';
|
|
12
|
+
import type { Dayjs } from 'dayjs';
|
|
12
13
|
import { DatePicker } from 'antd';
|
|
13
14
|
import { DatePicker as AntdMobileDatePicker } from 'antd-mobile';
|
|
14
15
|
import React from 'react';
|
|
15
16
|
import { useCallback, useState } from 'react';
|
|
16
17
|
|
|
18
|
+
type DateValue = string | number | Date | Dayjs | null | undefined;
|
|
19
|
+
|
|
20
|
+
function toNativeDate(value: DateValue): Date | null {
|
|
21
|
+
if (value === null || value === undefined || value === '') {
|
|
22
|
+
return null;
|
|
23
|
+
}
|
|
24
|
+
if (value instanceof Date) {
|
|
25
|
+
return Number.isNaN(value.getTime()) ? null : value;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const parsed = dayjs.isDayjs(value) ? value : dayjs(value);
|
|
29
|
+
return parsed.isValid() ? parsed.toDate() : null;
|
|
30
|
+
}
|
|
31
|
+
|
|
17
32
|
export const MobileDatePicker = (props) => {
|
|
18
33
|
const {
|
|
19
34
|
value,
|
|
@@ -56,9 +71,9 @@ export const MobileDatePicker = (props) => {
|
|
|
56
71
|
return data;
|
|
57
72
|
}
|
|
58
73
|
}, []);
|
|
59
|
-
|
|
60
|
-
const minDate =
|
|
61
|
-
const maxDate =
|
|
74
|
+
const mobileValue = toNativeDate(value);
|
|
75
|
+
const minDate = toNativeDate(min) ?? new Date(1950, 0, 1);
|
|
76
|
+
const maxDate = toNativeDate(max) ?? new Date(2050, 11, 31);
|
|
62
77
|
|
|
63
78
|
return (
|
|
64
79
|
<>
|
|
@@ -78,6 +93,7 @@ export const MobileDatePicker = (props) => {
|
|
|
78
93
|
cancelText={t('Cancel')}
|
|
79
94
|
confirmText={t('Confirm')}
|
|
80
95
|
visible={visible}
|
|
96
|
+
value={mobileValue}
|
|
81
97
|
title={<a onClick={handleClear}>{t('Clear')}</a>}
|
|
82
98
|
onClose={() => {
|
|
83
99
|
setVisible(false);
|
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
import { useFlowModelContext } from '@nocobase/flow-engine';
|
|
11
11
|
import { Select } from 'antd';
|
|
12
12
|
import type { CSSProperties } from 'react';
|
|
13
|
-
import React, { useCallback, useEffect, useMemo, useState } from 'react';
|
|
13
|
+
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
14
14
|
import { Button, CheckList, Popup, SearchBar, SpinLoading } from 'antd-mobile';
|
|
15
15
|
import { css } from '@emotion/css';
|
|
16
16
|
import {
|
|
@@ -51,7 +51,7 @@ function deriveRecordsFromValue(
|
|
|
51
51
|
) {
|
|
52
52
|
if (isMultiple) {
|
|
53
53
|
if (Array.isArray(value)) {
|
|
54
|
-
return (value.filter(
|
|
54
|
+
return (value.filter((item) => item !== null && item !== undefined) as any[]).map((item) => {
|
|
55
55
|
if (valueMode === 'value') {
|
|
56
56
|
return optionMap.get(item) ?? { [valueKey]: item };
|
|
57
57
|
}
|
|
@@ -113,11 +113,13 @@ export function MobileLazySelect(props: Readonly<LazySelectProps>) {
|
|
|
113
113
|
);
|
|
114
114
|
|
|
115
115
|
const [selectedRecords, setSelectedRecords] = useState<AssociationOption[]>(() => derivedRecords);
|
|
116
|
+
const wasVisibleRef = useRef(visible);
|
|
116
117
|
|
|
117
118
|
useEffect(() => {
|
|
118
|
-
if (visible) {
|
|
119
|
+
if (visible && !wasVisibleRef.current) {
|
|
119
120
|
setSelectedRecords(derivedRecords);
|
|
120
121
|
}
|
|
122
|
+
wasVisibleRef.current = visible;
|
|
121
123
|
}, [derivedRecords, visible]);
|
|
122
124
|
|
|
123
125
|
useEffect(() => {
|
|
@@ -0,0 +1,94 @@
|
|
|
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 React from 'react';
|
|
11
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
12
|
+
import { act, fireEvent, render, screen } from '@nocobase/test/client';
|
|
13
|
+
import { dayjs } from '@nocobase/utils/client';
|
|
14
|
+
import { MobileDatePicker } from '../MobileDatePicker';
|
|
15
|
+
|
|
16
|
+
type MockDatePickerProps = Record<string, unknown> & {
|
|
17
|
+
value?: unknown;
|
|
18
|
+
visible?: boolean;
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const mockState = vi.hoisted(
|
|
22
|
+
(): {
|
|
23
|
+
antdDatePickerProps?: MockDatePickerProps;
|
|
24
|
+
mobileDatePickerProps?: MockDatePickerProps;
|
|
25
|
+
} => ({
|
|
26
|
+
antdDatePickerProps: undefined,
|
|
27
|
+
mobileDatePickerProps: undefined,
|
|
28
|
+
}),
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
vi.mock('@nocobase/flow-engine', async () => {
|
|
32
|
+
const actual = await vi.importActual<typeof import('@nocobase/flow-engine')>('@nocobase/flow-engine');
|
|
33
|
+
return {
|
|
34
|
+
...actual,
|
|
35
|
+
useFlowModelContext: () => ({
|
|
36
|
+
t: (value: string) => value,
|
|
37
|
+
}),
|
|
38
|
+
};
|
|
39
|
+
});
|
|
40
|
+
|
|
41
|
+
vi.mock('antd', async () => {
|
|
42
|
+
const actual = await vi.importActual<typeof import('antd')>('antd');
|
|
43
|
+
return {
|
|
44
|
+
...actual,
|
|
45
|
+
DatePicker: (props: MockDatePickerProps) => {
|
|
46
|
+
mockState.antdDatePickerProps = props;
|
|
47
|
+
return <div data-testid="antd-date-picker" />;
|
|
48
|
+
},
|
|
49
|
+
};
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
vi.mock('antd-mobile', () => ({
|
|
53
|
+
DatePicker: (props: MockDatePickerProps) => {
|
|
54
|
+
mockState.mobileDatePickerProps = props;
|
|
55
|
+
return props.visible ? <div data-testid="mobile-date-picker" /> : null;
|
|
56
|
+
},
|
|
57
|
+
}));
|
|
58
|
+
|
|
59
|
+
describe('MobileDatePicker', () => {
|
|
60
|
+
beforeEach(() => {
|
|
61
|
+
mockState.antdDatePickerProps = undefined;
|
|
62
|
+
mockState.mobileDatePickerProps = undefined;
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('uses the form value as the mobile popup value', () => {
|
|
66
|
+
render(
|
|
67
|
+
<MobileDatePicker
|
|
68
|
+
value={dayjs('2037-03-06 12:34:56')}
|
|
69
|
+
showTime
|
|
70
|
+
picker="date"
|
|
71
|
+
timeFormat="HH:mm:ss"
|
|
72
|
+
onChange={vi.fn()}
|
|
73
|
+
/>,
|
|
74
|
+
);
|
|
75
|
+
|
|
76
|
+
const trigger = screen.getByTestId('antd-date-picker').parentElement as HTMLElement;
|
|
77
|
+
act(() => {
|
|
78
|
+
fireEvent.click(trigger);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
const popupValue = mockState.mobileDatePickerProps?.value;
|
|
82
|
+
expect(screen.getByTestId('mobile-date-picker')).toBeInTheDocument();
|
|
83
|
+
expect(popupValue).toBeInstanceOf(Date);
|
|
84
|
+
if (!(popupValue instanceof Date)) {
|
|
85
|
+
throw new Error('Expected popup value to be a Date');
|
|
86
|
+
}
|
|
87
|
+
expect(popupValue.getFullYear()).toBe(2037);
|
|
88
|
+
expect(popupValue.getMonth()).toBe(2);
|
|
89
|
+
expect(popupValue.getDate()).toBe(6);
|
|
90
|
+
expect(popupValue.getHours()).toBe(12);
|
|
91
|
+
expect(popupValue.getMinutes()).toBe(34);
|
|
92
|
+
expect(popupValue.getSeconds()).toBe(56);
|
|
93
|
+
});
|
|
94
|
+
});
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
import React from 'react';
|
|
11
11
|
import { beforeEach, describe, it, expect, vi } from 'vitest';
|
|
12
12
|
import { act, fireEvent, render, screen } from '@nocobase/test/client';
|
|
13
|
+
import { MobileLazySelect } from '../MobileLazySelect';
|
|
13
14
|
import { MobileSelect } from '../MobileSelect';
|
|
14
15
|
|
|
15
16
|
const DEFAULT_OPTIONS = [
|
|
@@ -17,6 +18,11 @@ const DEFAULT_OPTIONS = [
|
|
|
17
18
|
{ label: 'Option B', value: 'b' },
|
|
18
19
|
];
|
|
19
20
|
|
|
21
|
+
const RELATION_OPTIONS = [
|
|
22
|
+
{ uuid: '05f6a3b4-bfb7-7943-578a-3819e2687a7e' },
|
|
23
|
+
{ uuid: 'c7d99828-a1de-9e70-4c2d-b0139abdf02e' },
|
|
24
|
+
];
|
|
25
|
+
|
|
20
26
|
const mockState = vi.hoisted(() => ({
|
|
21
27
|
selectProps: undefined as any,
|
|
22
28
|
popupProps: undefined as any,
|
|
@@ -44,6 +50,13 @@ function openPopup() {
|
|
|
44
50
|
expect(screen.getByTestId('popup')).toBeInTheDocument();
|
|
45
51
|
}
|
|
46
52
|
|
|
53
|
+
function openLazyPopup() {
|
|
54
|
+
act(() => {
|
|
55
|
+
mockState.selectProps?.onClick?.();
|
|
56
|
+
});
|
|
57
|
+
expect(screen.getByTestId('popup')).toBeInTheDocument();
|
|
58
|
+
}
|
|
59
|
+
|
|
47
60
|
function selectValues(values: string[]) {
|
|
48
61
|
act(() => {
|
|
49
62
|
mockState.checklistProps?.onChange?.(values);
|
|
@@ -73,6 +86,30 @@ function renderMobileSelect(props: Record<string, any> = {}) {
|
|
|
73
86
|
return { onChange, onChangeComplete };
|
|
74
87
|
}
|
|
75
88
|
|
|
89
|
+
function renderMobileLazySelect(props: Record<string, any> = {}) {
|
|
90
|
+
const onChange = props.onChange ?? vi.fn();
|
|
91
|
+
const renderComponent = (nextProps: Record<string, any> = {}) => (
|
|
92
|
+
<MobileLazySelect
|
|
93
|
+
fieldNames={{ label: 'uuid', value: 'uuid' }}
|
|
94
|
+
value={[]}
|
|
95
|
+
multiple
|
|
96
|
+
allowMultiple
|
|
97
|
+
options={RELATION_OPTIONS}
|
|
98
|
+
{...props}
|
|
99
|
+
{...nextProps}
|
|
100
|
+
onChange={onChange}
|
|
101
|
+
/>
|
|
102
|
+
);
|
|
103
|
+
|
|
104
|
+
const result = render(renderComponent());
|
|
105
|
+
|
|
106
|
+
return {
|
|
107
|
+
...result,
|
|
108
|
+
onChange,
|
|
109
|
+
rerender: (nextProps: Record<string, any> = {}) => result.rerender(renderComponent(nextProps)),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
76
113
|
vi.mock('@nocobase/flow-engine', async () => {
|
|
77
114
|
const actual = await vi.importActual<any>('@nocobase/flow-engine');
|
|
78
115
|
return {
|
|
@@ -80,6 +117,12 @@ vi.mock('@nocobase/flow-engine', async () => {
|
|
|
80
117
|
useFlowModelContext: () => ({
|
|
81
118
|
t: (value: string) => value,
|
|
82
119
|
}),
|
|
120
|
+
useFlowModel: () => ({
|
|
121
|
+
context: {
|
|
122
|
+
collectionField: {},
|
|
123
|
+
},
|
|
124
|
+
subModels: {},
|
|
125
|
+
}),
|
|
83
126
|
};
|
|
84
127
|
});
|
|
85
128
|
|
|
@@ -240,3 +283,30 @@ describe('MobileSelect in SubForm/SubTable containers', () => {
|
|
|
240
283
|
expect(onCommit).toHaveBeenNthCalledWith(2, ['a', 'b']);
|
|
241
284
|
});
|
|
242
285
|
});
|
|
286
|
+
|
|
287
|
+
describe('MobileLazySelect', () => {
|
|
288
|
+
beforeEach(() => {
|
|
289
|
+
resetMockState();
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
it('keeps pending relation records selected until confirm', () => {
|
|
293
|
+
const { onChange, rerender } = renderMobileLazySelect();
|
|
294
|
+
|
|
295
|
+
openLazyPopup();
|
|
296
|
+
expect(mockState.checklistProps?.value).toEqual([]);
|
|
297
|
+
|
|
298
|
+
selectValues(['c7d99828-a1de-9e70-4c2d-b0139abdf02e']);
|
|
299
|
+
expect(mockState.checklistProps?.value).toEqual(['c7d99828-a1de-9e70-4c2d-b0139abdf02e']);
|
|
300
|
+
|
|
301
|
+
rerender({
|
|
302
|
+
options: RELATION_OPTIONS.map((item) => ({ ...item })),
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
expect(mockState.checklistProps?.value).toEqual(['c7d99828-a1de-9e70-4c2d-b0139abdf02e']);
|
|
306
|
+
|
|
307
|
+
confirmSelection();
|
|
308
|
+
|
|
309
|
+
expect(onChange).toHaveBeenCalledTimes(1);
|
|
310
|
+
expect(onChange).toHaveBeenCalledWith([RELATION_OPTIONS[1]]);
|
|
311
|
+
});
|
|
312
|
+
});
|
|
@@ -282,7 +282,7 @@ const UIEditorTopbarAction = observer(
|
|
|
282
282
|
const { token } = theme.useToken();
|
|
283
283
|
const customToken = token as CustomToken;
|
|
284
284
|
const designable = !!flowEngine.context.flowSettingsEnabled;
|
|
285
|
-
const isMobileLayout = !!
|
|
285
|
+
const isMobileLayout = !!model.context.isMobileLayout;
|
|
286
286
|
|
|
287
287
|
useHotkeys(
|
|
288
288
|
'ctrl+shift+u',
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
11
|
+
import { dateTimeFormat } from '../../actions/dateTimeFormat';
|
|
12
|
+
|
|
13
|
+
describe('dateTimeFormat', () => {
|
|
14
|
+
it('only shows the time format schema for interface time fields', () => {
|
|
15
|
+
const ctx = {
|
|
16
|
+
model: {
|
|
17
|
+
context: {
|
|
18
|
+
collectionField: {
|
|
19
|
+
type: 'string',
|
|
20
|
+
interface: 'time',
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
expect(Object.keys(dateTimeFormat.uiSchema(ctx))).toEqual(['timeFormat']);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it('treats interface time fields as time fields', () => {
|
|
30
|
+
const setProps = vi.fn();
|
|
31
|
+
const ctx = {
|
|
32
|
+
model: {
|
|
33
|
+
context: {
|
|
34
|
+
collectionField: {
|
|
35
|
+
type: 'string',
|
|
36
|
+
interface: 'time',
|
|
37
|
+
},
|
|
38
|
+
},
|
|
39
|
+
setProps,
|
|
40
|
+
},
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
dateTimeFormat.handler(ctx, { timeFormat: 'hh:mm:ss a' });
|
|
44
|
+
|
|
45
|
+
expect(setProps).toHaveBeenCalledWith({
|
|
46
|
+
timeFormat: 'hh:mm:ss a',
|
|
47
|
+
format: 'hh:mm:ss a',
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
it('uses format as the default time format when timeFormat is missing', () => {
|
|
52
|
+
const ctx = {
|
|
53
|
+
model: {
|
|
54
|
+
props: {},
|
|
55
|
+
context: {
|
|
56
|
+
collectionField: {
|
|
57
|
+
interface: 'time',
|
|
58
|
+
getComponentProps: () => ({
|
|
59
|
+
format: 'hh:mm:ss a',
|
|
60
|
+
}),
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
expect(dateTimeFormat.defaultParams(ctx)).toMatchObject({
|
|
67
|
+
timeFormat: 'hh:mm:ss a',
|
|
68
|
+
});
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('does not use datetime format as the default time format for non-time fields', () => {
|
|
72
|
+
const ctx = {
|
|
73
|
+
model: {
|
|
74
|
+
props: {},
|
|
75
|
+
context: {
|
|
76
|
+
collectionField: {
|
|
77
|
+
type: 'datetime',
|
|
78
|
+
interface: 'datetime',
|
|
79
|
+
getComponentProps: () => ({
|
|
80
|
+
format: 'YYYY-MM-DD hh:mm:ss a',
|
|
81
|
+
}),
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
expect(dateTimeFormat.defaultParams(ctx)).toMatchObject({
|
|
88
|
+
timeFormat: 'HH:mm:ss',
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
});
|