@nocobase/client-v2 2.1.0-beta.36 → 2.1.0-beta.38
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/es/Application.d.ts +1 -0
- package/es/BaseApplication.d.ts +4 -0
- package/es/RouterManager.d.ts +1 -0
- package/es/components/KeepAlive.d.ts +22 -0
- package/es/components/RouterBridge.d.ts +9 -0
- package/es/components/form/DialogFormLayout.d.ts +5 -29
- package/es/components/form/filter/CollectionFilter.d.ts +41 -0
- package/es/components/form/filter/CollectionFilterItem.d.ts +41 -0
- package/es/components/form/filter/DateFilterDynamicComponent.d.ts +57 -0
- package/es/components/form/filter/FilterValueInput.d.ts +29 -0
- package/es/components/form/filter/index.d.ts +11 -0
- package/es/components/form/filter/useFilterActionProps.d.ts +96 -0
- package/es/components/form/index.d.ts +1 -0
- package/es/data-source/ExtendCollectionsProvider.d.ts +50 -0
- package/es/data-source/index.d.ts +9 -0
- package/es/flow/FlowPage.d.ts +2 -1
- package/es/flow/admin-shell/AdminLayoutRouteCoordinator.d.ts +8 -40
- package/es/flow/admin-shell/BaseLayoutModel.d.ts +89 -0
- package/es/flow/admin-shell/BaseLayoutRouteCoordinator.d.ts +74 -0
- package/es/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.d.ts +12 -0
- package/es/flow/admin-shell/admin-layout/AdminLayoutModel.d.ts +7 -92
- package/es/flow/admin-shell/admin-layout/index.d.ts +2 -0
- package/es/flow/admin-shell/useAdminLayoutRoutePage.d.ts +2 -2
- package/es/flow/admin-shell/useLayoutRoutePage.d.ts +23 -0
- package/es/flow/components/FlowRoute.d.ts +10 -1
- package/es/flow/components/filter/index.d.ts +2 -0
- package/es/flow/components/filter/useFilterOptions.d.ts +54 -0
- package/es/flow/index.d.ts +4 -0
- package/es/flow/models/base/PageModel/PageModel.d.ts +3 -1
- package/es/flow/models/blocks/form/FormActionGroupModel.d.ts +1 -0
- package/es/flow/models/blocks/table/TableBlockModel.d.ts +10 -0
- package/es/flow/models/fields/AssociationFieldModel/SubTableFieldModel/index.d.ts +1 -1
- package/es/flow-compat/passwordUtils.d.ts +1 -1
- package/es/index.d.ts +2 -0
- package/es/index.mjs +491 -439
- package/es/layout-manager/LayoutContentRoute.d.ts +14 -0
- package/es/layout-manager/LayoutManager.d.ts +22 -0
- package/es/layout-manager/LayoutRoute.d.ts +14 -0
- package/es/layout-manager/index.d.ts +13 -0
- package/es/layout-manager/types.d.ts +20 -0
- package/es/layout-manager/utils.d.ts +14 -0
- package/es/nocobase-buildin-plugin/index.d.ts +3 -10
- package/es/settings-center/index.d.ts +1 -1
- package/es/settings-center/plugin-manager/BulkEnableButton.d.ts +15 -0
- package/es/settings-center/plugin-manager/PluginCard.d.ts +15 -0
- package/es/settings-center/plugin-manager/PluginDetail.d.ts +16 -0
- package/es/settings-center/{PluginManagerPage.d.ts → plugin-manager/index.d.ts} +1 -7
- package/es/settings-center/plugin-manager/types.d.ts +34 -0
- package/lib/index.js +491 -439
- package/package.json +8 -7
- package/src/Application.tsx +27 -12
- package/src/BaseApplication.tsx +19 -0
- package/src/PluginSettingsManager.ts +1 -1
- package/src/RouterManager.tsx +17 -1
- package/src/__tests__/PluginSettingsManager.test.ts +41 -2
- package/src/__tests__/app.test.tsx +17 -1
- package/src/__tests__/globalDeps.test.ts +1 -0
- package/src/__tests__/nocobase-buildin-plugin-auth.test.tsx +45 -2
- package/src/__tests__/plugin-manager.test.tsx +177 -0
- package/src/__tests__/settings-center.test.tsx +24 -2
- package/src/components/KeepAlive.tsx +131 -0
- package/src/components/README.md +89 -6
- package/src/components/README.zh-CN.md +89 -7
- package/src/components/RouterBridge.tsx +28 -4
- package/src/components/__tests__/KeepAlive.test.tsx +63 -0
- package/src/components/__tests__/RouterBridge.test.tsx +27 -0
- package/src/components/form/DialogFormLayout.tsx +5 -29
- package/src/components/form/filter/CollectionFilter.tsx +101 -0
- package/src/components/form/filter/CollectionFilterItem.tsx +176 -0
- package/src/components/form/filter/DateFilterDynamicComponent.tsx +283 -0
- package/src/components/form/filter/FilterValueInput.tsx +198 -0
- package/src/components/form/filter/__tests__/CollectionFilterItem.test.tsx +205 -0
- package/src/components/form/filter/__tests__/DateFilterDynamicComponent.test.tsx +148 -0
- package/src/components/form/filter/__tests__/FilterValueInput.test.tsx +243 -0
- package/src/components/form/filter/__tests__/compileFilterGroup.test.ts +146 -0
- package/src/components/form/filter/index.ts +13 -0
- package/src/components/form/filter/useFilterActionProps.ts +200 -0
- package/src/components/form/index.tsx +1 -0
- package/src/data-source/ExtendCollectionsProvider.tsx +144 -0
- package/src/data-source/__tests__/ExtendCollectionsProvider.test.tsx +264 -0
- package/src/data-source/index.ts +10 -0
- package/src/flow/FlowPage.tsx +35 -7
- package/src/flow/__tests__/FlowPage.test.tsx +79 -0
- package/src/flow/__tests__/FlowRoute.test.tsx +529 -2
- package/src/flow/actions/__tests__/linkageRules.subFormSetFieldProps.test.ts +191 -0
- package/src/flow/actions/__tests__/openView.subModelKey.test.tsx +33 -0
- package/src/flow/actions/aclCheck.tsx +4 -0
- package/src/flow/actions/aclCheckRefresh.tsx +4 -0
- package/src/flow/actions/dateTimeFormat.tsx +12 -8
- package/src/flow/actions/linkageRules.tsx +122 -0
- package/src/flow/actions/openView.tsx +28 -4
- package/src/flow/admin-shell/AdminLayoutRouteCoordinator.ts +11 -329
- package/src/flow/admin-shell/BaseLayoutModel.tsx +455 -0
- package/src/flow/admin-shell/BaseLayoutRouteCoordinator.ts +502 -0
- package/src/flow/admin-shell/__tests__/AdminLayoutRouteCoordinator.test.ts +547 -3
- package/src/flow/admin-shell/admin-layout/AdminLayoutComponent.tsx +4 -4
- package/src/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.tsx +160 -0
- package/src/flow/admin-shell/admin-layout/AdminLayoutMenuModels.tsx +0 -12
- package/src/flow/admin-shell/admin-layout/AdminLayoutModel.tsx +28 -201
- package/src/flow/admin-shell/admin-layout/AdminLayoutSlotModels.tsx +11 -2
- package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutMenuModels.test.ts +1 -26
- package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutModel.test.tsx +149 -27
- package/src/flow/admin-shell/admin-layout/index.ts +2 -0
- package/src/flow/admin-shell/useAdminLayoutRoutePage.ts +10 -26
- package/src/flow/admin-shell/useLayoutRoutePage.ts +61 -0
- package/src/flow/components/AdminLayout.tsx +4 -154
- package/src/flow/components/FlowRoute.tsx +105 -15
- package/src/flow/components/filter/index.ts +3 -0
- package/src/flow/components/filter/useFilterOptions.ts +80 -0
- package/src/flow/index.ts +4 -0
- package/src/flow/models/base/ActionModel.tsx +8 -1
- package/src/flow/models/base/PageModel/PageModel.tsx +51 -18
- package/src/flow/models/base/PageModel/RootPageModel.tsx +6 -13
- package/src/flow/models/base/PageModel/__tests__/PageModel.test.ts +102 -1
- package/src/flow/models/base/RouteModel.tsx +1 -1
- package/src/flow/models/blocks/form/FormActionGroupModel.tsx +14 -0
- package/src/flow/models/blocks/form/FormItemModel.tsx +8 -1
- package/src/flow/models/blocks/form/__tests__/FormActionGroupModel.test.ts +46 -0
- package/src/flow/models/blocks/form/submitValues.ts +4 -1
- package/src/flow/models/blocks/table/TableBlockModel.tsx +118 -16
- package/src/flow/models/blocks/table/__tests__/TableBlockModel.rowSelection.test.tsx +114 -0
- package/src/flow/models/fields/AssociationFieldModel/SubFormFieldModel.tsx +7 -1
- package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/SubTableField.tsx +1 -1
- package/src/flow/models/fields/AssociationFieldModel/SubTableFieldModel/index.tsx +6 -5
- package/src/flow/models/fields/ClickableFieldModel.tsx +9 -1
- package/src/flow/models/fields/DisplayTimeFieldModel.tsx +1 -1
- package/src/flow/models/fields/TimeFieldModel.tsx +1 -1
- package/src/flow/models/fields/__tests__/TimeFieldModel.test.tsx +61 -0
- package/src/flow/models/fields/mobile-components/MobileDatePicker.tsx +19 -3
- package/src/flow/models/fields/mobile-components/__tests__/MobileDatePicker.test.tsx +94 -0
- package/src/flow/models/topbar/TopbarActionModel.tsx +1 -1
- package/src/flow/utils/__tests__/dateTimeFormat.test.ts +91 -0
- package/src/index.ts +2 -0
- package/src/layout-manager/LayoutContentRoute.tsx +90 -0
- package/src/layout-manager/LayoutManager.tsx +185 -0
- package/src/layout-manager/LayoutRoute.tsx +138 -0
- package/src/layout-manager/__tests__/LayoutManager.test.tsx +335 -0
- package/src/layout-manager/__tests__/LayoutRoute.test.tsx +473 -0
- package/src/layout-manager/index.ts +14 -0
- package/src/layout-manager/types.ts +22 -0
- package/src/layout-manager/utils.ts +37 -0
- package/src/nocobase-buildin-plugin/index.tsx +69 -67
- package/src/nocobase-buildin-plugin/plugins/LocalePlugin.ts +1 -0
- package/src/settings-center/index.ts +1 -1
- package/src/settings-center/plugin-manager/BulkEnableButton.tsx +111 -0
- package/src/settings-center/plugin-manager/PluginCard.tsx +270 -0
- package/src/settings-center/plugin-manager/PluginDetail.tsx +195 -0
- package/src/settings-center/plugin-manager/index.tsx +254 -0
- package/src/settings-center/plugin-manager/types.ts +35 -0
- package/src/settings-center/utils.tsx +8 -1
- package/src/theme/__tests__/globalStyles.test.ts +24 -0
- package/src/theme/globalStyles.ts +10 -0
- package/src/utils/globalDeps.ts +2 -0
- package/src/settings-center/PluginManagerPage.tsx +0 -162
|
@@ -43,6 +43,7 @@ import {
|
|
|
43
43
|
type FlowModel,
|
|
44
44
|
} from '@nocobase/flow-engine';
|
|
45
45
|
import { AdminLayoutModel, getAdminLayoutModel } from '..';
|
|
46
|
+
import { getLayoutPageRouteName, getLayoutPageViewRouteName } from '../../../../layout-manager/utils';
|
|
46
47
|
import { TopbarActionModel } from '../../../models/topbar/TopbarActionModel';
|
|
47
48
|
import { UserCenterTopbarActionModel } from '../../../models/topbar/UserCenterTopbarActionModel';
|
|
48
49
|
import { TopbarActionsBar } from '../TopbarActionsBar';
|
|
@@ -113,7 +114,7 @@ describe('AdminLayoutModel runtime', () => {
|
|
|
113
114
|
}).toThrowError(/admin-layout-model/);
|
|
114
115
|
});
|
|
115
116
|
|
|
116
|
-
it('should expose live layoutContentElement on
|
|
117
|
+
it('should expose live layoutContentElement on layout context', async () => {
|
|
117
118
|
const engine = new FlowEngine();
|
|
118
119
|
|
|
119
120
|
render(
|
|
@@ -131,29 +132,99 @@ describe('AdminLayoutModel runtime', () => {
|
|
|
131
132
|
model.setLayoutContentElement(element);
|
|
132
133
|
});
|
|
133
134
|
|
|
134
|
-
expect(
|
|
135
|
+
expect(model.context.layoutContentElement).toBe(element);
|
|
135
136
|
|
|
136
137
|
act(() => {
|
|
137
138
|
model.setLayoutContentElement(null);
|
|
138
139
|
});
|
|
139
140
|
|
|
140
|
-
expect(
|
|
141
|
+
expect(model.context.layoutContentElement).toBeNull();
|
|
141
142
|
});
|
|
142
143
|
|
|
143
|
-
it('should expose
|
|
144
|
+
it('should expose layout definition only while mounted', async () => {
|
|
145
|
+
const engine = new FlowEngine();
|
|
146
|
+
const { unmount } = render(
|
|
147
|
+
<FlowEngineProvider engine={engine}>
|
|
148
|
+
<TestAdminLayoutHost />
|
|
149
|
+
</FlowEngineProvider>,
|
|
150
|
+
);
|
|
151
|
+
const model = engine.getModel<TestAdminLayoutModel>('admin-layout-model');
|
|
152
|
+
expect(model).toBeTruthy();
|
|
153
|
+
|
|
154
|
+
expect(model.context.layout).toMatchObject({
|
|
155
|
+
routeName: 'admin',
|
|
156
|
+
routePath: '/admin',
|
|
157
|
+
rootRouteName: 'admin',
|
|
158
|
+
rootPageModelClass: 'RootPageModel',
|
|
159
|
+
childPageModelClass: 'ChildPageModel',
|
|
160
|
+
});
|
|
161
|
+
expect(engine.context.layout).toBeUndefined();
|
|
162
|
+
|
|
163
|
+
unmount();
|
|
164
|
+
|
|
165
|
+
expect(model.context.layout).toBeUndefined();
|
|
166
|
+
expect(model.context.currentRoute).toEqual({});
|
|
167
|
+
expect(model.context.layoutContentElement).toBeNull();
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
it('should expose layoutRoute from local layout route sync', async () => {
|
|
144
171
|
const engine = new FlowEngine();
|
|
145
|
-
const routeMap = {
|
|
146
|
-
'page-1': { title: 'Page 1' },
|
|
147
|
-
'page-2': { title: 'Page 2' },
|
|
148
|
-
};
|
|
149
172
|
engine.context.defineProperty('routeRepository', {
|
|
150
173
|
value: {
|
|
151
|
-
getRouteBySchemaUid: (pageUid: string) =>
|
|
174
|
+
getRouteBySchemaUid: (pageUid: string) => ({ title: pageUid }),
|
|
152
175
|
},
|
|
153
176
|
});
|
|
177
|
+
|
|
178
|
+
render(
|
|
179
|
+
<FlowEngineProvider engine={engine}>
|
|
180
|
+
<TestAdminLayoutHost />
|
|
181
|
+
</FlowEngineProvider>,
|
|
182
|
+
);
|
|
183
|
+
const model = engine.getModel<TestAdminLayoutModel>('admin-layout-model');
|
|
184
|
+
expect(model).toBeTruthy();
|
|
185
|
+
|
|
186
|
+
act(() => {
|
|
187
|
+
model.syncLayoutRoute({
|
|
188
|
+
name: getLayoutPageViewRouteName('admin'),
|
|
189
|
+
pathname: '/admin/page-1/view/popup',
|
|
190
|
+
layoutBasePathname: '/admin',
|
|
191
|
+
});
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
await waitFor(() => {
|
|
195
|
+
expect(model.context.layoutRoute).toMatchObject({
|
|
196
|
+
type: 'page',
|
|
197
|
+
pageUid: 'page-1',
|
|
198
|
+
viewStack: [{ viewUid: 'page-1' }, { viewUid: 'popup' }],
|
|
199
|
+
});
|
|
200
|
+
expect(model.context.currentRoute.title).toBe('page-1');
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
act(() => {
|
|
204
|
+
model.syncLayoutRoute({
|
|
205
|
+
name: 'admin.settings',
|
|
206
|
+
pathname: '/admin/settings',
|
|
207
|
+
});
|
|
208
|
+
});
|
|
209
|
+
|
|
210
|
+
await waitFor(() => {
|
|
211
|
+
expect(model.context.layoutRoute).toBeNull();
|
|
212
|
+
expect(model.context.currentRoute).toEqual({});
|
|
213
|
+
});
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it('should not consume global routes that belong to nested layouts', async () => {
|
|
217
|
+
const engine = new FlowEngine();
|
|
154
218
|
const routeRef = observable.ref({
|
|
155
|
-
|
|
156
|
-
pathname: '/admin/
|
|
219
|
+
name: getLayoutPageViewRouteName('admin.settings.publicForms'),
|
|
220
|
+
pathname: '/admin/settings/public-forms/form-1/view/popup',
|
|
221
|
+
params: { name: 'form-1' },
|
|
222
|
+
layoutBasePathname: '/admin/settings/public-forms',
|
|
223
|
+
});
|
|
224
|
+
engine.context.defineProperty('routeRepository', {
|
|
225
|
+
value: {
|
|
226
|
+
getRouteBySchemaUid: (pageUid: string) => ({ title: pageUid }),
|
|
227
|
+
},
|
|
157
228
|
});
|
|
158
229
|
engine.context.defineProperty('route', {
|
|
159
230
|
get: () => routeRef.value,
|
|
@@ -169,6 +240,55 @@ describe('AdminLayoutModel runtime', () => {
|
|
|
169
240
|
const model = engine.getModel<TestAdminLayoutModel>('admin-layout-model');
|
|
170
241
|
expect(model).toBeTruthy();
|
|
171
242
|
|
|
243
|
+
await waitFor(() => {
|
|
244
|
+
expect(model.context.layoutRoute).toBeNull();
|
|
245
|
+
expect(model.context.currentRoute).toEqual({});
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
act(() => {
|
|
249
|
+
routeRef.value = {
|
|
250
|
+
name: getLayoutPageViewRouteName('admin.settings.publicForms'),
|
|
251
|
+
pathname: '/admin/settings/public-forms/form-2/view/popup',
|
|
252
|
+
params: { name: 'form-2' },
|
|
253
|
+
layoutBasePathname: '/admin/settings/public-forms',
|
|
254
|
+
};
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
await waitFor(() => {
|
|
258
|
+
expect(model.context.layoutRoute).toBeNull();
|
|
259
|
+
expect(model.context.currentRoute).toEqual({});
|
|
260
|
+
});
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
it('should expose live layout currentRoute when active page changes', async () => {
|
|
264
|
+
const engine = new FlowEngine();
|
|
265
|
+
const routeMap = {
|
|
266
|
+
'page-1': { title: 'Page 1' },
|
|
267
|
+
'page-2': { title: 'Page 2' },
|
|
268
|
+
};
|
|
269
|
+
engine.context.defineProperty('routeRepository', {
|
|
270
|
+
value: {
|
|
271
|
+
getRouteBySchemaUid: (pageUid: string) => routeMap[pageUid],
|
|
272
|
+
},
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
render(
|
|
276
|
+
<FlowEngineProvider engine={engine}>
|
|
277
|
+
<TestAdminLayoutHost />
|
|
278
|
+
</FlowEngineProvider>,
|
|
279
|
+
);
|
|
280
|
+
|
|
281
|
+
const model = engine.getModel<TestAdminLayoutModel>('admin-layout-model');
|
|
282
|
+
expect(model).toBeTruthy();
|
|
283
|
+
|
|
284
|
+
act(() => {
|
|
285
|
+
model.syncLayoutRoute({
|
|
286
|
+
name: getLayoutPageRouteName('admin'),
|
|
287
|
+
pathname: '/admin/page-1',
|
|
288
|
+
layoutBasePathname: '/admin',
|
|
289
|
+
});
|
|
290
|
+
});
|
|
291
|
+
|
|
172
292
|
model.registerRoutePage('page-1', {
|
|
173
293
|
active: true,
|
|
174
294
|
});
|
|
@@ -177,36 +297,29 @@ describe('AdminLayoutModel runtime', () => {
|
|
|
177
297
|
});
|
|
178
298
|
|
|
179
299
|
await waitFor(() => {
|
|
180
|
-
expect(
|
|
300
|
+
expect(model.context.currentRoute.title).toBe('Page 1');
|
|
181
301
|
});
|
|
182
302
|
|
|
183
303
|
act(() => {
|
|
184
|
-
|
|
185
|
-
|
|
304
|
+
model.syncLayoutRoute({
|
|
305
|
+
name: getLayoutPageRouteName('admin'),
|
|
186
306
|
pathname: '/admin/page-2',
|
|
187
|
-
|
|
307
|
+
layoutBasePathname: '/admin',
|
|
308
|
+
});
|
|
188
309
|
});
|
|
189
310
|
|
|
190
311
|
await waitFor(() => {
|
|
191
|
-
expect(
|
|
312
|
+
expect(model.context.currentRoute.title).toBe('Page 2');
|
|
192
313
|
});
|
|
193
314
|
});
|
|
194
315
|
|
|
195
316
|
it('should keep pageActive in sync after non-active route page updates', async () => {
|
|
196
317
|
const engine = new FlowEngine();
|
|
197
|
-
const routeRef = observable.ref({
|
|
198
|
-
params: { name: 'page-1' },
|
|
199
|
-
pathname: '/admin/page-1',
|
|
200
|
-
});
|
|
201
318
|
engine.context.defineProperty('routeRepository', {
|
|
202
319
|
value: {
|
|
203
320
|
getRouteBySchemaUid: (pageUid: string) => ({ title: pageUid }),
|
|
204
321
|
},
|
|
205
322
|
});
|
|
206
|
-
engine.context.defineProperty('route', {
|
|
207
|
-
get: () => routeRef.value,
|
|
208
|
-
cache: false,
|
|
209
|
-
});
|
|
210
323
|
|
|
211
324
|
render(
|
|
212
325
|
<FlowEngineProvider engine={engine}>
|
|
@@ -217,6 +330,14 @@ describe('AdminLayoutModel runtime', () => {
|
|
|
217
330
|
const model = engine.getModel<TestAdminLayoutModel>('admin-layout-model');
|
|
218
331
|
expect(model).toBeTruthy();
|
|
219
332
|
|
|
333
|
+
act(() => {
|
|
334
|
+
model.syncLayoutRoute({
|
|
335
|
+
name: getLayoutPageRouteName('admin'),
|
|
336
|
+
pathname: '/admin/page-1',
|
|
337
|
+
layoutBasePathname: '/admin',
|
|
338
|
+
});
|
|
339
|
+
});
|
|
340
|
+
|
|
220
341
|
model.registerRoutePage('page-1', {
|
|
221
342
|
active: false,
|
|
222
343
|
});
|
|
@@ -236,10 +357,11 @@ describe('AdminLayoutModel runtime', () => {
|
|
|
236
357
|
expect(routeModel.context.pageActive.value).toBe(true);
|
|
237
358
|
|
|
238
359
|
act(() => {
|
|
239
|
-
|
|
240
|
-
|
|
360
|
+
model.syncLayoutRoute({
|
|
361
|
+
name: getLayoutPageRouteName('admin'),
|
|
241
362
|
pathname: '/admin/page-2',
|
|
242
|
-
|
|
363
|
+
layoutBasePathname: '/admin',
|
|
364
|
+
});
|
|
243
365
|
});
|
|
244
366
|
|
|
245
367
|
await waitFor(() => {
|
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
|
|
10
10
|
export * from './AdminLayoutComponent';
|
|
11
11
|
export * from './AdminLayoutModel';
|
|
12
|
+
export * from '../BaseLayoutModel';
|
|
13
|
+
export * from '../BaseLayoutRouteCoordinator';
|
|
12
14
|
export * from './AdminLayoutSlotModels';
|
|
13
15
|
export * from './AdminLayoutMenuModels';
|
|
14
16
|
export * from './AdminLayoutMenuFlowUtils';
|
|
@@ -8,14 +8,15 @@
|
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
10
|
import type { FlowEngine } from '@nocobase/flow-engine';
|
|
11
|
-
import {
|
|
11
|
+
import type { RefObject } from 'react';
|
|
12
12
|
import { getAdminLayoutModel, type AdminLayoutModel } from './admin-layout/AdminLayoutModel';
|
|
13
|
+
import { useLayoutRoutePage } from './useLayoutRoutePage';
|
|
13
14
|
|
|
14
15
|
type UseAdminLayoutRoutePageOptions = {
|
|
15
16
|
flowEngine: FlowEngine;
|
|
16
17
|
pageUid: string;
|
|
17
18
|
refreshDesktopRoutes?: () => Promise<unknown>;
|
|
18
|
-
layoutContentRef:
|
|
19
|
+
layoutContentRef: RefObject<HTMLDivElement>;
|
|
19
20
|
};
|
|
20
21
|
|
|
21
22
|
/**
|
|
@@ -29,28 +30,11 @@ type UseAdminLayoutRoutePageOptions = {
|
|
|
29
30
|
*/
|
|
30
31
|
export function useAdminLayoutRoutePage(options: UseAdminLayoutRoutePageOptions) {
|
|
31
32
|
const { flowEngine, pageUid, refreshDesktopRoutes, layoutContentRef } = options;
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
active: false,
|
|
40
|
-
refreshDesktopRoutes: refreshRef.current,
|
|
41
|
-
layoutContentElement: layoutContentRef.current,
|
|
42
|
-
});
|
|
43
|
-
return () => {
|
|
44
|
-
adminLayoutModel.unregisterRoutePage(pageUid);
|
|
45
|
-
};
|
|
46
|
-
}, [adminLayoutModel, pageUid, layoutContentRef]);
|
|
47
|
-
|
|
48
|
-
useEffect(() => {
|
|
49
|
-
adminLayoutModel.updateRoutePage(pageUid, {
|
|
50
|
-
refreshDesktopRoutes,
|
|
51
|
-
layoutContentElement: layoutContentRef.current,
|
|
52
|
-
});
|
|
53
|
-
}, [adminLayoutModel, pageUid, refreshDesktopRoutes, layoutContentRef]);
|
|
54
|
-
|
|
55
|
-
return adminLayoutModel;
|
|
33
|
+
return useLayoutRoutePage<AdminLayoutModel>({
|
|
34
|
+
flowEngine,
|
|
35
|
+
pageUid,
|
|
36
|
+
refreshDesktopRoutes,
|
|
37
|
+
layoutContentRef,
|
|
38
|
+
getLayoutModel: (engine) => getAdminLayoutModel<AdminLayoutModel>(engine, { required: true }),
|
|
39
|
+
});
|
|
56
40
|
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file is part of the NocoBase (R) project.
|
|
3
|
+
* Copyright (c) 2020-2024 NocoBase Co., Ltd.
|
|
4
|
+
* Authors: NocoBase Team.
|
|
5
|
+
*
|
|
6
|
+
* This project is dual-licensed under AGPL-3.0 and NocoBase Commercial License.
|
|
7
|
+
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { FlowEngine } from '@nocobase/flow-engine';
|
|
11
|
+
import { useEffect, useRef, type RefObject } from 'react';
|
|
12
|
+
import type { BaseLayoutModel } from './BaseLayoutModel';
|
|
13
|
+
|
|
14
|
+
export type UseLayoutRoutePageOptions<TModel extends BaseLayoutModel = BaseLayoutModel> = {
|
|
15
|
+
flowEngine: FlowEngine;
|
|
16
|
+
pageUid: string;
|
|
17
|
+
active?: boolean;
|
|
18
|
+
refreshDesktopRoutes?: () => Promise<unknown>;
|
|
19
|
+
layoutContentRef: RefObject<HTMLElement>;
|
|
20
|
+
getLayoutModel: (flowEngine: FlowEngine) => TModel | undefined;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* 把 FlowRoute 页面的生命周期桥接到指定 Layout host model。
|
|
25
|
+
*/
|
|
26
|
+
export function useLayoutRoutePage<TModel extends BaseLayoutModel = BaseLayoutModel>(
|
|
27
|
+
options: UseLayoutRoutePageOptions<TModel>,
|
|
28
|
+
) {
|
|
29
|
+
const { flowEngine, pageUid, active, refreshDesktopRoutes, layoutContentRef, getLayoutModel } = options;
|
|
30
|
+
const layoutModel = getLayoutModel(flowEngine);
|
|
31
|
+
const activeRef = useRef(active);
|
|
32
|
+
const refreshRef = useRef(refreshDesktopRoutes);
|
|
33
|
+
|
|
34
|
+
if (!layoutModel) {
|
|
35
|
+
throw new Error('[NocoBase] FlowRoute requires layout model. Please render FlowRoute under Layout.');
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
activeRef.current = active;
|
|
39
|
+
refreshRef.current = refreshDesktopRoutes;
|
|
40
|
+
|
|
41
|
+
useEffect(() => {
|
|
42
|
+
layoutModel.registerRoutePage(pageUid, {
|
|
43
|
+
active: activeRef.current ?? false,
|
|
44
|
+
refreshDesktopRoutes: refreshRef.current,
|
|
45
|
+
layoutContentElement: layoutContentRef.current,
|
|
46
|
+
});
|
|
47
|
+
return () => {
|
|
48
|
+
layoutModel.unregisterRoutePage(pageUid);
|
|
49
|
+
};
|
|
50
|
+
}, [layoutModel, pageUid, layoutContentRef]);
|
|
51
|
+
|
|
52
|
+
useEffect(() => {
|
|
53
|
+
layoutModel.updateRoutePage(pageUid, {
|
|
54
|
+
active,
|
|
55
|
+
refreshDesktopRoutes,
|
|
56
|
+
layoutContentElement: layoutContentRef.current,
|
|
57
|
+
});
|
|
58
|
+
}, [active, layoutModel, pageUid, refreshDesktopRoutes, layoutContentRef]);
|
|
59
|
+
|
|
60
|
+
return layoutModel;
|
|
61
|
+
}
|
|
@@ -7,161 +7,11 @@
|
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import {
|
|
11
|
-
import
|
|
12
|
-
import { getAdminLayoutModel, AdminLayoutModel } from '..';
|
|
13
|
-
import { useApp } from '../../hooks/useApp';
|
|
14
|
-
import { useLocation, useNavigate, useParams } from 'react-router-dom';
|
|
15
|
-
import { NocoBaseDesktopRouteType } from '../../flow-compat';
|
|
16
|
-
import {
|
|
17
|
-
findFirstV2LandingRoute,
|
|
18
|
-
resolveAdminRouteRuntimeTarget,
|
|
19
|
-
toRouterNavigationPath,
|
|
20
|
-
} from '../admin-shell/admin-layout/resolveAdminRouteRuntimeTarget';
|
|
10
|
+
import React, { type FC } from 'react';
|
|
11
|
+
import { LayoutRoute } from '../../layout-manager/LayoutRoute';
|
|
21
12
|
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
const app = useApp();
|
|
25
|
-
const navigate = useNavigate();
|
|
26
|
-
const location = useLocation();
|
|
27
|
-
const params = useParams();
|
|
28
|
-
const [ready, setReady] = useState(false);
|
|
29
|
-
const replaceTriggeredRef = useRef(false);
|
|
30
|
-
const routeRepository = flowEngine.context.routeRepository;
|
|
31
|
-
const isAdminRoot = useMemo(() => {
|
|
32
|
-
const pathname = toRouterNavigationPath(location.pathname, app.router.getBasename());
|
|
33
|
-
return pathname === '/admin';
|
|
34
|
-
}, [app, location.pathname]);
|
|
35
|
-
|
|
36
|
-
useEffect(() => {
|
|
37
|
-
replaceTriggeredRef.current = false;
|
|
38
|
-
}, [location.pathname, location.search, location.hash, params.name]);
|
|
39
|
-
|
|
40
|
-
useEffect(() => {
|
|
41
|
-
let active = true;
|
|
42
|
-
|
|
43
|
-
const run = async () => {
|
|
44
|
-
setReady(false);
|
|
45
|
-
|
|
46
|
-
if (!isAdminRoot && !params.name) {
|
|
47
|
-
if (active) {
|
|
48
|
-
setReady(true);
|
|
49
|
-
}
|
|
50
|
-
return;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (!routeRepository?.isAccessibleLoaded?.()) {
|
|
54
|
-
try {
|
|
55
|
-
await routeRepository?.ensureAccessibleLoaded?.();
|
|
56
|
-
} catch (_error) {
|
|
57
|
-
if (active) {
|
|
58
|
-
setReady(true);
|
|
59
|
-
}
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
if (!active || replaceTriggeredRef.current) {
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (params.name) {
|
|
69
|
-
const currentRoute = routeRepository?.getRouteBySchemaUid?.(params.name);
|
|
70
|
-
if (currentRoute?.type === NocoBaseDesktopRouteType.page) {
|
|
71
|
-
const target = resolveAdminRouteRuntimeTarget({
|
|
72
|
-
app,
|
|
73
|
-
route: currentRoute,
|
|
74
|
-
location: {
|
|
75
|
-
pathname: window.location.pathname,
|
|
76
|
-
search: window.location.search,
|
|
77
|
-
hash: window.location.hash,
|
|
78
|
-
},
|
|
79
|
-
preserveLocationState: true,
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
if (target.navigationMode === 'document' && target.runtimePath) {
|
|
83
|
-
replaceTriggeredRef.current = true;
|
|
84
|
-
window.location.replace(target.runtimePath);
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
if (active) {
|
|
90
|
-
setReady(true);
|
|
91
|
-
}
|
|
92
|
-
return;
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
const firstAccessibleRoute = findFirstV2LandingRoute(routeRepository?.listAccessible?.() || []);
|
|
96
|
-
if (!firstAccessibleRoute) {
|
|
97
|
-
if (active) {
|
|
98
|
-
setReady(true);
|
|
99
|
-
}
|
|
100
|
-
return;
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
const target = resolveAdminRouteRuntimeTarget({
|
|
104
|
-
app,
|
|
105
|
-
route: firstAccessibleRoute,
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
if (!target.runtimePath) {
|
|
109
|
-
if (active) {
|
|
110
|
-
setReady(true);
|
|
111
|
-
}
|
|
112
|
-
return;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
replaceTriggeredRef.current = true;
|
|
116
|
-
if (target.navigationMode === 'document') {
|
|
117
|
-
window.location.replace(target.runtimePath);
|
|
118
|
-
return;
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
navigate(toRouterNavigationPath(target.runtimePath, app.router.getBasename()), { replace: true });
|
|
122
|
-
};
|
|
123
|
-
|
|
124
|
-
void run();
|
|
125
|
-
|
|
126
|
-
return () => {
|
|
127
|
-
active = false;
|
|
128
|
-
};
|
|
129
|
-
}, [
|
|
130
|
-
app,
|
|
131
|
-
flowEngine,
|
|
132
|
-
isAdminRoot,
|
|
133
|
-
location.hash,
|
|
134
|
-
location.pathname,
|
|
135
|
-
location.search,
|
|
136
|
-
navigate,
|
|
137
|
-
params.name,
|
|
138
|
-
routeRepository,
|
|
139
|
-
]);
|
|
140
|
-
|
|
141
|
-
if (!ready) {
|
|
142
|
-
return null;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
return <>{children}</>;
|
|
146
|
-
};
|
|
147
|
-
|
|
148
|
-
const AdminLayout: FC = (props) => {
|
|
149
|
-
const flowEngine = useFlowEngine();
|
|
150
|
-
const model = getAdminLayoutModel(flowEngine, {
|
|
151
|
-
create: true,
|
|
152
|
-
props,
|
|
153
|
-
use: AdminLayoutModel,
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
if (!model) {
|
|
157
|
-
throw new Error('[NocoBase] Failed to create admin-layout-model.');
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
return (
|
|
161
|
-
<AdminLayoutEntryGuard>
|
|
162
|
-
<FlowModelRenderer model={model} />
|
|
163
|
-
</AdminLayoutEntryGuard>
|
|
164
|
-
);
|
|
13
|
+
const AdminLayout: FC = () => {
|
|
14
|
+
return <LayoutRoute layoutRouteName="admin" />;
|
|
165
15
|
};
|
|
166
16
|
|
|
167
17
|
export default AdminLayout;
|