@nocobase/client-v2 2.2.0-beta.8 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/es/APIClient.d.ts +13 -3
- package/es/BaseApplication.d.ts +3 -0
- package/es/RouteRepository.d.ts +8 -0
- package/es/RouterManager.d.ts +15 -0
- package/es/authRedirect.d.ts +1 -0
- package/es/collection-field-interface/CollectionFieldInterface.d.ts +1 -0
- package/es/collection-field-interface/CollectionFieldInterfaceManager.d.ts +1 -0
- package/es/components/category-tabs/SortableCategoryTabs.d.ts +55 -0
- package/es/components/category-tabs/index.d.ts +9 -0
- package/es/components/form/ScanInput/useCodeScanner.d.ts +3 -2
- package/es/components/form/TypedVariableInput.d.ts +31 -5
- package/es/components/form/filter/CollectionFilter.d.ts +2 -0
- package/es/components/form/filter/CollectionFilterItem.d.ts +11 -1
- package/es/components/form/filter/CollectionFilterPanel.d.ts +2 -0
- package/es/components/form/filter/index.d.ts +2 -0
- package/es/components/form/filter/useFilterActionProps.d.ts +2 -0
- package/es/components/index.d.ts +1 -0
- package/es/entry-actions/EntryActionManager.d.ts +24 -0
- package/es/entry-actions/index.d.ts +9 -0
- package/es/flow/actions/index.d.ts +1 -1
- package/es/flow/actions/linkageRules.d.ts +27 -0
- package/es/flow/admin-shell/BaseLayoutModel.d.ts +6 -0
- package/es/flow/admin-shell/BaseLayoutRouteCoordinator.d.ts +7 -0
- package/es/flow/admin-shell/admin-layout/AdminLayoutMenuModels.d.ts +1 -0
- package/es/flow/admin-shell/admin-layout/AppListRender.d.ts +2 -1
- package/es/flow/admin-shell/admin-layout/AppSwitcherActionPanelModel.d.ts +24 -0
- package/es/flow/admin-shell/admin-layout/index.d.ts +1 -0
- package/es/flow/admin-shell/admin-layout/useApplications.d.ts +7 -2
- package/es/flow/components/FieldAssignExactDatePicker.d.ts +1 -0
- package/es/flow/components/FieldAssignValueInput.d.ts +7 -24
- package/es/flow/components/FlowRoute.d.ts +2 -2
- package/es/flow/components/RunJSValueEditor.d.ts +1 -0
- package/es/flow/components/field-value-variable/DateVariableEditor.d.ts +24 -0
- package/es/flow/components/field-value-variable/FieldValueVariableInput.d.ts +31 -0
- package/es/flow/components/field-value-variable/dateValue.d.ts +36 -0
- package/es/flow/components/field-value-variable/index.d.ts +11 -0
- package/es/flow/components/filter/FilterGroup.d.ts +1 -0
- package/es/flow/components/filter/VariableFilterItem.d.ts +6 -1
- package/es/flow/components/placeholders/BlockPlaceholder.d.ts +1 -0
- package/es/flow/index.d.ts +1 -0
- package/es/flow/internal/registerDeviceTypeContext.d.ts +10 -0
- package/es/flow/internal/utils/operatorSchemaHelper.d.ts +2 -2
- package/es/flow/models/actions/UpdateRecordActionUtils.d.ts +8 -2
- package/es/flow/models/base/ActionModelCore.d.ts +6 -2
- package/es/flow/models/base/BlockGridModel.d.ts +3 -0
- package/es/flow/models/base/CollectionBlockModel.d.ts +3 -0
- package/es/flow/models/base/PageModel/PageModel.d.ts +12 -0
- package/es/flow/models/base/PageModel/PageModelTabBar.d.ts +22 -0
- package/es/flow/models/base/PageModel/PageTabModel.d.ts +12 -0
- package/es/flow/models/blocks/details/DetailsBlockModel.d.ts +3 -0
- package/es/flow/models/blocks/filter-form/FilterFormGridModel.d.ts +1 -0
- package/es/flow/models/blocks/filter-form/FilterFormSubmitActionModel.d.ts +3 -1
- package/es/flow/models/blocks/form/FormBlockModel.d.ts +7 -0
- package/es/flow/models/blocks/form/FormGridModel.d.ts +6 -0
- package/es/flow/models/blocks/form/QuickEditFormModel.d.ts +17 -2
- package/es/flow/models/blocks/form/value-runtime/rules.d.ts +1 -0
- package/es/flow/models/blocks/table/JSColumnModel.d.ts +2 -0
- package/es/flow/models/blocks/table/TableBlockModel.d.ts +1 -0
- package/es/flow/models/blocks/table/TableColumnModel.d.ts +12 -0
- package/es/flow/models/blocks/table/utils.d.ts +1 -0
- package/es/flow/models/fields/AssociationFieldModel/RecordPickerFieldModel.d.ts +2 -1
- package/es/flow/models/fields/AssociationFieldModel/RecordSelectFieldModel.d.ts +0 -17
- package/es/flow/models/fields/AssociationFieldModel/recordSelectShared.d.ts +41 -0
- package/es/flow/models/fields/DateTimeFieldModel/dateLimit.d.ts +15 -7
- package/es/flow/routeTransientInputArgs.d.ts +14 -0
- package/es/flow-compat/fieldValidationConstants.d.ts +1 -1
- package/es/flow-compat/passwordUtils.d.ts +1 -1
- package/es/flow-compat/routeTypes.d.ts +1 -0
- package/es/index.d.ts +7 -0
- package/es/index.mjs +301 -177
- package/es/ui-operation/index.d.ts +15 -0
- package/es/ui-operation/ui-operation-codec.d.ts +10 -0
- package/es/utils/getRouteRuntimeVersion.d.ts +23 -0
- package/es/utils/index.d.ts +1 -0
- package/es/utils/markdownSanitize.d.ts +11 -0
- package/lib/index.js +313 -189
- package/lib/locale/languageCodes.js +3 -1
- package/package.json +9 -7
- package/src/APIClient.ts +90 -7
- package/src/Application.tsx +7 -1
- package/src/BaseApplication.tsx +13 -6
- package/src/RouteRepository.ts +25 -0
- package/src/RouterManager.tsx +142 -1
- package/src/__tests__/APIClient.test.tsx +58 -0
- package/src/__tests__/RouteRepository.test.ts +23 -0
- package/src/__tests__/RouterManager.test.ts +125 -0
- package/src/__tests__/app.test.tsx +73 -0
- package/src/__tests__/authRedirect.test.ts +17 -0
- package/src/__tests__/browserChecker.test.ts +61 -0
- package/src/__tests__/getRouteRuntimeVersion.test.ts +68 -0
- package/src/__tests__/nocobase-buildin-plugin-auth.test.tsx +35 -2
- package/src/__tests__/settings-center.test.tsx +270 -6
- package/src/acl/ACLProvider.tsx +2 -0
- package/src/acl/__tests__/ACLProvider.test.tsx +92 -0
- package/src/authRedirect.ts +38 -0
- package/src/collection-field-interface/CollectionFieldInterface.ts +1 -0
- package/src/collection-field-interface/CollectionFieldInterfaceManager.ts +1 -0
- package/src/collection-manager/field-validation.ts +1 -1
- package/src/components/README.md +7 -1
- package/src/components/README.zh-CN.md +6 -1
- package/src/components/category-tabs/SortableCategoryTabs.tsx +210 -0
- package/src/components/category-tabs/index.ts +10 -0
- package/src/components/form/JsonTextArea.tsx +4 -0
- package/src/components/form/ScanInput/CodeScanner.tsx +79 -35
- package/src/components/form/ScanInput/__tests__/CodeScanner.test.tsx +101 -0
- package/src/components/form/ScanInput/__tests__/useCodeScanner.test.tsx +284 -11
- package/src/components/form/ScanInput/useCodeScanner.ts +332 -24
- package/src/components/form/TypedVariableInput.tsx +452 -101
- package/src/components/form/__tests__/TypedVariableInput.test.tsx +364 -12
- package/src/components/form/filter/CollectionFilter.tsx +4 -0
- package/src/components/form/filter/CollectionFilterItem.tsx +36 -9
- package/src/components/form/filter/CollectionFilterPanel.tsx +4 -0
- package/src/components/form/filter/__tests__/CollectionFilterItem.test.tsx +55 -0
- package/src/components/form/filter/__tests__/useFilterActionProps.test.tsx +95 -0
- package/src/components/form/filter/index.ts +2 -0
- package/src/components/form/filter/useFilterActionProps.ts +37 -6
- package/src/components/form/table/Table.tsx +81 -6
- package/src/components/form/table/__tests__/Table.columnWidth.test.tsx +433 -0
- package/src/components/index.ts +1 -0
- package/src/entry-actions/EntryActionManager.ts +76 -0
- package/src/entry-actions/index.ts +10 -0
- package/src/flow/FlowPage.tsx +38 -3
- package/src/flow/__tests__/FlowPage.test.tsx +201 -27
- package/src/flow/__tests__/FlowRoute.test.tsx +675 -12
- package/src/flow/__tests__/PluginFlowEngine.test.ts +58 -0
- package/src/flow/actions/__tests__/actionLinkageRules.forkProps.test.ts +314 -0
- package/src/flow/actions/__tests__/dataScopeFilter.test.ts +62 -0
- package/src/flow/actions/__tests__/dataScopeFormValueClear.test.ts +102 -0
- package/src/flow/actions/__tests__/linkageRules.actionStates.test.ts +33 -0
- package/src/flow/actions/__tests__/linkageRules.subFormSetFieldProps.test.ts +72 -0
- package/src/flow/actions/__tests__/linkageRules.tab.test.ts +171 -0
- package/src/flow/actions/__tests__/linkageRulesRefresh.test.ts +7 -3
- package/src/flow/actions/__tests__/openView.defineProps.route.test.tsx +80 -20
- package/src/flow/actions/dataScopeFilter.ts +10 -1
- package/src/flow/actions/dateTimeFormat.tsx +2 -2
- package/src/flow/actions/index.ts +2 -0
- package/src/flow/actions/linkageRules.tsx +144 -26
- package/src/flow/actions/linkageRulesRefresh.tsx +2 -6
- package/src/flow/actions/openView.tsx +21 -1
- package/src/flow/admin-shell/BaseLayoutModel.tsx +124 -0
- package/src/flow/admin-shell/BaseLayoutRouteCoordinator.ts +184 -42
- package/src/flow/admin-shell/__tests__/AdminLayoutRouteCoordinator.test.ts +1016 -119
- package/src/flow/admin-shell/admin-layout/AdminLayoutComponent.tsx +41 -5
- package/src/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.test.tsx +177 -1
- package/src/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.tsx +20 -0
- package/src/flow/admin-shell/admin-layout/AdminLayoutMenuUtils.tsx +78 -59
- package/src/flow/admin-shell/admin-layout/AppListRender.tsx +13 -2
- package/src/flow/admin-shell/admin-layout/AppSwitcherActionPanelModel.tsx +289 -0
- package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutComponent.test.tsx +253 -6
- package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutMenuModels.test.ts +228 -0
- package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutModel.test.tsx +436 -2
- package/src/flow/admin-shell/admin-layout/__tests__/TopbarActionsBar.test.tsx +48 -0
- package/src/flow/admin-shell/admin-layout/index.ts +1 -0
- package/src/flow/admin-shell/admin-layout/useApplications.tsx +81 -12
- package/src/flow/common/Markdown/Display.tsx +14 -3
- package/src/flow/common/Markdown/Edit.tsx +19 -7
- package/src/flow/common/Markdown/style.ts +4 -0
- package/src/flow/components/BlockItemCard.tsx +2 -2
- package/src/flow/components/FieldAssignExactDatePicker.tsx +25 -11
- package/src/flow/components/FieldAssignValueInput.tsx +72 -584
- package/src/flow/components/FlowRoute.tsx +204 -46
- package/src/flow/components/RunJSValueEditor.tsx +9 -1
- package/src/flow/components/__tests__/FieldAssignValueInput.context.test.tsx +216 -0
- package/src/flow/components/field-value-variable/DateVariableEditor.tsx +181 -0
- package/src/flow/components/field-value-variable/FieldValueVariableInput.tsx +326 -0
- package/src/flow/components/field-value-variable/__tests__/FieldValueVariableInput.test.tsx +380 -0
- package/src/flow/components/field-value-variable/dateValue.ts +223 -0
- package/src/flow/components/field-value-variable/index.ts +12 -0
- package/src/flow/components/filter/FilterGroup.tsx +33 -5
- package/src/flow/components/filter/VariableFilterItem.tsx +170 -13
- package/src/flow/components/filter/__tests__/FilterGroup.test.tsx +45 -0
- package/src/flow/components/filter/__tests__/VariableFilterItem.leftMetaTree.test.tsx +9 -0
- package/src/flow/components/filter/__tests__/VariableFilterItem.test.tsx +195 -1
- package/src/flow/components/placeholders/BlockPlaceholder.tsx +70 -23
- package/src/flow/components/placeholders/__tests__/BlockPlaceholder.test.tsx +57 -7
- package/src/flow/index.ts +3 -0
- package/src/flow/internal/components/Markdown/util.ts +2 -1
- package/src/flow/internal/registerDeviceTypeContext.ts +39 -0
- package/src/flow/internal/utils/operatorSchemaHelper.ts +3 -2
- package/src/flow/models/actions/UpdateRecordActionModel.tsx +18 -1
- package/src/flow/models/actions/UpdateRecordActionUtils.ts +18 -6
- package/src/flow/models/actions/__tests__/UpdateRecordActionModel.test.ts +76 -4
- package/src/flow/models/base/ActionModel.tsx +10 -8
- package/src/flow/models/base/ActionModelCore.tsx +16 -2
- package/src/flow/models/base/BlockGridModel.tsx +26 -0
- package/src/flow/models/base/CollectionBlockModel.tsx +38 -3
- package/src/flow/models/base/PageModel/PageModel.tsx +387 -53
- package/src/flow/models/base/PageModel/PageModelTabBar.tsx +114 -0
- package/src/flow/models/base/PageModel/PageTabModel.tsx +249 -18
- package/src/flow/models/base/PageModel/__tests__/PageModel.test.ts +790 -10
- package/src/flow/models/base/PageModel/__tests__/PageModelTabBar.module-isolation.test.tsx +130 -0
- package/src/flow/models/base/PageModel/__tests__/PageModelTabBar.test.tsx +118 -0
- package/src/flow/models/base/PageModel/__tests__/PageTabModel.test.ts +1075 -7
- package/src/flow/models/base/__tests__/ActionModelCore.render.test.tsx +49 -0
- package/src/flow/models/base/__tests__/BlockGridModel.selectSceneActivation.test.ts +124 -0
- package/src/flow/models/base/__tests__/CollectionBlockModel.addAppends.test.ts +41 -0
- package/src/flow/models/base/__tests__/CollectionBlockModel.initialBeforeRenderRefresh.test.ts +125 -9
- package/src/flow/models/blocks/assign-form/AssignFormItemModel.tsx +28 -53
- package/src/flow/models/blocks/details/DetailsBlockModel.tsx +8 -3
- package/src/flow/models/blocks/details/__tests__/DetailsBlockModel.initialPaginationChangeRefresh.test.ts +32 -1
- package/src/flow/models/blocks/filter-form/FilterFormBlockModel.tsx +28 -3
- package/src/flow/models/blocks/filter-form/FilterFormGridModel.tsx +36 -5
- package/src/flow/models/blocks/filter-form/FilterFormItemModel.tsx +155 -25
- package/src/flow/models/blocks/filter-form/FilterFormSubmitActionModel.tsx +57 -4
- package/src/flow/models/blocks/filter-form/__tests__/FilterFormGridModel.onModelCreated.test.ts +174 -1
- package/src/flow/models/blocks/filter-form/__tests__/FilterFormItemModel.defineChildren.test.ts +395 -1
- package/src/flow/models/blocks/filter-form/__tests__/FilterFormItemModel.getFilterValue.test.ts +72 -0
- package/src/flow/models/blocks/filter-form/__tests__/FilterFormSubmitActionModel.lifecycle.test.ts +90 -0
- package/src/flow/models/blocks/filter-form/__tests__/defaultValues.wiring.test.ts +66 -4
- package/src/flow/models/blocks/filter-manager/FilterManager.ts +5 -0
- package/src/flow/models/blocks/filter-manager/__tests__/FilterManager.test.ts +40 -0
- package/src/flow/models/blocks/form/FormBlockModel.tsx +47 -0
- package/src/flow/models/blocks/form/FormGridModel.tsx +4 -0
- package/src/flow/models/blocks/form/QuickEditFormModel.tsx +189 -36
- package/src/flow/models/blocks/form/__tests__/FormBlockModel.test.tsx +8 -2
- package/src/flow/models/blocks/form/__tests__/QuickEditFormModel.quickEdit.test.ts +350 -2
- package/src/flow/models/blocks/form/__tests__/runJsFormSubmit.test.ts +131 -0
- package/src/flow/models/blocks/form/value-runtime/__tests__/runtime.test.ts +435 -0
- package/src/flow/models/blocks/form/value-runtime/rules.ts +67 -14
- package/src/flow/models/blocks/form/value-runtime/runtime.ts +43 -19
- package/src/flow/models/blocks/js-block/JSBlock.tsx +1 -1
- package/src/flow/models/blocks/table/JSColumnModel.tsx +10 -1
- package/src/flow/models/blocks/table/TableActionsColumnModel.tsx +2 -1
- package/src/flow/models/blocks/table/TableBlockModel.tsx +29 -3
- package/src/flow/models/blocks/table/TableColumnModel.tsx +54 -11
- package/src/flow/models/blocks/table/__tests__/JSColumnModel.test.tsx +52 -5
- package/src/flow/models/blocks/table/__tests__/TableBlockModel.filterReset.test.ts +78 -0
- package/src/flow/models/blocks/table/__tests__/TableBlockModel.quickEditRefresh.test.ts +12 -0
- package/src/flow/models/blocks/table/__tests__/TableColumnModel.test.tsx +84 -0
- package/src/flow/models/blocks/table/utils.ts +7 -0
- package/src/flow/models/fields/AssociationFieldModel/CascadeSelectFieldModel.tsx +33 -1
- package/src/flow/models/fields/AssociationFieldModel/PopupSubTableFieldModel/PopupSubTableFieldModel.tsx +10 -1
- package/src/flow/models/fields/AssociationFieldModel/PopupSubTableFieldModel/__tests__/popupContext.test.ts +120 -0
- package/src/flow/models/fields/AssociationFieldModel/PopupSubTableFieldModel/actions/PopupSubTableEditActionModel.tsx +10 -2
- package/src/flow/models/fields/AssociationFieldModel/RecordPickerFieldModel.tsx +24 -1
- package/src/flow/models/fields/AssociationFieldModel/RecordSelectFieldModel.tsx +54 -149
- package/src/flow/models/fields/AssociationFieldModel/__tests__/RecordPickerFieldModel.itemContext.test.ts +167 -3
- package/src/flow/models/fields/AssociationFieldModel/recordSelectShared.tsx +156 -0
- package/src/flow/models/fields/DateTimeFieldModel/__tests__/DateTimeNoTzFieldModel.dateLimit.test.tsx +149 -0
- package/src/flow/models/fields/DateTimeFieldModel/dateLimit.ts +149 -113
- package/src/flow/models/fields/DisplayNumberFieldModel.tsx +1 -1
- package/src/flow/models/fields/JsonFieldModel.tsx +31 -8
- package/src/flow/models/fields/NumberFieldModel.tsx +1 -1
- package/src/flow/models/fields/TextareaFieldModel.tsx +42 -19
- package/src/flow/models/fields/VariableFieldFormModel.tsx +3 -3
- package/src/flow/models/fields/__tests__/DisplayNumberFieldModel.test.ts +33 -0
- package/src/flow/models/fields/__tests__/JsonFieldModel.test.ts +82 -0
- package/src/flow/models/fields/__tests__/NumberFieldModel.test.tsx +47 -0
- package/src/flow/models/fields/__tests__/TextareaFieldModel.test.tsx +32 -1
- package/src/flow/models/fields/__tests__/VariableFieldFormModel.test.tsx +51 -0
- package/src/flow/models/fields/mobile-components/MobileLazySelect.tsx +26 -10
- package/src/flow/models/fields/mobile-components/MobileSelect.tsx +51 -14
- package/src/flow/models/fields/mobile-components/__tests__/MobileSelect.test.tsx +139 -13
- package/src/flow/models/topbar/TopbarActionModel.tsx +78 -3
- package/src/flow/routeTransientInputArgs.ts +27 -0
- package/src/flow/utils/__tests__/dateTimeFormat.test.ts +42 -0
- package/src/flow/utils/dataScopeFormValueClear.ts +4 -3
- package/src/flow-compat/fieldValidationConstants.ts +1 -1
- package/src/flow-compat/routeTypes.ts +1 -0
- package/src/index.ts +7 -0
- package/src/layout-manager/LayoutContentRoute.tsx +2 -1
- package/src/layout-manager/LayoutRoute.tsx +2 -1
- package/src/layout-manager/__tests__/LayoutRoute.test.tsx +87 -1
- package/src/locale/languageCodes.ts +3 -1
- package/src/nocobase-buildin-plugin/index.tsx +19 -1
- package/src/settings-center/AdminSettingsLayout.tsx +23 -2
- package/src/ui-operation/index.ts +33 -0
- package/src/ui-operation/ui-operation-codec.ts +54 -0
- package/src/utils/getRouteRuntimeVersion.ts +185 -0
- package/src/utils/index.tsx +1 -0
- package/src/utils/markdownSanitize.ts +88 -0
|
@@ -9,11 +9,12 @@
|
|
|
9
9
|
|
|
10
10
|
import React from 'react';
|
|
11
11
|
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
12
|
-
import { MemoryRouter, Route, Routes } from 'react-router-dom';
|
|
13
|
-
import { render, screen, waitFor } from '@testing-library/react';
|
|
12
|
+
import { MemoryRouter, Route, Router, Routes, useNavigate } from 'react-router-dom';
|
|
13
|
+
import { act, render, screen, waitFor } from '@testing-library/react';
|
|
14
14
|
import { FlowContextProvider, FlowEngine, FlowEngineProvider, type FlowModel } from '@nocobase/flow-engine';
|
|
15
15
|
import FlowRoute from '../components/FlowRoute';
|
|
16
16
|
import { RouteRepository } from '../../RouteRepository';
|
|
17
|
+
import { NocoBaseDesktopRouteType } from '../../flow-compat';
|
|
17
18
|
|
|
18
19
|
type MockAdminLayoutModel = FlowModel & {
|
|
19
20
|
registerRoutePage: ReturnType<typeof vi.fn>;
|
|
@@ -21,6 +22,8 @@ type MockAdminLayoutModel = FlowModel & {
|
|
|
21
22
|
unregisterRoutePage: ReturnType<typeof vi.fn>;
|
|
22
23
|
};
|
|
23
24
|
|
|
25
|
+
type RouterNavigator = React.ComponentProps<typeof Router>['navigator'];
|
|
26
|
+
|
|
24
27
|
const { hookState } = vi.hoisted(() => {
|
|
25
28
|
return {
|
|
26
29
|
hookState: {
|
|
@@ -113,6 +116,7 @@ describe('FlowRoute', () => {
|
|
|
113
116
|
}),
|
|
114
117
|
);
|
|
115
118
|
});
|
|
119
|
+
expect(engine.context.deviceType).toBe('computer');
|
|
116
120
|
|
|
117
121
|
rerender(
|
|
118
122
|
<FlowEngineProvider engine={engine}>
|
|
@@ -578,14 +582,14 @@ describe('FlowRoute', () => {
|
|
|
578
582
|
expect(getRouteBySchemaUid).toHaveBeenCalledTimes(1);
|
|
579
583
|
});
|
|
580
584
|
|
|
581
|
-
it('should
|
|
585
|
+
it('should explain how to open a legacy page outside the v2 runtime', async () => {
|
|
582
586
|
const originalLocation = window.location;
|
|
583
587
|
const replace = vi.fn();
|
|
584
588
|
Object.defineProperty(window, 'location', {
|
|
585
589
|
configurable: true,
|
|
586
590
|
value: {
|
|
587
591
|
...originalLocation,
|
|
588
|
-
pathname: '/v2/admin/test-page/tab/tab-1',
|
|
592
|
+
pathname: '/nocobase/v2/apps/jhb20/admin/test-page/tab/tab-1',
|
|
589
593
|
search: '?from=direct',
|
|
590
594
|
hash: '#dialog',
|
|
591
595
|
replace,
|
|
@@ -604,9 +608,9 @@ describe('FlowRoute', () => {
|
|
|
604
608
|
});
|
|
605
609
|
engine.context.defineProperty('app', {
|
|
606
610
|
value: {
|
|
607
|
-
getPublicPath: () => '/v2/',
|
|
611
|
+
getPublicPath: () => '/nocobase/v2/',
|
|
608
612
|
router: {
|
|
609
|
-
getBasename: () => '/v2',
|
|
613
|
+
getBasename: () => '/nocobase/v2',
|
|
610
614
|
},
|
|
611
615
|
},
|
|
612
616
|
});
|
|
@@ -622,15 +626,25 @@ describe('FlowRoute', () => {
|
|
|
622
626
|
|
|
623
627
|
render(
|
|
624
628
|
<FlowEngineProvider engine={engine}>
|
|
625
|
-
<MemoryRouter initialEntries={['/
|
|
629
|
+
<MemoryRouter initialEntries={['/nocobase/v2/apps/jhb20/admin/test-page/tab/tab-1?from=direct#dialog']}>
|
|
626
630
|
<Routes>
|
|
627
|
-
<Route path="/
|
|
631
|
+
<Route path="/nocobase/v2/apps/jhb20/admin/:name/*" element={<FlowRoute />} />
|
|
628
632
|
</Routes>
|
|
629
633
|
</MemoryRouter>
|
|
630
634
|
</FlowEngineProvider>,
|
|
631
635
|
);
|
|
632
636
|
|
|
633
|
-
expect(await screen.findByText('
|
|
637
|
+
expect(await screen.findByText('This page is not supported in the /v2/ branch')).toBeInTheDocument();
|
|
638
|
+
expect(
|
|
639
|
+
screen.getByText(
|
|
640
|
+
'The /v2/ branch only supports new pages. This page is a legacy page. Please open it from the original entry.',
|
|
641
|
+
),
|
|
642
|
+
).toBeInTheDocument();
|
|
643
|
+
expect(screen.queryByText('404')).not.toBeInTheDocument();
|
|
644
|
+
expect(screen.getByRole('link', { name: 'Open from the original entry' })).toHaveAttribute(
|
|
645
|
+
'href',
|
|
646
|
+
'/nocobase/apps/jhb20/admin/test-page/tab/tab-1?from=direct#dialog',
|
|
647
|
+
);
|
|
634
648
|
expect(replace).not.toHaveBeenCalled();
|
|
635
649
|
expect(adminLayoutModel.registerRoutePage).not.toHaveBeenCalled();
|
|
636
650
|
expect(adminLayoutModel.updateRoutePage).not.toHaveBeenCalled();
|
|
@@ -703,6 +717,113 @@ describe('FlowRoute', () => {
|
|
|
703
717
|
}
|
|
704
718
|
});
|
|
705
719
|
|
|
720
|
+
it('should render 404 for missing FlowModel in notFound mode without routeRepository', async () => {
|
|
721
|
+
const engine = new FlowEngine();
|
|
722
|
+
engine.context.defineProperty('app', {
|
|
723
|
+
value: {
|
|
724
|
+
getPublicPath: () => '/v2/',
|
|
725
|
+
router: {
|
|
726
|
+
getBasename: () => '/v2',
|
|
727
|
+
},
|
|
728
|
+
},
|
|
729
|
+
});
|
|
730
|
+
|
|
731
|
+
const adminLayoutModel: MockAdminLayoutModel = Object.assign(
|
|
732
|
+
engine.createModel({ uid: 'admin-layout-model', use: 'FlowModel' }),
|
|
733
|
+
{
|
|
734
|
+
registerRoutePage: vi.fn(),
|
|
735
|
+
updateRoutePage: vi.fn(),
|
|
736
|
+
unregisterRoutePage: vi.fn(),
|
|
737
|
+
},
|
|
738
|
+
);
|
|
739
|
+
|
|
740
|
+
render(
|
|
741
|
+
<FlowEngineProvider engine={engine}>
|
|
742
|
+
<MemoryRouter initialEntries={['/embed/missing-page']}>
|
|
743
|
+
<Routes>
|
|
744
|
+
<Route path="/embed/:name" element={<FlowRoute legacyPageBehavior="notFound" />} />
|
|
745
|
+
</Routes>
|
|
746
|
+
</MemoryRouter>
|
|
747
|
+
</FlowEngineProvider>,
|
|
748
|
+
);
|
|
749
|
+
|
|
750
|
+
expect(await screen.findByText('404')).toBeInTheDocument();
|
|
751
|
+
expect(adminLayoutModel.registerRoutePage).not.toHaveBeenCalled();
|
|
752
|
+
});
|
|
753
|
+
|
|
754
|
+
it('should bridge by default when routeRepository does not exist', async () => {
|
|
755
|
+
const engine = new FlowEngine();
|
|
756
|
+
engine.context.defineProperty('app', {
|
|
757
|
+
value: {
|
|
758
|
+
getPublicPath: () => '/v2/',
|
|
759
|
+
router: {
|
|
760
|
+
getBasename: () => '/v2',
|
|
761
|
+
},
|
|
762
|
+
},
|
|
763
|
+
});
|
|
764
|
+
|
|
765
|
+
const adminLayoutModel: MockAdminLayoutModel = Object.assign(
|
|
766
|
+
engine.createModel({ uid: 'admin-layout-model', use: 'FlowModel' }),
|
|
767
|
+
{
|
|
768
|
+
registerRoutePage: vi.fn(),
|
|
769
|
+
updateRoutePage: vi.fn(),
|
|
770
|
+
unregisterRoutePage: vi.fn(),
|
|
771
|
+
},
|
|
772
|
+
);
|
|
773
|
+
|
|
774
|
+
render(
|
|
775
|
+
<FlowEngineProvider engine={engine}>
|
|
776
|
+
<MemoryRouter initialEntries={['/flow/missing-page']}>
|
|
777
|
+
<Routes>
|
|
778
|
+
<Route path="/flow/:name" element={<FlowRoute />} />
|
|
779
|
+
</Routes>
|
|
780
|
+
</MemoryRouter>
|
|
781
|
+
</FlowEngineProvider>,
|
|
782
|
+
);
|
|
783
|
+
|
|
784
|
+
await waitFor(() => {
|
|
785
|
+
expect(adminLayoutModel.registerRoutePage).toHaveBeenCalledWith('missing-page', expect.any(Object));
|
|
786
|
+
});
|
|
787
|
+
expect(screen.queryByText('404')).not.toBeInTheDocument();
|
|
788
|
+
});
|
|
789
|
+
|
|
790
|
+
it('should bridge existing FlowModel in notFound mode without routeRepository', async () => {
|
|
791
|
+
const engine = new FlowEngine();
|
|
792
|
+
engine.createModel({ uid: 'test-page', use: 'FlowModel' });
|
|
793
|
+
engine.context.defineProperty('app', {
|
|
794
|
+
value: {
|
|
795
|
+
getPublicPath: () => '/v2/',
|
|
796
|
+
router: {
|
|
797
|
+
getBasename: () => '/v2',
|
|
798
|
+
},
|
|
799
|
+
},
|
|
800
|
+
});
|
|
801
|
+
|
|
802
|
+
const adminLayoutModel: MockAdminLayoutModel = Object.assign(
|
|
803
|
+
engine.createModel({ uid: 'admin-layout-model', use: 'FlowModel' }),
|
|
804
|
+
{
|
|
805
|
+
registerRoutePage: vi.fn(),
|
|
806
|
+
updateRoutePage: vi.fn(),
|
|
807
|
+
unregisterRoutePage: vi.fn(),
|
|
808
|
+
},
|
|
809
|
+
);
|
|
810
|
+
|
|
811
|
+
render(
|
|
812
|
+
<FlowEngineProvider engine={engine}>
|
|
813
|
+
<MemoryRouter initialEntries={['/embed/test-page']}>
|
|
814
|
+
<Routes>
|
|
815
|
+
<Route path="/embed/:name" element={<FlowRoute legacyPageBehavior="notFound" />} />
|
|
816
|
+
</Routes>
|
|
817
|
+
</MemoryRouter>
|
|
818
|
+
</FlowEngineProvider>,
|
|
819
|
+
);
|
|
820
|
+
|
|
821
|
+
await waitFor(() => {
|
|
822
|
+
expect(adminLayoutModel.registerRoutePage).toHaveBeenCalledWith('test-page', expect.any(Object));
|
|
823
|
+
});
|
|
824
|
+
expect(screen.queryByText('404')).not.toBeInTheDocument();
|
|
825
|
+
});
|
|
826
|
+
|
|
706
827
|
it('should bridge existing FlowModel when behavior is notFound and routeRepository has no route', async () => {
|
|
707
828
|
const engine = new FlowEngine();
|
|
708
829
|
engine.setModelRepository({
|
|
@@ -893,6 +1014,548 @@ describe('FlowRoute', () => {
|
|
|
893
1014
|
expect(adminLayoutModel.registerRoutePage).not.toHaveBeenCalled();
|
|
894
1015
|
});
|
|
895
1016
|
|
|
1017
|
+
it('should render blank content when current admin route matches an accessible empty group id', async () => {
|
|
1018
|
+
const engine = new FlowEngine();
|
|
1019
|
+
const listAccessible = vi.fn(() => [
|
|
1020
|
+
{
|
|
1021
|
+
id: 371750686228480,
|
|
1022
|
+
schemaUid: 'group-schema',
|
|
1023
|
+
title: '789',
|
|
1024
|
+
type: NocoBaseDesktopRouteType.group,
|
|
1025
|
+
},
|
|
1026
|
+
]);
|
|
1027
|
+
engine.context.defineProperty('routeRepository', {
|
|
1028
|
+
value: {
|
|
1029
|
+
refreshAccessible: hookState.refresh,
|
|
1030
|
+
isAccessibleLoaded: () => true,
|
|
1031
|
+
ensureAccessibleLoaded: vi.fn().mockResolvedValue([]),
|
|
1032
|
+
getRouteBySchemaUid: vi.fn(() => undefined),
|
|
1033
|
+
listAccessible,
|
|
1034
|
+
},
|
|
1035
|
+
});
|
|
1036
|
+
engine.context.defineProperty('app', {
|
|
1037
|
+
value: {
|
|
1038
|
+
getPublicPath: () => '/v2/',
|
|
1039
|
+
router: {
|
|
1040
|
+
getBasename: () => '/v2',
|
|
1041
|
+
},
|
|
1042
|
+
},
|
|
1043
|
+
});
|
|
1044
|
+
|
|
1045
|
+
const adminLayoutModel: MockAdminLayoutModel = Object.assign(
|
|
1046
|
+
engine.createModel({ uid: 'admin-layout-model', use: 'FlowModel' }),
|
|
1047
|
+
{
|
|
1048
|
+
registerRoutePage: vi.fn(),
|
|
1049
|
+
updateRoutePage: vi.fn(),
|
|
1050
|
+
unregisterRoutePage: vi.fn(),
|
|
1051
|
+
},
|
|
1052
|
+
);
|
|
1053
|
+
|
|
1054
|
+
const { container } = render(
|
|
1055
|
+
<FlowEngineProvider engine={engine}>
|
|
1056
|
+
<MemoryRouter initialEntries={['/admin/371750686228480']}>
|
|
1057
|
+
<Routes>
|
|
1058
|
+
<Route path="/admin/:name" element={<FlowRoute />} />
|
|
1059
|
+
</Routes>
|
|
1060
|
+
</MemoryRouter>
|
|
1061
|
+
</FlowEngineProvider>,
|
|
1062
|
+
);
|
|
1063
|
+
|
|
1064
|
+
await waitFor(() => {
|
|
1065
|
+
expect(listAccessible).toHaveBeenCalled();
|
|
1066
|
+
});
|
|
1067
|
+
expect(container).toBeEmptyDOMElement();
|
|
1068
|
+
expect(screen.queryByText('404')).not.toBeInTheDocument();
|
|
1069
|
+
expect(adminLayoutModel.registerRoutePage).not.toHaveBeenCalled();
|
|
1070
|
+
});
|
|
1071
|
+
|
|
1072
|
+
it('should navigate a current admin group route to its first accessible flow page', async () => {
|
|
1073
|
+
const engine = new FlowEngine();
|
|
1074
|
+
const childRoute = {
|
|
1075
|
+
schemaUid: 'child-flow-page',
|
|
1076
|
+
title: 'Child flow page',
|
|
1077
|
+
type: NocoBaseDesktopRouteType.flowPage,
|
|
1078
|
+
};
|
|
1079
|
+
const groupRoute = {
|
|
1080
|
+
id: 371750686228480,
|
|
1081
|
+
schemaUid: 'group-schema',
|
|
1082
|
+
title: 'Group with child',
|
|
1083
|
+
type: NocoBaseDesktopRouteType.group,
|
|
1084
|
+
children: [childRoute],
|
|
1085
|
+
};
|
|
1086
|
+
const getRouteBySchemaUid = vi.fn((schemaUid: string) =>
|
|
1087
|
+
schemaUid === 'child-flow-page' ? childRoute : undefined,
|
|
1088
|
+
);
|
|
1089
|
+
const listAccessible = vi.fn(() => [groupRoute]);
|
|
1090
|
+
engine.context.defineProperty('routeRepository', {
|
|
1091
|
+
value: {
|
|
1092
|
+
refreshAccessible: hookState.refresh,
|
|
1093
|
+
isAccessibleLoaded: () => true,
|
|
1094
|
+
ensureAccessibleLoaded: vi.fn().mockResolvedValue([]),
|
|
1095
|
+
getRouteBySchemaUid,
|
|
1096
|
+
listAccessible,
|
|
1097
|
+
},
|
|
1098
|
+
});
|
|
1099
|
+
engine.context.defineProperty('app', {
|
|
1100
|
+
value: {
|
|
1101
|
+
getPublicPath: () => '/v2/',
|
|
1102
|
+
router: {
|
|
1103
|
+
getBasename: () => '/v2',
|
|
1104
|
+
},
|
|
1105
|
+
},
|
|
1106
|
+
});
|
|
1107
|
+
|
|
1108
|
+
const adminLayoutModel: MockAdminLayoutModel = Object.assign(
|
|
1109
|
+
engine.createModel({ uid: 'admin-layout-model', use: 'FlowModel' }),
|
|
1110
|
+
{
|
|
1111
|
+
registerRoutePage: vi.fn(),
|
|
1112
|
+
updateRoutePage: vi.fn(),
|
|
1113
|
+
unregisterRoutePage: vi.fn(),
|
|
1114
|
+
},
|
|
1115
|
+
);
|
|
1116
|
+
|
|
1117
|
+
render(
|
|
1118
|
+
<FlowEngineProvider engine={engine}>
|
|
1119
|
+
<MemoryRouter initialEntries={['/admin/371750686228480']}>
|
|
1120
|
+
<Routes>
|
|
1121
|
+
<Route path="/admin/:name" element={<FlowRoute />} />
|
|
1122
|
+
</Routes>
|
|
1123
|
+
</MemoryRouter>
|
|
1124
|
+
</FlowEngineProvider>,
|
|
1125
|
+
);
|
|
1126
|
+
|
|
1127
|
+
await waitFor(() => {
|
|
1128
|
+
expect(adminLayoutModel.registerRoutePage).toHaveBeenCalledWith('child-flow-page', expect.any(Object));
|
|
1129
|
+
});
|
|
1130
|
+
expect(adminLayoutModel.registerRoutePage).not.toHaveBeenCalledWith('371750686228480', expect.any(Object));
|
|
1131
|
+
expect(screen.queryByText('404')).not.toBeInTheDocument();
|
|
1132
|
+
});
|
|
1133
|
+
|
|
1134
|
+
it('should keep rendering 404 when a group id is opened with a nested admin route path', async () => {
|
|
1135
|
+
const engine = new FlowEngine();
|
|
1136
|
+
const childRoute = {
|
|
1137
|
+
schemaUid: 'child-flow-page',
|
|
1138
|
+
title: 'Child flow page',
|
|
1139
|
+
type: NocoBaseDesktopRouteType.flowPage,
|
|
1140
|
+
};
|
|
1141
|
+
const groupRoute = {
|
|
1142
|
+
id: 371750686228480,
|
|
1143
|
+
schemaUid: 'group-schema',
|
|
1144
|
+
title: 'Group with child',
|
|
1145
|
+
type: NocoBaseDesktopRouteType.group,
|
|
1146
|
+
children: [childRoute],
|
|
1147
|
+
};
|
|
1148
|
+
engine.context.defineProperty('routeRepository', {
|
|
1149
|
+
value: {
|
|
1150
|
+
refreshAccessible: hookState.refresh,
|
|
1151
|
+
isAccessibleLoaded: () => true,
|
|
1152
|
+
ensureAccessibleLoaded: vi.fn().mockResolvedValue([]),
|
|
1153
|
+
getRouteBySchemaUid: vi.fn((schemaUid: string) => (schemaUid === 'child-flow-page' ? childRoute : undefined)),
|
|
1154
|
+
listAccessible: vi.fn(() => [groupRoute]),
|
|
1155
|
+
},
|
|
1156
|
+
});
|
|
1157
|
+
engine.context.defineProperty('app', {
|
|
1158
|
+
value: {
|
|
1159
|
+
getPublicPath: () => '/v2/',
|
|
1160
|
+
router: {
|
|
1161
|
+
getBasename: () => '/v2',
|
|
1162
|
+
},
|
|
1163
|
+
},
|
|
1164
|
+
});
|
|
1165
|
+
|
|
1166
|
+
const adminLayoutModel: MockAdminLayoutModel = Object.assign(
|
|
1167
|
+
engine.createModel({ uid: 'admin-layout-model', use: 'FlowModel' }),
|
|
1168
|
+
{
|
|
1169
|
+
registerRoutePage: vi.fn(),
|
|
1170
|
+
updateRoutePage: vi.fn(),
|
|
1171
|
+
unregisterRoutePage: vi.fn(),
|
|
1172
|
+
},
|
|
1173
|
+
);
|
|
1174
|
+
|
|
1175
|
+
render(
|
|
1176
|
+
<FlowEngineProvider engine={engine}>
|
|
1177
|
+
<MemoryRouter initialEntries={['/admin/371750686228480/view/not-exists']}>
|
|
1178
|
+
<Routes>
|
|
1179
|
+
<Route path="/admin/:name/view/*" element={<FlowRoute />} />
|
|
1180
|
+
</Routes>
|
|
1181
|
+
</MemoryRouter>
|
|
1182
|
+
</FlowEngineProvider>,
|
|
1183
|
+
);
|
|
1184
|
+
|
|
1185
|
+
expect(await screen.findByText('404')).toBeInTheDocument();
|
|
1186
|
+
expect(adminLayoutModel.registerRoutePage).not.toHaveBeenCalledWith('child-flow-page', expect.any(Object));
|
|
1187
|
+
expect(adminLayoutModel.registerRoutePage).not.toHaveBeenCalledWith('371750686228480', expect.any(Object));
|
|
1188
|
+
});
|
|
1189
|
+
|
|
1190
|
+
it('should keep rendering 404 when a group id is opened with a tab admin route path', async () => {
|
|
1191
|
+
const engine = new FlowEngine();
|
|
1192
|
+
const childRoute = {
|
|
1193
|
+
schemaUid: 'child-flow-page',
|
|
1194
|
+
title: 'Child flow page',
|
|
1195
|
+
type: NocoBaseDesktopRouteType.flowPage,
|
|
1196
|
+
};
|
|
1197
|
+
const groupRoute = {
|
|
1198
|
+
id: 371750686228480,
|
|
1199
|
+
schemaUid: 'group-schema',
|
|
1200
|
+
title: 'Group with child',
|
|
1201
|
+
type: NocoBaseDesktopRouteType.group,
|
|
1202
|
+
children: [childRoute],
|
|
1203
|
+
};
|
|
1204
|
+
engine.context.defineProperty('routeRepository', {
|
|
1205
|
+
value: {
|
|
1206
|
+
refreshAccessible: hookState.refresh,
|
|
1207
|
+
isAccessibleLoaded: () => true,
|
|
1208
|
+
ensureAccessibleLoaded: vi.fn().mockResolvedValue([]),
|
|
1209
|
+
getRouteBySchemaUid: vi.fn((schemaUid: string) => (schemaUid === 'child-flow-page' ? childRoute : undefined)),
|
|
1210
|
+
listAccessible: vi.fn(() => [groupRoute]),
|
|
1211
|
+
},
|
|
1212
|
+
});
|
|
1213
|
+
engine.context.defineProperty('app', {
|
|
1214
|
+
value: {
|
|
1215
|
+
getPublicPath: () => '/v2/',
|
|
1216
|
+
router: {
|
|
1217
|
+
getBasename: () => '/v2',
|
|
1218
|
+
},
|
|
1219
|
+
},
|
|
1220
|
+
});
|
|
1221
|
+
|
|
1222
|
+
const adminLayoutModel: MockAdminLayoutModel = Object.assign(
|
|
1223
|
+
engine.createModel({ uid: 'admin-layout-model', use: 'FlowModel' }),
|
|
1224
|
+
{
|
|
1225
|
+
registerRoutePage: vi.fn(),
|
|
1226
|
+
updateRoutePage: vi.fn(),
|
|
1227
|
+
unregisterRoutePage: vi.fn(),
|
|
1228
|
+
},
|
|
1229
|
+
);
|
|
1230
|
+
|
|
1231
|
+
render(
|
|
1232
|
+
<FlowEngineProvider engine={engine}>
|
|
1233
|
+
<MemoryRouter initialEntries={['/admin/371750686228480/tab/not-exists']}>
|
|
1234
|
+
<Routes>
|
|
1235
|
+
<Route path="/admin/:name/tab/:tabUid" element={<FlowRoute />} />
|
|
1236
|
+
</Routes>
|
|
1237
|
+
</MemoryRouter>
|
|
1238
|
+
</FlowEngineProvider>,
|
|
1239
|
+
);
|
|
1240
|
+
|
|
1241
|
+
expect(await screen.findByText('404')).toBeInTheDocument();
|
|
1242
|
+
expect(adminLayoutModel.registerRoutePage).not.toHaveBeenCalledWith('child-flow-page', expect.any(Object));
|
|
1243
|
+
expect(adminLayoutModel.registerRoutePage).not.toHaveBeenCalledWith('371750686228480', expect.any(Object));
|
|
1244
|
+
});
|
|
1245
|
+
|
|
1246
|
+
it('should keep blank content while a group child navigation is already pending for the current path', async () => {
|
|
1247
|
+
const engine = new FlowEngine();
|
|
1248
|
+
const childRoute = {
|
|
1249
|
+
schemaUid: 'child-flow-page',
|
|
1250
|
+
title: 'Child flow page',
|
|
1251
|
+
type: NocoBaseDesktopRouteType.flowPage,
|
|
1252
|
+
};
|
|
1253
|
+
const groupRoute = {
|
|
1254
|
+
id: 371750686228480,
|
|
1255
|
+
schemaUid: 'group-schema',
|
|
1256
|
+
title: 'Group with child',
|
|
1257
|
+
type: NocoBaseDesktopRouteType.group,
|
|
1258
|
+
children: [childRoute],
|
|
1259
|
+
};
|
|
1260
|
+
engine.context.defineProperty('routeRepository', {
|
|
1261
|
+
value: {
|
|
1262
|
+
refreshAccessible: hookState.refresh,
|
|
1263
|
+
isAccessibleLoaded: () => true,
|
|
1264
|
+
ensureAccessibleLoaded: vi.fn().mockResolvedValue([]),
|
|
1265
|
+
getRouteBySchemaUid: vi.fn((schemaUid: string) => (schemaUid === 'child-flow-page' ? childRoute : undefined)),
|
|
1266
|
+
listAccessible: vi.fn(() => [groupRoute]),
|
|
1267
|
+
},
|
|
1268
|
+
});
|
|
1269
|
+
engine.context.defineProperty('app', {
|
|
1270
|
+
value: {
|
|
1271
|
+
getPublicPath: () => '/v2/',
|
|
1272
|
+
router: {
|
|
1273
|
+
getBasename: () => '/v2',
|
|
1274
|
+
},
|
|
1275
|
+
},
|
|
1276
|
+
});
|
|
1277
|
+
|
|
1278
|
+
const replace = vi.fn();
|
|
1279
|
+
const navigator: RouterNavigator = {
|
|
1280
|
+
createHref: (to: { pathname?: string; search?: string; hash?: string } | string) =>
|
|
1281
|
+
typeof to === 'string' ? to : `${to.pathname || ''}${to.search || ''}${to.hash || ''}`,
|
|
1282
|
+
go: vi.fn(),
|
|
1283
|
+
push: vi.fn(),
|
|
1284
|
+
replace,
|
|
1285
|
+
};
|
|
1286
|
+
|
|
1287
|
+
const RerenderAfterReplace = () => {
|
|
1288
|
+
const [rerendered, setRerendered] = React.useState(false);
|
|
1289
|
+
React.useEffect(() => {
|
|
1290
|
+
if (!rerendered && replace.mock.calls.length > 0) {
|
|
1291
|
+
setRerendered(true);
|
|
1292
|
+
}
|
|
1293
|
+
}, [rerendered]);
|
|
1294
|
+
|
|
1295
|
+
return <FlowRoute legacyPageBehavior={rerendered ? 'bridge' : undefined} />;
|
|
1296
|
+
};
|
|
1297
|
+
|
|
1298
|
+
render(
|
|
1299
|
+
<FlowEngineProvider engine={engine}>
|
|
1300
|
+
<Router location="/admin/371750686228480" navigator={navigator}>
|
|
1301
|
+
<Routes>
|
|
1302
|
+
<Route path="/admin/:name" element={<RerenderAfterReplace />} />
|
|
1303
|
+
</Routes>
|
|
1304
|
+
</Router>
|
|
1305
|
+
</FlowEngineProvider>,
|
|
1306
|
+
);
|
|
1307
|
+
|
|
1308
|
+
await waitFor(() => {
|
|
1309
|
+
expect(replace).toHaveBeenCalled();
|
|
1310
|
+
});
|
|
1311
|
+
await act(async () => {
|
|
1312
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
1313
|
+
});
|
|
1314
|
+
expect(screen.queryByText('404')).not.toBeInTheDocument();
|
|
1315
|
+
});
|
|
1316
|
+
|
|
1317
|
+
it('should reset group navigation guard when page uid changes in the same route instance', async () => {
|
|
1318
|
+
const engine = new FlowEngine();
|
|
1319
|
+
const childRoute1 = {
|
|
1320
|
+
schemaUid: 'child-flow-page-1',
|
|
1321
|
+
title: 'Child flow page 1',
|
|
1322
|
+
type: NocoBaseDesktopRouteType.flowPage,
|
|
1323
|
+
};
|
|
1324
|
+
const childRoute2 = {
|
|
1325
|
+
schemaUid: 'child-flow-page-2',
|
|
1326
|
+
title: 'Child flow page 2',
|
|
1327
|
+
type: NocoBaseDesktopRouteType.flowPage,
|
|
1328
|
+
};
|
|
1329
|
+
const groupRoute1 = {
|
|
1330
|
+
id: 371750686228480,
|
|
1331
|
+
schemaUid: 'group-schema-1',
|
|
1332
|
+
title: 'Group with child 1',
|
|
1333
|
+
type: NocoBaseDesktopRouteType.group,
|
|
1334
|
+
children: [childRoute1],
|
|
1335
|
+
};
|
|
1336
|
+
const groupRoute2 = {
|
|
1337
|
+
id: 371750755434496,
|
|
1338
|
+
schemaUid: 'group-schema-2',
|
|
1339
|
+
title: 'Group with child 2',
|
|
1340
|
+
type: NocoBaseDesktopRouteType.group,
|
|
1341
|
+
children: [childRoute2],
|
|
1342
|
+
};
|
|
1343
|
+
const routeMap: Record<string, typeof childRoute1 | typeof childRoute2> = {
|
|
1344
|
+
'child-flow-page-1': childRoute1,
|
|
1345
|
+
'child-flow-page-2': childRoute2,
|
|
1346
|
+
};
|
|
1347
|
+
const getRouteBySchemaUid = vi.fn((schemaUid: string) => routeMap[schemaUid]);
|
|
1348
|
+
const listAccessible = vi.fn(() => [groupRoute1, groupRoute2]);
|
|
1349
|
+
engine.context.defineProperty('routeRepository', {
|
|
1350
|
+
value: {
|
|
1351
|
+
refreshAccessible: hookState.refresh,
|
|
1352
|
+
isAccessibleLoaded: () => true,
|
|
1353
|
+
ensureAccessibleLoaded: vi.fn().mockResolvedValue([]),
|
|
1354
|
+
getRouteBySchemaUid,
|
|
1355
|
+
listAccessible,
|
|
1356
|
+
},
|
|
1357
|
+
});
|
|
1358
|
+
engine.context.defineProperty('app', {
|
|
1359
|
+
value: {
|
|
1360
|
+
getPublicPath: () => '/v2/',
|
|
1361
|
+
router: {
|
|
1362
|
+
getBasename: () => '/v2',
|
|
1363
|
+
},
|
|
1364
|
+
},
|
|
1365
|
+
});
|
|
1366
|
+
|
|
1367
|
+
const adminLayoutModel: MockAdminLayoutModel = Object.assign(
|
|
1368
|
+
engine.createModel({ uid: 'admin-layout-model', use: 'FlowModel' }),
|
|
1369
|
+
{
|
|
1370
|
+
registerRoutePage: vi.fn(),
|
|
1371
|
+
updateRoutePage: vi.fn(),
|
|
1372
|
+
unregisterRoutePage: vi.fn(),
|
|
1373
|
+
},
|
|
1374
|
+
);
|
|
1375
|
+
let navigateTo: (path: string) => void = () => {};
|
|
1376
|
+
const CaptureNavigate = () => {
|
|
1377
|
+
const navigate = useNavigate();
|
|
1378
|
+
React.useEffect(() => {
|
|
1379
|
+
navigateTo = navigate;
|
|
1380
|
+
}, [navigate]);
|
|
1381
|
+
return null;
|
|
1382
|
+
};
|
|
1383
|
+
|
|
1384
|
+
render(
|
|
1385
|
+
<FlowEngineProvider engine={engine}>
|
|
1386
|
+
<MemoryRouter initialEntries={['/admin/371750686228480']}>
|
|
1387
|
+
<CaptureNavigate />
|
|
1388
|
+
<Routes>
|
|
1389
|
+
<Route path="/admin/:name" element={<FlowRoute />} />
|
|
1390
|
+
</Routes>
|
|
1391
|
+
</MemoryRouter>
|
|
1392
|
+
</FlowEngineProvider>,
|
|
1393
|
+
);
|
|
1394
|
+
|
|
1395
|
+
await waitFor(() => {
|
|
1396
|
+
expect(adminLayoutModel.registerRoutePage).toHaveBeenCalledWith('child-flow-page-1', expect.any(Object));
|
|
1397
|
+
});
|
|
1398
|
+
|
|
1399
|
+
act(() => {
|
|
1400
|
+
navigateTo('/admin/371750755434496');
|
|
1401
|
+
});
|
|
1402
|
+
|
|
1403
|
+
await waitFor(() => {
|
|
1404
|
+
expect(adminLayoutModel.registerRoutePage).toHaveBeenCalledWith('child-flow-page-2', expect.any(Object));
|
|
1405
|
+
});
|
|
1406
|
+
expect(adminLayoutModel.registerRoutePage).not.toHaveBeenCalledWith('371750755434496', expect.any(Object));
|
|
1407
|
+
expect(screen.queryByText('404')).not.toBeInTheDocument();
|
|
1408
|
+
});
|
|
1409
|
+
|
|
1410
|
+
it('should keep rendering 404 when current admin route matches no accessible schema uid or id', async () => {
|
|
1411
|
+
const engine = new FlowEngine();
|
|
1412
|
+
engine.context.defineProperty('routeRepository', {
|
|
1413
|
+
value: {
|
|
1414
|
+
refreshAccessible: hookState.refresh,
|
|
1415
|
+
isAccessibleLoaded: () => true,
|
|
1416
|
+
ensureAccessibleLoaded: vi.fn().mockResolvedValue([]),
|
|
1417
|
+
getRouteBySchemaUid: vi.fn(() => undefined),
|
|
1418
|
+
listAccessible: vi.fn(() => [
|
|
1419
|
+
{
|
|
1420
|
+
id: 371750686228480,
|
|
1421
|
+
schemaUid: 'group-schema',
|
|
1422
|
+
title: '789',
|
|
1423
|
+
type: NocoBaseDesktopRouteType.group,
|
|
1424
|
+
},
|
|
1425
|
+
]),
|
|
1426
|
+
},
|
|
1427
|
+
});
|
|
1428
|
+
engine.context.defineProperty('app', {
|
|
1429
|
+
value: {
|
|
1430
|
+
getPublicPath: () => '/v2/',
|
|
1431
|
+
router: {
|
|
1432
|
+
getBasename: () => '/v2',
|
|
1433
|
+
},
|
|
1434
|
+
},
|
|
1435
|
+
});
|
|
1436
|
+
|
|
1437
|
+
const adminLayoutModel: MockAdminLayoutModel = Object.assign(
|
|
1438
|
+
engine.createModel({ uid: 'admin-layout-model', use: 'FlowModel' }),
|
|
1439
|
+
{
|
|
1440
|
+
registerRoutePage: vi.fn(),
|
|
1441
|
+
updateRoutePage: vi.fn(),
|
|
1442
|
+
unregisterRoutePage: vi.fn(),
|
|
1443
|
+
},
|
|
1444
|
+
);
|
|
1445
|
+
|
|
1446
|
+
render(
|
|
1447
|
+
<FlowEngineProvider engine={engine}>
|
|
1448
|
+
<MemoryRouter initialEntries={['/admin/not-exists-4822']}>
|
|
1449
|
+
<Routes>
|
|
1450
|
+
<Route path="/admin/:name" element={<FlowRoute />} />
|
|
1451
|
+
</Routes>
|
|
1452
|
+
</MemoryRouter>
|
|
1453
|
+
</FlowEngineProvider>,
|
|
1454
|
+
);
|
|
1455
|
+
|
|
1456
|
+
expect(await screen.findByText('404')).toBeInTheDocument();
|
|
1457
|
+
expect(adminLayoutModel.registerRoutePage).not.toHaveBeenCalled();
|
|
1458
|
+
});
|
|
1459
|
+
|
|
1460
|
+
it('should keep rendering 404 when current admin route matches only a non-group route id', async () => {
|
|
1461
|
+
const engine = new FlowEngine();
|
|
1462
|
+
engine.context.defineProperty('routeRepository', {
|
|
1463
|
+
value: {
|
|
1464
|
+
refreshAccessible: hookState.refresh,
|
|
1465
|
+
isAccessibleLoaded: () => true,
|
|
1466
|
+
ensureAccessibleLoaded: vi.fn().mockResolvedValue([]),
|
|
1467
|
+
getRouteBySchemaUid: vi.fn(() => undefined),
|
|
1468
|
+
listAccessible: vi.fn(() => [
|
|
1469
|
+
{
|
|
1470
|
+
id: 10001,
|
|
1471
|
+
schemaUid: 'flow-page-schema',
|
|
1472
|
+
title: 'Flow page',
|
|
1473
|
+
type: NocoBaseDesktopRouteType.flowPage,
|
|
1474
|
+
},
|
|
1475
|
+
]),
|
|
1476
|
+
},
|
|
1477
|
+
});
|
|
1478
|
+
engine.context.defineProperty('app', {
|
|
1479
|
+
value: {
|
|
1480
|
+
getPublicPath: () => '/v2/',
|
|
1481
|
+
router: {
|
|
1482
|
+
getBasename: () => '/v2',
|
|
1483
|
+
},
|
|
1484
|
+
},
|
|
1485
|
+
});
|
|
1486
|
+
|
|
1487
|
+
const adminLayoutModel: MockAdminLayoutModel = Object.assign(
|
|
1488
|
+
engine.createModel({ uid: 'admin-layout-model', use: 'FlowModel' }),
|
|
1489
|
+
{
|
|
1490
|
+
registerRoutePage: vi.fn(),
|
|
1491
|
+
updateRoutePage: vi.fn(),
|
|
1492
|
+
unregisterRoutePage: vi.fn(),
|
|
1493
|
+
},
|
|
1494
|
+
);
|
|
1495
|
+
|
|
1496
|
+
render(
|
|
1497
|
+
<FlowEngineProvider engine={engine}>
|
|
1498
|
+
<MemoryRouter initialEntries={['/admin/10001']}>
|
|
1499
|
+
<Routes>
|
|
1500
|
+
<Route path="/admin/:name" element={<FlowRoute />} />
|
|
1501
|
+
</Routes>
|
|
1502
|
+
</MemoryRouter>
|
|
1503
|
+
</FlowEngineProvider>,
|
|
1504
|
+
);
|
|
1505
|
+
|
|
1506
|
+
expect(await screen.findByText('404')).toBeInTheDocument();
|
|
1507
|
+
expect(adminLayoutModel.registerRoutePage).not.toHaveBeenCalled();
|
|
1508
|
+
});
|
|
1509
|
+
|
|
1510
|
+
it('should keep rendering 404 when current admin route matches only a group schema uid', async () => {
|
|
1511
|
+
const engine = new FlowEngine();
|
|
1512
|
+
const groupRoute = {
|
|
1513
|
+
id: 371750686228480,
|
|
1514
|
+
schemaUid: 'group-schema',
|
|
1515
|
+
title: '789',
|
|
1516
|
+
type: NocoBaseDesktopRouteType.group,
|
|
1517
|
+
};
|
|
1518
|
+
engine.context.defineProperty('routeRepository', {
|
|
1519
|
+
value: {
|
|
1520
|
+
refreshAccessible: hookState.refresh,
|
|
1521
|
+
isAccessibleLoaded: () => true,
|
|
1522
|
+
ensureAccessibleLoaded: vi.fn().mockResolvedValue([]),
|
|
1523
|
+
getRouteBySchemaUid: vi.fn((schemaUid: string) => (schemaUid === 'group-schema' ? groupRoute : undefined)),
|
|
1524
|
+
listAccessible: vi.fn(() => [groupRoute]),
|
|
1525
|
+
},
|
|
1526
|
+
});
|
|
1527
|
+
engine.context.defineProperty('app', {
|
|
1528
|
+
value: {
|
|
1529
|
+
getPublicPath: () => '/v2/',
|
|
1530
|
+
router: {
|
|
1531
|
+
getBasename: () => '/v2',
|
|
1532
|
+
},
|
|
1533
|
+
},
|
|
1534
|
+
});
|
|
1535
|
+
|
|
1536
|
+
const adminLayoutModel: MockAdminLayoutModel = Object.assign(
|
|
1537
|
+
engine.createModel({ uid: 'admin-layout-model', use: 'FlowModel' }),
|
|
1538
|
+
{
|
|
1539
|
+
registerRoutePage: vi.fn(),
|
|
1540
|
+
updateRoutePage: vi.fn(),
|
|
1541
|
+
unregisterRoutePage: vi.fn(),
|
|
1542
|
+
},
|
|
1543
|
+
);
|
|
1544
|
+
|
|
1545
|
+
render(
|
|
1546
|
+
<FlowEngineProvider engine={engine}>
|
|
1547
|
+
<MemoryRouter initialEntries={['/admin/group-schema']}>
|
|
1548
|
+
<Routes>
|
|
1549
|
+
<Route path="/admin/:name" element={<FlowRoute />} />
|
|
1550
|
+
</Routes>
|
|
1551
|
+
</MemoryRouter>
|
|
1552
|
+
</FlowEngineProvider>,
|
|
1553
|
+
);
|
|
1554
|
+
|
|
1555
|
+
expect(await screen.findByText('404')).toBeInTheDocument();
|
|
1556
|
+
expect(adminLayoutModel.registerRoutePage).not.toHaveBeenCalled();
|
|
1557
|
+
});
|
|
1558
|
+
|
|
896
1559
|
it('should not use flowModels:findOne to bridge a missing route for protected layouts', async () => {
|
|
897
1560
|
const engine = new FlowEngine();
|
|
898
1561
|
const findOne = vi.fn().mockResolvedValue({
|
|
@@ -1121,7 +1784,7 @@ describe('FlowRoute', () => {
|
|
|
1121
1784
|
expect(engine.getModel('public-form-1')).toBeUndefined();
|
|
1122
1785
|
});
|
|
1123
1786
|
|
|
1124
|
-
it('should
|
|
1787
|
+
it('should skip accessible route loading when layout authCheck is false', async () => {
|
|
1125
1788
|
const engine = new FlowEngine();
|
|
1126
1789
|
const ensureAccessibleLoaded = vi.fn().mockRejectedValue(new Error('cannot load accessible routes'));
|
|
1127
1790
|
const getRouteBySchemaUid = vi.fn();
|
|
@@ -1190,7 +1853,7 @@ describe('FlowRoute', () => {
|
|
|
1190
1853
|
await waitFor(() => {
|
|
1191
1854
|
expect(layoutModel.registerRoutePage).toHaveBeenCalledWith('public-form-1', expect.any(Object));
|
|
1192
1855
|
});
|
|
1193
|
-
expect(ensureAccessibleLoaded).
|
|
1856
|
+
expect(ensureAccessibleLoaded).not.toHaveBeenCalled();
|
|
1194
1857
|
expect(getRouteBySchemaUid).not.toHaveBeenCalled();
|
|
1195
1858
|
});
|
|
1196
1859
|
|
|
@@ -1256,7 +1919,7 @@ describe('FlowRoute', () => {
|
|
|
1256
1919
|
}
|
|
1257
1920
|
});
|
|
1258
1921
|
|
|
1259
|
-
it('should render
|
|
1922
|
+
it('should render 404 when route and FlowModel do not exist', async () => {
|
|
1260
1923
|
const originalLocation = window.location;
|
|
1261
1924
|
const replace = vi.fn();
|
|
1262
1925
|
Object.defineProperty(window, 'location', {
|