@nocobase/client-v2 2.2.0-beta.9 → 3.0.0-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/es/APIClient.d.ts +1 -3
- package/es/BaseApplication.d.ts +1 -0
- package/es/acl/ACLProvider.d.ts +10 -0
- package/es/authRedirect.d.ts +5 -0
- package/es/collection-field-interface/CollectionFieldInterface.d.ts +1 -0
- package/es/collection-field-interface/CollectionFieldInterfaceManager.d.ts +1 -0
- package/es/components/AttachmentUpload.d.ts +51 -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 +2 -0
- package/es/flow/actions/index.d.ts +1 -1
- package/es/flow/actions/linkageRules.d.ts +3 -0
- package/es/flow/admin-shell/admin-layout/AdminLayoutMenuModels.d.ts +1 -0
- package/es/flow/admin-shell/admin-layout/NocoBaseLogo.d.ts +10 -0
- package/es/flow/components/FieldAssignExactDatePicker.d.ts +1 -0
- package/es/flow/components/FieldAssignValueInput.d.ts +9 -0
- package/es/flow/components/FlowRoute.d.ts +2 -2
- package/es/flow/components/RunJSValueEditor.d.ts +1 -0
- package/es/flow/components/filter/FilterGroup.d.ts +1 -0
- package/es/flow/components/filter/VariableFilterItem.d.ts +6 -1
- package/es/flow/index.d.ts +1 -0
- package/es/flow/internal/registerDeviceTypeContext.d.ts +10 -0
- package/es/flow/models/base/ActionModelCore.d.ts +4 -2
- package/es/flow/models/base/BlockGridModel.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/form/QuickEditFormModel.d.ts +17 -2
- package/es/flow/models/blocks/table/TableColumnModel.d.ts +1 -0
- package/es/flow/models/fields/DateTimeFieldModel/dateLimit.d.ts +15 -7
- package/es/flow-compat/fieldValidationConstants.d.ts +1 -1
- package/es/flow-compat/routeTypes.d.ts +1 -0
- package/es/index.d.ts +8 -1
- package/es/index.mjs +190 -141
- package/es/nocobase-buildin-plugin/currentUserAuthStatus.d.ts +11 -0
- package/es/nocobase-buildin-plugin/index.d.ts +9 -0
- package/es/settings-app/SettingsApplication.d.ts +18 -0
- package/es/settings-app/SettingsBrand.d.ts +16 -0
- package/es/settings-app/SettingsBuildInPlugin.d.ts +9 -0
- package/es/settings-app/SettingsDocumentRedirect.d.ts +10 -0
- package/es/settings-app/SettingsGroupNav.d.ts +17 -0
- package/es/settings-app/SettingsPluginSettingsManager.d.ts +14 -0
- package/es/settings-app/SettingsRouterManager.d.ts +15 -0
- package/es/settings-app/SettingsSearch.d.ts +17 -0
- package/es/settings-app/SettingsShell.d.ts +10 -0
- package/es/settings-app/isSettingsApp.d.ts +18 -0
- package/es/settings-app/runtimePaths.d.ts +18 -0
- package/es/settings-app/settingsDocumentPath.d.ts +14 -0
- package/es/settings-app/settingsTheme.d.ts +87 -0
- package/es/settings-app/useSettingsThemeConfig.d.ts +22 -0
- package/es/settings-center/AdminSettingsLayout.d.ts +2 -2
- package/es/settings-center/groups.d.ts +66 -0
- package/es/settings-center/useSettingsGroups.d.ts +36 -0
- package/es/settings-center/useSettingsSearch.d.ts +35 -0
- package/es/settings-center/utils.d.ts +24 -0
- package/es/theme/index.d.ts +1 -0
- package/es/theme/itemActive.d.ts +24 -0
- package/es/theme/type.d.ts +9 -0
- package/es/utils/getRouteRuntimeVersion.d.ts +23 -0
- package/es/utils/index.d.ts +1 -0
- package/lib/index.js +195 -146
- package/lib/locale/languageCodes.js +3 -1
- package/package.json +9 -7
- package/src/APIClient.ts +1 -10
- package/src/Application.tsx +4 -0
- package/src/BaseApplication.tsx +11 -6
- package/src/__tests__/app.test.tsx +73 -0
- package/src/__tests__/authRedirect.test.ts +137 -0
- package/src/__tests__/browserChecker.test.ts +185 -6
- package/src/__tests__/getRouteRuntimeVersion.test.ts +68 -0
- package/src/__tests__/mockSettingsApplication.ts +29 -0
- package/src/__tests__/nocobase-buildin-plugin-auth.test.tsx +79 -10
- package/src/__tests__/plugin-manager.test.tsx +7 -6
- package/src/__tests__/settings-application.test.ts +164 -0
- package/src/__tests__/settings-auth-routes.test.ts +71 -0
- package/src/__tests__/settings-center.test.tsx +38 -37
- package/src/__tests__/settings-layout-root.test.tsx +260 -0
- package/src/__tests__/settings-runtime-paths.test.ts +99 -0
- package/src/__tests__/settings-shell.test.tsx +200 -0
- package/src/acl/ACLProvider.tsx +21 -0
- package/src/authRedirect.ts +72 -3
- 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/AttachmentUpload.tsx +275 -0
- 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 +32 -7
- package/src/components/form/filter/CollectionFilterPanel.tsx +4 -0
- package/src/components/form/filter/__tests__/CollectionFilterItem.test.tsx +38 -0
- package/src/components/form/filter/__tests__/useFilterActionProps.test.tsx +95 -0
- package/src/components/form/filter/index.ts +2 -0
- package/src/components/form/filter/useFilterActionProps.ts +37 -6
- package/src/components/index.ts +2 -0
- package/src/flow/FlowPage.tsx +9 -1
- package/src/flow/__tests__/FlowPage.test.tsx +50 -3
- package/src/flow/__tests__/FlowRoute.test.tsx +128 -10
- package/src/flow/__tests__/PluginFlowEngine.test.ts +58 -0
- package/src/flow/actions/__tests__/actionLinkageRules.forkProps.test.ts +314 -0
- package/src/flow/actions/__tests__/dataScopeFormValueClear.test.ts +102 -0
- package/src/flow/actions/__tests__/linkageRules.tab.test.ts +171 -0
- package/src/flow/actions/__tests__/linkageRulesRefresh.test.ts +7 -3
- package/src/flow/actions/index.ts +2 -0
- package/src/flow/actions/linkageRules.tsx +111 -16
- package/src/flow/actions/linkageRulesRefresh.tsx +2 -6
- package/src/flow/admin-shell/admin-layout/AdminLayoutComponent.tsx +1 -57
- package/src/flow/admin-shell/admin-layout/NocoBaseLogo.tsx +77 -0
- package/src/flow/admin-shell/admin-layout/TopbarActionsBar.tsx +37 -14
- package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutComponent.test.tsx +253 -6
- package/src/flow/admin-shell/admin-layout/__tests__/TopbarActionsBar.test.tsx +77 -13
- 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 +91 -20
- package/src/flow/components/FlowRoute.tsx +78 -32
- package/src/flow/components/RunJSValueEditor.tsx +9 -1
- package/src/flow/components/__tests__/FieldAssignValueInput.context.test.tsx +216 -0
- package/src/flow/components/filter/FilterGroup.tsx +33 -5
- package/src/flow/components/filter/VariableFilterItem.tsx +158 -10
- package/src/flow/components/filter/__tests__/FilterGroup.test.tsx +45 -0
- package/src/flow/components/filter/__tests__/VariableFilterItem.leftMetaTree.test.tsx +9 -0
- package/src/flow/components/filter/__tests__/VariableFilterItem.test.tsx +70 -1
- package/src/flow/index.ts +3 -0
- package/src/flow/internal/registerDeviceTypeContext.ts +39 -0
- package/src/flow/models/base/ActionModelCore.tsx +11 -2
- package/src/flow/models/base/BlockGridModel.tsx +26 -0
- package/src/flow/models/base/CollectionBlockModel.tsx +6 -2
- 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/blocks/filter-form/FilterFormBlockModel.tsx +28 -3
- package/src/flow/models/blocks/filter-form/FilterFormItemModel.tsx +27 -12
- package/src/flow/models/blocks/filter-form/__tests__/FilterFormItemModel.defineChildren.test.ts +36 -0
- package/src/flow/models/blocks/filter-form/__tests__/defaultValues.wiring.test.ts +66 -4
- package/src/flow/models/blocks/form/QuickEditFormModel.tsx +189 -36
- package/src/flow/models/blocks/form/__tests__/QuickEditFormModel.quickEdit.test.ts +350 -2
- package/src/flow/models/blocks/js-block/JSBlock.tsx +1 -1
- package/src/flow/models/blocks/table/TableActionsColumnModel.tsx +2 -1
- package/src/flow/models/blocks/table/TableBlockModel.tsx +4 -2
- package/src/flow/models/blocks/table/TableColumnModel.tsx +30 -1
- package/src/flow/models/blocks/table/__tests__/TableBlockModel.quickEditRefresh.test.ts +12 -0
- package/src/flow/models/blocks/table/__tests__/TableColumnModel.test.tsx +33 -0
- package/src/flow/models/fields/AssociationFieldModel/PopupSubTableFieldModel/PopupSubTableFieldModel.tsx +2 -1
- 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/JsonFieldModel.tsx +31 -8
- package/src/flow/models/fields/VariableFieldFormModel.tsx +3 -3
- package/src/flow/models/fields/__tests__/JsonFieldModel.test.ts +82 -0
- package/src/flow/models/fields/__tests__/VariableFieldFormModel.test.tsx +51 -0
- package/src/flow/models/fields/mobile-components/MobileLazySelect.tsx +20 -10
- package/src/flow/models/fields/mobile-components/MobileSelect.tsx +24 -12
- package/src/flow/models/topbar/TopbarActionModel.tsx +52 -180
- 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 +14 -1
- package/src/locale/languageCodes.ts +3 -1
- package/src/nocobase-buildin-plugin/currentUserAuthStatus.ts +58 -0
- package/src/nocobase-buildin-plugin/index.tsx +110 -70
- package/src/settings-app/SettingsApplication.ts +31 -0
- package/src/settings-app/SettingsBrand.tsx +108 -0
- package/src/settings-app/SettingsBuildInPlugin.ts +10 -0
- package/src/settings-app/SettingsDocumentRedirect.tsx +26 -0
- package/src/settings-app/SettingsGroupNav.tsx +124 -0
- package/src/settings-app/SettingsPluginSettingsManager.ts +38 -0
- package/src/settings-app/SettingsRouterManager.ts +92 -0
- package/src/settings-app/SettingsSearch.tsx +238 -0
- package/src/settings-app/SettingsShell.tsx +167 -0
- package/src/settings-app/isSettingsApp.ts +21 -0
- package/src/settings-app/runtimePaths.ts +104 -0
- package/src/settings-app/settingsDocumentPath.ts +66 -0
- package/src/settings-app/settingsTheme.ts +301 -0
- package/src/settings-app/useSettingsThemeConfig.ts +100 -0
- package/src/settings-center/AdminSettingsLayout.tsx +122 -141
- package/src/settings-center/SystemSettingsPage.tsx +4 -170
- package/src/settings-center/groups.ts +108 -0
- package/src/settings-center/useSettingsGroups.ts +105 -0
- package/src/settings-center/useSettingsSearch.ts +173 -0
- package/src/settings-center/utils.tsx +50 -1
- package/src/theme/index.tsx +1 -0
- package/src/theme/itemActive.ts +31 -0
- package/src/theme/type.ts +10 -0
- package/src/utils/getRouteRuntimeVersion.ts +185 -0
- package/src/utils/index.tsx +1 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { afterEach, describe, expect, it } from 'vitest';
|
|
11
|
+
import { getRouteRuntimeVersion } from '../utils/getRouteRuntimeVersion';
|
|
12
|
+
|
|
13
|
+
function replacePathname(pathname: string) {
|
|
14
|
+
Object.defineProperty(window, 'location', {
|
|
15
|
+
configurable: true,
|
|
16
|
+
value: {
|
|
17
|
+
...window.location,
|
|
18
|
+
pathname,
|
|
19
|
+
},
|
|
20
|
+
});
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
describe('getRouteRuntimeVersion', () => {
|
|
24
|
+
afterEach(() => {
|
|
25
|
+
delete window.__nocobase_modern_client_prefix__;
|
|
26
|
+
delete window.__nocobase_public_path__;
|
|
27
|
+
replacePathname('/');
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('returns modern when the current pathname is inside the modern client prefix', () => {
|
|
31
|
+
window.__nocobase_modern_client_prefix__ = 'v';
|
|
32
|
+
window.__nocobase_public_path__ = '/nocobase/v/';
|
|
33
|
+
replacePathname('/nocobase/v/admin/settings/workflow');
|
|
34
|
+
|
|
35
|
+
expect(getRouteRuntimeVersion()).toBe('modern');
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('returns legacy when reused v2 components run under the v1 settings page', () => {
|
|
39
|
+
window.__nocobase_modern_client_prefix__ = 'v';
|
|
40
|
+
window.__nocobase_public_path__ = '/nocobase/';
|
|
41
|
+
replacePathname('/nocobase/admin/settings/workflow/workflows/123');
|
|
42
|
+
|
|
43
|
+
expect(getRouteRuntimeVersion()).toBe('legacy');
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it('returns legacy when root public path is "/"', () => {
|
|
47
|
+
window.__nocobase_modern_client_prefix__ = 'v';
|
|
48
|
+
window.__nocobase_public_path__ = '/';
|
|
49
|
+
replacePathname('/admin/settings/workflow/workflows/123');
|
|
50
|
+
|
|
51
|
+
expect(getRouteRuntimeVersion()).toBe('legacy');
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('returns modern when root public path is "/v/"', () => {
|
|
55
|
+
window.__nocobase_modern_client_prefix__ = 'v';
|
|
56
|
+
window.__nocobase_public_path__ = '/v/';
|
|
57
|
+
replacePathname('/v/admin/workflow/workflows/123');
|
|
58
|
+
|
|
59
|
+
expect(getRouteRuntimeVersion()).toBe('modern');
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('falls back to pathname matching when public path is unavailable', () => {
|
|
63
|
+
window.__nocobase_modern_client_prefix__ = 'v';
|
|
64
|
+
replacePathname('/v/admin/workflow/workflows/123');
|
|
65
|
+
|
|
66
|
+
expect(getRouteRuntimeVersion()).toBe('modern');
|
|
67
|
+
});
|
|
68
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
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 MockAdapter from 'axios-mock-adapter';
|
|
11
|
+
import type { ApplicationOptions } from '../Application';
|
|
12
|
+
import { SettingsApplication } from '../settings-app/SettingsApplication';
|
|
13
|
+
|
|
14
|
+
class MockSettingsApplication extends SettingsApplication {
|
|
15
|
+
readonly apiMock: MockAdapter;
|
|
16
|
+
|
|
17
|
+
constructor(options: ApplicationOptions = {}) {
|
|
18
|
+
super({
|
|
19
|
+
router: { type: 'memory', initialEntries: ['/settings'] },
|
|
20
|
+
ws: false,
|
|
21
|
+
...options,
|
|
22
|
+
});
|
|
23
|
+
this.apiMock = new MockAdapter(this.apiClient.axios);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function createMockSettingsClient(options?: ApplicationOptions) {
|
|
28
|
+
return new MockSettingsApplication(options);
|
|
29
|
+
}
|
|
@@ -51,10 +51,32 @@ class AuthBootstrapRoutePlugin extends Plugin {
|
|
|
51
51
|
}
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
class TestAdminPortalPlugin extends Plugin {
|
|
55
|
+
async load() {
|
|
56
|
+
this.app.layoutManager.registerLayout({
|
|
57
|
+
routeName: 'admin',
|
|
58
|
+
routePath: '/admin',
|
|
59
|
+
uid: 'admin-layout-model',
|
|
60
|
+
layoutModelClass: 'AdminLayoutModel',
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
class TestRootPortalPlugin extends Plugin {
|
|
66
|
+
async load() {
|
|
67
|
+
this.router.add('root', {
|
|
68
|
+
path: '/',
|
|
69
|
+
authCheck: true,
|
|
70
|
+
Component: () => <div>portal landing</div>,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
54
75
|
describe('nocobase buildin plugin auth redirect', () => {
|
|
55
76
|
const originalLocation = globalThis.window.location;
|
|
56
77
|
|
|
57
78
|
beforeEach(() => {
|
|
79
|
+
globalThis.window.localStorage.clear();
|
|
58
80
|
// These fixtures mount the modern client under the `v2` segment; tell the
|
|
59
81
|
// runtime-prefix helper so v2-runtime detection matches (server injects it
|
|
60
82
|
// in production).
|
|
@@ -75,6 +97,7 @@ describe('nocobase buildin plugin auth redirect', () => {
|
|
|
75
97
|
});
|
|
76
98
|
|
|
77
99
|
afterEach(() => {
|
|
100
|
+
globalThis.window.localStorage.clear();
|
|
78
101
|
delete (globalThis.window as any).__nocobase_modern_client_prefix__;
|
|
79
102
|
Object.defineProperty(globalThis.window, 'location', {
|
|
80
103
|
configurable: true,
|
|
@@ -83,6 +106,16 @@ describe('nocobase buildin plugin auth redirect', () => {
|
|
|
83
106
|
vi.restoreAllMocks();
|
|
84
107
|
});
|
|
85
108
|
|
|
109
|
+
it('should leave Admin portal registration to runtime plugins', async () => {
|
|
110
|
+
const app = createMockClient();
|
|
111
|
+
const plugin = new NocoBaseBuildInPlugin({}, app);
|
|
112
|
+
|
|
113
|
+
await plugin.load();
|
|
114
|
+
|
|
115
|
+
expect(app.layoutManager.hasLayout('admin')).toBe(false);
|
|
116
|
+
expect(app.router.has('root')).toBe(false);
|
|
117
|
+
});
|
|
118
|
+
|
|
86
119
|
it('should navigate to v2 signin when /auth:check returns no user', async () => {
|
|
87
120
|
// Aligns with v1: use react-router navigate (virtual) rather than
|
|
88
121
|
// `window.location.replace`, so a `window.location.href` queued elsewhere
|
|
@@ -90,7 +123,7 @@ describe('nocobase buildin plugin auth redirect', () => {
|
|
|
90
123
|
// overridden.
|
|
91
124
|
const app = createMockClient({
|
|
92
125
|
publicPath: '/v2/',
|
|
93
|
-
plugins: [NocoBaseBuildInPlugin as any],
|
|
126
|
+
plugins: [NocoBaseBuildInPlugin as any, TestAdminPortalPlugin as typeof Plugin],
|
|
94
127
|
router: { type: 'memory', initialEntries: ['/v2/admin/7vu4c2sdk6h'] },
|
|
95
128
|
});
|
|
96
129
|
app.apiMock.onGet('app:getLang').reply(200, {
|
|
@@ -113,9 +146,10 @@ describe('nocobase buildin plugin auth redirect', () => {
|
|
|
113
146
|
// and race the 2FA response interceptor with its own signin redirect.
|
|
114
147
|
const app = createMockClient({
|
|
115
148
|
publicPath: '/v2/',
|
|
116
|
-
plugins: [NocoBaseBuildInPlugin as any],
|
|
149
|
+
plugins: [NocoBaseBuildInPlugin as any, TestAdminPortalPlugin as typeof Plugin],
|
|
117
150
|
router: { type: 'memory', initialEntries: ['/v2/admin'] },
|
|
118
151
|
});
|
|
152
|
+
app.apiClient.auth.setToken('test-token');
|
|
119
153
|
app.apiMock.onGet('app:getLang').reply(200, {
|
|
120
154
|
data: { lang: 'en-US', resources: { client: {} }, cron: {} },
|
|
121
155
|
});
|
|
@@ -130,31 +164,37 @@ describe('nocobase buildin plugin auth redirect', () => {
|
|
|
130
164
|
await new Promise((resolve) => setTimeout(resolve, 50));
|
|
131
165
|
expect(app.router.router.state.location.pathname).toBe('/v2/admin');
|
|
132
166
|
expect(app.router.router.state.location.search).toBe('');
|
|
167
|
+
expect(app.apiMock.history.post.filter((request) => request.url === 'auth:syncCookies')).toHaveLength(0);
|
|
133
168
|
});
|
|
134
169
|
|
|
135
|
-
it('should redirect unauthenticated
|
|
170
|
+
it('should redirect an unauthenticated Portal root to v2 signin', async () => {
|
|
136
171
|
const app = createMockClient({
|
|
137
172
|
publicPath: '/nocobase/v2/',
|
|
138
|
-
plugins: [NocoBaseBuildInPlugin as any],
|
|
173
|
+
plugins: [NocoBaseBuildInPlugin as any, TestRootPortalPlugin as typeof Plugin],
|
|
139
174
|
router: { type: 'memory', initialEntries: ['/nocobase/v2/'] },
|
|
140
175
|
});
|
|
141
176
|
app.apiMock.onGet('app:getLang').reply(200, {
|
|
142
177
|
data: { lang: 'en-US', resources: { client: {} }, cron: {} },
|
|
143
178
|
});
|
|
179
|
+
app.apiMock.onGet('/auth:check').reply(200, { data: {} });
|
|
144
180
|
|
|
145
181
|
const Root = app.getRootComponent();
|
|
146
182
|
render(<Root />);
|
|
147
183
|
|
|
148
184
|
await waitFor(() => {
|
|
149
185
|
expect(app.router.router.state.location.pathname).toBe('/nocobase/v2/signin');
|
|
150
|
-
expect(app.router.router.state.location.search).toBe('?redirect=%2Fnocobase%2Fv2
|
|
186
|
+
expect(app.router.router.state.location.search).toBe('?redirect=%2Fnocobase%2Fv2');
|
|
151
187
|
});
|
|
152
188
|
});
|
|
153
189
|
|
|
154
190
|
it('should check current user after navigating from skipped route to v2 admin', async () => {
|
|
155
191
|
const app = createMockClient({
|
|
156
192
|
publicPath: '/v2/',
|
|
157
|
-
plugins: [
|
|
193
|
+
plugins: [
|
|
194
|
+
NocoBaseBuildInPlugin as any,
|
|
195
|
+
TestAdminPortalPlugin as typeof Plugin,
|
|
196
|
+
SkippedPublicRoutePlugin as typeof Plugin,
|
|
197
|
+
],
|
|
158
198
|
router: { type: 'memory', initialEntries: ['/v2/public'] },
|
|
159
199
|
});
|
|
160
200
|
app.apiMock.onGet('app:getLang').reply(200, {
|
|
@@ -326,6 +366,29 @@ describe('nocobase buildin plugin auth redirect', () => {
|
|
|
326
366
|
data: { lang: 'en-US', resources: { client: {} }, cron: {} },
|
|
327
367
|
});
|
|
328
368
|
app.apiMock.onGet('/auth:check').reply(200, { data: { id: 1 } });
|
|
369
|
+
app.apiMock.onPost('auth:syncCookies').reply(200, { data: { synced: true } });
|
|
370
|
+
const ensureLoaded = vi.spyOn(app.dataSourceManager, 'ensureLoaded').mockResolvedValue(undefined);
|
|
371
|
+
|
|
372
|
+
const Root = app.getRootComponent();
|
|
373
|
+
render(<Root />);
|
|
374
|
+
|
|
375
|
+
expect(await screen.findByText('secure page')).toBeInTheDocument();
|
|
376
|
+
expect(ensureLoaded).toHaveBeenCalledTimes(1);
|
|
377
|
+
expect(app.apiMock.history.post.filter((request) => request.url === 'auth:syncCookies')).toHaveLength(1);
|
|
378
|
+
});
|
|
379
|
+
|
|
380
|
+
it('should keep authenticated v2 startup working when cookie bootstrap fails', async () => {
|
|
381
|
+
const app = createMockClient({
|
|
382
|
+
publicPath: '/v2/',
|
|
383
|
+
plugins: [NocoBaseBuildInPlugin as any, AuthBootstrapRoutePlugin as any],
|
|
384
|
+
router: { type: 'memory', initialEntries: ['/v2/secure'] },
|
|
385
|
+
});
|
|
386
|
+
app.apiClient.auth.setToken('test-token');
|
|
387
|
+
app.apiMock.onGet('app:getLang').reply(200, {
|
|
388
|
+
data: { lang: 'en-US', resources: { client: {} }, cron: {} },
|
|
389
|
+
});
|
|
390
|
+
app.apiMock.onGet('/auth:check').reply(200, { data: { id: 1 } });
|
|
391
|
+
app.apiMock.onPost('auth:syncCookies').reply(500, { errors: [{ message: 'cookie sync failed' }] });
|
|
329
392
|
const ensureLoaded = vi.spyOn(app.dataSourceManager, 'ensureLoaded').mockResolvedValue(undefined);
|
|
330
393
|
|
|
331
394
|
const Root = app.getRootComponent();
|
|
@@ -333,6 +396,7 @@ describe('nocobase buildin plugin auth redirect', () => {
|
|
|
333
396
|
|
|
334
397
|
expect(await screen.findByText('secure page')).toBeInTheDocument();
|
|
335
398
|
expect(ensureLoaded).toHaveBeenCalledTimes(1);
|
|
399
|
+
expect(app.apiMock.history.post.filter((request) => request.url === 'auth:syncCookies')).toHaveLength(1);
|
|
336
400
|
});
|
|
337
401
|
|
|
338
402
|
it('should not auth-check or bootstrap authCheck false routes', async () => {
|
|
@@ -357,7 +421,7 @@ describe('nocobase buildin plugin auth redirect', () => {
|
|
|
357
421
|
it('should render v2 admin root without redirecting away', async () => {
|
|
358
422
|
const app = createMockClient({
|
|
359
423
|
publicPath: '/v2/',
|
|
360
|
-
plugins: [NocoBaseBuildInPlugin as any],
|
|
424
|
+
plugins: [NocoBaseBuildInPlugin as any, TestAdminPortalPlugin as typeof Plugin],
|
|
361
425
|
router: { type: 'memory', initialEntries: ['/v2/admin'] },
|
|
362
426
|
});
|
|
363
427
|
app.apiMock.onGet('app:getLang').reply(200, {
|
|
@@ -387,11 +451,11 @@ describe('nocobase buildin plugin auth redirect', () => {
|
|
|
387
451
|
});
|
|
388
452
|
|
|
389
453
|
it.each(['/v2/admin/legacy-page/tab/tab-1', '/v2/admin/legacy-page/view/detail'])(
|
|
390
|
-
'should
|
|
454
|
+
'should explain authenticated direct v1-style v2 page access: %s',
|
|
391
455
|
async (pathname) => {
|
|
392
456
|
const app = createMockClient({
|
|
393
457
|
publicPath: '/v2/',
|
|
394
|
-
plugins: [NocoBaseBuildInPlugin as any],
|
|
458
|
+
plugins: [NocoBaseBuildInPlugin as any, TestAdminPortalPlugin as typeof Plugin],
|
|
395
459
|
router: { type: 'memory', initialEntries: [pathname] },
|
|
396
460
|
});
|
|
397
461
|
app.apiMock.onGet('app:getLang').reply(200, {
|
|
@@ -413,7 +477,12 @@ describe('nocobase buildin plugin auth redirect', () => {
|
|
|
413
477
|
const Root = app.getRootComponent();
|
|
414
478
|
render(<Root />);
|
|
415
479
|
|
|
416
|
-
expect(await screen.findByText('
|
|
480
|
+
expect(await screen.findByText('This page is not supported in the /v2/ branch')).toBeInTheDocument();
|
|
481
|
+
expect(screen.queryByText('404')).not.toBeInTheDocument();
|
|
482
|
+
expect(screen.getByRole('link', { name: 'Open from the original entry' })).toHaveAttribute(
|
|
483
|
+
'href',
|
|
484
|
+
pathname.replace(/^\/v2/, ''),
|
|
485
|
+
);
|
|
417
486
|
expect(app.router.router.state.location.pathname).toBe(pathname);
|
|
418
487
|
},
|
|
419
488
|
);
|
|
@@ -7,10 +7,11 @@
|
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import { ACLRolesCheckProvider,
|
|
10
|
+
import { ACLRolesCheckProvider, Plugin } from '@nocobase/client-v2';
|
|
11
11
|
import { fireEvent, render, screen, waitFor, within } from '@testing-library/react';
|
|
12
12
|
import React from 'react';
|
|
13
|
-
import {
|
|
13
|
+
import { SettingsBuildInPlugin } from '../settings-app/SettingsBuildInPlugin';
|
|
14
|
+
import { createMockSettingsClient } from './mockSettingsApplication';
|
|
14
15
|
|
|
15
16
|
class TestAclPlugin extends Plugin {
|
|
16
17
|
async load() {
|
|
@@ -31,7 +32,7 @@ class TestSettingsLinkPlugin extends Plugin {
|
|
|
31
32
|
}
|
|
32
33
|
}
|
|
33
34
|
|
|
34
|
-
type MockClientApplication = ReturnType<typeof
|
|
35
|
+
type MockClientApplication = ReturnType<typeof createMockSettingsClient>;
|
|
35
36
|
|
|
36
37
|
const renderApp = (app: MockClientApplication) => {
|
|
37
38
|
const Root = app.getRootComponent();
|
|
@@ -49,9 +50,9 @@ const waitForGetRequests = async (app: MockClientApplication, urls: string[]) =>
|
|
|
49
50
|
};
|
|
50
51
|
|
|
51
52
|
const setupApp = (pmList: any[], plugins: Array<typeof Plugin> = []) => {
|
|
52
|
-
const app =
|
|
53
|
-
plugins: [
|
|
54
|
-
router: { type: 'memory', initialEntries: ['/
|
|
53
|
+
const app = createMockSettingsClient({
|
|
54
|
+
plugins: [SettingsBuildInPlugin, TestAclPlugin, ...plugins],
|
|
55
|
+
router: { type: 'memory', initialEntries: ['/settings/plugin-manager'] },
|
|
55
56
|
});
|
|
56
57
|
|
|
57
58
|
app.apiMock.onGet('/auth:check').reply(200, {
|
|
@@ -0,0 +1,164 @@
|
|
|
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 MockAdapter from 'axios-mock-adapter';
|
|
11
|
+
import { describe, expect, it } from 'vitest';
|
|
12
|
+
import { Application } from '../index';
|
|
13
|
+
import { SettingsApplication } from '../settings-app/SettingsApplication';
|
|
14
|
+
import { SettingsBuildInPlugin } from '../settings-app/SettingsBuildInPlugin';
|
|
15
|
+
|
|
16
|
+
describe('SettingsApplication', () => {
|
|
17
|
+
it('uses the standalone settings route namespace', () => {
|
|
18
|
+
const adminApp = new Application({ router: { type: 'memory' }, ws: false });
|
|
19
|
+
const settingsApp = new SettingsApplication({ router: { type: 'memory' }, ws: false });
|
|
20
|
+
|
|
21
|
+
expect(adminApp.pluginSettingsManager.getRouteName('demo.index')).toBe('admin.settings.demo.index');
|
|
22
|
+
expect(adminApp.pluginSettingsManager.getRoutePath('demo.index')).toBe('/admin/settings/demo');
|
|
23
|
+
|
|
24
|
+
expect(settingsApp.pluginSettingsManager.getRouteName('demo.index')).toBe('settings.demo.index');
|
|
25
|
+
expect(settingsApp.pluginSettingsManager.getRoutePath('demo.index')).toBe('/settings/demo');
|
|
26
|
+
expect(settingsApp.pluginSettingsManager.getRoutePath('')).toBe('/settings/');
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it.each(['apps', '_app'])('uses basename-relative paths for the %s sub-application Settings runtime', (scope) => {
|
|
30
|
+
const app = new SettingsApplication({
|
|
31
|
+
publicPath: '/nocobase/',
|
|
32
|
+
router: { type: 'memory', basename: `/nocobase/settings/${scope}/demo/` },
|
|
33
|
+
ws: false,
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
expect(app.pluginSettingsManager.getRouteName('demo.index')).toBe('settings.demo.index');
|
|
37
|
+
expect(app.pluginSettingsManager.getRoutePath('')).toBe('/');
|
|
38
|
+
expect(app.pluginSettingsManager.getRoutePath('demo.index')).toBe('/demo');
|
|
39
|
+
|
|
40
|
+
app.router.add('settings', { path: '/settings' });
|
|
41
|
+
app.router.add('settingsDetails.workflow.canvas', { path: '/settings/workflow/workflows/:id' });
|
|
42
|
+
app.router.add('settingsDetails.preview', { path: '/settings-preview/:id' });
|
|
43
|
+
app.router.add('auth.signin', { path: '/signin' });
|
|
44
|
+
|
|
45
|
+
expect(app.router.get('settings')).toMatchObject({ path: '/' });
|
|
46
|
+
expect(app.router.get('settingsDetails.workflow.canvas')).toMatchObject({
|
|
47
|
+
path: '/workflow/workflows/:id',
|
|
48
|
+
authCheck: true,
|
|
49
|
+
});
|
|
50
|
+
expect(
|
|
51
|
+
app.router
|
|
52
|
+
.matchRoutes(`/nocobase/settings/${scope}/demo/workflow/workflows/1`)
|
|
53
|
+
?.some((match) => match.route.id === 'settingsDetails.workflow.canvas'),
|
|
54
|
+
).toBe(true);
|
|
55
|
+
expect(
|
|
56
|
+
app.router
|
|
57
|
+
.matchRoutes(`/nocobase/settings/${scope}/demo/settings/workflow/workflows/1`)
|
|
58
|
+
?.some((match) => match.route.id === 'settingsDetails.workflow.canvas'),
|
|
59
|
+
).toBe(false);
|
|
60
|
+
expect(app.router.get('settingsDetails.preview')).toMatchObject({ path: '/settings-preview/:id' });
|
|
61
|
+
expect(app.router.get('auth.signin')).toMatchObject({ path: '/signin' });
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it('does not treat an apps segment inside the main application public path as a sub-application scope', () => {
|
|
65
|
+
const app = new SettingsApplication({
|
|
66
|
+
router: { type: 'memory', basename: '/tenant/apps/root/' },
|
|
67
|
+
ws: false,
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
expect(app.pluginSettingsManager.getRoutePath('')).toBe('/settings/');
|
|
71
|
+
expect(app.pluginSettingsManager.getRoutePath('demo.index')).toBe('/settings/demo');
|
|
72
|
+
|
|
73
|
+
app.router.add('settingsDetails.workflow.canvas', { path: '/settings/workflow/workflows/:id' });
|
|
74
|
+
expect(app.router.get('settingsDetails.workflow.canvas')).toMatchObject({
|
|
75
|
+
path: '/settings/workflow/workflows/:id',
|
|
76
|
+
});
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it.each(['apps', '_app'])(
|
|
80
|
+
'does not treat a scoped-looking %s suffix inside the main public path as a sub-application scope',
|
|
81
|
+
(scope) => {
|
|
82
|
+
const publicPath = `/tenant/settings/${scope}/root/`;
|
|
83
|
+
const app = new SettingsApplication({
|
|
84
|
+
publicPath,
|
|
85
|
+
router: { type: 'memory', basename: publicPath },
|
|
86
|
+
ws: false,
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
expect(app.pluginSettingsManager.getRoutePath('')).toBe('/settings/');
|
|
90
|
+
expect(app.pluginSettingsManager.getRoutePath('demo.index')).toBe('/settings/demo');
|
|
91
|
+
|
|
92
|
+
app.router.add('settingsDetails.workflow.canvas', { path: '/settings/workflow/workflows/:id' });
|
|
93
|
+
app.router.add('auth.signin', { path: '/signin' });
|
|
94
|
+
|
|
95
|
+
expect(app.router.get('settingsDetails.workflow.canvas')).toMatchObject({
|
|
96
|
+
path: '/settings/workflow/workflows/:id',
|
|
97
|
+
});
|
|
98
|
+
expect(app.router.get('auth.signin')).toMatchObject({ path: '/settings/signin' });
|
|
99
|
+
},
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
it('keeps only routes owned by the settings runtime', () => {
|
|
103
|
+
const app = new SettingsApplication({ router: { type: 'memory' }, ws: false });
|
|
104
|
+
|
|
105
|
+
app.router.add('settings', { path: '/settings' });
|
|
106
|
+
app.router.add('settings.demo', { path: 'demo' });
|
|
107
|
+
app.router.add('settingsDetails.workflow.canvas', { path: '/settings/workflow/workflows/:id' });
|
|
108
|
+
app.router.add('admin.demo', { path: '/admin/demo' });
|
|
109
|
+
app.router.add('public-forms', { path: '/public-forms/:key' });
|
|
110
|
+
app.router.add('mobile', { path: '/mobile' });
|
|
111
|
+
|
|
112
|
+
expect(app.router.has('settings')).toBe(true);
|
|
113
|
+
expect(app.router.has('settings.demo')).toBe(true);
|
|
114
|
+
expect(app.router.get('settingsDetails.workflow.canvas')).toMatchObject({
|
|
115
|
+
path: '/settings/workflow/workflows/:id',
|
|
116
|
+
authCheck: true,
|
|
117
|
+
});
|
|
118
|
+
expect(app.router.has('admin.demo')).toBe(false);
|
|
119
|
+
expect(app.router.has('public-forms')).toBe(false);
|
|
120
|
+
expect(app.router.has('mobile')).toBe(false);
|
|
121
|
+
expect(app.router.has('not-found')).toBe(true);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
it('keeps hidden plugin detail pages in the normal Settings route tree', () => {
|
|
125
|
+
const app = new SettingsApplication({ router: { type: 'memory' }, ws: false });
|
|
126
|
+
|
|
127
|
+
app.pluginSettingsManager.addMenuItem({ key: 'public-forms', title: 'Public forms' });
|
|
128
|
+
app.pluginSettingsManager.addPageTabItem({
|
|
129
|
+
menuKey: 'public-forms',
|
|
130
|
+
key: ':name',
|
|
131
|
+
title: false,
|
|
132
|
+
hidden: true,
|
|
133
|
+
Component: () => null,
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
expect(app.pluginSettingsManager.get('public-forms.:name')).toMatchObject({
|
|
137
|
+
hidden: true,
|
|
138
|
+
path: '/settings/public-forms/:name',
|
|
139
|
+
});
|
|
140
|
+
expect(app.router.get('settings.public-forms.:name')).toMatchObject({ path: ':name' });
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('registers the authenticated settings shell without the admin layout', async () => {
|
|
144
|
+
const app = new SettingsApplication({ router: { type: 'memory' }, ws: false });
|
|
145
|
+
const apiMock = new MockAdapter(app.apiClient.axios);
|
|
146
|
+
apiMock.onGet('app:getLang').reply(200, { data: { lang: 'en-US', resources: { client: {} }, cron: {} } });
|
|
147
|
+
const plugin = new SettingsBuildInPlugin({ name: 'settings-buildin' }, app);
|
|
148
|
+
|
|
149
|
+
await plugin.afterAdd();
|
|
150
|
+
await plugin.load();
|
|
151
|
+
app.router.add('settingsDetails.workflow.canvas', { path: '/settings/workflow/workflows/:id' });
|
|
152
|
+
|
|
153
|
+
expect(app.router.get('settings')).toMatchObject({ path: '/settings', authCheck: true });
|
|
154
|
+
expect(app.router.get('settingsDetails')).toMatchObject({ path: '/settings', authCheck: true });
|
|
155
|
+
expect(
|
|
156
|
+
app.router.matchRoutes('/settings/workflow/workflows/1')?.some((match) => match.route.authCheck === true),
|
|
157
|
+
).toBe(true);
|
|
158
|
+
expect(app.router.has('admin')).toBe(false);
|
|
159
|
+
expect(app.layoutManager.hasLayout('admin')).toBe(false);
|
|
160
|
+
expect(app.pluginSettingsManager.has('plugin-manager')).toBe(true);
|
|
161
|
+
expect(app.pluginSettingsManager.has('system-settings')).toBe(true);
|
|
162
|
+
expect(app.pluginSettingsManager.has('security')).toBe(true);
|
|
163
|
+
});
|
|
164
|
+
});
|
|
@@ -0,0 +1,71 @@
|
|
|
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 { Application } from '../index';
|
|
11
|
+
import { SettingsApplication } from '../settings-app/SettingsApplication';
|
|
12
|
+
|
|
13
|
+
describe('standalone settings authentication routes', () => {
|
|
14
|
+
it('keeps and rebases the auth and 2fa route families', () => {
|
|
15
|
+
const app = new SettingsApplication({ router: { type: 'memory' }, ws: false });
|
|
16
|
+
|
|
17
|
+
app.router.add('auth', { Component: () => null });
|
|
18
|
+
app.router.add('auth.signin', { path: '/signin', skipAuthCheck: true, Component: () => null });
|
|
19
|
+
app.router.add('auth.signup', { path: '/signup', skipAuthCheck: true, Component: () => null });
|
|
20
|
+
app.router.add('auth.forgotPassword', {
|
|
21
|
+
path: '/forgot-password',
|
|
22
|
+
skipAuthCheck: true,
|
|
23
|
+
Component: () => null,
|
|
24
|
+
});
|
|
25
|
+
app.router.add('auth.resetPassword', {
|
|
26
|
+
path: '/reset-password',
|
|
27
|
+
skipAuthCheck: true,
|
|
28
|
+
Component: () => null,
|
|
29
|
+
});
|
|
30
|
+
app.router.add('2fa', { Component: () => null });
|
|
31
|
+
app.router.add('2fa.verify', { path: '/2fa', skipAuthCheck: true, Component: () => null });
|
|
32
|
+
|
|
33
|
+
expect(app.router.get('auth.signin')).toMatchObject({ path: '/settings/signin', skipAuthCheck: true });
|
|
34
|
+
expect(app.router.get('auth.signup')).toMatchObject({ path: '/settings/signup', skipAuthCheck: true });
|
|
35
|
+
expect(app.router.get('auth.forgotPassword')).toMatchObject({
|
|
36
|
+
path: '/settings/forgot-password',
|
|
37
|
+
skipAuthCheck: true,
|
|
38
|
+
});
|
|
39
|
+
expect(app.router.get('auth.resetPassword')).toMatchObject({
|
|
40
|
+
path: '/settings/reset-password',
|
|
41
|
+
skipAuthCheck: true,
|
|
42
|
+
});
|
|
43
|
+
expect(app.router.get('2fa.verify')).toMatchObject({ path: '/settings/2fa', skipAuthCheck: true });
|
|
44
|
+
expect(app.router.matchRoutes('/settings/signin')?.map((match) => match.route.id)).toContain('auth.signin');
|
|
45
|
+
expect(app.router.isSkippedAuthCheckRoute('/settings/reset-password')).toBe(true);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('does not change the default Client V2 authentication routes', () => {
|
|
49
|
+
const app = new Application({ router: { type: 'memory' }, ws: false });
|
|
50
|
+
|
|
51
|
+
app.router.add('auth', { Component: () => null });
|
|
52
|
+
app.router.add('auth.signin', { path: '/signin', skipAuthCheck: true, Component: () => null });
|
|
53
|
+
app.router.add('2fa', { Component: () => null });
|
|
54
|
+
app.router.add('2fa.verify', { path: '/2fa', skipAuthCheck: true, Component: () => null });
|
|
55
|
+
|
|
56
|
+
expect(app.router.get('auth.signin')).toMatchObject({ path: '/signin', skipAuthCheck: true });
|
|
57
|
+
expect(app.router.get('2fa.verify')).toMatchObject({ path: '/2fa', skipAuthCheck: true });
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('continues to reject unrelated routes from the shared plugin lane', () => {
|
|
61
|
+
const app = new SettingsApplication({ router: { type: 'memory' }, ws: false });
|
|
62
|
+
|
|
63
|
+
app.router.add('admin.demo', { path: '/admin/demo' });
|
|
64
|
+
app.router.add('public.demo', { path: '/public/demo' });
|
|
65
|
+
app.router.add('mobile.demo', { path: '/mobile/demo' });
|
|
66
|
+
|
|
67
|
+
expect(app.router.has('admin.demo')).toBe(false);
|
|
68
|
+
expect(app.router.has('public.demo')).toBe(false);
|
|
69
|
+
expect(app.router.has('mobile.demo')).toBe(false);
|
|
70
|
+
});
|
|
71
|
+
});
|