@nocobase/client-v2 2.2.0-alpha.1 → 2.2.0-alpha.3
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/PluginSettingsManager.d.ts +33 -0
- package/es/RouteRepository.d.ts +21 -6
- package/es/components/category-tabs/SortableCategoryTabs.d.ts +55 -0
- package/es/components/category-tabs/index.d.ts +9 -0
- package/es/components/form/JsonTextArea.d.ts +2 -1
- package/es/components/form/TypedVariableInput.d.ts +22 -4
- package/es/components/form/VariableJsonTextArea.d.ts +19 -0
- package/es/components/form/filter/CollectionFilterItem.d.ts +11 -1
- package/es/components/form/filter/index.d.ts +2 -0
- package/es/components/form/index.d.ts +1 -0
- package/es/components/index.d.ts +2 -0
- package/es/flow/actions/afterSuccess.d.ts +8 -1
- package/es/flow/actions/index.d.ts +1 -1
- package/es/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.d.ts +2 -0
- package/es/flow/admin-shell/admin-layout/AdminLayoutMenuFlowUtils.d.ts +2 -1
- package/es/flow/admin-shell/admin-layout/AdminLayoutMenuModels.d.ts +2 -0
- package/es/flow/admin-shell/admin-layout/AdminLayoutMenuUtils.d.ts +3 -2
- package/es/flow/admin-shell/admin-layout/AdminLayoutSlotModels.d.ts +5 -0
- package/es/flow/admin-shell/admin-layout/resolveAdminRouteRuntimeTarget.d.ts +6 -0
- package/es/flow/components/FieldAssignRulesEditor.d.ts +3 -1
- package/es/flow/components/FieldAssignValueInput.d.ts +2 -0
- package/es/flow/index.d.ts +1 -0
- package/es/flow/models/base/GridModel.d.ts +1 -1
- package/es/flow/models/blocks/filter-form/FilterFormBlockModel.d.ts +5 -0
- package/es/flow/models/blocks/form/FormBlockModel.d.ts +4 -0
- package/es/flow/models/blocks/form/submitHandler.d.ts +1 -1
- package/es/flow/models/blocks/form/value-runtime/rules.d.ts +21 -0
- package/es/flow/models/blocks/form/value-runtime/runtime.d.ts +30 -0
- package/es/flow/models/blocks/form/value-runtime/types.d.ts +2 -2
- package/es/flow/models/blocks/js-block/JSBlock.d.ts +1 -0
- package/es/flow/models/blocks/table/TableActionsColumnModel.d.ts +1 -0
- package/es/flow/models/blocks/table/TableBlockModel.d.ts +1 -0
- package/es/flow/models/blocks/table/dragSort/dragSortHooks.d.ts +1 -1
- package/es/flow/models/blocks/table/dragSort/dragSortSettings.d.ts +2 -1
- package/es/flow/models/blocks/table/dragSort/dragSortUtils.d.ts +6 -4
- package/es/flow/models/fields/AssociationFieldModel/RecordSelectFieldModel.d.ts +2 -0
- package/es/flow/models/fields/AssociationFieldModel/SubTableFieldModel/SubTableColumnModel.d.ts +6 -0
- package/es/flow/resolveViewParamsToViewList.d.ts +1 -1
- package/es/flow/utils/dataScopeRowSnapshot.d.ts +59 -0
- package/es/flow/utils/dateTimeDisplayProps.d.ts +49 -0
- package/es/flow/utils/formValueDeps.d.ts +32 -0
- package/es/flow-compat/FieldValidation.d.ts +2 -1
- package/es/index.d.ts +2 -1
- package/es/index.mjs +233 -137
- package/lib/index.js +234 -138
- package/package.json +7 -7
- package/src/PluginSettingsManager.ts +53 -0
- package/src/RouteRepository.ts +126 -24
- package/src/__tests__/PluginSettingsManager.test.ts +13 -0
- package/src/__tests__/RouteRepository.test.ts +216 -0
- package/src/__tests__/browserChecker.test.ts +61 -0
- package/src/__tests__/exports.test.ts +16 -0
- package/src/__tests__/nocobase-buildin-plugin-auth.test.tsx +199 -0
- package/src/__tests__/plugin-manager.test.tsx +44 -2
- package/src/__tests__/settings-center.test.tsx +40 -1
- package/src/collection-manager/field-configure.ts +1 -1
- package/src/collection-manager/interfaces/id.ts +1 -1
- package/src/collection-manager/interfaces/m2m.tsx +2 -2
- package/src/collection-manager/interfaces/m2o.tsx +2 -2
- package/src/collection-manager/interfaces/nanoid.ts +1 -1
- package/src/collection-manager/interfaces/o2m.tsx +2 -2
- package/src/collection-manager/interfaces/obo.tsx +2 -2
- package/src/collection-manager/interfaces/oho.tsx +2 -2
- package/src/collection-manager/interfaces/properties/index.ts +2 -2
- package/src/collection-manager/interfaces/uuid.ts +1 -1
- package/src/components/AppComponents.tsx +19 -3
- package/src/components/README.md +7 -1
- package/src/components/README.zh-CN.md +6 -1
- package/src/components/category-tabs/SortableCategoryTabs.tsx +210 -0
- package/src/components/category-tabs/index.ts +10 -0
- package/src/components/form/JsonTextArea.tsx +21 -11
- package/src/components/form/TypedVariableInput.tsx +416 -93
- package/src/components/form/VariableJsonTextArea.tsx +175 -0
- package/src/components/form/__tests__/JsonTextArea.test.tsx +43 -0
- package/src/components/form/__tests__/TypedVariableInput.test.tsx +268 -9
- package/src/components/form/__tests__/VariableJsonTextArea.test.tsx +86 -0
- package/src/components/form/filter/CollectionFilterItem.tsx +32 -7
- package/src/components/form/filter/__tests__/CollectionFilterItem.test.tsx +38 -0
- package/src/components/form/filter/index.ts +2 -0
- package/src/components/form/index.tsx +1 -0
- package/src/components/index.ts +2 -0
- package/src/flow/__tests__/FlowRoute.test.tsx +443 -5
- package/src/flow/__tests__/getKey.test.ts +7 -0
- package/src/flow/__tests__/resolveViewParamsToViewList.test.ts +34 -0
- package/src/flow/actions/__tests__/afterSuccess.test.ts +73 -0
- package/src/flow/actions/__tests__/dataScopeFilter.test.ts +58 -0
- package/src/flow/actions/__tests__/dataScopeFormValueClear.test.ts +1022 -0
- package/src/flow/actions/__tests__/fieldLinkageRules.scopeDepth.test.ts +150 -1
- package/src/flow/actions/__tests__/linkageAssignField.legacy.test.ts +135 -0
- package/src/flow/actions/__tests__/linkageRules.hiddenSync.restore.test.ts +19 -5
- package/src/flow/actions/__tests__/linkageRules.subFormSetFieldProps.test.ts +92 -0
- package/src/flow/actions/__tests__/openView.defineProps.route.test.tsx +104 -0
- package/src/flow/actions/__tests__/subFormFieldLinkageRules.inputArgs.test.ts +2 -2
- package/src/flow/actions/afterSuccess.tsx +142 -3
- package/src/flow/actions/customVariable.tsx +1 -2
- package/src/flow/actions/dataScopeFilter.ts +10 -0
- package/src/flow/actions/dateTimeFormat.tsx +42 -28
- package/src/flow/actions/index.ts +1 -1
- package/src/flow/actions/linkageRules.tsx +123 -35
- package/src/flow/actions/linkageRulesFormValueRefresh.ts +22 -130
- package/src/flow/actions/openView.tsx +38 -4
- package/src/flow/actions/runjs.tsx +2 -14
- package/src/flow/actions/validation.tsx +62 -30
- package/src/flow/admin-shell/BaseLayoutModel.tsx +25 -3
- package/src/flow/admin-shell/BaseLayoutRouteCoordinator.ts +5 -2
- package/src/flow/admin-shell/__tests__/AdminLayoutRouteCoordinator.test.ts +13 -0
- package/src/flow/admin-shell/admin-layout/AdminLayoutComponent.tsx +34 -10
- package/src/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.test.tsx +310 -0
- package/src/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.tsx +44 -8
- package/src/flow/admin-shell/admin-layout/AdminLayoutMenuFlowUtils.ts +5 -3
- package/src/flow/admin-shell/admin-layout/AdminLayoutMenuModels.tsx +61 -9
- package/src/flow/admin-shell/admin-layout/AdminLayoutMenuUtils.tsx +71 -8
- package/src/flow/admin-shell/admin-layout/AdminLayoutModel.tsx +1 -1
- package/src/flow/admin-shell/admin-layout/AdminLayoutSlotModels.tsx +23 -9
- package/src/flow/admin-shell/admin-layout/HelpLite.tsx +1 -3
- package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutComponent.test.tsx +188 -0
- package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutMenuModels.test.ts +99 -0
- package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutModel.test.tsx +82 -0
- package/src/flow/admin-shell/admin-layout/__tests__/TopbarActionsBar.test.tsx +166 -2
- package/src/flow/admin-shell/admin-layout/resolveAdminRouteRuntimeTarget.test.ts +20 -0
- package/src/flow/admin-shell/admin-layout/resolveAdminRouteRuntimeTarget.ts +33 -5
- package/src/flow/components/DefaultValue.tsx +1 -2
- package/src/flow/components/DynamicFlowsIcon.tsx +447 -126
- package/src/flow/components/FieldAssignRulesEditor.tsx +128 -21
- package/src/flow/components/FieldAssignValueInput.tsx +10 -5
- package/src/flow/components/FlowRoute.tsx +56 -11
- package/src/flow/components/__tests__/DynamicFlowsIcon.test.tsx +148 -2
- package/src/flow/components/__tests__/FieldAssignRulesEditor.test.tsx +508 -4
- package/src/flow/components/__tests__/fieldAssignOptions.test.ts +151 -3
- package/src/flow/components/code-editor/__tests__/useCodeRunner.test.tsx +2 -17
- package/src/flow/components/code-editor/hooks/useCodeRunner.ts +2 -14
- package/src/flow/components/code-editor/runjsDiagnostics.ts +8 -45
- package/src/flow/components/fieldAssignOptions.ts +155 -27
- package/src/flow/flows/editMarkdownFlow.tsx +1 -1
- package/src/flow/getViewDiffAndUpdateHidden.tsx +1 -0
- package/src/flow/index.ts +2 -1
- package/src/flow/internal/utils/operatorSchemaHelper.ts +15 -1
- package/src/flow/models/actions/JSActionModel.tsx +2 -7
- package/src/flow/models/actions/JSCollectionActionModel.tsx +2 -7
- package/src/flow/models/actions/JSItemActionModel.tsx +2 -7
- package/src/flow/models/actions/JSRecordActionModel.tsx +2 -7
- package/src/flow/models/base/ActionModel.tsx +12 -1
- package/src/flow/models/base/ActionModelCore.tsx +6 -4
- package/src/flow/models/base/GridModel.tsx +38 -7
- package/src/flow/models/base/PageModel/PageModel.tsx +4 -1
- package/src/flow/models/base/PageModel/__tests__/PageModel.test.ts +28 -4
- package/src/flow/models/base/__tests__/ActionModel.test.ts +83 -0
- package/src/flow/models/base/__tests__/ActionModelCore.render.test.tsx +37 -0
- package/src/flow/models/base/__tests__/GridModel.dragSnapshotContainer.test.ts +239 -1
- package/src/flow/models/base/__tests__/transformRowsToSingleColumn.test.ts +48 -0
- package/src/flow/models/blocks/filter-form/FilterFormBlockModel.tsx +31 -3
- package/src/flow/models/blocks/filter-form/FilterFormJSActionModel.tsx +2 -7
- package/src/flow/models/blocks/filter-form/__tests__/defaultValues.wiring.test.ts +77 -0
- package/src/flow/models/blocks/filter-form/fields/FilterFormCustomFieldModel.tsx +1 -1
- package/src/flow/models/blocks/filter-manager/flow-actions/__tests__/customizeFilterRender.test.tsx +56 -1
- package/src/flow/models/blocks/form/EditFormModel.tsx +1 -0
- package/src/flow/models/blocks/form/FormActionModel.tsx +1 -1
- package/src/flow/models/blocks/form/FormBlockModel.tsx +7 -0
- package/src/flow/models/blocks/form/JSFormActionModel.tsx +2 -7
- package/src/flow/models/blocks/form/__tests__/FormBlockModel.test.tsx +17 -0
- package/src/flow/models/blocks/form/__tests__/submitHandler.test.ts +54 -1
- package/src/flow/models/blocks/form/submitHandler.ts +17 -3
- package/src/flow/models/blocks/form/value-runtime/__tests__/runtime.test.ts +940 -75
- package/src/flow/models/blocks/form/value-runtime/rules.ts +445 -13
- package/src/flow/models/blocks/form/value-runtime/runtime.ts +348 -13
- package/src/flow/models/blocks/form/value-runtime/types.ts +2 -2
- package/src/flow/models/blocks/js-block/JSBlock.tsx +225 -9
- package/src/flow/models/blocks/js-block/__tests__/JSBlockModel.test.tsx +150 -0
- package/src/flow/models/blocks/table/JSColumnModel.tsx +1 -9
- package/src/flow/models/blocks/table/TableActionsColumnModel.tsx +36 -13
- package/src/flow/models/blocks/table/TableBlockModel.tsx +38 -17
- package/src/flow/models/blocks/table/TableColumnModel.tsx +36 -3
- package/src/flow/models/blocks/table/__tests__/TableActionsColumnModel.test.tsx +111 -1
- package/src/flow/models/blocks/table/__tests__/TableBlockModel.dragSort.test.ts +127 -0
- package/src/flow/models/blocks/table/__tests__/TableBlockModel.mobileSettingsButtons.test.tsx +78 -0
- package/src/flow/models/blocks/table/__tests__/TableBlockModel.rowSelection.test.tsx +1 -0
- package/src/flow/models/blocks/table/__tests__/TableColumnModel.test.tsx +159 -1
- package/src/flow/models/blocks/table/dragSort/dragSortHooks.tsx +28 -17
- package/src/flow/models/blocks/table/dragSort/dragSortSettings.ts +13 -6
- package/src/flow/models/blocks/table/dragSort/dragSortUtils.ts +15 -2
- package/src/flow/models/fields/AssociationFieldModel/AssociationFieldModel.tsx +1 -1
- package/src/flow/models/fields/AssociationFieldModel/PopupSubTableFieldModel/PopupSubTableFieldModel.tsx +29 -6
- package/src/flow/models/fields/AssociationFieldModel/RecordSelectFieldModel.tsx +16 -4
- package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/SubTableColumnModel.tsx +141 -19
- package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/SubTableField.tsx +13 -1
- package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/__tests__/SubTableColumnModel.rowRecord.test.ts +197 -0
- package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/__tests__/SubTableFieldModel.reset.test.ts +180 -0
- package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/index.tsx +6 -4
- package/src/flow/models/fields/AssociationFieldModel/__tests__/AssociationFieldModel.updateAssociation.test.ts +72 -0
- package/src/flow/models/fields/AssociationFieldModel/__tests__/RecordPickerFieldModel.itemContext.test.ts +23 -0
- package/src/flow/models/fields/ClickableFieldModel.tsx +5 -0
- package/src/flow/models/fields/DisplayDateTimeFieldModel.tsx +29 -1
- package/src/flow/models/fields/InputFieldModel.tsx +40 -2
- package/src/flow/models/fields/JSEditableFieldModel.tsx +2 -11
- package/src/flow/models/fields/JSFieldModel.tsx +2 -7
- package/src/flow/models/fields/JSItemModel.tsx +2 -14
- package/src/flow/models/fields/SelectFieldModel.tsx +6 -4
- package/src/flow/models/fields/TextareaFieldModel.tsx +49 -3
- package/src/flow/models/fields/__tests__/DisplayDateTimeFieldModel.test.tsx +96 -0
- package/src/flow/models/fields/__tests__/InputFieldModel.test.tsx +117 -1
- package/src/flow/models/fields/__tests__/SelectFieldModel.test.tsx +43 -0
- package/src/flow/models/fields/__tests__/TextareaFieldModel.test.tsx +100 -0
- package/src/flow/models/topbar/TopbarActionModel.tsx +93 -10
- package/src/flow/resolveViewParamsToViewList.tsx +11 -3
- package/src/flow/utils/__tests__/dateTimeFormat.test.ts +258 -0
- package/src/flow/utils/dataScopeFormValueClear.ts +218 -81
- package/src/flow/utils/dataScopeRowSnapshot.ts +616 -0
- package/src/flow/utils/dateTimeDisplayProps.ts +135 -0
- package/src/flow/utils/formValueDeps.ts +170 -0
- package/src/flow-compat/FieldValidation.tsx +122 -60
- package/src/flow-compat/Popover.tsx +43 -4
- package/src/flow-compat/__tests__/Popover.test.tsx +34 -0
- package/src/index.ts +8 -1
- package/src/layout-manager/__tests__/LayoutRoute.test.tsx +41 -1
- package/src/nocobase-buildin-plugin/index.tsx +44 -14
- package/src/settings-center/AdminSettingsLayout.tsx +10 -2
- package/src/settings-center/SystemSettingsPage.tsx +1 -2
- package/src/settings-center/plugin-manager/PluginCard.tsx +2 -2
- package/src/settings-center/plugin-manager/index.tsx +3 -0
- package/src/settings-center/utils.tsx +0 -6
|
@@ -0,0 +1,310 @@
|
|
|
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, FlowEngineProvider } from '@nocobase/flow-engine';
|
|
11
|
+
import { act, render, screen, waitFor } from '@testing-library/react';
|
|
12
|
+
import React from 'react';
|
|
13
|
+
import { createMemoryRouter, RouterProvider } from 'react-router-dom';
|
|
14
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
15
|
+
import { RouteRepository } from '../../../RouteRepository';
|
|
16
|
+
import { AdminLayoutEntryGuard } from './AdminLayoutEntryGuard';
|
|
17
|
+
import type { AdminLayoutModel } from './AdminLayoutModel';
|
|
18
|
+
|
|
19
|
+
describe('AdminLayoutEntryGuard', () => {
|
|
20
|
+
it('should ensure accessible routes for the active layout before resolving the landing route', async () => {
|
|
21
|
+
const engine = new FlowEngine();
|
|
22
|
+
const request = vi.fn().mockResolvedValue({
|
|
23
|
+
data: {
|
|
24
|
+
data: [],
|
|
25
|
+
},
|
|
26
|
+
});
|
|
27
|
+
const routeRepository = new RouteRepository({
|
|
28
|
+
api: {
|
|
29
|
+
request,
|
|
30
|
+
resource: vi.fn(),
|
|
31
|
+
},
|
|
32
|
+
} as never);
|
|
33
|
+
routeRepository.setRoutes([], 'admin-layout-model');
|
|
34
|
+
const deactivateLayout = routeRepository.activateLayout({
|
|
35
|
+
uid: 'mobile-layout-model',
|
|
36
|
+
});
|
|
37
|
+
engine.context.defineProperty('routeRepository', {
|
|
38
|
+
value: routeRepository,
|
|
39
|
+
});
|
|
40
|
+
engine.context.defineProperty('app', {
|
|
41
|
+
value: {
|
|
42
|
+
router: {
|
|
43
|
+
getBasename: () => '',
|
|
44
|
+
},
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const model = {
|
|
49
|
+
layout: {
|
|
50
|
+
routeName: 'mobile',
|
|
51
|
+
routePath: '/mobile',
|
|
52
|
+
uid: 'mobile-layout-model',
|
|
53
|
+
},
|
|
54
|
+
} as AdminLayoutModel;
|
|
55
|
+
const router = createMemoryRouter(
|
|
56
|
+
[
|
|
57
|
+
{
|
|
58
|
+
path: '/mobile',
|
|
59
|
+
id: 'mobile',
|
|
60
|
+
element: (
|
|
61
|
+
<FlowEngineProvider engine={engine}>
|
|
62
|
+
<AdminLayoutEntryGuard model={model}>
|
|
63
|
+
<div>Mobile layout shell</div>
|
|
64
|
+
</AdminLayoutEntryGuard>
|
|
65
|
+
</FlowEngineProvider>
|
|
66
|
+
),
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
{
|
|
70
|
+
initialEntries: ['/mobile'],
|
|
71
|
+
},
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
render(<RouterProvider router={router} />);
|
|
75
|
+
|
|
76
|
+
await waitFor(() => {
|
|
77
|
+
expect(request).toHaveBeenCalledWith({
|
|
78
|
+
url: '/desktopRoutes:listAccessible',
|
|
79
|
+
params: {
|
|
80
|
+
tree: true,
|
|
81
|
+
sort: 'sort',
|
|
82
|
+
layout: 'mobile-layout-model',
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
expect(screen.getByText('Mobile layout shell')).toBeInTheDocument();
|
|
87
|
+
deactivateLayout();
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
it('should activate the guard layout before loading accessible routes', async () => {
|
|
91
|
+
const engine = new FlowEngine();
|
|
92
|
+
const request = vi.fn().mockResolvedValue({
|
|
93
|
+
data: {
|
|
94
|
+
data: [],
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
const routeRepository = new RouteRepository({
|
|
98
|
+
api: {
|
|
99
|
+
request,
|
|
100
|
+
resource: vi.fn(),
|
|
101
|
+
},
|
|
102
|
+
} as never);
|
|
103
|
+
engine.context.defineProperty('routeRepository', {
|
|
104
|
+
value: routeRepository,
|
|
105
|
+
});
|
|
106
|
+
engine.context.defineProperty('app', {
|
|
107
|
+
value: {
|
|
108
|
+
router: {
|
|
109
|
+
getBasename: () => '',
|
|
110
|
+
},
|
|
111
|
+
},
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
const model = {
|
|
115
|
+
layout: {
|
|
116
|
+
routeName: 'mobile',
|
|
117
|
+
routePath: '/mobile',
|
|
118
|
+
uid: 'mobile-layout-model',
|
|
119
|
+
},
|
|
120
|
+
} as AdminLayoutModel;
|
|
121
|
+
const router = createMemoryRouter(
|
|
122
|
+
[
|
|
123
|
+
{
|
|
124
|
+
path: '/mobile',
|
|
125
|
+
id: 'mobile',
|
|
126
|
+
element: (
|
|
127
|
+
<FlowEngineProvider engine={engine}>
|
|
128
|
+
<AdminLayoutEntryGuard model={model}>
|
|
129
|
+
<div>Mobile layout shell</div>
|
|
130
|
+
</AdminLayoutEntryGuard>
|
|
131
|
+
</FlowEngineProvider>
|
|
132
|
+
),
|
|
133
|
+
},
|
|
134
|
+
],
|
|
135
|
+
{
|
|
136
|
+
initialEntries: ['/mobile'],
|
|
137
|
+
},
|
|
138
|
+
);
|
|
139
|
+
|
|
140
|
+
render(<RouterProvider router={router} />);
|
|
141
|
+
|
|
142
|
+
await waitFor(() => {
|
|
143
|
+
expect(request).toHaveBeenCalledWith({
|
|
144
|
+
url: '/desktopRoutes:listAccessible',
|
|
145
|
+
params: {
|
|
146
|
+
tree: true,
|
|
147
|
+
sort: 'sort',
|
|
148
|
+
layout: 'mobile-layout-model',
|
|
149
|
+
},
|
|
150
|
+
});
|
|
151
|
+
});
|
|
152
|
+
expect(screen.getByText('Mobile layout shell')).toBeInTheDocument();
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
it('should keep guard stable when layout getter returns a new object with the same fields', async () => {
|
|
156
|
+
const engine = new FlowEngine();
|
|
157
|
+
const request = vi.fn().mockResolvedValue({
|
|
158
|
+
data: {
|
|
159
|
+
data: [],
|
|
160
|
+
},
|
|
161
|
+
});
|
|
162
|
+
const routeRepository = new RouteRepository({
|
|
163
|
+
api: {
|
|
164
|
+
request,
|
|
165
|
+
resource: vi.fn(),
|
|
166
|
+
},
|
|
167
|
+
} as never);
|
|
168
|
+
const activateLayout = vi.spyOn(routeRepository, 'activateLayout');
|
|
169
|
+
engine.context.defineProperty('routeRepository', {
|
|
170
|
+
value: routeRepository,
|
|
171
|
+
});
|
|
172
|
+
engine.context.defineProperty('app', {
|
|
173
|
+
value: {
|
|
174
|
+
router: {
|
|
175
|
+
getBasename: () => '',
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
const model = {
|
|
181
|
+
get layout() {
|
|
182
|
+
return {
|
|
183
|
+
authCheck: true,
|
|
184
|
+
routeName: 'admin',
|
|
185
|
+
routePath: '/admin',
|
|
186
|
+
uid: 'admin-layout-model',
|
|
187
|
+
};
|
|
188
|
+
},
|
|
189
|
+
} as AdminLayoutModel;
|
|
190
|
+
let forceRerender = () => {};
|
|
191
|
+
const GuardShell = () => {
|
|
192
|
+
const [, setVersion] = React.useState(0);
|
|
193
|
+
forceRerender = () => setVersion((version) => version + 1);
|
|
194
|
+
return (
|
|
195
|
+
<AdminLayoutEntryGuard model={model}>
|
|
196
|
+
<div>Admin layout shell</div>
|
|
197
|
+
</AdminLayoutEntryGuard>
|
|
198
|
+
);
|
|
199
|
+
};
|
|
200
|
+
const router = createMemoryRouter(
|
|
201
|
+
[
|
|
202
|
+
{
|
|
203
|
+
path: '/admin',
|
|
204
|
+
id: 'admin',
|
|
205
|
+
element: (
|
|
206
|
+
<FlowEngineProvider engine={engine}>
|
|
207
|
+
<GuardShell />
|
|
208
|
+
</FlowEngineProvider>
|
|
209
|
+
),
|
|
210
|
+
},
|
|
211
|
+
],
|
|
212
|
+
{
|
|
213
|
+
initialEntries: ['/admin'],
|
|
214
|
+
},
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
render(<RouterProvider router={router} />);
|
|
218
|
+
|
|
219
|
+
await waitFor(() => {
|
|
220
|
+
expect(screen.getByText('Admin layout shell')).toBeInTheDocument();
|
|
221
|
+
});
|
|
222
|
+
expect(activateLayout).toHaveBeenCalledTimes(1);
|
|
223
|
+
|
|
224
|
+
await act(async () => {
|
|
225
|
+
forceRerender();
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
expect(activateLayout).toHaveBeenCalledTimes(1);
|
|
229
|
+
expect(request).toHaveBeenCalledTimes(1);
|
|
230
|
+
});
|
|
231
|
+
|
|
232
|
+
it('should reactivate the guard when stable layout fields change', async () => {
|
|
233
|
+
const engine = new FlowEngine();
|
|
234
|
+
const request = vi.fn().mockResolvedValue({
|
|
235
|
+
data: {
|
|
236
|
+
data: [],
|
|
237
|
+
},
|
|
238
|
+
});
|
|
239
|
+
const routeRepository = new RouteRepository({
|
|
240
|
+
api: {
|
|
241
|
+
request,
|
|
242
|
+
resource: vi.fn(),
|
|
243
|
+
},
|
|
244
|
+
} as never);
|
|
245
|
+
const activateLayout = vi.spyOn(routeRepository, 'activateLayout');
|
|
246
|
+
engine.context.defineProperty('routeRepository', {
|
|
247
|
+
value: routeRepository,
|
|
248
|
+
});
|
|
249
|
+
engine.context.defineProperty('app', {
|
|
250
|
+
value: {
|
|
251
|
+
router: {
|
|
252
|
+
getBasename: () => '',
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
let layoutUid = 'admin-layout-model';
|
|
258
|
+
const model = {
|
|
259
|
+
get layout() {
|
|
260
|
+
return {
|
|
261
|
+
authCheck: true,
|
|
262
|
+
routeName: 'admin',
|
|
263
|
+
routePath: '/admin',
|
|
264
|
+
uid: layoutUid,
|
|
265
|
+
};
|
|
266
|
+
},
|
|
267
|
+
} as AdminLayoutModel;
|
|
268
|
+
let forceRerender = () => {};
|
|
269
|
+
const GuardShell = () => {
|
|
270
|
+
const [, setVersion] = React.useState(0);
|
|
271
|
+
forceRerender = () => setVersion((version) => version + 1);
|
|
272
|
+
return (
|
|
273
|
+
<AdminLayoutEntryGuard model={model}>
|
|
274
|
+
<div>Admin layout shell</div>
|
|
275
|
+
</AdminLayoutEntryGuard>
|
|
276
|
+
);
|
|
277
|
+
};
|
|
278
|
+
const router = createMemoryRouter(
|
|
279
|
+
[
|
|
280
|
+
{
|
|
281
|
+
path: '/admin',
|
|
282
|
+
id: 'admin',
|
|
283
|
+
element: (
|
|
284
|
+
<FlowEngineProvider engine={engine}>
|
|
285
|
+
<GuardShell />
|
|
286
|
+
</FlowEngineProvider>
|
|
287
|
+
),
|
|
288
|
+
},
|
|
289
|
+
],
|
|
290
|
+
{
|
|
291
|
+
initialEntries: ['/admin'],
|
|
292
|
+
},
|
|
293
|
+
);
|
|
294
|
+
|
|
295
|
+
render(<RouterProvider router={router} />);
|
|
296
|
+
|
|
297
|
+
await waitFor(() => {
|
|
298
|
+
expect(screen.getByText('Admin layout shell')).toBeInTheDocument();
|
|
299
|
+
});
|
|
300
|
+
expect(activateLayout).toHaveBeenCalledWith(expect.objectContaining({ uid: 'admin-layout-model' }));
|
|
301
|
+
|
|
302
|
+
await act(async () => {
|
|
303
|
+
layoutUid = 'admin-layout-next';
|
|
304
|
+
forceRerender();
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
expect(activateLayout).toHaveBeenCalledTimes(2);
|
|
308
|
+
expect(activateLayout).toHaveBeenLastCalledWith(expect.objectContaining({ uid: 'admin-layout-next' }));
|
|
309
|
+
});
|
|
310
|
+
});
|
|
@@ -13,13 +13,23 @@ import { useLocation, useMatches, useNavigate } from 'react-router-dom';
|
|
|
13
13
|
import { NocoBaseDesktopRouteType } from '../../../flow-compat';
|
|
14
14
|
import { useApp } from '../../../hooks/useApp';
|
|
15
15
|
import { isLayoutContentRouteName } from '../../../layout-manager/utils';
|
|
16
|
+
import type { LayoutDefinition } from '../../../layout-manager/types';
|
|
16
17
|
import {
|
|
17
18
|
findFirstV2LandingRoute,
|
|
19
|
+
getAdminLayoutRoutePath,
|
|
18
20
|
resolveAdminRouteRuntimeTarget,
|
|
21
|
+
type AdminLayoutRoutePathLike,
|
|
19
22
|
toRouterNavigationPath,
|
|
20
23
|
} from './resolveAdminRouteRuntimeTarget';
|
|
24
|
+
import type { AdminLayoutModel } from './AdminLayoutModel';
|
|
21
25
|
|
|
22
|
-
|
|
26
|
+
type StableAdminEntryLayout = AdminLayoutRoutePathLike &
|
|
27
|
+
Partial<Pick<LayoutDefinition, 'authCheck' | 'routeName' | 'uid'>>;
|
|
28
|
+
|
|
29
|
+
export const AdminLayoutEntryGuard: FC<{ children: React.ReactNode; model?: AdminLayoutModel }> = ({
|
|
30
|
+
children,
|
|
31
|
+
model,
|
|
32
|
+
}) => {
|
|
23
33
|
const flowEngine = useFlowEngine();
|
|
24
34
|
const app = useApp();
|
|
25
35
|
const navigate = useNavigate();
|
|
@@ -28,24 +38,44 @@ export const AdminLayoutEntryGuard: FC<{ children: React.ReactNode }> = ({ child
|
|
|
28
38
|
const [ready, setReady] = useState(false);
|
|
29
39
|
const replaceTriggeredRef = useRef(false);
|
|
30
40
|
const routeRepository = flowEngine.context.routeRepository;
|
|
41
|
+
const rawLayout = model?.layout;
|
|
42
|
+
const layoutUid = rawLayout?.uid;
|
|
43
|
+
const layoutRouteNameValue = rawLayout?.routeName;
|
|
44
|
+
const layoutRoutePathValue = rawLayout?.routePath;
|
|
45
|
+
const layoutAuthCheck = rawLayout?.authCheck;
|
|
46
|
+
const layout = useMemo<StableAdminEntryLayout | undefined>(() => {
|
|
47
|
+
if (!layoutUid && !layoutRouteNameValue && !layoutRoutePathValue && typeof layoutAuthCheck === 'undefined') {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
return {
|
|
52
|
+
authCheck: layoutAuthCheck,
|
|
53
|
+
routeName: layoutRouteNameValue,
|
|
54
|
+
routePath: layoutRoutePathValue || '',
|
|
55
|
+
uid: layoutUid,
|
|
56
|
+
};
|
|
57
|
+
}, [layoutAuthCheck, layoutRouteNameValue, layoutRoutePathValue, layoutUid]);
|
|
58
|
+
const layoutRoutePath = getAdminLayoutRoutePath(layout);
|
|
59
|
+
const layoutRouteName = layout?.routeName || 'admin';
|
|
60
|
+
const layoutRuntime = useMemo(() => ({ routePath: layoutRoutePath }), [layoutRoutePath]);
|
|
31
61
|
const isAdminRoot = useMemo(() => {
|
|
32
62
|
const pathname = toRouterNavigationPath(location.pathname, app.router.getBasename());
|
|
33
|
-
return pathname ===
|
|
34
|
-
}, [app, location.pathname]);
|
|
63
|
+
return pathname === layoutRoutePath;
|
|
64
|
+
}, [app, layoutRoutePath, location.pathname]);
|
|
35
65
|
const pageUid = useMemo(() => {
|
|
36
66
|
const lastMatch = matches[matches.length - 1];
|
|
37
|
-
if (!isLayoutContentRouteName(
|
|
67
|
+
if (!isLayoutContentRouteName(layoutRouteName, lastMatch?.id)) {
|
|
38
68
|
return '';
|
|
39
69
|
}
|
|
40
|
-
const adminMatch = matches.find((match) => match.id ===
|
|
70
|
+
const adminMatch = matches.find((match) => match.id === layoutRouteName);
|
|
41
71
|
return (
|
|
42
72
|
(lastMatch.params?.name as string) ||
|
|
43
73
|
parsePathnameToViewParams(location.pathname, {
|
|
44
|
-
basePath: adminMatch?.pathname ||
|
|
74
|
+
basePath: adminMatch?.pathname || layoutRoutePath,
|
|
45
75
|
})[0]?.viewUid ||
|
|
46
76
|
''
|
|
47
77
|
);
|
|
48
|
-
}, [location.pathname, matches]);
|
|
78
|
+
}, [layoutRouteName, layoutRoutePath, location.pathname, matches]);
|
|
49
79
|
|
|
50
80
|
useEffect(() => {
|
|
51
81
|
replaceTriggeredRef.current = false;
|
|
@@ -53,6 +83,7 @@ export const AdminLayoutEntryGuard: FC<{ children: React.ReactNode }> = ({ child
|
|
|
53
83
|
|
|
54
84
|
useEffect(() => {
|
|
55
85
|
let active = true;
|
|
86
|
+
const deactivateLayout = routeRepository?.activateLayout?.(layout);
|
|
56
87
|
|
|
57
88
|
const run = async () => {
|
|
58
89
|
setReady(false);
|
|
@@ -85,6 +116,7 @@ export const AdminLayoutEntryGuard: FC<{ children: React.ReactNode }> = ({ child
|
|
|
85
116
|
const target = resolveAdminRouteRuntimeTarget({
|
|
86
117
|
app,
|
|
87
118
|
route: currentRoute,
|
|
119
|
+
layout: layoutRuntime,
|
|
88
120
|
location: {
|
|
89
121
|
pathname: window.location.pathname,
|
|
90
122
|
search: window.location.search,
|
|
@@ -117,6 +149,7 @@ export const AdminLayoutEntryGuard: FC<{ children: React.ReactNode }> = ({ child
|
|
|
117
149
|
const target = resolveAdminRouteRuntimeTarget({
|
|
118
150
|
app,
|
|
119
151
|
route: firstAccessibleRoute,
|
|
152
|
+
layout: layoutRuntime,
|
|
120
153
|
});
|
|
121
154
|
|
|
122
155
|
if (!target.runtimePath) {
|
|
@@ -135,15 +168,18 @@ export const AdminLayoutEntryGuard: FC<{ children: React.ReactNode }> = ({ child
|
|
|
135
168
|
navigate(toRouterNavigationPath(target.runtimePath, app.router.getBasename()), { replace: true });
|
|
136
169
|
};
|
|
137
170
|
|
|
138
|
-
|
|
171
|
+
run();
|
|
139
172
|
|
|
140
173
|
return () => {
|
|
141
174
|
active = false;
|
|
175
|
+
deactivateLayout?.();
|
|
142
176
|
};
|
|
143
177
|
}, [
|
|
144
178
|
app,
|
|
145
179
|
flowEngine,
|
|
146
180
|
isAdminRoot,
|
|
181
|
+
layout,
|
|
182
|
+
layoutRuntime,
|
|
147
183
|
location.hash,
|
|
148
184
|
location.pathname,
|
|
149
185
|
location.search,
|
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
getAdminLayoutMenuMovePositionOptions,
|
|
18
18
|
} from './AdminLayoutMenuUtils';
|
|
19
19
|
import { getFlowPageMenuSchema, getPageMenuSchema, isVariable } from './AdminLayoutCompat';
|
|
20
|
+
import { joinAdminLayoutRoutePath, type AdminLayoutRoutePathLike } from './resolveAdminRouteRuntimeTarget';
|
|
20
21
|
|
|
21
22
|
const buildLinkSettingSchema = (t: (title: any) => any) => ({
|
|
22
23
|
href: {
|
|
@@ -298,6 +299,7 @@ export const matchesRoutePath = (
|
|
|
298
299
|
route: NocoBaseDesktopRoute | undefined,
|
|
299
300
|
pathname: string,
|
|
300
301
|
basename = '/',
|
|
302
|
+
layout?: AdminLayoutRoutePathLike | null,
|
|
301
303
|
): boolean => {
|
|
302
304
|
if (!route) {
|
|
303
305
|
return false;
|
|
@@ -310,8 +312,8 @@ export const matchesRoutePath = (
|
|
|
310
312
|
: pathname;
|
|
311
313
|
|
|
312
314
|
const candidates = [
|
|
313
|
-
route.id != null ?
|
|
314
|
-
route.schemaUid ?
|
|
315
|
+
route.id != null ? joinAdminLayoutRoutePath(layout, route.id) : null,
|
|
316
|
+
route.schemaUid ? joinAdminLayoutRoutePath(layout, route.schemaUid) : null,
|
|
315
317
|
].filter(Boolean) as string[];
|
|
316
318
|
|
|
317
319
|
if (
|
|
@@ -321,7 +323,7 @@ export const matchesRoutePath = (
|
|
|
321
323
|
}
|
|
322
324
|
|
|
323
325
|
return Array.isArray(route.children)
|
|
324
|
-
? route.children.some((child) => matchesRoutePath(child, normalizedPathname, '/'))
|
|
326
|
+
? route.children.some((child) => matchesRoutePath(child, normalizedPathname, '/', layout))
|
|
325
327
|
: false;
|
|
326
328
|
};
|
|
327
329
|
|
|
@@ -42,9 +42,11 @@ import {
|
|
|
42
42
|
} from './AdminLayoutMenuFlowUtils';
|
|
43
43
|
import { ADMIN_LAYOUT_MODEL_UID } from './constants';
|
|
44
44
|
import {
|
|
45
|
+
type AdminLayoutRoutePathLike,
|
|
45
46
|
findFirstAccessiblePageRoute,
|
|
46
47
|
findFirstV2LandingRoute,
|
|
47
48
|
isV2AdminRuntime,
|
|
49
|
+
joinAdminLayoutRoutePath,
|
|
48
50
|
resolveAdminRouteRuntimeTarget,
|
|
49
51
|
toRouterNavigationPath,
|
|
50
52
|
} from './resolveAdminRouteRuntimeTarget';
|
|
@@ -64,6 +66,26 @@ const omitMenuRuntimeProps = (props: Record<string, unknown> = {}) => {
|
|
|
64
66
|
return persistableProps;
|
|
65
67
|
};
|
|
66
68
|
|
|
69
|
+
type MenuRouteTreeRefreshableModel = FlowModel & {
|
|
70
|
+
refreshMenuRouteTree?: () => void;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
function isMenuRouteTreeRefreshableModel(model: FlowModel | undefined): model is MenuRouteTreeRefreshableModel {
|
|
74
|
+
return typeof (model as MenuRouteTreeRefreshableModel | undefined)?.refreshMenuRouteTree === 'function';
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function getOwnerMenuRouteTreeRefreshModel(model: FlowModel) {
|
|
78
|
+
let current = model.parent as FlowModel | undefined;
|
|
79
|
+
while (current) {
|
|
80
|
+
if (isMenuRouteTreeRefreshableModel(current)) {
|
|
81
|
+
return current;
|
|
82
|
+
}
|
|
83
|
+
current = current.parent as FlowModel | undefined;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return undefined;
|
|
87
|
+
}
|
|
88
|
+
|
|
67
89
|
export class AdminLayoutMenuItemModel extends FlowModel<AdminLayoutMenuItemStructure> {
|
|
68
90
|
private creationPersisted = false;
|
|
69
91
|
private persistedStateHydrated = false;
|
|
@@ -129,6 +151,24 @@ export class AdminLayoutMenuItemModel extends FlowModel<AdminLayoutMenuItemStruc
|
|
|
129
151
|
return this.context.routeRepository;
|
|
130
152
|
}
|
|
131
153
|
|
|
154
|
+
getLayout(): AdminLayoutRoutePathLike | undefined {
|
|
155
|
+
const contextLayout = this.context.layout as AdminLayoutRoutePathLike | undefined;
|
|
156
|
+
if (contextLayout?.routePath) {
|
|
157
|
+
return contextLayout;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
let current: FlowModel | undefined = this;
|
|
161
|
+
while (current) {
|
|
162
|
+
const propsLayout = current.props?.layout as AdminLayoutRoutePathLike | undefined;
|
|
163
|
+
if (propsLayout?.routePath) {
|
|
164
|
+
return propsLayout;
|
|
165
|
+
}
|
|
166
|
+
current = current.parent as FlowModel | undefined;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
return undefined;
|
|
170
|
+
}
|
|
171
|
+
|
|
132
172
|
hasPersistedMenuInstanceFlowFlag(route = this.getRoute()) {
|
|
133
173
|
return route?.options?.hasPersistedMenuInstanceFlow === true;
|
|
134
174
|
}
|
|
@@ -280,7 +320,12 @@ export class AdminLayoutMenuItemModel extends FlowModel<AdminLayoutMenuItemStruc
|
|
|
280
320
|
const previous = this.hidden;
|
|
281
321
|
super.setHidden(value);
|
|
282
322
|
if (previous !== this.hidden) {
|
|
283
|
-
|
|
323
|
+
const defaultLayoutModel = this.flowEngine.getModel?.(ADMIN_LAYOUT_MODEL_UID);
|
|
324
|
+
const refreshableModel =
|
|
325
|
+
getOwnerMenuRouteTreeRefreshModel(this) ||
|
|
326
|
+
(isMenuRouteTreeRefreshableModel(defaultLayoutModel) ? defaultLayoutModel : undefined);
|
|
327
|
+
|
|
328
|
+
refreshableModel?.refreshMenuRouteTree?.();
|
|
284
329
|
}
|
|
285
330
|
}
|
|
286
331
|
|
|
@@ -533,9 +578,10 @@ export class AdminLayoutMenuItemModel extends FlowModel<AdminLayoutMenuItemStruc
|
|
|
533
578
|
return false;
|
|
534
579
|
}
|
|
535
580
|
|
|
581
|
+
const layout = this.getLayout();
|
|
536
582
|
const allAccessRoutes = this.getRouteRepository().listAccessible();
|
|
537
583
|
const pathname = this.context.location?.pathname || window.location.pathname;
|
|
538
|
-
const shouldNavigate = matchesRoutePath(route, pathname, this.context.router?.basename);
|
|
584
|
+
const shouldNavigate = matchesRoutePath(route, pathname, this.context.router?.basename, layout);
|
|
539
585
|
const prevSibling = findPrevSiblingRoute(allAccessRoutes, route);
|
|
540
586
|
const nextSibling = findNextSiblingRoute(allAccessRoutes, route);
|
|
541
587
|
|
|
@@ -554,6 +600,7 @@ export class AdminLayoutMenuItemModel extends FlowModel<AdminLayoutMenuItemStruc
|
|
|
554
600
|
const target = resolveAdminRouteRuntimeTarget({
|
|
555
601
|
app: this.context.app,
|
|
556
602
|
route: sibling,
|
|
603
|
+
layout,
|
|
557
604
|
});
|
|
558
605
|
|
|
559
606
|
if (!target.runtimePath) {
|
|
@@ -584,6 +631,7 @@ export class AdminLayoutMenuItemModel extends FlowModel<AdminLayoutMenuItemStruc
|
|
|
584
631
|
|
|
585
632
|
const shouldShowIconInTitle = shouldRenderIconInTitle({ depth, isMobile: options.isMobile });
|
|
586
633
|
const { name, icon } = buildMenuTitleWithIcon(route, options.t, shouldShowIconInTitle);
|
|
634
|
+
const layout = this.getLayout();
|
|
587
635
|
|
|
588
636
|
if (route.type === NocoBaseDesktopRouteType.link) {
|
|
589
637
|
const identity = route.id ?? route.schemaUid ?? route.menuSchemaUid ?? route.title ?? this.uid;
|
|
@@ -591,7 +639,7 @@ export class AdminLayoutMenuItemModel extends FlowModel<AdminLayoutMenuItemStruc
|
|
|
591
639
|
return {
|
|
592
640
|
name,
|
|
593
641
|
icon,
|
|
594
|
-
path: getAdminLayoutMenuVirtualPath('link', identity),
|
|
642
|
+
path: getAdminLayoutMenuVirtualPath('link', identity, layout),
|
|
595
643
|
hideInMenu: route.hideInMenu,
|
|
596
644
|
_route: route,
|
|
597
645
|
_parentRoute: parentRoute,
|
|
@@ -604,6 +652,7 @@ export class AdminLayoutMenuItemModel extends FlowModel<AdminLayoutMenuItemStruc
|
|
|
604
652
|
const runtimeTarget = resolveAdminRouteRuntimeTarget({
|
|
605
653
|
app: this.context.app,
|
|
606
654
|
route,
|
|
655
|
+
layout,
|
|
607
656
|
});
|
|
608
657
|
|
|
609
658
|
if (runtimeTarget.reason === 'unsupportedV2Runtime') {
|
|
@@ -611,14 +660,14 @@ export class AdminLayoutMenuItemModel extends FlowModel<AdminLayoutMenuItemStruc
|
|
|
611
660
|
}
|
|
612
661
|
|
|
613
662
|
const path = route.schemaUid
|
|
614
|
-
?
|
|
615
|
-
: getAdminLayoutMenuVirtualPath('link', `${this.uid}-invalid
|
|
663
|
+
? joinAdminLayoutRoutePath(layout, route.schemaUid)
|
|
664
|
+
: getAdminLayoutMenuVirtualPath('link', `${this.uid}-invalid`, layout);
|
|
616
665
|
|
|
617
666
|
return {
|
|
618
667
|
name,
|
|
619
668
|
icon,
|
|
620
669
|
path,
|
|
621
|
-
redirect: route.schemaUid ?
|
|
670
|
+
redirect: route.schemaUid ? joinAdminLayoutRoutePath(layout, route.schemaUid) : undefined,
|
|
622
671
|
hideInMenu: route.hideInMenu,
|
|
623
672
|
disabled: !runtimeTarget.runtimePath,
|
|
624
673
|
_runtimePath: runtimeTarget.runtimePath,
|
|
@@ -644,7 +693,7 @@ export class AdminLayoutMenuItemModel extends FlowModel<AdminLayoutMenuItemStruc
|
|
|
644
693
|
.filter(Boolean) || [];
|
|
645
694
|
|
|
646
695
|
if (options.designable && depth === 0) {
|
|
647
|
-
children.push(getAdminLayoutMenuInitializerButton('schema-initializer-Menu-side', this, route));
|
|
696
|
+
children.push(getAdminLayoutMenuInitializerButton('schema-initializer-Menu-side', this, route, layout));
|
|
648
697
|
}
|
|
649
698
|
|
|
650
699
|
const landingRoute = isV2AdminRuntime(this.context.app)
|
|
@@ -653,14 +702,17 @@ export class AdminLayoutMenuItemModel extends FlowModel<AdminLayoutMenuItemStruc
|
|
|
653
702
|
const runtimeTarget = resolveAdminRouteRuntimeTarget({
|
|
654
703
|
app: this.context.app,
|
|
655
704
|
route: isV2AdminRuntime(this.context.app) && landingRoute ? landingRoute : route,
|
|
705
|
+
layout,
|
|
656
706
|
});
|
|
657
707
|
|
|
658
708
|
const groupRoute: AdminLayoutMenuNode = {
|
|
659
709
|
name,
|
|
660
710
|
icon,
|
|
661
|
-
path:
|
|
711
|
+
path: joinAdminLayoutRoutePath(layout, route.id),
|
|
662
712
|
redirect:
|
|
663
|
-
children[0]?.key === 'x-designer-button'
|
|
713
|
+
children[0]?.key === 'x-designer-button'
|
|
714
|
+
? undefined
|
|
715
|
+
: joinAdminLayoutRoutePath(layout, landingRoute?.schemaUid || route.id),
|
|
664
716
|
hideInMenu: route.hideInMenu,
|
|
665
717
|
_runtimePath: runtimeTarget.runtimePath,
|
|
666
718
|
_navigationMode: runtimeTarget.navigationMode,
|