@nocobase/portal-template-default 1.0.8 → 1.0.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/.env.example +5 -0
- package/.github/workflows/publish.yml +106 -0
- package/.gitignore +33 -0
- package/AGENTS.md +19 -0
- package/README.MD +61 -180
- package/package.json +3 -5
- package/scripts/build-html.mjs +12 -0
- package/src/App.css +2 -0
- package/src/App.tsx +35 -186
- package/src/app/development.tsx +154 -0
- package/src/app/extension.ts +5 -0
- package/src/app/extensions.tsx +18 -4
- package/src/app/routes.tsx +65 -0
- package/src/components/access-control/acl-bootstrap.tsx +11 -3
- package/src/components/access-control/acl-gate.tsx +7 -6
- package/src/components/access-control/can-access.tsx +17 -0
- package/src/components/access-control/navigate-to-accessible-resource.tsx +8 -3
- package/src/components/app-shell/sidebar.tsx +21 -5
- package/src/components/auth/auto-redirect-provider.tsx +2 -1
- package/src/extensions/nocobase-acl/README.md +74 -0
- package/{registry → src/extensions}/nocobase-acl/components/acl-boundary.tsx +22 -25
- package/{registry → src/extensions}/nocobase-acl/components/role-switcher.tsx +26 -23
- package/src/extensions/nocobase-acl/demo/acl-preview-provider.tsx +81 -0
- package/{registry → src/extensions}/nocobase-acl/demo/boundary-api.tsx +58 -0
- package/{registry → src/extensions}/nocobase-acl/demo/index.tsx +243 -105
- package/{registry → src/extensions}/nocobase-acl/demo/prompt-generator.tsx +3 -1
- package/src/extensions/nocobase-acl/extension.tsx +73 -0
- package/{registry → src/extensions}/nocobase-ai/README.md +21 -5
- package/{registry → src/extensions}/nocobase-ai/components/chat/chat-composer.tsx +3 -1
- package/{registry → src/extensions}/nocobase-ai/components/chat/chat-messages.tsx +38 -3
- package/{registry → src/extensions}/nocobase-ai/components/chat/tool-call-card.tsx +1 -9
- package/{registry → src/extensions}/nocobase-ai/components/index.ts +5 -0
- package/src/extensions/nocobase-ai/components/surfaces/chat-dialog.tsx +17 -0
- package/src/extensions/nocobase-ai/components/surfaces/chat-side-panel.tsx +35 -0
- package/src/extensions/nocobase-ai/components/surfaces/chat-surface.tsx +108 -0
- package/{registry → src/extensions}/nocobase-ai/components/triggers/ai-chat-floating-trigger.tsx +2 -2
- package/{registry → src/extensions}/nocobase-ai/demo/configuration-gate.tsx +4 -1
- package/{registry → src/extensions}/nocobase-ai/demo/container-showcase.tsx +2 -2
- package/{registry → src/extensions}/nocobase-ai/demo/floating.tsx +45 -15
- package/{registry → src/extensions}/nocobase-ai/demo/index.tsx +116 -74
- package/{registry → src/extensions}/nocobase-ai/demo/prompt-generator.tsx +3 -3
- package/{registry → src/extensions}/nocobase-ai/demo/tool-cards.tsx +2 -3
- package/src/extensions/nocobase-ai/extension.tsx +160 -0
- package/{registry → src/extensions}/nocobase-ai/global-ai-chat.tsx +12 -28
- package/{registry → src/extensions}/nocobase-ai/providers/ai-provider.tsx +14 -1
- package/{registry → src/extensions}/nocobase-ai/providers/chat-context.tsx +1 -0
- package/{registry → src/extensions}/nocobase-ai/providers/chat-provider.tsx +29 -8
- package/{registry → src/extensions}/nocobase-ai/providers/use-chat-attachments.ts +6 -1
- package/{registry → src/extensions}/nocobase-ai/providers/use-chat-work-context.ts +4 -1
- package/{registry → src/extensions}/nocobase-route-surfaces/README.md +2 -1
- package/{registry → src/extensions}/nocobase-route-surfaces/demo/index.tsx +33 -7
- package/{registry → src/extensions}/nocobase-route-surfaces/demo/scenarios.ts +20 -14
- package/{registry → src/extensions}/nocobase-route-surfaces/extension.tsx +55 -52
- package/src/{pages/users → extensions/nocobase-users-example}/create.tsx +4 -4
- package/src/{pages/users → extensions/nocobase-users-example}/edit.tsx +5 -9
- package/src/extensions/nocobase-users-example/extension.tsx +109 -0
- package/src/{pages/users → extensions/nocobase-users-example}/form-context.ts +11 -9
- package/src/extensions/nocobase-users-example/layout.tsx +16 -0
- package/src/{pages/users → extensions/nocobase-users-example}/list.tsx +1 -1
- package/src/extensions/nocobase-users-example/locales/en-US.ts +77 -0
- package/src/extensions/nocobase-users-example/locales/index.ts +8 -0
- package/src/extensions/nocobase-users-example/locales/zh-CN.ts +73 -0
- package/src/extensions/nocobase-users-example/optional-ai.ts +67 -0
- package/src/{pages/users → extensions/nocobase-users-example}/role-detail.tsx +4 -15
- package/src/{pages/users → extensions/nocobase-users-example}/routes.ts +1 -4
- package/src/extensions/nocobase-users-example/show.tsx +266 -0
- package/src/lib/nocobase/acl/context.ts +32 -0
- package/src/lib/nocobase/acl/evaluator.ts +186 -0
- package/src/lib/nocobase/acl/hooks.ts +40 -0
- package/src/lib/nocobase/acl/index.ts +4 -1
- package/src/lib/nocobase/acl/menu.ts +6 -6
- package/src/lib/nocobase/acl/record-permissions.ts +37 -7
- package/src/lib/nocobase/acl/store-provider.tsx +14 -0
- package/src/lib/nocobase/acl/store.ts +92 -86
- package/src/lib/nocobase/acl/types.ts +52 -32
- package/src/lib/nocobase/auth-session.ts +128 -0
- package/src/lib/nocobase/client.ts +48 -50
- package/src/locales/en-US.ts +0 -78
- package/src/locales/index.ts +2 -7
- package/src/locales/zh-CN.ts +0 -74
- package/src/providers/access-control.ts +43 -8
- package/src/providers/auth-callback.ts +1 -0
- package/src/providers/auth.ts +24 -26
- package/src/providers/constants.ts +0 -4
- package/src/providers/data.ts +14 -26
- package/src/providers/runtime-config.ts +40 -0
- package/src/vite-env.d.ts +9 -0
- package/tests/auth-session-regression.mjs +101 -0
- package/tsconfig.json +2 -1
- package/vite.config.ts +9 -1
- package/registry/nocobase-acl/README.md +0 -19
- package/registry/nocobase-acl/extension.tsx +0 -71
- package/registry/nocobase-acl/tests/acl-regression.mjs +0 -314
- package/registry/nocobase-ai/components/surfaces/chat-dialog.tsx +0 -31
- package/registry/nocobase-ai/components/surfaces/chat-side-panel.tsx +0 -74
- package/registry/nocobase-ai/extension.tsx +0 -158
- package/registry/nocobase-ai/tests/business-report-regression.mjs +0 -70
- package/registry/nocobase-ai/tests/form-filler-regression.mjs +0 -129
- package/registry/nocobase-ai/tests/frontend-tool-regression.mjs +0 -128
- package/registry/nocobase-ai/tests/page-context-regression.mjs +0 -48
- package/registry/nocobase-ai/tests/stream-regression.mjs +0 -207
- package/registry/nocobase-auth-cas/README.md +0 -6
- package/registry/nocobase-auth-cas/cas-sign-in-button.tsx +0 -41
- package/registry/nocobase-auth-cas/demo.tsx +0 -20
- package/registry/nocobase-auth-cas/extension.tsx +0 -46
- package/registry/nocobase-auth-cas/index.ts +0 -1
- package/registry/nocobase-auth-cas/use-cas-sign-in.ts +0 -29
- package/registry/nocobase-auth-dingtalk/README.md +0 -7
- package/registry/nocobase-auth-dingtalk/auto-login-provider.tsx +0 -154
- package/registry/nocobase-auth-dingtalk/demo.tsx +0 -23
- package/registry/nocobase-auth-dingtalk/dingtalk-sign-in-button.tsx +0 -45
- package/registry/nocobase-auth-dingtalk/extension.tsx +0 -55
- package/registry/nocobase-auth-dingtalk/index.ts +0 -4
- package/registry/nocobase-auth-dingtalk/use-dingtalk-sign-in.ts +0 -64
- package/registry/nocobase-auth-ldap/README.md +0 -6
- package/registry/nocobase-auth-ldap/demo.tsx +0 -21
- package/registry/nocobase-auth-ldap/extension.tsx +0 -46
- package/registry/nocobase-auth-ldap/index.ts +0 -1
- package/registry/nocobase-auth-ldap/ldap-sign-in-form.tsx +0 -69
- package/registry/nocobase-auth-ldap/use-ldap-sign-in.ts +0 -5
- package/registry/nocobase-auth-oidc/README.md +0 -11
- package/registry/nocobase-auth-oidc/auto-redirect-provider.tsx +0 -13
- package/registry/nocobase-auth-oidc/demo.tsx +0 -20
- package/registry/nocobase-auth-oidc/extension.tsx +0 -51
- package/registry/nocobase-auth-oidc/index.ts +0 -1
- package/registry/nocobase-auth-oidc/oidc-sign-in-button.tsx +0 -44
- package/registry/nocobase-auth-oidc/use-oidc-sign-in.ts +0 -58
- package/registry/nocobase-auth-saml/README.md +0 -6
- package/registry/nocobase-auth-saml/auto-redirect-provider.tsx +0 -13
- package/registry/nocobase-auth-saml/demo.tsx +0 -20
- package/registry/nocobase-auth-saml/extension.tsx +0 -51
- package/registry/nocobase-auth-saml/index.ts +0 -1
- package/registry/nocobase-auth-saml/saml-sign-in-button.tsx +0 -43
- package/registry/nocobase-auth-saml/use-saml-sign-in.ts +0 -51
- package/registry/nocobase-auth-sms/README.md +0 -7
- package/registry/nocobase-auth-sms/demo.tsx +0 -25
- package/registry/nocobase-auth-sms/extension.tsx +0 -46
- package/registry/nocobase-auth-sms/index.ts +0 -1
- package/registry/nocobase-auth-sms/sms-sign-in-form.tsx +0 -107
- package/registry/nocobase-auth-sms/use-sms-sign-in.ts +0 -88
- package/registry/nocobase-auth-wecom/README.md +0 -6
- package/registry/nocobase-auth-wecom/auto-login-provider.tsx +0 -21
- package/registry/nocobase-auth-wecom/demo.tsx +0 -23
- package/registry/nocobase-auth-wecom/extension.tsx +0 -49
- package/registry/nocobase-auth-wecom/index.ts +0 -1
- package/registry/nocobase-auth-wecom/use-wecom-sign-in.ts +0 -62
- package/registry/nocobase-auth-wecom/wecom-sign-in-button.tsx +0 -70
- package/registry/nocobase-i18n/README.md +0 -44
- package/registry/nocobase-i18n/components/index.ts +0 -1
- package/registry/nocobase-i18n/components/language-switcher.tsx +0 -138
- package/registry/nocobase-i18n/demo/index.tsx +0 -209
- package/registry/nocobase-i18n/demo/prompt-generator.tsx +0 -132
- package/registry/nocobase-i18n/extension.tsx +0 -45
- package/registry/nocobase-i18n/index.ts +0 -7
- package/registry/nocobase-i18n/locales/en-US.ts +0 -39
- package/registry/nocobase-i18n/locales/index.ts +0 -8
- package/registry/nocobase-i18n/locales/zh-CN.ts +0 -35
- package/registry/nocobase-i18n/provider.tsx +0 -44
- package/registry/nocobase-i18n/server-resources.ts +0 -166
- package/registry/nocobase-i18n/tests/i18n-regression.mjs +0 -51
- package/registry.config.json +0 -302
- package/scripts/registry.mjs +0 -164
- package/src/components/access-control/resource-access-guard.tsx +0 -21
- package/src/components/access-control/use-acl-runtime.ts +0 -28
- package/src/lib/nocobase/acl/action.ts +0 -147
- package/src/pages/users/layout.tsx +0 -15
- package/src/pages/users/show.tsx +0 -278
- /package/{registry → src/extensions}/nocobase-acl/components/index.ts +0 -0
- /package/{registry → src/extensions}/nocobase-acl/components/role-options.ts +0 -0
- /package/{registry → src/extensions}/nocobase-acl/demo/components.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-acl/demo/lazy-route.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-acl/demo/role-switcher-prompt-generator.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-acl/demo/scenario-section.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-acl/index.ts +0 -0
- /package/{registry → src/extensions}/nocobase-ai/adapters/react-hook-form.ts +0 -0
- /package/{registry → src/extensions}/nocobase-ai/assets/nocobase-ai-chat.svg +0 -0
- /package/{registry → src/extensions}/nocobase-ai/components/ai-root-provider.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-ai/components/chat/ai-employee-avatar.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-ai/components/chat/chat-attachment.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-ai/components/chat/chat-compact.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-ai/components/chat/chat-empty-state.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-ai/components/chat/chat-header.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-ai/components/chat/chat-history-dialog.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-ai/components/chat/chat-message.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-ai/components/chat/chat-window.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-ai/components/chat/conversation-list.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-ai/components/chat/markdown-message.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-ai/components/chat/model-select-options.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-ai/components/chat/reasoning-panel.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-ai/components/chat/sub-agent-conversation.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-ai/components/chat/user-prompt-editor.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-ai/components/chat/work-context-chip.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-ai/components/page-elements/ai-form.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-ai/components/page-elements/page-element-provider.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-ai/components/surfaces/chat-inline.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-ai/components/surfaces/chat-page.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-ai/components/surfaces/chat-side-panel-layout.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-ai/components/surfaces/chat-surface-actions.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-ai/components/tools/builtin-tool-renderers.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-ai/components/tools/business-report-dialog.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-ai/components/tools/business-report-renderer.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-ai/components/tools/business-report-utils.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-ai/components/tools/chart-renderer.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-ai/components/tools/echarts-preview.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-ai/components/tools/echarts-runtime-advanced.ts +0 -0
- /package/{registry → src/extensions}/nocobase-ai/components/tools/echarts-runtime-common.ts +0 -0
- /package/{registry → src/extensions}/nocobase-ai/components/tools/echarts-runtime-components.ts +0 -0
- /package/{registry → src/extensions}/nocobase-ai/components/tools/echarts-runtime-hierarchy.ts +0 -0
- /package/{registry → src/extensions}/nocobase-ai/components/tools/echarts-runtime.ts +0 -0
- /package/{registry → src/extensions}/nocobase-ai/components/tools/sub-agent-renderer.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-ai/components/tools/suggestions-renderer.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-ai/components/tools/tool-renderer-provider.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-ai/components/tools/tool-renderer-utils.ts +0 -0
- /package/{registry → src/extensions}/nocobase-ai/components/tools/workflow-renderer.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-ai/components/triggers/ai-employee-shortcut.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-ai/demo/interaction-showcase.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-ai/demo/page-context-prompt-generator.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-ai/demo/page-context.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-ai/demo/page-element-showcase.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-ai/demo/prompt-card.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-ai/demo/shortcut.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-ai/index.ts +0 -0
- /package/{registry → src/extensions}/nocobase-ai/providers/avatars.ts +0 -0
- /package/{registry → src/extensions}/nocobase-ai/providers/chat-controller.ts +0 -0
- /package/{registry → src/extensions}/nocobase-ai/providers/chat-message-utils.ts +0 -0
- /package/{registry → src/extensions}/nocobase-ai/providers/chat-reducer.ts +0 -0
- /package/{registry → src/extensions}/nocobase-ai/providers/chat-task-utils.ts +0 -0
- /package/{registry → src/extensions}/nocobase-ai/providers/chat-transport.ts +0 -0
- /package/{registry → src/extensions}/nocobase-ai/providers/form-registry.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-ai/providers/frontend-tool-registry.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-ai/providers/index.ts +0 -0
- /package/{registry → src/extensions}/nocobase-ai/providers/model.ts +0 -0
- /package/{registry → src/extensions}/nocobase-ai/providers/page-context.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-ai/providers/stream-coalescer.ts +0 -0
- /package/{registry → src/extensions}/nocobase-ai/providers/stream-event-utils.ts +0 -0
- /package/{registry → src/extensions}/nocobase-ai/providers/stream-parser.ts +0 -0
- /package/{registry → src/extensions}/nocobase-ai/providers/sub-agent-stream.ts +0 -0
- /package/{registry → src/extensions}/nocobase-ai/providers/types.ts +0 -0
- /package/{registry → src/extensions}/nocobase-ai/providers/ui-message-stream.ts +0 -0
- /package/{registry → src/extensions}/nocobase-ai/providers/use-automatic-tool-approval.ts +0 -0
- /package/{registry → src/extensions}/nocobase-ai/providers/use-chat-message-actions.ts +0 -0
- /package/{registry → src/extensions}/nocobase-ai/providers/use-chat-runtime.ts +0 -0
- /package/{registry → src/extensions}/nocobase-ai/providers/use-conversation-catalog.ts +0 -0
- /package/{registry → src/extensions}/nocobase-ai/providers/use-conversation-history.ts +0 -0
- /package/{registry → src/extensions}/nocobase-ai/services/index.ts +0 -0
- /package/{registry → src/extensions}/nocobase-ai/services/nocobase-ai-service.ts +0 -0
- /package/{registry → src/extensions}/nocobase-ai/services/types.ts +0 -0
- /package/{registry → src/extensions}/nocobase-route-surfaces/demo/lazy-route.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-route-surfaces/demo/prompt-generator.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-route-surfaces/index.ts +0 -0
- /package/{registry → src/extensions}/nocobase-route-surfaces/route-dialog.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-route-surfaces/route-drawer.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-route-surfaces/route-page.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-route-surfaces/route-surface-context.ts +0 -0
- /package/{registry → src/extensions}/nocobase-route-surfaces/use-refine-unsaved-changes.tsx +0 -0
- /package/{registry → src/extensions}/nocobase-route-surfaces/use-route-surface-close.ts +0 -0
- /package/{registry → src/extensions}/nocobase-route-surfaces/use-route-surface-state.ts +0 -0
- /package/src/{pages/users → extensions/nocobase-users-example}/form-fields.tsx +0 -0
- /package/src/{pages/users → extensions/nocobase-users-example}/index.ts +0 -0
- /package/src/{pages/users → extensions/nocobase-users-example}/role-badges.tsx +0 -0
- /package/src/{pages/users → extensions/nocobase-users-example}/role-utils.ts +0 -0
- /package/src/{pages/users → extensions/nocobase-users-example}/types.ts +0 -0
|
@@ -1,15 +1,42 @@
|
|
|
1
1
|
import type { AccessControlProvider } from "@refinedev/core";
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
aclStore,
|
|
5
|
+
evaluateAccess,
|
|
6
|
+
getAclState,
|
|
6
7
|
loadAcl,
|
|
8
|
+
type AclAccessRequest,
|
|
9
|
+
type RoleConstraint,
|
|
7
10
|
} from "@/lib/nocobase/acl";
|
|
8
11
|
|
|
12
|
+
const toAclAccessRequest = ({
|
|
13
|
+
resource,
|
|
14
|
+
action,
|
|
15
|
+
params,
|
|
16
|
+
}: Parameters<AccessControlProvider["can"]>[0]): AclAccessRequest => ({
|
|
17
|
+
resource,
|
|
18
|
+
action,
|
|
19
|
+
id: params?.id,
|
|
20
|
+
field: typeof params?.field === "string" ? params.field : undefined,
|
|
21
|
+
dataSourceKey:
|
|
22
|
+
typeof params?.dataSourceKey === "string"
|
|
23
|
+
? params.dataSourceKey
|
|
24
|
+
: undefined,
|
|
25
|
+
roles: params?.roles as RoleConstraint | undefined,
|
|
26
|
+
meta: params?.meta as Record<string, unknown> | undefined,
|
|
27
|
+
resourceItem: params?.resource,
|
|
28
|
+
});
|
|
29
|
+
|
|
9
30
|
export const accessControlProvider: AccessControlProvider = {
|
|
10
|
-
can: async (
|
|
11
|
-
const
|
|
12
|
-
const can =
|
|
31
|
+
can: async (request) => {
|
|
32
|
+
const state = await loadAcl();
|
|
33
|
+
const can =
|
|
34
|
+
state.status === "ready" &&
|
|
35
|
+
evaluateAccess(
|
|
36
|
+
state.permissions,
|
|
37
|
+
toAclAccessRequest(request),
|
|
38
|
+
aclStore.recordPermissions.getPermission
|
|
39
|
+
);
|
|
13
40
|
|
|
14
41
|
return {
|
|
15
42
|
can,
|
|
@@ -29,6 +56,14 @@ export const accessControlProvider: AccessControlProvider = {
|
|
|
29
56
|
},
|
|
30
57
|
};
|
|
31
58
|
|
|
32
|
-
export const canAccessCurrentAcl = (
|
|
33
|
-
|
|
34
|
-
|
|
59
|
+
export const canAccessCurrentAcl = (request: AclAccessRequest) => {
|
|
60
|
+
const state = getAclState();
|
|
61
|
+
return (
|
|
62
|
+
state.status === "ready" &&
|
|
63
|
+
evaluateAccess(
|
|
64
|
+
state.permissions,
|
|
65
|
+
request,
|
|
66
|
+
aclStore.recordPermissions.getPermission
|
|
67
|
+
)
|
|
68
|
+
);
|
|
69
|
+
};
|
package/src/providers/auth.ts
CHANGED
|
@@ -30,7 +30,7 @@ type NocoBaseSignOutResponse = {
|
|
|
30
30
|
};
|
|
31
31
|
|
|
32
32
|
type CurrentUserCache = {
|
|
33
|
-
|
|
33
|
+
sessionKey: string;
|
|
34
34
|
user: NocoBaseUser;
|
|
35
35
|
expiresAt: number;
|
|
36
36
|
};
|
|
@@ -51,10 +51,14 @@ const clearCurrentUserCache = () => {
|
|
|
51
51
|
|
|
52
52
|
const getCurrentUser = async (): Promise<NocoBaseUser> => {
|
|
53
53
|
const token = nocobaseClient.getToken();
|
|
54
|
-
|
|
54
|
+
const sessionKey = token ?? "cookie";
|
|
55
55
|
|
|
56
56
|
const cached = currentUserCache;
|
|
57
|
-
if (
|
|
57
|
+
if (
|
|
58
|
+
cached &&
|
|
59
|
+
cached.sessionKey === sessionKey &&
|
|
60
|
+
cached.expiresAt > Date.now()
|
|
61
|
+
) {
|
|
58
62
|
return cached.user;
|
|
59
63
|
}
|
|
60
64
|
|
|
@@ -63,10 +67,12 @@ const getCurrentUser = async (): Promise<NocoBaseUser> => {
|
|
|
63
67
|
currentUserRequest = (async () => {
|
|
64
68
|
const user = await nocobaseClient.action<NocoBaseUser>("auth", "check", {
|
|
65
69
|
token,
|
|
66
|
-
|
|
70
|
+
// A default authenticator header would override the server's
|
|
71
|
+
// authenticator cookie during a Cookie-only SSO session.
|
|
72
|
+
authenticator: token ? undefined : null,
|
|
67
73
|
});
|
|
68
74
|
currentUserCache = {
|
|
69
|
-
|
|
75
|
+
sessionKey: nocobaseClient.getToken() ?? "cookie",
|
|
70
76
|
user,
|
|
71
77
|
expiresAt: Date.now() + CURRENT_USER_CACHE_MS,
|
|
72
78
|
};
|
|
@@ -216,22 +222,18 @@ export const authProvider: AuthProvider = {
|
|
|
216
222
|
const token = nocobaseClient.getToken();
|
|
217
223
|
let redirect: string | undefined;
|
|
218
224
|
try {
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
redirect = result?.redirect;
|
|
230
|
-
}
|
|
225
|
+
const result = await nocobaseClient.action<NocoBaseSignOutResponse>(
|
|
226
|
+
"auth",
|
|
227
|
+
"signOut",
|
|
228
|
+
{
|
|
229
|
+
method: "POST",
|
|
230
|
+
token,
|
|
231
|
+
authenticator: token ? undefined : null,
|
|
232
|
+
}
|
|
233
|
+
);
|
|
234
|
+
redirect = result?.redirect;
|
|
231
235
|
} finally {
|
|
232
|
-
nocobaseClient.
|
|
233
|
-
nocobaseClient.setAuthenticator(null);
|
|
234
|
-
nocobaseClient.setRole(null);
|
|
236
|
+
nocobaseClient.clearAuthentication();
|
|
235
237
|
clearCurrentUserCache();
|
|
236
238
|
clearAcl();
|
|
237
239
|
}
|
|
@@ -249,9 +251,7 @@ export const authProvider: AuthProvider = {
|
|
|
249
251
|
await getCurrentUser();
|
|
250
252
|
return { authenticated: true };
|
|
251
253
|
} catch {
|
|
252
|
-
nocobaseClient.
|
|
253
|
-
nocobaseClient.setAuthenticator(null);
|
|
254
|
-
nocobaseClient.setRole(null);
|
|
254
|
+
nocobaseClient.clearAuthentication();
|
|
255
255
|
clearCurrentUserCache();
|
|
256
256
|
clearAcl();
|
|
257
257
|
return { authenticated: false, redirectTo: "/login" };
|
|
@@ -291,9 +291,7 @@ export const authProvider: AuthProvider = {
|
|
|
291
291
|
(error as { status?: number; statusCode?: number }).statusCode;
|
|
292
292
|
|
|
293
293
|
if (status === 401) {
|
|
294
|
-
nocobaseClient.
|
|
295
|
-
nocobaseClient.setAuthenticator(null);
|
|
296
|
-
nocobaseClient.setRole(null);
|
|
294
|
+
nocobaseClient.clearAuthentication();
|
|
297
295
|
clearCurrentUserCache();
|
|
298
296
|
clearAcl();
|
|
299
297
|
return { logout: true, redirectTo: "/login" };
|
|
@@ -36,9 +36,5 @@ const toProxyRelativeUrl = (url: string, target?: string) => {
|
|
|
36
36
|
|
|
37
37
|
export const API_URL = toProxyRelativeUrl(rawApiUrl, proxyTarget);
|
|
38
38
|
export const API_ORIGIN = getDefaultProxyTarget(rawApiUrl);
|
|
39
|
-
export const NOCOBASE_TOKEN_KEY = "nocobase-auth-token";
|
|
40
|
-
export const NOCOBASE_AUTHENTICATOR_KEY = "nocobase-authenticator";
|
|
41
|
-
export const NOCOBASE_ROLE_KEY = "nocobase-auth-role";
|
|
42
|
-
export const NOCOBASE_LOCALE_KEY = "nocobase-locale";
|
|
43
39
|
export const NOCOBASE_AUTHENTICATOR =
|
|
44
40
|
import.meta.env.NOCOBASE_AUTHENTICATOR ?? "basic";
|
package/src/providers/data.ts
CHANGED
|
@@ -24,7 +24,6 @@ import type {
|
|
|
24
24
|
|
|
25
25
|
import { nocobaseClient } from "@/lib/nocobase/client";
|
|
26
26
|
import {
|
|
27
|
-
notifyRecordPermissionsChanged,
|
|
28
27
|
resolveAclDataSourceKey,
|
|
29
28
|
type ResourceAcl,
|
|
30
29
|
updateRecordPermissions,
|
|
@@ -122,9 +121,7 @@ const request = async <T>(
|
|
|
122
121
|
},
|
|
123
122
|
body: options.body,
|
|
124
123
|
token: options.meta?.token,
|
|
125
|
-
headers: dataSourceKey
|
|
126
|
-
? { "X-Data-Source": dataSourceKey }
|
|
127
|
-
: undefined,
|
|
124
|
+
headers: dataSourceKey ? { "X-Data-Source": dataSourceKey } : undefined,
|
|
128
125
|
unwrap: options.unwrapData === false ? "none" : "data",
|
|
129
126
|
});
|
|
130
127
|
};
|
|
@@ -200,9 +197,7 @@ export const dataProvider: DataProvider = {
|
|
|
200
197
|
? { rows: response.data, count: response.meta?.count }
|
|
201
198
|
: response.data ?? response;
|
|
202
199
|
const records = list.rows ?? [];
|
|
203
|
-
|
|
204
|
-
notifyRecordPermissionsChanged();
|
|
205
|
-
}
|
|
200
|
+
cacheAllowedActions({ resource, records, response, meta });
|
|
206
201
|
|
|
207
202
|
return {
|
|
208
203
|
data: records,
|
|
@@ -226,16 +221,12 @@ export const dataProvider: DataProvider = {
|
|
|
226
221
|
}
|
|
227
222
|
);
|
|
228
223
|
const data = getResponseData(response);
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
})
|
|
236
|
-
) {
|
|
237
|
-
notifyRecordPermissionsChanged();
|
|
238
|
-
}
|
|
224
|
+
cacheAllowedActions({
|
|
225
|
+
resource,
|
|
226
|
+
records: [data],
|
|
227
|
+
response: response as NocoBaseListResponse<TData>,
|
|
228
|
+
meta,
|
|
229
|
+
});
|
|
239
230
|
return {
|
|
240
231
|
data,
|
|
241
232
|
};
|
|
@@ -256,17 +247,14 @@ export const dataProvider: DataProvider = {
|
|
|
256
247
|
)
|
|
257
248
|
);
|
|
258
249
|
const data = responses.map(getResponseData);
|
|
259
|
-
let permissionsChanged = false;
|
|
260
250
|
responses.forEach((response, index) => {
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
}) || permissionsChanged;
|
|
251
|
+
cacheAllowedActions({
|
|
252
|
+
resource,
|
|
253
|
+
records: [data[index]],
|
|
254
|
+
response: response as NocoBaseListResponse<TData>,
|
|
255
|
+
meta,
|
|
256
|
+
});
|
|
268
257
|
});
|
|
269
|
-
if (permissionsChanged) notifyRecordPermissionsChanged();
|
|
270
258
|
return { data };
|
|
271
259
|
},
|
|
272
260
|
|
|
@@ -17,3 +17,43 @@ export const getPortalBase = () =>
|
|
|
17
17
|
|
|
18
18
|
export const getRuntimeApiUrl = () =>
|
|
19
19
|
getWindowValue("NOCOBASE_API_URL") ?? import.meta.env.NOCOBASE_API_URL;
|
|
20
|
+
|
|
21
|
+
const getAppNameFromPortalBase = (base: string) =>
|
|
22
|
+
base.match(/\/x\/apps\/([^/]+)(?:\/|$)/)?.[1];
|
|
23
|
+
|
|
24
|
+
const getAppNameFromApiUrl = (apiUrl?: string) =>
|
|
25
|
+
apiUrl?.match(/\/api\/__app\/([^/?#]+)(?:[/?#]|$)/)?.[1];
|
|
26
|
+
|
|
27
|
+
export const resolveNocoBaseAppName = (portalBase: string, apiUrl?: string) =>
|
|
28
|
+
getAppNameFromPortalBase(portalBase) ??
|
|
29
|
+
getAppNameFromApiUrl(apiUrl) ??
|
|
30
|
+
"main";
|
|
31
|
+
|
|
32
|
+
export const getNocoBaseAppName = () =>
|
|
33
|
+
resolveNocoBaseAppName(getPortalBase(), getRuntimeApiUrl());
|
|
34
|
+
|
|
35
|
+
export const resolvePortalUrl = (path = "/") => {
|
|
36
|
+
if (typeof window === "undefined") return path;
|
|
37
|
+
if (/^[a-z][a-z\d+.-]*:/i.test(path)) return path;
|
|
38
|
+
|
|
39
|
+
const portalBase = getPortalBase();
|
|
40
|
+
const relativePath = path.replace(/^\/+/, "");
|
|
41
|
+
const portalUrl = new URL(
|
|
42
|
+
relativePath,
|
|
43
|
+
`${window.location.origin}${portalBase}`
|
|
44
|
+
);
|
|
45
|
+
const apiUrl = new URL(
|
|
46
|
+
getRuntimeApiUrl() || "/api",
|
|
47
|
+
window.location.origin
|
|
48
|
+
);
|
|
49
|
+
|
|
50
|
+
// Same-origin deployments should use a root-relative callback. Besides
|
|
51
|
+
// avoiding unnecessary origin coupling, this remains compatible with older
|
|
52
|
+
// SSO plugins that only accept NocoBase-local redirect paths. A standalone
|
|
53
|
+
// Portal dev server keeps the absolute URL so the callback can return to
|
|
54
|
+
// Vite instead of the deployed Portal route.
|
|
55
|
+
if (apiUrl.origin === portalUrl.origin) {
|
|
56
|
+
return `${portalUrl.pathname}${portalUrl.search}${portalUrl.hash}`;
|
|
57
|
+
}
|
|
58
|
+
return portalUrl.toString();
|
|
59
|
+
};
|
package/src/vite-env.d.ts
CHANGED
|
@@ -3,4 +3,13 @@
|
|
|
3
3
|
interface Window {
|
|
4
4
|
NOCOBASE_PORTAL_BASE?: string;
|
|
5
5
|
NOCOBASE_API_URL?: string;
|
|
6
|
+
__nocobase_api_client_storage_prefix__?: string;
|
|
7
|
+
__nocobase_api_client_storage_type__?: string;
|
|
8
|
+
__nocobase_api_client_share_token__?: boolean | string;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
interface ImportMetaEnv {
|
|
12
|
+
readonly API_CLIENT_STORAGE_PREFIX?: string;
|
|
13
|
+
readonly API_CLIENT_STORAGE_TYPE?: string;
|
|
14
|
+
readonly API_CLIENT_SHARE_TOKEN?: string;
|
|
6
15
|
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import assert from "node:assert/strict";
|
|
2
|
+
import { createServer } from "vite";
|
|
3
|
+
|
|
4
|
+
const server = await createServer({
|
|
5
|
+
appType: "custom",
|
|
6
|
+
logLevel: "silent",
|
|
7
|
+
server: { middlewareMode: true },
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
const createStorage = () => {
|
|
11
|
+
const values = new Map();
|
|
12
|
+
return {
|
|
13
|
+
getItem: (key) => values.get(key) ?? null,
|
|
14
|
+
setItem: (key, value) => values.set(key, value),
|
|
15
|
+
removeItem: (key) => values.delete(key),
|
|
16
|
+
};
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
const { AuthSession } = await server.ssrLoadModule(
|
|
21
|
+
"/src/lib/nocobase/auth-session.ts"
|
|
22
|
+
);
|
|
23
|
+
const { resolveNocoBaseAppName, resolvePortalUrl } = await server.ssrLoadModule(
|
|
24
|
+
"/src/providers/runtime-config.ts"
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
assert.equal(
|
|
28
|
+
resolveNocoBaseAppName(
|
|
29
|
+
"/nocobase/x/apps/crm/customer/",
|
|
30
|
+
"/nocobase/api/__app/crm"
|
|
31
|
+
),
|
|
32
|
+
"crm"
|
|
33
|
+
);
|
|
34
|
+
assert.equal(
|
|
35
|
+
resolveNocoBaseAppName("/x/customer/", "/api/__app/analytics"),
|
|
36
|
+
"analytics"
|
|
37
|
+
);
|
|
38
|
+
assert.equal(resolveNocoBaseAppName("/x/customer/", "/api"), "main");
|
|
39
|
+
|
|
40
|
+
const originalWindow = globalThis.window;
|
|
41
|
+
Object.defineProperty(globalThis, "window", {
|
|
42
|
+
configurable: true,
|
|
43
|
+
value: {
|
|
44
|
+
location: { origin: "http://localhost:14000" },
|
|
45
|
+
NOCOBASE_API_URL: "/api",
|
|
46
|
+
NOCOBASE_PORTAL_BASE: "/x/demo/",
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
assert.equal(
|
|
50
|
+
resolvePortalUrl("/users?tab=active#list"),
|
|
51
|
+
"/x/demo/users?tab=active#list"
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
window.NOCOBASE_API_URL = "/api/__app/crm";
|
|
55
|
+
window.NOCOBASE_PORTAL_BASE = "/x/apps/crm/customer/";
|
|
56
|
+
assert.equal(
|
|
57
|
+
resolvePortalUrl("/users?tab=active#list"),
|
|
58
|
+
"/x/apps/crm/customer/users?tab=active#list"
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
window.NOCOBASE_API_URL = "http://127.0.0.1:13000/api";
|
|
62
|
+
window.NOCOBASE_PORTAL_BASE = "/x/demo/";
|
|
63
|
+
assert.equal(
|
|
64
|
+
resolvePortalUrl("/users?tab=active#list"),
|
|
65
|
+
"http://localhost:14000/x/demo/users?tab=active#list"
|
|
66
|
+
);
|
|
67
|
+
|
|
68
|
+
if (originalWindow === undefined) {
|
|
69
|
+
delete globalThis.window;
|
|
70
|
+
} else {
|
|
71
|
+
Object.defineProperty(globalThis, "window", {
|
|
72
|
+
configurable: true,
|
|
73
|
+
value: originalWindow,
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
const main = new AuthSession({ appName: "main", storage: createStorage() });
|
|
78
|
+
assert.equal(main.getStorageKey("token"), "NOCOBASE_TOKEN");
|
|
79
|
+
assert.equal(main.getStorageKey("auth"), "NOCOBASE_AUTH");
|
|
80
|
+
assert.equal(main.getStorageKey("role"), "NOCOBASE_ROLE");
|
|
81
|
+
|
|
82
|
+
const subApp = new AuthSession({
|
|
83
|
+
appName: "crm",
|
|
84
|
+
storage: createStorage(),
|
|
85
|
+
});
|
|
86
|
+
assert.equal(subApp.getStorageKey("token"), "NOCOBASE_CRM_TOKEN");
|
|
87
|
+
assert.equal(subApp.getStorageKey("auth"), "NOCOBASE_CRM_AUTH");
|
|
88
|
+
assert.equal(subApp.getStorageKey("role"), "NOCOBASE_CRM_ROLE");
|
|
89
|
+
|
|
90
|
+
const sharedToken = new AuthSession({
|
|
91
|
+
appName: "crm",
|
|
92
|
+
shareToken: true,
|
|
93
|
+
storage: createStorage(),
|
|
94
|
+
});
|
|
95
|
+
assert.equal(sharedToken.getStorageKey("token"), "NOCOBASE_TOKEN");
|
|
96
|
+
assert.equal(sharedToken.getStorageKey("auth"), "NOCOBASE_CRM_AUTH");
|
|
97
|
+
|
|
98
|
+
console.log("NocoBase authentication session regression tests passed");
|
|
99
|
+
} finally {
|
|
100
|
+
await server.close();
|
|
101
|
+
}
|
package/tsconfig.json
CHANGED
package/vite.config.ts
CHANGED
|
@@ -37,6 +37,9 @@ const defaultRuntimeConfig = `<!-- nocobase-runtime-config:start -->
|
|
|
37
37
|
<script>
|
|
38
38
|
window.NOCOBASE_PORTAL_BASE = "/";
|
|
39
39
|
window.NOCOBASE_API_URL = "/api";
|
|
40
|
+
window.__nocobase_api_client_storage_prefix__ = window.__nocobase_api_client_storage_prefix__ ?? "NOCOBASE_";
|
|
41
|
+
window.__nocobase_api_client_storage_type__ = window.__nocobase_api_client_storage_type__ ?? "localStorage";
|
|
42
|
+
window.__nocobase_api_client_share_token__ = window.__nocobase_api_client_share_token__ ?? false;
|
|
40
43
|
</script>
|
|
41
44
|
<!-- nocobase-runtime-config:end -->
|
|
42
45
|
`;
|
|
@@ -96,13 +99,18 @@ export default defineConfig(({ mode }) => {
|
|
|
96
99
|
: undefined;
|
|
97
100
|
|
|
98
101
|
const portalBase = normalizeBase(env.NOCOBASE_PORTAL_BASE);
|
|
102
|
+
const registrySourceRoot = path.resolve(__dirname, "./registry");
|
|
103
|
+
const extensionsRoot = fs.existsSync(registrySourceRoot)
|
|
104
|
+
? registrySourceRoot
|
|
105
|
+
: path.resolve(__dirname, "./src/extensions");
|
|
99
106
|
|
|
100
107
|
return {
|
|
101
108
|
base: portalBase,
|
|
102
|
-
envPrefix: ["VITE_", "NOCOBASE_"],
|
|
109
|
+
envPrefix: ["VITE_", "NOCOBASE_", "API_CLIENT_"],
|
|
103
110
|
plugins: [react(), tailwindcss(), copyRawIndexHtmlPlugin(portalBase)],
|
|
104
111
|
resolve: {
|
|
105
112
|
alias: {
|
|
113
|
+
"@/extensions": extensionsRoot,
|
|
106
114
|
"@": path.resolve(__dirname, "./src"),
|
|
107
115
|
},
|
|
108
116
|
},
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
# NocoBase ACL UI
|
|
2
|
-
|
|
3
|
-
Reusable ACL composition components for the NocoBase Refine starter.
|
|
4
|
-
|
|
5
|
-
After installation, import the components from `@/extensions/nocobase-acl`.
|
|
6
|
-
|
|
7
|
-
- `AclPage` combines page-level permissions.
|
|
8
|
-
- `AclRegion` hides or replaces individual data regions.
|
|
9
|
-
- `AclField` applies NocoBase field whitelists.
|
|
10
|
-
- `RoleSwitcher` can be placed in any application surface. It supports
|
|
11
|
-
normal roles, Anonymous when enabled, and Full permissions through the
|
|
12
|
-
`__union__` role when the system role mode allows it.
|
|
13
|
-
|
|
14
|
-
Mark non-collection resources with `meta.acl.type = "authenticated"`, or use
|
|
15
|
-
the `collection`, `snippet`, and `route` ACL metadata variants when the resource
|
|
16
|
-
should participate in NocoBase permission checks.
|
|
17
|
-
|
|
18
|
-
The underlying `accessControlProvider`, `roles:check` cache, record permissions,
|
|
19
|
-
and Refine integration are provided by the compatible Starter.
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import type { AppExtension } from "@/app/extension";
|
|
2
|
-
import { Blocks, PanelsTopLeft, ShieldCheck } from "lucide-react";
|
|
3
|
-
import { lazy } from "react";
|
|
4
|
-
import { Outlet, Route } from "react-router";
|
|
5
|
-
import { LazyAclRoute } from "./demo/lazy-route";
|
|
6
|
-
|
|
7
|
-
const AclComponentsPage = lazy(() =>
|
|
8
|
-
import("./demo/components").then((module) => ({
|
|
9
|
-
default: module.AclComponentsPage,
|
|
10
|
-
}))
|
|
11
|
-
);
|
|
12
|
-
const AclPatternsPage = lazy(() =>
|
|
13
|
-
import("./demo").then((module) => ({ default: module.AclPatternsPage }))
|
|
14
|
-
);
|
|
15
|
-
|
|
16
|
-
const nocobaseAclExtension: AppExtension = {
|
|
17
|
-
id: "nocobase-acl",
|
|
18
|
-
resources: [
|
|
19
|
-
{
|
|
20
|
-
name: "acl-integration",
|
|
21
|
-
meta: {
|
|
22
|
-
label: "Access control",
|
|
23
|
-
icon: <ShieldCheck />,
|
|
24
|
-
description: "NocoBase ACL integration for admin applications.",
|
|
25
|
-
acl: { type: "authenticated" },
|
|
26
|
-
},
|
|
27
|
-
},
|
|
28
|
-
{
|
|
29
|
-
name: "acl-components",
|
|
30
|
-
list: "/acl",
|
|
31
|
-
meta: {
|
|
32
|
-
parent: "acl-integration",
|
|
33
|
-
label: "Role switcher",
|
|
34
|
-
icon: <Blocks />,
|
|
35
|
-
acl: { type: "authenticated" },
|
|
36
|
-
},
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
name: "acl-patterns",
|
|
40
|
-
list: "/acl/patterns",
|
|
41
|
-
meta: {
|
|
42
|
-
parent: "acl-integration",
|
|
43
|
-
label: "Permission patterns",
|
|
44
|
-
icon: <PanelsTopLeft />,
|
|
45
|
-
acl: { type: "authenticated" },
|
|
46
|
-
},
|
|
47
|
-
},
|
|
48
|
-
],
|
|
49
|
-
routes: (
|
|
50
|
-
<Route key="nocobase-acl" path="/acl" element={<Outlet />}>
|
|
51
|
-
<Route
|
|
52
|
-
index
|
|
53
|
-
element={
|
|
54
|
-
<LazyAclRoute>
|
|
55
|
-
<AclComponentsPage />
|
|
56
|
-
</LazyAclRoute>
|
|
57
|
-
}
|
|
58
|
-
/>
|
|
59
|
-
<Route
|
|
60
|
-
path="patterns"
|
|
61
|
-
element={
|
|
62
|
-
<LazyAclRoute>
|
|
63
|
-
<AclPatternsPage />
|
|
64
|
-
</LazyAclRoute>
|
|
65
|
-
}
|
|
66
|
-
/>
|
|
67
|
-
</Route>
|
|
68
|
-
),
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
export default nocobaseAclExtension;
|