@nocobase/portal-template-default 1.0.9 → 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/dist/assets/CoordinateSystem-C8P-Cleg.js +0 -1
- package/dist/assets/LegendVisualProvider-Bdgkckq-.js +0 -1
- package/dist/assets/LineDraw-C0m1GONT.js +0 -1
- package/dist/assets/SymbolDraw-CCospe5G.js +0 -1
- package/dist/assets/VisualMapping-Cbv1v7Cd.js +0 -1
- package/dist/assets/ai-employee-shortcut-B253WWow.js +0 -1
- package/dist/assets/calendar-B3dXXyIv.js +0 -1
- package/dist/assets/chat-inline-xpQ9iq4p.js +0 -1
- package/dist/assets/chat-side-panel-layout-BVWsp5rr.js +0 -1
- package/dist/assets/components-ChhJaNRc.js +0 -20
- package/dist/assets/configuration-gate-Dwdq_lxf.js +0 -1
- package/dist/assets/createClipPathFromCoordSys-uEftn1Mq.js +0 -1
- package/dist/assets/createSeriesDataSimply-CI7l7Ufv.js +0 -1
- package/dist/assets/customGraphicKeyframeAnimation-DE3jSfMd.js +0 -3
- package/dist/assets/echarts-preview-C-cNUtJF.js +0 -1
- package/dist/assets/echarts-runtime-CEgJbv68.js +0 -58
- package/dist/assets/echarts-runtime-advanced-Buhm2BHz.js +0 -1
- package/dist/assets/echarts-runtime-common-DLAdBAIa.js +0 -1
- package/dist/assets/echarts-runtime-components-ypnyLkYx.js +0 -1
- package/dist/assets/echarts-runtime-hierarchy-ClStquCF.js +0 -1
- package/dist/assets/floating-BarTmn-b.js +0 -13
- package/dist/assets/index-BJIcYTdc.js +0 -53
- package/dist/assets/index-C6xNKxpg.js +0 -656
- package/dist/assets/index-D4JQi1TM.js +0 -54
- package/dist/assets/index-YA7-AUO8.css +0 -1
- package/dist/assets/index-g8zWVpP9.js +0 -23
- package/dist/assets/labelHelper-C137W5gU.js +0 -1
- package/dist/assets/nocobase-ai-chat-VTMaZFQB.svg +0 -50
- package/dist/assets/page-context-Cxx11gzg.js +0 -73
- package/dist/assets/prompt-card-BsYMW_rq.js +0 -1
- package/dist/assets/sectorHelper-Fqgz3uEk.js +0 -1
- package/dist/assets/shortcut-xtghDP63.js +0 -47
- package/dist/assets/static.browser-CfQQzERe.js +0 -30
- package/dist/assets/switch-DrxImI8F.js +0 -1
- package/dist/assets/tool-cards-BGfsY8JF.js +0 -41
- package/dist/favicon.ico +0 -0
- package/dist/index.html +0 -40
- package/dist/index.raw.html +0 -46
- package/dist/logo-dark.png +0 -0
- package/dist/logo-mark-dark.png +0 -0
- package/dist/logo-mark.png +0 -0
- package/dist/logo.png +0 -0
- 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
package/registry.config.json
DELETED
|
@@ -1,302 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "nocobase-ai",
|
|
3
|
-
"homepage": "https://www.nocobase.com",
|
|
4
|
-
"items": [
|
|
5
|
-
{
|
|
6
|
-
"name": "route-surfaces",
|
|
7
|
-
"type": "registry:lib",
|
|
8
|
-
"title": "NocoBase Route Surfaces",
|
|
9
|
-
"description": "URL-backed drawer, dialog, and page containers with nested drawer stacking and a shared close lifecycle.",
|
|
10
|
-
"dependencies": [
|
|
11
|
-
"@base-ui/react@^1.6.0",
|
|
12
|
-
"@refinedev/core@^5.0.8",
|
|
13
|
-
"lucide-react@^0.487.0",
|
|
14
|
-
"react-router@^7.0.2"
|
|
15
|
-
],
|
|
16
|
-
"registryDependencies": [
|
|
17
|
-
"alert-dialog",
|
|
18
|
-
"badge",
|
|
19
|
-
"button",
|
|
20
|
-
"card",
|
|
21
|
-
"input",
|
|
22
|
-
"label",
|
|
23
|
-
"select",
|
|
24
|
-
"textarea"
|
|
25
|
-
],
|
|
26
|
-
"docs": "Provides presentation containers plus an integrated Demo and Prompt generator. Route definitions, ACL guards, data fetching, and business content remain application-owned.",
|
|
27
|
-
"source": {
|
|
28
|
-
"root": "registry/nocobase-route-surfaces",
|
|
29
|
-
"target": "src/extensions/nocobase-route-surfaces",
|
|
30
|
-
"include": ["."]
|
|
31
|
-
}
|
|
32
|
-
},
|
|
33
|
-
{
|
|
34
|
-
"name": "i18n",
|
|
35
|
-
"type": "registry:block",
|
|
36
|
-
"title": "NocoBase i18n",
|
|
37
|
-
"description": "Optional NocoBase server-language resources, user preference persistence, reusable language controls, and an integrated showcase for the Starter's built-in i18n runtime.",
|
|
38
|
-
"dependencies": [
|
|
39
|
-
"@refinedev/core@^5.0.8",
|
|
40
|
-
"lucide-react@^0.487.0",
|
|
41
|
-
"react-router@^7.0.2"
|
|
42
|
-
],
|
|
43
|
-
"registryDependencies": [
|
|
44
|
-
"badge",
|
|
45
|
-
"button",
|
|
46
|
-
"card",
|
|
47
|
-
"dropdown-menu",
|
|
48
|
-
"input",
|
|
49
|
-
"label",
|
|
50
|
-
"select",
|
|
51
|
-
"textarea"
|
|
52
|
-
],
|
|
53
|
-
"docs": "Requires a compatible NocoBase Starter with the built-in i18n provider, shared System Settings bootstrap, and AppExtension Provider/UserMenuItems host fields. The Registry reuses systemSettings:get data and calls app:getLang only for registered dynamic namespaces such as lm-collections.",
|
|
54
|
-
"source": {
|
|
55
|
-
"root": "registry/nocobase-i18n",
|
|
56
|
-
"target": "src/extensions/nocobase-i18n",
|
|
57
|
-
"install": false,
|
|
58
|
-
"include": ["."]
|
|
59
|
-
}
|
|
60
|
-
},
|
|
61
|
-
{
|
|
62
|
-
"name": "auth-oidc",
|
|
63
|
-
"type": "registry:block",
|
|
64
|
-
"title": "NocoBase OIDC Authentication",
|
|
65
|
-
"description": "Dynamic OIDC sign-in adapter, headless sign-in hook, and integrated component demo.",
|
|
66
|
-
"dependencies": [
|
|
67
|
-
"lucide-react@^0.487.0",
|
|
68
|
-
"react-router@^7.0.2"
|
|
69
|
-
],
|
|
70
|
-
"docs": "Requires the Starter authentication runtime and an enabled OIDC authenticator in NocoBase. The default UI is discovered automatically and can be replaced per authentication type or authenticator instance from the application login page.",
|
|
71
|
-
"source": {
|
|
72
|
-
"root": "registry/nocobase-auth-oidc",
|
|
73
|
-
"target": "src/extensions/nocobase-auth-oidc",
|
|
74
|
-
"install": false,
|
|
75
|
-
"include": ["."]
|
|
76
|
-
}
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
"name": "auth-saml",
|
|
80
|
-
"type": "registry:block",
|
|
81
|
-
"title": "NocoBase SAML Authentication",
|
|
82
|
-
"description": "Dynamic SAML sign-in adapter, automatic redirect provider, headless hook, and integrated demo.",
|
|
83
|
-
"dependencies": [
|
|
84
|
-
"lucide-react@^0.487.0",
|
|
85
|
-
"react-router@^7.0.2"
|
|
86
|
-
],
|
|
87
|
-
"docs": "Requires the Starter authentication runtime and an enabled SAML authenticator in NocoBase.",
|
|
88
|
-
"source": {
|
|
89
|
-
"root": "registry/nocobase-auth-saml",
|
|
90
|
-
"target": "src/extensions/nocobase-auth-saml",
|
|
91
|
-
"install": false,
|
|
92
|
-
"include": ["."]
|
|
93
|
-
}
|
|
94
|
-
},
|
|
95
|
-
{
|
|
96
|
-
"name": "auth-cas",
|
|
97
|
-
"type": "registry:block",
|
|
98
|
-
"title": "NocoBase CAS Authentication",
|
|
99
|
-
"description": "Dynamic CAS sign-in adapter, headless sign-in hook, and integrated component demo.",
|
|
100
|
-
"dependencies": [
|
|
101
|
-
"lucide-react@^0.487.0",
|
|
102
|
-
"react-router@^7.0.2"
|
|
103
|
-
],
|
|
104
|
-
"docs": "Requires the Starter authentication runtime and an enabled CAS authenticator in NocoBase.",
|
|
105
|
-
"source": {
|
|
106
|
-
"root": "registry/nocobase-auth-cas",
|
|
107
|
-
"target": "src/extensions/nocobase-auth-cas",
|
|
108
|
-
"install": false,
|
|
109
|
-
"include": ["."]
|
|
110
|
-
}
|
|
111
|
-
},
|
|
112
|
-
{
|
|
113
|
-
"name": "auth-ldap",
|
|
114
|
-
"type": "registry:block",
|
|
115
|
-
"title": "NocoBase LDAP Authentication",
|
|
116
|
-
"description": "Dynamic LDAP account/password form, headless sign-in hook, and integrated component demo.",
|
|
117
|
-
"docs": "Requires the Starter authentication runtime and an enabled LDAP authenticator in NocoBase.",
|
|
118
|
-
"source": {
|
|
119
|
-
"root": "registry/nocobase-auth-ldap",
|
|
120
|
-
"target": "src/extensions/nocobase-auth-ldap",
|
|
121
|
-
"install": false,
|
|
122
|
-
"include": ["."]
|
|
123
|
-
}
|
|
124
|
-
},
|
|
125
|
-
{
|
|
126
|
-
"name": "auth-sms",
|
|
127
|
-
"type": "registry:block",
|
|
128
|
-
"title": "NocoBase SMS Authentication",
|
|
129
|
-
"description": "Dynamic SMS verification-code form, delivery countdown, headless hook, and integrated demo.",
|
|
130
|
-
"docs": "Requires the Starter authentication runtime, an enabled SMS authenticator, and a configured public SMS verifier in NocoBase.",
|
|
131
|
-
"source": {
|
|
132
|
-
"root": "registry/nocobase-auth-sms",
|
|
133
|
-
"target": "src/extensions/nocobase-auth-sms",
|
|
134
|
-
"install": false,
|
|
135
|
-
"include": ["."]
|
|
136
|
-
}
|
|
137
|
-
},
|
|
138
|
-
{
|
|
139
|
-
"name": "auth-wecom",
|
|
140
|
-
"type": "registry:block",
|
|
141
|
-
"title": "NocoBase WeCom Authentication",
|
|
142
|
-
"description": "Dynamic WeCom sign-in adapter, browser automatic login, headless hook, and integrated demo.",
|
|
143
|
-
"dependencies": [
|
|
144
|
-
"lucide-react@^0.487.0",
|
|
145
|
-
"react-router@^7.0.2"
|
|
146
|
-
],
|
|
147
|
-
"docs": "Requires the Starter authentication runtime and an enabled WeCom authenticator in NocoBase.",
|
|
148
|
-
"source": {
|
|
149
|
-
"root": "registry/nocobase-auth-wecom",
|
|
150
|
-
"target": "src/extensions/nocobase-auth-wecom",
|
|
151
|
-
"install": false,
|
|
152
|
-
"include": ["."]
|
|
153
|
-
}
|
|
154
|
-
},
|
|
155
|
-
{
|
|
156
|
-
"name": "auth-dingtalk",
|
|
157
|
-
"type": "registry:block",
|
|
158
|
-
"title": "NocoBase DingTalk Authentication",
|
|
159
|
-
"description": "Dynamic DingTalk sign-in adapter, automatic login, headless hook, and integrated demo.",
|
|
160
|
-
"dependencies": [
|
|
161
|
-
"dingtalk-jsapi@3.1.1",
|
|
162
|
-
"lucide-react@^0.487.0",
|
|
163
|
-
"react-router@^7.0.2"
|
|
164
|
-
],
|
|
165
|
-
"docs": "Requires the Starter authentication runtime and an enabled DingTalk authenticator in NocoBase. DingTalk JSAPI is loaded lazily for internal micro-app login.",
|
|
166
|
-
"source": {
|
|
167
|
-
"root": "registry/nocobase-auth-dingtalk",
|
|
168
|
-
"target": "src/extensions/nocobase-auth-dingtalk",
|
|
169
|
-
"install": false,
|
|
170
|
-
"include": ["."]
|
|
171
|
-
}
|
|
172
|
-
},
|
|
173
|
-
{
|
|
174
|
-
"name": "ai-runtime",
|
|
175
|
-
"type": "registry:lib",
|
|
176
|
-
"title": "NocoBase AI Runtime",
|
|
177
|
-
"description": "NocoBase AI services, providers, transports, controllers, and avatars.",
|
|
178
|
-
"dependencies": [
|
|
179
|
-
"@ai-sdk/react@2.0.0",
|
|
180
|
-
"ai@5.0.0",
|
|
181
|
-
"@dicebear/core@^9.4.3",
|
|
182
|
-
"@nocobase/ai-employee-avatars@^1.0.2",
|
|
183
|
-
"eventsource-parser@3.1.0"
|
|
184
|
-
],
|
|
185
|
-
"source": {
|
|
186
|
-
"root": "registry/nocobase-ai",
|
|
187
|
-
"target": "src/extensions/nocobase-ai",
|
|
188
|
-
"include": ["providers", "services"]
|
|
189
|
-
}
|
|
190
|
-
},
|
|
191
|
-
{
|
|
192
|
-
"name": "ai-chat",
|
|
193
|
-
"type": "registry:block",
|
|
194
|
-
"title": "NocoBase AI Chat Components",
|
|
195
|
-
"description": "Reusable NocoBase AI chat window, containers, floating trigger, and employee shortcut.",
|
|
196
|
-
"dependencies": [
|
|
197
|
-
"echarts@^5.5.0",
|
|
198
|
-
"echarts-for-react@3.0.2",
|
|
199
|
-
"lucide-react@^0.487.0",
|
|
200
|
-
"next-themes@^0.4.6",
|
|
201
|
-
"react-markdown@^10.1.0",
|
|
202
|
-
"remark-gfm@^4.0.1"
|
|
203
|
-
],
|
|
204
|
-
"registryDependencies": [
|
|
205
|
-
"@nocobase/ai-runtime",
|
|
206
|
-
"badge",
|
|
207
|
-
"button",
|
|
208
|
-
"collapsible",
|
|
209
|
-
"dialog",
|
|
210
|
-
"dropdown-menu",
|
|
211
|
-
"hover-card",
|
|
212
|
-
"input",
|
|
213
|
-
"input-group",
|
|
214
|
-
"label",
|
|
215
|
-
"popover",
|
|
216
|
-
"select",
|
|
217
|
-
"tabs",
|
|
218
|
-
"textarea",
|
|
219
|
-
"tooltip"
|
|
220
|
-
],
|
|
221
|
-
"source": {
|
|
222
|
-
"root": "registry/nocobase-ai",
|
|
223
|
-
"target": "src/extensions/nocobase-ai",
|
|
224
|
-
"include": ["components", "assets", "index.ts", "README.md"]
|
|
225
|
-
}
|
|
226
|
-
},
|
|
227
|
-
{
|
|
228
|
-
"name": "ai-react-hook-form",
|
|
229
|
-
"type": "registry:lib",
|
|
230
|
-
"title": "NocoBase AI React Hook Form Adapter",
|
|
231
|
-
"description": "Optional React Hook Form adapter for the built-in AI Form filler.",
|
|
232
|
-
"dependencies": ["react-hook-form@^7.57.0"],
|
|
233
|
-
"registryDependencies": ["@nocobase/ai-chat"],
|
|
234
|
-
"source": {
|
|
235
|
-
"root": "registry/nocobase-ai",
|
|
236
|
-
"target": "src/extensions/nocobase-ai",
|
|
237
|
-
"include": ["adapters/react-hook-form.ts"]
|
|
238
|
-
}
|
|
239
|
-
},
|
|
240
|
-
{
|
|
241
|
-
"name": "ai",
|
|
242
|
-
"type": "registry:block",
|
|
243
|
-
"title": "NocoBase AI Components and Demo",
|
|
244
|
-
"description": "Complete NocoBase AI component runtime with application resources, routes, and component showcase pages.",
|
|
245
|
-
"dependencies": ["@refinedev/core@^5.0.8", "react-router@^7.0.2"],
|
|
246
|
-
"registryDependencies": [
|
|
247
|
-
"@nocobase/ai-chat",
|
|
248
|
-
"@nocobase/ai-react-hook-form",
|
|
249
|
-
"accordion",
|
|
250
|
-
"alert",
|
|
251
|
-
"badge",
|
|
252
|
-
"card",
|
|
253
|
-
"checkbox",
|
|
254
|
-
"input",
|
|
255
|
-
"switch",
|
|
256
|
-
"table",
|
|
257
|
-
"textarea"
|
|
258
|
-
],
|
|
259
|
-
"docs": "This item includes the AI extension integration and Demo pages. It is designed for a compatible starter with the AppExtension host enabled. After installation, src/extensions/nocobase-ai/extension.tsx is discovered automatically and contributes its application resources and routes without AI-specific App.tsx edits.",
|
|
260
|
-
"source": {
|
|
261
|
-
"root": "registry/nocobase-ai",
|
|
262
|
-
"target": "src/extensions/nocobase-ai",
|
|
263
|
-
"include": ["demo", "extension.tsx", "global-ai-chat.tsx"]
|
|
264
|
-
}
|
|
265
|
-
},
|
|
266
|
-
{
|
|
267
|
-
"name": "acl-ui",
|
|
268
|
-
"type": "registry:block",
|
|
269
|
-
"title": "NocoBase ACL UI",
|
|
270
|
-
"description": "Page, region, field, and role-switching components backed by the Starter's NocoBase accessControlProvider.",
|
|
271
|
-
"dependencies": ["@refinedev/core@^5.0.8", "lucide-react@^0.487.0"],
|
|
272
|
-
"registryDependencies": ["badge", "select"],
|
|
273
|
-
"docs": "Requires a compatible NocoBase Starter with the built-in accessControlProvider and ACL store.",
|
|
274
|
-
"source": {
|
|
275
|
-
"root": "registry/nocobase-acl",
|
|
276
|
-
"target": "src/extensions/nocobase-acl",
|
|
277
|
-
"include": ["components", "index.ts", "README.md"]
|
|
278
|
-
}
|
|
279
|
-
},
|
|
280
|
-
{
|
|
281
|
-
"name": "acl",
|
|
282
|
-
"type": "registry:block",
|
|
283
|
-
"title": "NocoBase ACL Components and Demo",
|
|
284
|
-
"description": "Complete ACL composition demo with live role switching, action matrix, multi-collection regions, and field permissions.",
|
|
285
|
-
"dependencies": ["@refinedev/core@^5.0.8", "react-router@^7.0.2"],
|
|
286
|
-
"registryDependencies": [
|
|
287
|
-
"@nocobase/acl-ui",
|
|
288
|
-
"button",
|
|
289
|
-
"card",
|
|
290
|
-
"input",
|
|
291
|
-
"label",
|
|
292
|
-
"table",
|
|
293
|
-
"textarea"
|
|
294
|
-
],
|
|
295
|
-
"source": {
|
|
296
|
-
"root": "registry/nocobase-acl",
|
|
297
|
-
"target": "src/extensions/nocobase-acl",
|
|
298
|
-
"include": ["demo", "extension.tsx"]
|
|
299
|
-
}
|
|
300
|
-
}
|
|
301
|
-
]
|
|
302
|
-
}
|
package/scripts/registry.mjs
DELETED
|
@@ -1,164 +0,0 @@
|
|
|
1
|
-
import fs from "node:fs";
|
|
2
|
-
import path from "node:path";
|
|
3
|
-
import { fileURLToPath } from "node:url";
|
|
4
|
-
|
|
5
|
-
const projectRoot = path.resolve(
|
|
6
|
-
path.dirname(fileURLToPath(import.meta.url)),
|
|
7
|
-
".."
|
|
8
|
-
);
|
|
9
|
-
const configPath = path.join(projectRoot, "registry.config.json");
|
|
10
|
-
const outputPath = path.join(projectRoot, "registry.json");
|
|
11
|
-
const action = process.argv[2];
|
|
12
|
-
|
|
13
|
-
if (!new Set(["build", "install-missing", "preview"]).has(action)) {
|
|
14
|
-
throw new Error(
|
|
15
|
-
"Usage: node scripts/registry.mjs <build|install-missing|preview>"
|
|
16
|
-
);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
function toPosix(value) {
|
|
20
|
-
return value.split(path.sep).join("/");
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function walkFiles(directory, root = directory) {
|
|
24
|
-
return fs
|
|
25
|
-
.readdirSync(directory, { withFileTypes: true })
|
|
26
|
-
.flatMap((entry) => {
|
|
27
|
-
const entryPath = path.join(directory, entry.name);
|
|
28
|
-
return entry.isDirectory()
|
|
29
|
-
? walkFiles(entryPath, root)
|
|
30
|
-
: [toPosix(path.relative(root, entryPath))];
|
|
31
|
-
})
|
|
32
|
-
.sort((left, right) => left.localeCompare(right));
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function isIncluded(file, include) {
|
|
36
|
-
return include.some((entry) => {
|
|
37
|
-
const normalized = entry.replace(/^\.\//, "").replace(/\/$/, "");
|
|
38
|
-
return (
|
|
39
|
-
normalized === "." ||
|
|
40
|
-
file === normalized ||
|
|
41
|
-
file.startsWith(`${normalized}/`)
|
|
42
|
-
);
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function assertSafePath(value, prefix, label) {
|
|
47
|
-
if (!value.startsWith(prefix) || value.includes("..")) {
|
|
48
|
-
throw new Error(`Unsafe ${label} path: ${value}`);
|
|
49
|
-
}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
const sourceConfig = JSON.parse(fs.readFileSync(configPath, "utf8"));
|
|
53
|
-
const sourceFiles = new Map();
|
|
54
|
-
const sourceMappings = new Map();
|
|
55
|
-
const itemNames = new Set();
|
|
56
|
-
|
|
57
|
-
const items = sourceConfig.items.map((item) => {
|
|
58
|
-
if (!item.name || itemNames.has(item.name)) {
|
|
59
|
-
throw new Error(`Registry item name must be unique: ${item.name}`);
|
|
60
|
-
}
|
|
61
|
-
itemNames.add(item.name);
|
|
62
|
-
const source = item.source;
|
|
63
|
-
if (!source) {
|
|
64
|
-
throw new Error(`Registry item ${item.name} is missing its source mapping`);
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
assertSafePath(source.root, "registry/", "source");
|
|
68
|
-
assertSafePath(source.target, "src/extensions/", "target");
|
|
69
|
-
|
|
70
|
-
const sourceRoot = path.join(projectRoot, source.root);
|
|
71
|
-
if (!fs.existsSync(sourceRoot)) {
|
|
72
|
-
throw new Error(`Registry source does not exist: ${source.root}`);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
if (!Array.isArray(source.include) || !source.include.length) {
|
|
76
|
-
throw new Error(`Registry item ${item.name} must include at least one path`);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const mappingKey = `${source.root}\0${source.target}`;
|
|
80
|
-
const mapping = sourceMappings.get(mappingKey) ?? {
|
|
81
|
-
root: source.root,
|
|
82
|
-
target: source.target,
|
|
83
|
-
include: new Set(),
|
|
84
|
-
install: source.install !== false,
|
|
85
|
-
};
|
|
86
|
-
source.include.forEach((entry) => mapping.include.add(entry));
|
|
87
|
-
mapping.install = mapping.install || source.install !== false;
|
|
88
|
-
sourceMappings.set(mappingKey, mapping);
|
|
89
|
-
|
|
90
|
-
const allFiles = sourceFiles.get(source.root) ?? walkFiles(sourceRoot);
|
|
91
|
-
sourceFiles.set(source.root, allFiles);
|
|
92
|
-
const includedFiles = allFiles.filter((file) =>
|
|
93
|
-
isIncluded(file, source.include)
|
|
94
|
-
);
|
|
95
|
-
if (!includedFiles.length) {
|
|
96
|
-
throw new Error(
|
|
97
|
-
`Registry item ${item.name} include paths did not match any files`
|
|
98
|
-
);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
if (action !== "build") return item;
|
|
102
|
-
const { source: _source, ...registryItem } = item;
|
|
103
|
-
|
|
104
|
-
return {
|
|
105
|
-
...registryItem,
|
|
106
|
-
files: includedFiles.map((file) => ({
|
|
107
|
-
path: path.posix.join(source.root, file),
|
|
108
|
-
type: "registry:file",
|
|
109
|
-
target: path.posix.join(source.target, file),
|
|
110
|
-
})),
|
|
111
|
-
};
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
function copySource(source, overwrite) {
|
|
115
|
-
const sourcePath = path.join(projectRoot, source.root);
|
|
116
|
-
const targetPath = path.join(projectRoot, source.target);
|
|
117
|
-
|
|
118
|
-
if (fs.existsSync(targetPath) && !overwrite) {
|
|
119
|
-
console.log(`${source.target}: already installed, preserved`);
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
fs.mkdirSync(path.dirname(targetPath), { recursive: true });
|
|
124
|
-
const temporaryRoot = fs.mkdtempSync(
|
|
125
|
-
path.join(path.dirname(targetPath), `.${path.basename(targetPath)}-install-`)
|
|
126
|
-
);
|
|
127
|
-
const temporaryTarget = path.join(temporaryRoot, path.basename(targetPath));
|
|
128
|
-
|
|
129
|
-
try {
|
|
130
|
-
const includedFiles = walkFiles(sourcePath).filter((file) =>
|
|
131
|
-
isIncluded(file, [...source.include])
|
|
132
|
-
);
|
|
133
|
-
for (const file of includedFiles) {
|
|
134
|
-
const sourceFile = path.join(sourcePath, file);
|
|
135
|
-
const targetFile = path.join(temporaryTarget, file);
|
|
136
|
-
fs.mkdirSync(path.dirname(targetFile), { recursive: true });
|
|
137
|
-
fs.copyFileSync(sourceFile, targetFile);
|
|
138
|
-
}
|
|
139
|
-
if (overwrite) fs.rmSync(targetPath, { recursive: true, force: true });
|
|
140
|
-
fs.renameSync(temporaryTarget, targetPath);
|
|
141
|
-
console.log(
|
|
142
|
-
`${source.target}: ${overwrite ? "preview refreshed" : "installed"}`
|
|
143
|
-
);
|
|
144
|
-
} finally {
|
|
145
|
-
fs.rmSync(temporaryRoot, { recursive: true, force: true });
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
|
|
149
|
-
if (action === "build") {
|
|
150
|
-
const registry = {
|
|
151
|
-
$schema: "https://ui.shadcn.com/schema/registry.json",
|
|
152
|
-
...sourceConfig,
|
|
153
|
-
items,
|
|
154
|
-
};
|
|
155
|
-
fs.writeFileSync(outputPath, `${JSON.stringify(registry, null, 2)}\n`);
|
|
156
|
-
for (const item of items) {
|
|
157
|
-
console.log(`${item.name}: ${item.files.length} files`);
|
|
158
|
-
}
|
|
159
|
-
} else {
|
|
160
|
-
for (const source of sourceMappings.values()) {
|
|
161
|
-
if (action === "install-missing" && !source.install) continue;
|
|
162
|
-
copySource(source, action === "preview");
|
|
163
|
-
}
|
|
164
|
-
}
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { CanAccess } from "@refinedev/core";
|
|
2
|
-
import type { PropsWithChildren, ReactNode } from "react";
|
|
3
|
-
|
|
4
|
-
import { AccessDenied } from "./access-denied";
|
|
5
|
-
|
|
6
|
-
export function ResourceAccessGuard({
|
|
7
|
-
resource,
|
|
8
|
-
action,
|
|
9
|
-
children,
|
|
10
|
-
fallback = <AccessDenied />,
|
|
11
|
-
}: PropsWithChildren<{
|
|
12
|
-
resource: string;
|
|
13
|
-
action: string;
|
|
14
|
-
fallback?: ReactNode;
|
|
15
|
-
}>) {
|
|
16
|
-
return (
|
|
17
|
-
<CanAccess resource={resource} action={action} fallback={fallback}>
|
|
18
|
-
{children}
|
|
19
|
-
</CanAccess>
|
|
20
|
-
);
|
|
21
|
-
}
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { useQueryClient } from "@tanstack/react-query";
|
|
2
|
-
import { useEffect, useRef } from "react";
|
|
3
|
-
|
|
4
|
-
import { loadAcl, useAclSnapshot } from "@/lib/nocobase/acl";
|
|
5
|
-
|
|
6
|
-
export function useAclRuntime() {
|
|
7
|
-
const snapshot = useAclSnapshot();
|
|
8
|
-
const queryClient = useQueryClient();
|
|
9
|
-
const lastReadyVersion = useRef<number | undefined>(undefined);
|
|
10
|
-
|
|
11
|
-
useEffect(() => {
|
|
12
|
-
if (snapshot.status === "idle") {
|
|
13
|
-
void loadAcl().catch(() => undefined);
|
|
14
|
-
}
|
|
15
|
-
}, [snapshot.status]);
|
|
16
|
-
|
|
17
|
-
useEffect(() => {
|
|
18
|
-
if (snapshot.status !== "ready") return;
|
|
19
|
-
if (lastReadyVersion.current === undefined) {
|
|
20
|
-
lastReadyVersion.current = snapshot.version;
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
if (lastReadyVersion.current === snapshot.version) return;
|
|
24
|
-
|
|
25
|
-
lastReadyVersion.current = snapshot.version;
|
|
26
|
-
void queryClient.invalidateQueries({ queryKey: ["access"] });
|
|
27
|
-
}, [queryClient, snapshot.status, snapshot.version]);
|
|
28
|
-
}
|
|
@@ -1,147 +0,0 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
AclActionParams,
|
|
3
|
-
AclCanParams,
|
|
4
|
-
AclRoleData,
|
|
5
|
-
AclSnapshot,
|
|
6
|
-
ResourceAcl,
|
|
7
|
-
} from "./types";
|
|
8
|
-
import ignore from "ignore";
|
|
9
|
-
import { getRecordActionPermission } from "./record-permissions";
|
|
10
|
-
import { resolveAclDataSourceKey } from "./data-source";
|
|
11
|
-
|
|
12
|
-
const REFINE_ACTION_MAP: Record<string, string> = {
|
|
13
|
-
list: "list",
|
|
14
|
-
show: "get",
|
|
15
|
-
create: "create",
|
|
16
|
-
edit: "update",
|
|
17
|
-
delete: "destroy",
|
|
18
|
-
clone: "create",
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
const getResourceAcl = (params?: AclCanParams["params"]) =>
|
|
22
|
-
params?.resource?.meta?.acl as ResourceAcl | undefined;
|
|
23
|
-
|
|
24
|
-
export const mapRefineAction = (action: string) =>
|
|
25
|
-
REFINE_ACTION_MAP[action] ?? action;
|
|
26
|
-
|
|
27
|
-
export const getAclDataForDataSource = (
|
|
28
|
-
snapshot: AclSnapshot,
|
|
29
|
-
dataSourceKey = "main"
|
|
30
|
-
): AclRoleData => {
|
|
31
|
-
const dataSourceAcl = snapshot.meta.dataSources?.[dataSourceKey];
|
|
32
|
-
return dataSourceAcl
|
|
33
|
-
? {
|
|
34
|
-
...snapshot.data,
|
|
35
|
-
...dataSourceAcl,
|
|
36
|
-
snippets: snapshot.data.snippets,
|
|
37
|
-
}
|
|
38
|
-
: snapshot.data;
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
export const resolveActionPermission = ({
|
|
42
|
-
snapshot,
|
|
43
|
-
resource,
|
|
44
|
-
action,
|
|
45
|
-
dataSourceKey = "main",
|
|
46
|
-
}: {
|
|
47
|
-
snapshot: AclSnapshot;
|
|
48
|
-
resource: string;
|
|
49
|
-
action: string;
|
|
50
|
-
dataSourceKey?: string;
|
|
51
|
-
}): AclActionParams | null => {
|
|
52
|
-
const data = getAclDataForDataSource(snapshot, dataSourceKey);
|
|
53
|
-
if (data.allowAll) return {};
|
|
54
|
-
|
|
55
|
-
const canonicalAction = data.actionAlias?.[action] ?? action;
|
|
56
|
-
if (data.resources?.includes(resource)) {
|
|
57
|
-
return (
|
|
58
|
-
data.actions?.[`${resource}:${canonicalAction}`] ??
|
|
59
|
-
data.actions?.[`${resource}:${action}`] ??
|
|
60
|
-
null
|
|
61
|
-
);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
const strategyAllowed = data.strategy?.actions?.some(
|
|
65
|
-
(item) => item.split(":")[0] === canonicalAction
|
|
66
|
-
);
|
|
67
|
-
return strategyAllowed ? {} : null;
|
|
68
|
-
};
|
|
69
|
-
|
|
70
|
-
const matchesSnippet = (snippets: string[], target: string) =>
|
|
71
|
-
!target || target === "*" || ignore().add(snippets).ignores(target);
|
|
72
|
-
|
|
73
|
-
export const canAccessWithSnapshot = (
|
|
74
|
-
snapshot: AclSnapshot,
|
|
75
|
-
{ resource, action, params }: AclCanParams
|
|
76
|
-
) => {
|
|
77
|
-
if (snapshot.status !== "ready") return false;
|
|
78
|
-
|
|
79
|
-
const resourceAcl = getResourceAcl(params);
|
|
80
|
-
if (resourceAcl === false || resourceAcl?.type === "authenticated") {
|
|
81
|
-
return true;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (resourceAcl?.type === "snippet") {
|
|
85
|
-
return (
|
|
86
|
-
snapshot.data.allowAll ||
|
|
87
|
-
matchesSnippet(snapshot.data.snippets ?? [], resourceAcl.name)
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (resourceAcl?.type === "route") {
|
|
92
|
-
return (
|
|
93
|
-
snapshot.data.allowAll ||
|
|
94
|
-
(snapshot.data.allowMenuItemIds ?? [])
|
|
95
|
-
.map(String)
|
|
96
|
-
.includes(String(resourceAcl.routeId))
|
|
97
|
-
);
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const targetResource =
|
|
101
|
-
resourceAcl?.type === "collection" && resourceAcl.resource
|
|
102
|
-
? resourceAcl.resource
|
|
103
|
-
: resource;
|
|
104
|
-
if (!targetResource) return true;
|
|
105
|
-
|
|
106
|
-
const dataSourceKey =
|
|
107
|
-
resolveAclDataSourceKey(
|
|
108
|
-
params,
|
|
109
|
-
params?.meta as { dataSourceKey?: unknown; acl?: ResourceAcl } | undefined,
|
|
110
|
-
params?.resource?.meta as
|
|
111
|
-
| { dataSourceKey?: unknown; acl?: ResourceAcl }
|
|
112
|
-
| undefined
|
|
113
|
-
) ?? "main";
|
|
114
|
-
const mappedAction =
|
|
115
|
-
(resourceAcl?.type === "collection" && resourceAcl.actionMap?.[action]) ||
|
|
116
|
-
mapRefineAction(action);
|
|
117
|
-
const permission = resolveActionPermission({
|
|
118
|
-
snapshot,
|
|
119
|
-
resource: targetResource,
|
|
120
|
-
action: mappedAction,
|
|
121
|
-
dataSourceKey,
|
|
122
|
-
});
|
|
123
|
-
if (!permission) return false;
|
|
124
|
-
|
|
125
|
-
if (params?.id !== undefined) {
|
|
126
|
-
const recordPermission = getRecordActionPermission({
|
|
127
|
-
dataSourceKey,
|
|
128
|
-
resource: targetResource,
|
|
129
|
-
action: mappedAction,
|
|
130
|
-
id: params.id,
|
|
131
|
-
actionAlias: getAclDataForDataSource(snapshot, dataSourceKey).actionAlias,
|
|
132
|
-
});
|
|
133
|
-
if (recordPermission !== undefined) return recordPermission;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
if (typeof params?.field === "string") {
|
|
137
|
-
const fields = [
|
|
138
|
-
...(permission.fields ?? []),
|
|
139
|
-
...(permission.whitelist ?? []),
|
|
140
|
-
...(permission.appends ?? []),
|
|
141
|
-
];
|
|
142
|
-
if (!fields.length) return true;
|
|
143
|
-
return fields.includes(params.field);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
return true;
|
|
147
|
-
};
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
import { Outlet } from "react-router";
|
|
2
|
-
|
|
3
|
-
import { ResourceAccessGuard } from "@/components/access-control/resource-access-guard";
|
|
4
|
-
import { UserList } from "./list";
|
|
5
|
-
|
|
6
|
-
export function UserResourceLayout() {
|
|
7
|
-
return (
|
|
8
|
-
<>
|
|
9
|
-
<ResourceAccessGuard resource="users" action="list">
|
|
10
|
-
<UserList />
|
|
11
|
-
</ResourceAccessGuard>
|
|
12
|
-
<Outlet />
|
|
13
|
-
</>
|
|
14
|
-
);
|
|
15
|
-
}
|