@nocobase/client-v2 2.1.31 → 2.2.0-alpha.10
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 +2 -0
- package/es/PluginSettingsManager.d.ts +33 -0
- package/es/RouteRepository.d.ts +29 -6
- package/es/RouterManager.d.ts +15 -0
- package/es/authRedirect.d.ts +1 -0
- package/es/components/category-tabs/SortableCategoryTabs.d.ts +55 -0
- package/es/components/category-tabs/index.d.ts +9 -0
- package/es/components/form/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/entry-actions/EntryActionManager.d.ts +24 -0
- package/es/entry-actions/index.d.ts +9 -0
- package/es/flow/actions/index.d.ts +1 -1
- package/es/flow/actions/linkageRules.d.ts +2 -0
- 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 +3 -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/AppListRender.d.ts +2 -1
- package/es/flow/admin-shell/admin-layout/AppSwitcherActionPanelModel.d.ts +24 -0
- package/es/flow/admin-shell/admin-layout/index.d.ts +1 -0
- package/es/flow/admin-shell/admin-layout/resolveAdminRouteRuntimeTarget.d.ts +6 -0
- package/es/flow/admin-shell/admin-layout/useApplications.d.ts +7 -2
- package/es/flow/components/FieldAssignExactDatePicker.d.ts +1 -0
- package/es/flow/components/FieldAssignValueInput.d.ts +9 -0
- 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/models/base/ActionModelCore.d.ts +2 -0
- package/es/flow/models/base/GridModel.d.ts +1 -1
- 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/value-runtime/runtime.d.ts +9 -0
- package/es/flow-compat/routeTypes.d.ts +1 -0
- package/es/index.d.ts +7 -1
- package/es/index.mjs +223 -135
- package/es/utils/getRouteRuntimeVersion.d.ts +23 -0
- package/es/utils/index.d.ts +1 -0
- package/lib/index.js +220 -132
- package/package.json +7 -7
- package/src/APIClient.ts +1 -10
- package/src/Application.tsx +4 -0
- package/src/BaseApplication.tsx +2 -0
- package/src/PluginSettingsManager.ts +53 -0
- package/src/RouteRepository.ts +151 -24
- package/src/RouterManager.tsx +142 -1
- package/src/__tests__/PluginSettingsManager.test.ts +13 -0
- package/src/__tests__/RouteRepository.test.ts +239 -0
- package/src/__tests__/RouterManager.test.ts +125 -0
- package/src/__tests__/app.test.tsx +18 -0
- package/src/__tests__/authRedirect.test.ts +17 -0
- package/src/__tests__/browserChecker.test.ts +61 -0
- package/src/__tests__/exports.test.ts +16 -0
- package/src/__tests__/getRouteRuntimeVersion.test.ts +68 -0
- package/src/__tests__/nocobase-buildin-plugin-auth.test.tsx +28 -0
- package/src/__tests__/plugin-manager.test.tsx +44 -2
- package/src/__tests__/settings-center.test.tsx +40 -1
- package/src/authRedirect.ts +38 -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/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/entry-actions/EntryActionManager.ts +76 -0
- package/src/entry-actions/index.ts +10 -0
- package/src/flow/__tests__/FlowRoute.test.tsx +1084 -145
- package/src/flow/actions/__tests__/linkageRules.tab.test.ts +171 -0
- package/src/flow/actions/customVariable.tsx +1 -2
- package/src/flow/actions/index.ts +2 -0
- package/src/flow/actions/linkageRules.tsx +65 -8
- package/src/flow/actions/runjs.tsx +2 -14
- package/src/flow/admin-shell/BaseLayoutModel.tsx +13 -0
- package/src/flow/admin-shell/admin-layout/AdminLayoutComponent.tsx +46 -13
- package/src/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.test.tsx +486 -0
- package/src/flow/admin-shell/admin-layout/AdminLayoutEntryGuard.tsx +64 -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/AppListRender.tsx +13 -2
- package/src/flow/admin-shell/admin-layout/AppSwitcherActionPanelModel.tsx +289 -0
- package/src/flow/admin-shell/admin-layout/__tests__/AdminLayoutComponent.test.tsx +435 -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 +77 -0
- package/src/flow/admin-shell/admin-layout/__tests__/TopbarActionsBar.test.tsx +214 -2
- package/src/flow/admin-shell/admin-layout/index.ts +1 -0
- 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/admin-shell/admin-layout/useApplications.tsx +81 -12
- package/src/flow/components/DefaultValue.tsx +1 -2
- package/src/flow/components/FieldAssignExactDatePicker.tsx +25 -11
- package/src/flow/components/FieldAssignValueInput.tsx +76 -9
- package/src/flow/components/FlowRoute.tsx +185 -28
- package/src/flow/components/RunJSValueEditor.tsx +9 -1
- package/src/flow/components/__tests__/FieldAssignValueInput.context.test.tsx +84 -2
- 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/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 +1 -0
- 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 +21 -8
- package/src/flow/models/base/ActionModelCore.tsx +5 -0
- package/src/flow/models/base/GridModel.tsx +38 -7
- 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 +186 -3
- package/src/flow/models/base/PageModel/__tests__/PageModel.test.ts +790 -14
- 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 +586 -1
- package/src/flow/models/base/__tests__/ActionModel.test.ts +83 -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 +1 -2
- package/src/flow/models/blocks/filter-form/FilterFormJSActionModel.tsx +2 -7
- package/src/flow/models/blocks/form/JSFormActionModel.tsx +2 -7
- package/src/flow/models/blocks/form/value-runtime/__tests__/runtime.test.ts +87 -0
- package/src/flow/models/blocks/form/value-runtime/rules.ts +2 -2
- package/src/flow/models/blocks/form/value-runtime/runtime.ts +91 -0
- package/src/flow/models/blocks/js-block/JSBlock.tsx +2 -7
- package/src/flow/models/blocks/table/JSColumnModel.tsx +1 -9
- package/src/flow/models/blocks/table/TableActionsColumnModel.tsx +1 -1
- package/src/flow/models/blocks/table/TableBlockModel.tsx +13 -3
- package/src/flow/models/blocks/table/__tests__/TableActionsColumnModel.test.tsx +54 -0
- package/src/flow/models/blocks/table/__tests__/TableBlockModel.mobileSettingsButtons.test.tsx +78 -0
- 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/VariableFieldFormModel.tsx +3 -3
- package/src/flow/models/fields/__tests__/VariableFieldFormModel.test.tsx +51 -0
- package/src/flow/models/topbar/TopbarActionModel.tsx +168 -10
- package/src/flow-compat/Popover.tsx +43 -4
- package/src/flow-compat/__tests__/Popover.test.tsx +34 -0
- package/src/flow-compat/routeTypes.ts +1 -0
- package/src/index.ts +13 -1
- package/src/layout-manager/__tests__/LayoutRoute.test.tsx +41 -1
- package/src/nocobase-buildin-plugin/index.tsx +19 -3
- package/src/settings-center/AdminSettingsLayout.tsx +10 -2
- package/src/settings-center/SystemSettingsPage.tsx +0 -1
- package/src/settings-center/plugin-manager/PluginCard.tsx +2 -2
- package/src/settings-center/utils.tsx +0 -6
- package/src/utils/getRouteRuntimeVersion.ts +185 -0
- package/src/utils/index.tsx +1 -0
|
@@ -0,0 +1,171 @@
|
|
|
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 { ActionScene } from '@nocobase/flow-engine';
|
|
11
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
12
|
+
|
|
13
|
+
import * as registeredActions from '../index';
|
|
14
|
+
import * as linkageActions from '../linkageRules';
|
|
15
|
+
|
|
16
|
+
const tabLinkageRules = (linkageActions as Record<string, unknown>).tabLinkageRules as
|
|
17
|
+
| typeof linkageActions.menuLinkageRules
|
|
18
|
+
| undefined;
|
|
19
|
+
const linkageSetTabProps = (linkageActions as Record<string, unknown>).linkageSetTabProps as
|
|
20
|
+
| typeof linkageActions.linkageSetMenuItemProps
|
|
21
|
+
| undefined;
|
|
22
|
+
|
|
23
|
+
function createRuntime() {
|
|
24
|
+
let matched = true;
|
|
25
|
+
const setProps = vi.fn(function (this: { props: Record<string, unknown> }, props: Record<string, unknown>) {
|
|
26
|
+
this.props = {
|
|
27
|
+
...this.props,
|
|
28
|
+
...props,
|
|
29
|
+
};
|
|
30
|
+
});
|
|
31
|
+
const setHidden = vi.fn(function (this: { hidden: boolean }, value: boolean) {
|
|
32
|
+
this.hidden = value;
|
|
33
|
+
});
|
|
34
|
+
const model = {
|
|
35
|
+
uid: 'tab-1',
|
|
36
|
+
props: {} as Record<string, unknown>,
|
|
37
|
+
hidden: false,
|
|
38
|
+
__allModels: [],
|
|
39
|
+
setProps,
|
|
40
|
+
setHidden,
|
|
41
|
+
};
|
|
42
|
+
const ctx = {
|
|
43
|
+
app: { jsonLogic: { apply: () => matched } },
|
|
44
|
+
model,
|
|
45
|
+
t: (text: string) => text,
|
|
46
|
+
getAction: (name: string) => (name === 'linkageSetTabProps' ? linkageSetTabProps : undefined),
|
|
47
|
+
resolveJsonTemplate: vi.fn(async (value: unknown) => value),
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
return {
|
|
51
|
+
ctx,
|
|
52
|
+
model,
|
|
53
|
+
setMatched(value: boolean) {
|
|
54
|
+
matched = value;
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const hideRule = {
|
|
60
|
+
value: [
|
|
61
|
+
{
|
|
62
|
+
key: 'rule-1',
|
|
63
|
+
title: 'Hide tab',
|
|
64
|
+
enable: true,
|
|
65
|
+
condition: {
|
|
66
|
+
logic: '$and',
|
|
67
|
+
items: [{ path: 'status', operator: '$eq', value: 'visible' }],
|
|
68
|
+
},
|
|
69
|
+
actions: [
|
|
70
|
+
{
|
|
71
|
+
key: 'action-1',
|
|
72
|
+
name: 'linkageSetTabProps',
|
|
73
|
+
params: { value: 'hidden' },
|
|
74
|
+
},
|
|
75
|
+
],
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
describe('tab linkage rules', () => {
|
|
81
|
+
it('should append the tab linkage scene without changing existing scene values', () => {
|
|
82
|
+
const scenes = ActionScene as unknown as Record<string, number>;
|
|
83
|
+
|
|
84
|
+
expect(scenes.MENU_LINKAGE_RULES).toBe(7);
|
|
85
|
+
expect(scenes.TAB_LINKAGE_RULES).toBe(8);
|
|
86
|
+
expect(scenes.TAB_LINKAGE_RULES).toBe(Math.max(...Object.values(scenes).filter(Number.isInteger)));
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('should register tab linkage actions from the actions entry', () => {
|
|
90
|
+
expect((registeredActions as Record<string, unknown>).tabLinkageRules).toBe(tabLinkageRules);
|
|
91
|
+
expect((registeredActions as Record<string, unknown>).linkageSetTabProps).toBe(linkageSetTabProps);
|
|
92
|
+
expect(tabLinkageRules).toBeDefined();
|
|
93
|
+
expect(linkageSetTabProps).toBeDefined();
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('should expose tab state and runjs actions in ui schema', () => {
|
|
97
|
+
expect(tabLinkageRules).toBeDefined();
|
|
98
|
+
expect(linkageSetTabProps).toBeDefined();
|
|
99
|
+
|
|
100
|
+
const schema = tabLinkageRules?.uiSchema?.({
|
|
101
|
+
getActions: () =>
|
|
102
|
+
new Map([
|
|
103
|
+
['linkageSetTabProps', linkageSetTabProps],
|
|
104
|
+
['linkageRunjs', linkageActions.linkageRunjs],
|
|
105
|
+
['linkageSetMenuItemProps', linkageActions.linkageSetMenuItemProps],
|
|
106
|
+
]),
|
|
107
|
+
} as never) as Record<string, Record<string, Record<string, unknown>>> | undefined;
|
|
108
|
+
|
|
109
|
+
expect(schema?.value?.['x-component-props']?.supportedActions).toEqual(['linkageSetTabProps', 'linkageRunjs']);
|
|
110
|
+
expect(linkageSetTabProps?.scene).toBe((ActionScene as unknown as Record<string, number>).TAB_LINKAGE_RULES);
|
|
111
|
+
expect(linkageActions.linkageRunjs.scene).toContain(
|
|
112
|
+
(ActionScene as unknown as Record<string, number>).TAB_LINKAGE_RULES,
|
|
113
|
+
);
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('should hide the tab when the condition matches and restore it when the condition misses', async () => {
|
|
117
|
+
expect(tabLinkageRules).toBeDefined();
|
|
118
|
+
const runtime = createRuntime();
|
|
119
|
+
|
|
120
|
+
await tabLinkageRules?.handler(runtime.ctx as never, hideRule);
|
|
121
|
+
expect(runtime.model.hidden).toBe(true);
|
|
122
|
+
|
|
123
|
+
runtime.setMatched(false);
|
|
124
|
+
await tabLinkageRules?.handler(runtime.ctx as never, hideRule);
|
|
125
|
+
expect(runtime.model.hidden).toBe(false);
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
it('should restore the tab when linkage rules are cleared', async () => {
|
|
129
|
+
expect(tabLinkageRules).toBeDefined();
|
|
130
|
+
const runtime = createRuntime();
|
|
131
|
+
|
|
132
|
+
await tabLinkageRules?.handler(runtime.ctx as never, hideRule);
|
|
133
|
+
expect(runtime.model.hidden).toBe(true);
|
|
134
|
+
|
|
135
|
+
await tabLinkageRules?.handler(runtime.ctx as never, { value: [] });
|
|
136
|
+
expect(runtime.model.hidden).toBe(false);
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('should not restore stale tab props while applying or clearing visibility rules', async () => {
|
|
140
|
+
expect(tabLinkageRules).toBeDefined();
|
|
141
|
+
const runtime = createRuntime();
|
|
142
|
+
runtime.model.props = {
|
|
143
|
+
title: 'Original title',
|
|
144
|
+
icon: 'original-icon',
|
|
145
|
+
route: { options: { badge: 'original' } },
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
await tabLinkageRules?.handler(runtime.ctx as never, hideRule);
|
|
149
|
+
expect(runtime.model.hidden).toBe(true);
|
|
150
|
+
|
|
151
|
+
const updatedProps = {
|
|
152
|
+
title: 'Updated title',
|
|
153
|
+
icon: 'updated-icon',
|
|
154
|
+
route: { options: { badge: 'updated' } },
|
|
155
|
+
};
|
|
156
|
+
runtime.model.props = updatedProps;
|
|
157
|
+
|
|
158
|
+
await tabLinkageRules?.handler(runtime.ctx as never, hideRule);
|
|
159
|
+
expect(runtime.model.props).toMatchObject(updatedProps);
|
|
160
|
+
expect(runtime.model.hidden).toBe(true);
|
|
161
|
+
|
|
162
|
+
runtime.setMatched(false);
|
|
163
|
+
await tabLinkageRules?.handler(runtime.ctx as never, hideRule);
|
|
164
|
+
expect(runtime.model.props).toMatchObject(updatedProps);
|
|
165
|
+
expect(runtime.model.hidden).toBe(false);
|
|
166
|
+
|
|
167
|
+
await tabLinkageRules?.handler(runtime.ctx as never, { value: [] });
|
|
168
|
+
expect(runtime.model.props).toMatchObject(updatedProps);
|
|
169
|
+
expect(runtime.model.hidden).toBe(false);
|
|
170
|
+
});
|
|
171
|
+
});
|
|
@@ -12,7 +12,6 @@ import {
|
|
|
12
12
|
defineAction,
|
|
13
13
|
isRunJSValue,
|
|
14
14
|
normalizeRunJSValue,
|
|
15
|
-
runjsWithSafeGlobals,
|
|
16
15
|
tExpr,
|
|
17
16
|
type RunJSValue,
|
|
18
17
|
useFlowContext,
|
|
@@ -43,7 +42,7 @@ export const customVariable = defineAction({
|
|
|
43
42
|
if (variable.type === 'runjs') {
|
|
44
43
|
const getFunction = async () => {
|
|
45
44
|
const { code, version } = normalizeRunJSValue(variable.runjs);
|
|
46
|
-
return
|
|
45
|
+
return ctx.runjs(code, undefined, { version });
|
|
47
46
|
};
|
|
48
47
|
const metaFunction = () => ({
|
|
49
48
|
title: variable.title,
|
|
@@ -43,10 +43,12 @@ export {
|
|
|
43
43
|
linkageSetDetailsFieldProps,
|
|
44
44
|
actionLinkageRules,
|
|
45
45
|
menuLinkageRules,
|
|
46
|
+
tabLinkageRules,
|
|
46
47
|
blockLinkageRules,
|
|
47
48
|
linkageSetBlockProps,
|
|
48
49
|
linkageSetActionProps,
|
|
49
50
|
linkageSetMenuItemProps,
|
|
51
|
+
linkageSetTabProps,
|
|
50
52
|
linkageSetFieldProps,
|
|
51
53
|
subFormLinkageSetFieldProps,
|
|
52
54
|
linkageAssignField,
|
|
@@ -16,13 +16,9 @@ import {
|
|
|
16
16
|
FlowRuntimeContext,
|
|
17
17
|
useFlowContext,
|
|
18
18
|
useFlowEngine,
|
|
19
|
-
createSafeWindow,
|
|
20
|
-
createSafeDocument,
|
|
21
|
-
createSafeNavigator,
|
|
22
19
|
observer,
|
|
23
20
|
isRunJSValue,
|
|
24
21
|
normalizeRunJSValue,
|
|
25
|
-
runjsWithSafeGlobals,
|
|
26
22
|
} from '@nocobase/flow-engine';
|
|
27
23
|
import { evaluateConditions, FilterGroupType, removeInvalidFilterItems } from '@nocobase/utils/client';
|
|
28
24
|
import React from 'react';
|
|
@@ -492,7 +488,7 @@ async function resolveLinkageAssignRuntimeValue(ctx: FlowContext, rawValue: any)
|
|
|
492
488
|
|
|
493
489
|
try {
|
|
494
490
|
const { code, version } = normalizeRunJSValue(rawValue);
|
|
495
|
-
const ret = await
|
|
491
|
+
const ret = await ctx.runjs(code, undefined, { version });
|
|
496
492
|
if (!ret?.success) {
|
|
497
493
|
return SKIP_RUNJS_ASSIGN_VALUE;
|
|
498
494
|
}
|
|
@@ -735,6 +731,41 @@ export const linkageSetMenuItemProps = defineAction({
|
|
|
735
731
|
},
|
|
736
732
|
});
|
|
737
733
|
|
|
734
|
+
export const linkageSetTabProps = defineAction({
|
|
735
|
+
name: 'linkageSetTabProps',
|
|
736
|
+
title: tExpr('Set tab state'),
|
|
737
|
+
scene: ActionScene.TAB_LINKAGE_RULES,
|
|
738
|
+
sort: 100,
|
|
739
|
+
uiSchema: {
|
|
740
|
+
value: {
|
|
741
|
+
type: 'string',
|
|
742
|
+
'x-component': (props) => {
|
|
743
|
+
const { value, onChange } = props;
|
|
744
|
+
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
745
|
+
const ctx = useFlowContext();
|
|
746
|
+
const t = ctx.model.translate.bind(ctx.model);
|
|
747
|
+
|
|
748
|
+
return (
|
|
749
|
+
<Select
|
|
750
|
+
value={value}
|
|
751
|
+
onChange={onChange}
|
|
752
|
+
placeholder={t('Please select state')}
|
|
753
|
+
style={{ width: '100%' }}
|
|
754
|
+
options={[
|
|
755
|
+
{ label: t('Visible'), value: 'visible' },
|
|
756
|
+
{ label: t('Hidden'), value: 'hidden' },
|
|
757
|
+
]}
|
|
758
|
+
allowClear
|
|
759
|
+
/>
|
|
760
|
+
);
|
|
761
|
+
},
|
|
762
|
+
},
|
|
763
|
+
},
|
|
764
|
+
handler(ctx, { value, setProps }) {
|
|
765
|
+
setProps(ctx.model, { hiddenModel: value === 'hidden' });
|
|
766
|
+
},
|
|
767
|
+
});
|
|
768
|
+
|
|
738
769
|
export const linkageSetFieldProps = defineAction({
|
|
739
770
|
name: 'linkageSetFieldProps',
|
|
740
771
|
title: tExpr('Set field state'),
|
|
@@ -1343,6 +1374,7 @@ export const linkageRunjs = defineAction({
|
|
|
1343
1374
|
ActionScene.FIELD_LINKAGE_RULES,
|
|
1344
1375
|
ActionScene.ACTION_LINKAGE_RULES,
|
|
1345
1376
|
ActionScene.MENU_LINKAGE_RULES,
|
|
1377
|
+
ActionScene.TAB_LINKAGE_RULES,
|
|
1346
1378
|
ActionScene.DETAILS_FIELD_LINKAGE_RULES,
|
|
1347
1379
|
ActionScene.SUB_FORM_FIELD_LINKAGE_RULES,
|
|
1348
1380
|
],
|
|
@@ -1397,8 +1429,7 @@ export const linkageRunjs = defineAction({
|
|
|
1397
1429
|
}
|
|
1398
1430
|
|
|
1399
1431
|
try {
|
|
1400
|
-
|
|
1401
|
-
await ctx.runjs(script, { window: createSafeWindow({ navigator }), document: createSafeDocument(), navigator });
|
|
1432
|
+
await ctx.runjs(script);
|
|
1402
1433
|
} catch (error) {
|
|
1403
1434
|
console.error('Script execution error:', error);
|
|
1404
1435
|
// 可以选择显示错误信息给用户
|
|
@@ -2174,7 +2205,7 @@ const commonLinkageRulesHandler = async (ctx: FlowContext, params: any) => {
|
|
|
2174
2205
|
}
|
|
2175
2206
|
: props;
|
|
2176
2207
|
|
|
2177
|
-
//
|
|
2208
|
+
// 只记录联动实际控制的属性,避免之后恢复状态时把标题、路由等无关的新配置回滚到旧快照。
|
|
2178
2209
|
const originalProps = model.__originalProps || (model.__originalProps = {});
|
|
2179
2210
|
const rememberOriginalProp = (key: string, value: unknown) => {
|
|
2180
2211
|
if (!Object.prototype.hasOwnProperty.call(originalProps, key)) {
|
|
@@ -2480,6 +2511,32 @@ export const menuLinkageRules = defineAction({
|
|
|
2480
2511
|
},
|
|
2481
2512
|
});
|
|
2482
2513
|
|
|
2514
|
+
export const tabLinkageRules = defineAction({
|
|
2515
|
+
name: 'tabLinkageRules',
|
|
2516
|
+
title: tExpr('Tab linkage rules'),
|
|
2517
|
+
uiMode: 'embed',
|
|
2518
|
+
uiSchema(ctx) {
|
|
2519
|
+
return {
|
|
2520
|
+
value: {
|
|
2521
|
+
type: 'array',
|
|
2522
|
+
'x-component': LinkageRulesUI,
|
|
2523
|
+
'x-component-props': {
|
|
2524
|
+
supportedActions: getSupportedActions(ctx, ActionScene.TAB_LINKAGE_RULES),
|
|
2525
|
+
title: tExpr('Tab linkage rules'),
|
|
2526
|
+
},
|
|
2527
|
+
},
|
|
2528
|
+
};
|
|
2529
|
+
},
|
|
2530
|
+
defaultParams: {
|
|
2531
|
+
value: [],
|
|
2532
|
+
},
|
|
2533
|
+
useRawParams: true,
|
|
2534
|
+
handler: async (ctx, params) => {
|
|
2535
|
+
const resolved = await resolveLinkageRulesParamsPreservingRunJsScripts(ctx, params);
|
|
2536
|
+
return commonLinkageRulesHandler(ctx, resolved);
|
|
2537
|
+
},
|
|
2538
|
+
});
|
|
2539
|
+
|
|
2483
2540
|
export const fieldLinkageRules = defineAction({
|
|
2484
2541
|
name: 'fieldLinkageRules',
|
|
2485
2542
|
title: tExpr('Field linkage rules'),
|
|
@@ -7,14 +7,7 @@
|
|
|
7
7
|
* For more information, please refer to: https://www.nocobase.com/agreement.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import {
|
|
11
|
-
ActionScene,
|
|
12
|
-
defineAction,
|
|
13
|
-
tExpr,
|
|
14
|
-
createSafeWindow,
|
|
15
|
-
createSafeDocument,
|
|
16
|
-
createSafeNavigator,
|
|
17
|
-
} from '@nocobase/flow-engine';
|
|
10
|
+
import { ActionScene, defineAction, tExpr } from '@nocobase/flow-engine';
|
|
18
11
|
import { CodeEditor } from '../components/code-editor';
|
|
19
12
|
|
|
20
13
|
export const runjs = defineAction({
|
|
@@ -38,11 +31,6 @@ export const runjs = defineAction({
|
|
|
38
31
|
// 如果是 URL 触发的,则不执行代码
|
|
39
32
|
if (ctx.inputArgs?.navigation) return;
|
|
40
33
|
|
|
41
|
-
|
|
42
|
-
return ctx.runjs(params.code, {
|
|
43
|
-
window: createSafeWindow({ navigator }),
|
|
44
|
-
document: createSafeDocument(),
|
|
45
|
-
navigator,
|
|
46
|
-
});
|
|
34
|
+
return ctx.runjs(params.code);
|
|
47
35
|
},
|
|
48
36
|
});
|
|
@@ -20,6 +20,7 @@ import {
|
|
|
20
20
|
type BaseLayoutRouteCoordinatorOptions,
|
|
21
21
|
type RoutePageMeta,
|
|
22
22
|
} from './BaseLayoutRouteCoordinator';
|
|
23
|
+
import { NocoBaseDesktopRouteType } from '../../flow-compat';
|
|
23
24
|
import type { LayoutDefinition } from '../../layout-manager/types';
|
|
24
25
|
import { isLayoutContentRouteName } from '../../layout-manager/utils';
|
|
25
26
|
|
|
@@ -334,6 +335,18 @@ export class BaseLayoutModel<
|
|
|
334
335
|
};
|
|
335
336
|
}
|
|
336
337
|
|
|
338
|
+
const routeRepository = this.flowEngine.context.routeRepository;
|
|
339
|
+
const schemaRoute = routeRepository?.getRouteBySchemaUid?.(pageUid);
|
|
340
|
+
const route = schemaRoute ? undefined : routeRepository?.getRouteById?.(pageUid);
|
|
341
|
+
if (!schemaRoute && route?.type === NocoBaseDesktopRouteType.group) {
|
|
342
|
+
return {
|
|
343
|
+
type: 'root',
|
|
344
|
+
pathname,
|
|
345
|
+
basePathname,
|
|
346
|
+
relativePath,
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
|
|
337
350
|
return {
|
|
338
351
|
type: 'page',
|
|
339
352
|
pathname,
|
|
@@ -42,6 +42,7 @@ import {
|
|
|
42
42
|
FLOW_SETTINGS_PREFERENCE_STORAGE_KEY,
|
|
43
43
|
readFlowSettingsPreference,
|
|
44
44
|
} from './flowSettingsPreference';
|
|
45
|
+
import { joinAdminLayoutRoutePath, type AdminLayoutRoutePathLike } from './resolveAdminRouteRuntimeTarget';
|
|
45
46
|
import { useAppListRender } from './AppListRender';
|
|
46
47
|
|
|
47
48
|
const className1 = css`
|
|
@@ -294,6 +295,8 @@ function SetIsMobileLayout(props: { isMobile: boolean; children: any; model?: Ad
|
|
|
294
295
|
function AdminLayoutContentWithMobileState(props: {
|
|
295
296
|
isMobile: boolean;
|
|
296
297
|
model?: AdminLayoutModel;
|
|
298
|
+
designable?: boolean;
|
|
299
|
+
layout?: AdminLayoutModel['layout'];
|
|
297
300
|
onContentElementChange?: (element: HTMLDivElement | null) => void;
|
|
298
301
|
}) {
|
|
299
302
|
const modelRef = useRef(props.model);
|
|
@@ -311,7 +314,13 @@ function AdminLayoutContentWithMobileState(props: {
|
|
|
311
314
|
onContentElementChangeRef.current?.(element);
|
|
312
315
|
}, []);
|
|
313
316
|
|
|
314
|
-
return
|
|
317
|
+
return (
|
|
318
|
+
<AdminLayoutContent
|
|
319
|
+
designable={props.designable}
|
|
320
|
+
layout={props.layout}
|
|
321
|
+
onContentElementChange={handleContentElementChange}
|
|
322
|
+
/>
|
|
323
|
+
);
|
|
315
324
|
}
|
|
316
325
|
|
|
317
326
|
const DesignerButtonMenuItem: FC<{ item: AdminLayoutMenuNode; fallbackParentRoute?: NocoBaseDesktopRoute }> = (
|
|
@@ -337,25 +346,37 @@ const DesignerButtonMenuItem: FC<{ item: AdminLayoutMenuNode; fallbackParentRout
|
|
|
337
346
|
);
|
|
338
347
|
};
|
|
339
348
|
|
|
340
|
-
const matchesRoutePath = (
|
|
349
|
+
const matchesRoutePath = (
|
|
350
|
+
route: NocoBaseDesktopRoute | undefined,
|
|
351
|
+
pathname: string,
|
|
352
|
+
layout?: AdminLayoutRoutePathLike | null,
|
|
353
|
+
): boolean => {
|
|
341
354
|
if (!route) {
|
|
342
355
|
return false;
|
|
343
356
|
}
|
|
344
357
|
|
|
345
358
|
const candidates = [
|
|
346
|
-
route.id != null ?
|
|
347
|
-
route.schemaUid ?
|
|
359
|
+
route.id != null ? joinAdminLayoutRoutePath(layout, route.id) : null,
|
|
360
|
+
route.schemaUid ? joinAdminLayoutRoutePath(layout, route.schemaUid) : null,
|
|
348
361
|
].filter(Boolean) as string[];
|
|
349
362
|
|
|
350
363
|
if (candidates.some((candidate) => pathname === candidate || pathname.startsWith(`${candidate}/`))) {
|
|
351
364
|
return true;
|
|
352
365
|
}
|
|
353
366
|
|
|
354
|
-
return Array.isArray(route.children)
|
|
367
|
+
return Array.isArray(route.children)
|
|
368
|
+
? route.children.some((child) => matchesRoutePath(child, pathname, layout))
|
|
369
|
+
: false;
|
|
355
370
|
};
|
|
356
371
|
|
|
357
|
-
const findSelectedTopGroupRoute = (
|
|
358
|
-
|
|
372
|
+
const findSelectedTopGroupRoute = (
|
|
373
|
+
routes: NocoBaseDesktopRoute[],
|
|
374
|
+
pathname: string,
|
|
375
|
+
layout?: AdminLayoutRoutePathLike | null,
|
|
376
|
+
) => {
|
|
377
|
+
return routes.find(
|
|
378
|
+
(route) => route.type === NocoBaseDesktopRouteType.group && matchesRoutePath(route, pathname, layout),
|
|
379
|
+
);
|
|
359
380
|
};
|
|
360
381
|
|
|
361
382
|
const renderMenuNodeWithModel = (
|
|
@@ -399,6 +420,11 @@ export const AdminLayoutComponent = observer((props: any) => {
|
|
|
399
420
|
const { token } = antdTheme.useToken();
|
|
400
421
|
const customToken = token as CustomToken;
|
|
401
422
|
const isMobileLayout = !!adminLayoutModel?.isMobileLayout;
|
|
423
|
+
const adminLayoutRoutePath = adminLayoutModel?.layout?.routePath;
|
|
424
|
+
const adminLayoutRoutePathLike = useMemo<AdminLayoutRoutePathLike | undefined>(
|
|
425
|
+
() => (adminLayoutRoutePath ? { routePath: adminLayoutRoutePath } : undefined),
|
|
426
|
+
[adminLayoutRoutePath],
|
|
427
|
+
);
|
|
402
428
|
const menuRouteRefreshVersion = adminLayoutModel?.menuRouteRefreshVersion || 0;
|
|
403
429
|
const isMobileSider = isMobileLayout;
|
|
404
430
|
const [collapsed, setCollapsed] = useState(isMobileSider);
|
|
@@ -415,8 +441,8 @@ export const AdminLayoutComponent = observer((props: any) => {
|
|
|
415
441
|
);
|
|
416
442
|
const designable = !isMobileSider && preferredFlowSettingsEnabled;
|
|
417
443
|
const { styles } = useHeaderStyle();
|
|
418
|
-
const { appList } = useApplications();
|
|
419
|
-
const appListRender = useAppListRender();
|
|
444
|
+
const { appList, appSwitcherModel } = useApplications(adminLayoutModel);
|
|
445
|
+
const appListRender = useAppListRender(appSwitcherModel);
|
|
420
446
|
const flowSettingsSyncRef = useRef(0);
|
|
421
447
|
const desiredFlowSettingsEnabledRef = useRef(false);
|
|
422
448
|
const handleLayoutContentElementChange = useCallback(
|
|
@@ -426,8 +452,8 @@ export const AdminLayoutComponent = observer((props: any) => {
|
|
|
426
452
|
[adminLayoutModel],
|
|
427
453
|
);
|
|
428
454
|
const selectedTopGroupRoute = useMemo(
|
|
429
|
-
() => findSelectedTopGroupRoute(allAccessRoutes, location.pathname),
|
|
430
|
-
[allAccessRoutes, location.pathname],
|
|
455
|
+
() => findSelectedTopGroupRoute(allAccessRoutes, location.pathname, adminLayoutRoutePathLike),
|
|
456
|
+
[adminLayoutRoutePathLike, allAccessRoutes, location.pathname],
|
|
431
457
|
);
|
|
432
458
|
|
|
433
459
|
const handleMenuDragEnd = useCallback(
|
|
@@ -481,6 +507,7 @@ export const AdminLayoutComponent = observer((props: any) => {
|
|
|
481
507
|
|
|
482
508
|
useEffect(() => {
|
|
483
509
|
const routeRepository = flowEngine.context.routeRepository;
|
|
510
|
+
const deactivateLayout = routeRepository?.activateLayout?.(adminLayoutModel?.layout);
|
|
484
511
|
const subscriber = () => {
|
|
485
512
|
const updatedRoutes = routeRepository?.listAccessible() || [];
|
|
486
513
|
setAllAccessRoutes(updatedRoutes);
|
|
@@ -493,8 +520,9 @@ export const AdminLayoutComponent = observer((props: any) => {
|
|
|
493
520
|
|
|
494
521
|
return () => {
|
|
495
522
|
routeRepository?.unsubscribe(subscriber);
|
|
523
|
+
deactivateLayout?.();
|
|
496
524
|
};
|
|
497
|
-
}, [flowEngine]);
|
|
525
|
+
}, [adminLayoutModel, adminLayoutModel?.layout?.uid, flowEngine]);
|
|
498
526
|
|
|
499
527
|
useEffect(() => {
|
|
500
528
|
if (typeof window === 'undefined') {
|
|
@@ -637,6 +665,10 @@ export const AdminLayoutComponent = observer((props: any) => {
|
|
|
637
665
|
z-index: 2000 !important;
|
|
638
666
|
}
|
|
639
667
|
|
|
668
|
+
.ant-pro-layout-apps-popover .ant-popover-content {
|
|
669
|
+
margin-top: 12px;
|
|
670
|
+
}
|
|
671
|
+
|
|
640
672
|
.ant-pro-layout-apps-icon {
|
|
641
673
|
color: ${customToken.colorTextHeaderMenu || 'rgba(255, 255, 255, 0.85)'};
|
|
642
674
|
}
|
|
@@ -680,7 +712,6 @@ export const AdminLayoutComponent = observer((props: any) => {
|
|
|
680
712
|
<MobileMenuControlContext.Provider value={{ closeMobileMenu }}>
|
|
681
713
|
<DndProvider collisionDetection={menuCollisionDetection} onDragEnd={handleMenuDragEnd}>
|
|
682
714
|
<ProLayout
|
|
683
|
-
key={`admin-layout-menu-${menuRouteRefreshVersion}`}
|
|
684
715
|
{...props}
|
|
685
716
|
contentStyle={contentStyle}
|
|
686
717
|
siderWidth={customToken.siderWidth || 200}
|
|
@@ -723,6 +754,8 @@ export const AdminLayoutComponent = observer((props: any) => {
|
|
|
723
754
|
<AdminLayoutContentWithMobileState
|
|
724
755
|
isMobile={isMobile}
|
|
725
756
|
model={adminLayoutModel}
|
|
757
|
+
designable={designable}
|
|
758
|
+
layout={adminLayoutModel?.layout}
|
|
726
759
|
onContentElementChange={handleLayoutContentElementChange}
|
|
727
760
|
/>
|
|
728
761
|
</ConfigProvider>
|