@nocobase/portal-template-default 1.0.9 → 1.0.11

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.
Files changed (338) hide show
  1. package/.env.example +5 -0
  2. package/.github/workflows/publish.yml +106 -0
  3. package/.gitignore +33 -0
  4. package/AGENTS.md +19 -0
  5. package/README.MD +61 -180
  6. package/dist/assets/{LineDraw-C0m1GONT.js → LineDraw-iG-ADes-.js} +1 -1
  7. package/dist/assets/{SymbolDraw-CCospe5G.js → SymbolDraw-DXoSw1tM.js} +1 -1
  8. package/dist/assets/VisualMapping-C_ee4Eht.js +1 -0
  9. package/dist/assets/auth-method-demo-DaOCuvsq.js +1 -0
  10. package/dist/assets/auto-login-provider-5Uxza9Ms.js +2 -0
  11. package/dist/assets/auto-login-provider-DyaPGK2D.js +1 -0
  12. package/dist/assets/auto-redirect-provider-CfwRvYOI.js +1 -0
  13. package/dist/assets/auto-redirect-provider-Cr3jmYts.js +1 -0
  14. package/dist/assets/auto-redirect-provider-QkJQRBbG.js +1 -0
  15. package/dist/assets/calendar-DjDRfD5t.js +1 -0
  16. package/dist/assets/card-DuQBOS6A.js +1 -0
  17. package/dist/assets/cas-sign-in-button-CyqG1QME.js +1 -0
  18. package/dist/assets/components-D-ptYjX_.js +20 -0
  19. package/dist/assets/configuration-gate-C08mkkiX.js +1 -0
  20. package/dist/assets/{createClipPathFromCoordSys-uEftn1Mq.js → createClipPathFromCoordSys-wj34-b1B.js} +1 -1
  21. package/dist/assets/createSeriesDataSimply-D0A6SAVQ.js +1 -0
  22. package/dist/assets/customGraphicKeyframeAnimation-DWrhrHL_.js +3 -0
  23. package/dist/assets/demo-BYWHeKUe.js +1 -0
  24. package/dist/assets/demo-CPWoNtx8.js +1 -0
  25. package/dist/assets/demo-CyvJk5zV.js +1 -0
  26. package/dist/assets/demo-D4OiKplc.js +1 -0
  27. package/dist/assets/demo-DBueJg0m.js +1 -0
  28. package/dist/assets/demo-DkIhyiRK.js +1 -0
  29. package/dist/assets/demo-tpTjO0sC.js +1 -0
  30. package/dist/assets/dingtalk-sign-in-button-DSWsSruv.js +1 -0
  31. package/dist/assets/echarts-preview-DxHNfq1C.js +1 -0
  32. package/dist/assets/{echarts-runtime-CEgJbv68.js → echarts-runtime-D8kXn6ME.js} +3 -3
  33. package/dist/assets/{echarts-runtime-advanced-Buhm2BHz.js → echarts-runtime-advanced-QY8v95qK.js} +1 -1
  34. package/dist/assets/{echarts-runtime-common-DLAdBAIa.js → echarts-runtime-common-D-yqAK-r.js} +1 -1
  35. package/dist/assets/{echarts-runtime-components-ypnyLkYx.js → echarts-runtime-components-P4-i8jPU.js} +1 -1
  36. package/dist/assets/{echarts-runtime-hierarchy-ClStquCF.js → echarts-runtime-hierarchy-ByQZ-DbP.js} +1 -1
  37. package/dist/assets/floating-BFVEyPEp.js +15 -0
  38. package/dist/assets/index-BgCbGDMc.js +43 -0
  39. package/dist/assets/index-Btk35Nx-.js +23 -0
  40. package/dist/assets/index-CwNxd66J.js +1 -0
  41. package/dist/assets/index-MB-jfQld.js +686 -0
  42. package/dist/assets/index-NH3aqqQz.css +1 -0
  43. package/dist/assets/index-gFtCXH3o.js +58 -0
  44. package/dist/assets/index-um5hdKdZ.js +23 -0
  45. package/dist/assets/{labelHelper-C137W5gU.js → labelHelper-DQqRy3a_.js} +1 -1
  46. package/dist/assets/ldap-sign-in-form--6Gt3yGq.js +1 -0
  47. package/dist/assets/oidc-sign-in-button-CQdRcR_p.js +1 -0
  48. package/dist/assets/{page-context-Cxx11gzg.js → page-context-CnQ4GYM7.js} +10 -10
  49. package/dist/assets/prompt-card-B2RS4nt2.js +1 -0
  50. package/dist/assets/prompt-output-DZHRM2ft.js +1 -0
  51. package/dist/assets/saml-sign-in-button-BHL5a0JV.js +1 -0
  52. package/dist/assets/{sectorHelper-Fqgz3uEk.js → sectorHelper-DN_Vv6OL.js} +1 -1
  53. package/dist/assets/shortcut-C5x5LQWU.js +47 -0
  54. package/dist/assets/sms-sign-in-form-DTX9GV2I.js +1 -0
  55. package/dist/assets/{static.browser-CfQQzERe.js → static.browser-jI1psK0d.js} +8 -8
  56. package/dist/assets/{switch-DrxImI8F.js → switch-CRL8PmRI.js} +1 -1
  57. package/dist/assets/{tool-cards-BGfsY8JF.js → tool-cards-DFttLAfo.js} +6 -7
  58. package/dist/assets/use-authenticator-sign-in-CRGjzXju.js +1 -0
  59. package/dist/assets/use-dingtalk-sign-in-8WYzJ2jf.js +1 -0
  60. package/dist/assets/use-wecom-sign-in-C9j8wfCD.js +1 -0
  61. package/dist/assets/wecom-sign-in-button-mIS1zGSU.js +1 -0
  62. package/dist/index.html +2 -2
  63. package/dist/index.raw.html +5 -2
  64. package/package.json +3 -5
  65. package/scripts/build-html.mjs +12 -0
  66. package/src/App.css +2 -0
  67. package/src/App.tsx +35 -186
  68. package/src/app/development.tsx +154 -0
  69. package/src/app/extension.ts +5 -0
  70. package/src/app/extensions.tsx +18 -4
  71. package/src/app/routes.tsx +65 -0
  72. package/src/components/access-control/acl-bootstrap.tsx +11 -3
  73. package/src/components/access-control/acl-gate.tsx +7 -6
  74. package/src/components/access-control/can-access.tsx +17 -0
  75. package/src/components/access-control/navigate-to-accessible-resource.tsx +8 -3
  76. package/src/components/app-shell/sidebar.tsx +21 -5
  77. package/src/components/auth/auto-redirect-provider.tsx +2 -1
  78. package/src/extensions/nocobase-acl/README.md +74 -0
  79. package/{registry → src/extensions}/nocobase-acl/components/acl-boundary.tsx +22 -25
  80. package/{registry → src/extensions}/nocobase-acl/components/role-switcher.tsx +26 -23
  81. package/src/extensions/nocobase-acl/demo/acl-preview-provider.tsx +81 -0
  82. package/{registry → src/extensions}/nocobase-acl/demo/boundary-api.tsx +58 -0
  83. package/{registry → src/extensions}/nocobase-acl/demo/index.tsx +243 -105
  84. package/{registry → src/extensions}/nocobase-acl/demo/prompt-generator.tsx +3 -1
  85. package/src/extensions/nocobase-acl/extension.tsx +73 -0
  86. package/{registry → src/extensions}/nocobase-ai/README.md +21 -5
  87. package/{registry → src/extensions}/nocobase-ai/components/chat/chat-composer.tsx +3 -1
  88. package/{registry → src/extensions}/nocobase-ai/components/chat/chat-messages.tsx +38 -3
  89. package/{registry → src/extensions}/nocobase-ai/components/chat/tool-call-card.tsx +1 -9
  90. package/{registry → src/extensions}/nocobase-ai/components/index.ts +5 -0
  91. package/src/extensions/nocobase-ai/components/surfaces/chat-dialog.tsx +17 -0
  92. package/src/extensions/nocobase-ai/components/surfaces/chat-side-panel.tsx +35 -0
  93. package/src/extensions/nocobase-ai/components/surfaces/chat-surface.tsx +108 -0
  94. package/{registry → src/extensions}/nocobase-ai/components/triggers/ai-chat-floating-trigger.tsx +2 -2
  95. package/{registry → src/extensions}/nocobase-ai/demo/configuration-gate.tsx +4 -1
  96. package/{registry → src/extensions}/nocobase-ai/demo/container-showcase.tsx +2 -2
  97. package/{registry → src/extensions}/nocobase-ai/demo/floating.tsx +45 -15
  98. package/{registry → src/extensions}/nocobase-ai/demo/index.tsx +116 -74
  99. package/{registry → src/extensions}/nocobase-ai/demo/prompt-generator.tsx +3 -3
  100. package/{registry → src/extensions}/nocobase-ai/demo/tool-cards.tsx +2 -3
  101. package/src/extensions/nocobase-ai/extension.tsx +160 -0
  102. package/{registry → src/extensions}/nocobase-ai/global-ai-chat.tsx +12 -28
  103. package/{registry → src/extensions}/nocobase-ai/providers/ai-provider.tsx +14 -1
  104. package/{registry → src/extensions}/nocobase-ai/providers/chat-context.tsx +1 -0
  105. package/{registry → src/extensions}/nocobase-ai/providers/chat-provider.tsx +29 -8
  106. package/{registry → src/extensions}/nocobase-ai/providers/use-chat-attachments.ts +6 -1
  107. package/{registry → src/extensions}/nocobase-ai/providers/use-chat-work-context.ts +4 -1
  108. package/{registry → src/extensions}/nocobase-route-surfaces/README.md +2 -1
  109. package/{registry → src/extensions}/nocobase-route-surfaces/demo/index.tsx +33 -7
  110. package/{registry → src/extensions}/nocobase-route-surfaces/demo/scenarios.ts +20 -14
  111. package/{registry → src/extensions}/nocobase-route-surfaces/extension.tsx +55 -52
  112. package/src/{pages/users → extensions/nocobase-users-example}/create.tsx +4 -4
  113. package/src/{pages/users → extensions/nocobase-users-example}/edit.tsx +5 -9
  114. package/src/extensions/nocobase-users-example/extension.tsx +109 -0
  115. package/src/{pages/users → extensions/nocobase-users-example}/form-context.ts +11 -9
  116. package/src/extensions/nocobase-users-example/layout.tsx +16 -0
  117. package/src/{pages/users → extensions/nocobase-users-example}/list.tsx +1 -1
  118. package/src/extensions/nocobase-users-example/locales/en-US.ts +77 -0
  119. package/src/extensions/nocobase-users-example/locales/index.ts +8 -0
  120. package/src/extensions/nocobase-users-example/locales/zh-CN.ts +73 -0
  121. package/src/extensions/nocobase-users-example/optional-ai.ts +67 -0
  122. package/src/{pages/users → extensions/nocobase-users-example}/role-detail.tsx +4 -15
  123. package/src/{pages/users → extensions/nocobase-users-example}/routes.ts +1 -4
  124. package/src/extensions/nocobase-users-example/show.tsx +266 -0
  125. package/src/lib/nocobase/acl/context.ts +32 -0
  126. package/src/lib/nocobase/acl/evaluator.ts +186 -0
  127. package/src/lib/nocobase/acl/hooks.ts +40 -0
  128. package/src/lib/nocobase/acl/index.ts +4 -1
  129. package/src/lib/nocobase/acl/menu.ts +6 -6
  130. package/src/lib/nocobase/acl/record-permissions.ts +37 -7
  131. package/src/lib/nocobase/acl/store-provider.tsx +14 -0
  132. package/src/lib/nocobase/acl/store.ts +92 -86
  133. package/src/lib/nocobase/acl/types.ts +52 -32
  134. package/src/lib/nocobase/auth-session.ts +128 -0
  135. package/src/lib/nocobase/client.ts +48 -50
  136. package/src/locales/en-US.ts +0 -78
  137. package/src/locales/index.ts +2 -7
  138. package/src/locales/zh-CN.ts +0 -74
  139. package/src/providers/access-control.ts +43 -8
  140. package/src/providers/auth-callback.ts +1 -0
  141. package/src/providers/auth.ts +24 -26
  142. package/src/providers/constants.ts +0 -4
  143. package/src/providers/data.ts +14 -26
  144. package/src/providers/runtime-config.ts +40 -0
  145. package/src/vite-env.d.ts +9 -0
  146. package/tests/auth-session-regression.mjs +101 -0
  147. package/tsconfig.json +2 -1
  148. package/vite.config.ts +9 -1
  149. package/dist/assets/VisualMapping-Cbv1v7Cd.js +0 -1
  150. package/dist/assets/ai-employee-shortcut-B253WWow.js +0 -1
  151. package/dist/assets/calendar-B3dXXyIv.js +0 -1
  152. package/dist/assets/chat-inline-xpQ9iq4p.js +0 -1
  153. package/dist/assets/chat-side-panel-layout-BVWsp5rr.js +0 -1
  154. package/dist/assets/components-ChhJaNRc.js +0 -20
  155. package/dist/assets/configuration-gate-Dwdq_lxf.js +0 -1
  156. package/dist/assets/createSeriesDataSimply-CI7l7Ufv.js +0 -1
  157. package/dist/assets/customGraphicKeyframeAnimation-DE3jSfMd.js +0 -3
  158. package/dist/assets/echarts-preview-C-cNUtJF.js +0 -1
  159. package/dist/assets/floating-BarTmn-b.js +0 -13
  160. package/dist/assets/index-BJIcYTdc.js +0 -53
  161. package/dist/assets/index-C6xNKxpg.js +0 -656
  162. package/dist/assets/index-D4JQi1TM.js +0 -54
  163. package/dist/assets/index-YA7-AUO8.css +0 -1
  164. package/dist/assets/index-g8zWVpP9.js +0 -23
  165. package/dist/assets/prompt-card-BsYMW_rq.js +0 -1
  166. package/dist/assets/shortcut-xtghDP63.js +0 -47
  167. package/registry/nocobase-acl/README.md +0 -19
  168. package/registry/nocobase-acl/extension.tsx +0 -71
  169. package/registry/nocobase-acl/tests/acl-regression.mjs +0 -314
  170. package/registry/nocobase-ai/components/surfaces/chat-dialog.tsx +0 -31
  171. package/registry/nocobase-ai/components/surfaces/chat-side-panel.tsx +0 -74
  172. package/registry/nocobase-ai/extension.tsx +0 -158
  173. package/registry/nocobase-ai/tests/business-report-regression.mjs +0 -70
  174. package/registry/nocobase-ai/tests/form-filler-regression.mjs +0 -129
  175. package/registry/nocobase-ai/tests/frontend-tool-regression.mjs +0 -128
  176. package/registry/nocobase-ai/tests/page-context-regression.mjs +0 -48
  177. package/registry/nocobase-ai/tests/stream-regression.mjs +0 -207
  178. package/registry/nocobase-auth-cas/README.md +0 -6
  179. package/registry/nocobase-auth-cas/cas-sign-in-button.tsx +0 -41
  180. package/registry/nocobase-auth-cas/demo.tsx +0 -20
  181. package/registry/nocobase-auth-cas/extension.tsx +0 -46
  182. package/registry/nocobase-auth-cas/index.ts +0 -1
  183. package/registry/nocobase-auth-cas/use-cas-sign-in.ts +0 -29
  184. package/registry/nocobase-auth-dingtalk/README.md +0 -7
  185. package/registry/nocobase-auth-dingtalk/auto-login-provider.tsx +0 -154
  186. package/registry/nocobase-auth-dingtalk/demo.tsx +0 -23
  187. package/registry/nocobase-auth-dingtalk/dingtalk-sign-in-button.tsx +0 -45
  188. package/registry/nocobase-auth-dingtalk/extension.tsx +0 -55
  189. package/registry/nocobase-auth-dingtalk/index.ts +0 -4
  190. package/registry/nocobase-auth-dingtalk/use-dingtalk-sign-in.ts +0 -64
  191. package/registry/nocobase-auth-ldap/README.md +0 -6
  192. package/registry/nocobase-auth-ldap/demo.tsx +0 -21
  193. package/registry/nocobase-auth-ldap/extension.tsx +0 -46
  194. package/registry/nocobase-auth-ldap/index.ts +0 -1
  195. package/registry/nocobase-auth-ldap/ldap-sign-in-form.tsx +0 -69
  196. package/registry/nocobase-auth-ldap/use-ldap-sign-in.ts +0 -5
  197. package/registry/nocobase-auth-oidc/README.md +0 -11
  198. package/registry/nocobase-auth-oidc/auto-redirect-provider.tsx +0 -13
  199. package/registry/nocobase-auth-oidc/demo.tsx +0 -20
  200. package/registry/nocobase-auth-oidc/extension.tsx +0 -51
  201. package/registry/nocobase-auth-oidc/index.ts +0 -1
  202. package/registry/nocobase-auth-oidc/oidc-sign-in-button.tsx +0 -44
  203. package/registry/nocobase-auth-oidc/use-oidc-sign-in.ts +0 -58
  204. package/registry/nocobase-auth-saml/README.md +0 -6
  205. package/registry/nocobase-auth-saml/auto-redirect-provider.tsx +0 -13
  206. package/registry/nocobase-auth-saml/demo.tsx +0 -20
  207. package/registry/nocobase-auth-saml/extension.tsx +0 -51
  208. package/registry/nocobase-auth-saml/index.ts +0 -1
  209. package/registry/nocobase-auth-saml/saml-sign-in-button.tsx +0 -43
  210. package/registry/nocobase-auth-saml/use-saml-sign-in.ts +0 -51
  211. package/registry/nocobase-auth-sms/README.md +0 -7
  212. package/registry/nocobase-auth-sms/demo.tsx +0 -25
  213. package/registry/nocobase-auth-sms/extension.tsx +0 -46
  214. package/registry/nocobase-auth-sms/index.ts +0 -1
  215. package/registry/nocobase-auth-sms/sms-sign-in-form.tsx +0 -107
  216. package/registry/nocobase-auth-sms/use-sms-sign-in.ts +0 -88
  217. package/registry/nocobase-auth-wecom/README.md +0 -6
  218. package/registry/nocobase-auth-wecom/auto-login-provider.tsx +0 -21
  219. package/registry/nocobase-auth-wecom/demo.tsx +0 -23
  220. package/registry/nocobase-auth-wecom/extension.tsx +0 -49
  221. package/registry/nocobase-auth-wecom/index.ts +0 -1
  222. package/registry/nocobase-auth-wecom/use-wecom-sign-in.ts +0 -62
  223. package/registry/nocobase-auth-wecom/wecom-sign-in-button.tsx +0 -70
  224. package/registry/nocobase-i18n/README.md +0 -44
  225. package/registry/nocobase-i18n/components/index.ts +0 -1
  226. package/registry/nocobase-i18n/components/language-switcher.tsx +0 -138
  227. package/registry/nocobase-i18n/demo/index.tsx +0 -209
  228. package/registry/nocobase-i18n/demo/prompt-generator.tsx +0 -132
  229. package/registry/nocobase-i18n/extension.tsx +0 -45
  230. package/registry/nocobase-i18n/index.ts +0 -7
  231. package/registry/nocobase-i18n/locales/en-US.ts +0 -39
  232. package/registry/nocobase-i18n/locales/index.ts +0 -8
  233. package/registry/nocobase-i18n/locales/zh-CN.ts +0 -35
  234. package/registry/nocobase-i18n/provider.tsx +0 -44
  235. package/registry/nocobase-i18n/server-resources.ts +0 -166
  236. package/registry/nocobase-i18n/tests/i18n-regression.mjs +0 -51
  237. package/registry.config.json +0 -302
  238. package/scripts/registry.mjs +0 -164
  239. package/src/components/access-control/resource-access-guard.tsx +0 -21
  240. package/src/components/access-control/use-acl-runtime.ts +0 -28
  241. package/src/lib/nocobase/acl/action.ts +0 -147
  242. package/src/pages/users/layout.tsx +0 -15
  243. package/src/pages/users/show.tsx +0 -278
  244. /package/{registry → src/extensions}/nocobase-acl/components/index.ts +0 -0
  245. /package/{registry → src/extensions}/nocobase-acl/components/role-options.ts +0 -0
  246. /package/{registry → src/extensions}/nocobase-acl/demo/components.tsx +0 -0
  247. /package/{registry → src/extensions}/nocobase-acl/demo/lazy-route.tsx +0 -0
  248. /package/{registry → src/extensions}/nocobase-acl/demo/role-switcher-prompt-generator.tsx +0 -0
  249. /package/{registry → src/extensions}/nocobase-acl/demo/scenario-section.tsx +0 -0
  250. /package/{registry → src/extensions}/nocobase-acl/index.ts +0 -0
  251. /package/{registry → src/extensions}/nocobase-ai/adapters/react-hook-form.ts +0 -0
  252. /package/{registry → src/extensions}/nocobase-ai/assets/nocobase-ai-chat.svg +0 -0
  253. /package/{registry → src/extensions}/nocobase-ai/components/ai-root-provider.tsx +0 -0
  254. /package/{registry → src/extensions}/nocobase-ai/components/chat/ai-employee-avatar.tsx +0 -0
  255. /package/{registry → src/extensions}/nocobase-ai/components/chat/chat-attachment.tsx +0 -0
  256. /package/{registry → src/extensions}/nocobase-ai/components/chat/chat-compact.tsx +0 -0
  257. /package/{registry → src/extensions}/nocobase-ai/components/chat/chat-empty-state.tsx +0 -0
  258. /package/{registry → src/extensions}/nocobase-ai/components/chat/chat-header.tsx +0 -0
  259. /package/{registry → src/extensions}/nocobase-ai/components/chat/chat-history-dialog.tsx +0 -0
  260. /package/{registry → src/extensions}/nocobase-ai/components/chat/chat-message.tsx +0 -0
  261. /package/{registry → src/extensions}/nocobase-ai/components/chat/chat-window.tsx +0 -0
  262. /package/{registry → src/extensions}/nocobase-ai/components/chat/conversation-list.tsx +0 -0
  263. /package/{registry → src/extensions}/nocobase-ai/components/chat/markdown-message.tsx +0 -0
  264. /package/{registry → src/extensions}/nocobase-ai/components/chat/model-select-options.tsx +0 -0
  265. /package/{registry → src/extensions}/nocobase-ai/components/chat/reasoning-panel.tsx +0 -0
  266. /package/{registry → src/extensions}/nocobase-ai/components/chat/sub-agent-conversation.tsx +0 -0
  267. /package/{registry → src/extensions}/nocobase-ai/components/chat/user-prompt-editor.tsx +0 -0
  268. /package/{registry → src/extensions}/nocobase-ai/components/chat/work-context-chip.tsx +0 -0
  269. /package/{registry → src/extensions}/nocobase-ai/components/page-elements/ai-form.tsx +0 -0
  270. /package/{registry → src/extensions}/nocobase-ai/components/page-elements/page-element-provider.tsx +0 -0
  271. /package/{registry → src/extensions}/nocobase-ai/components/surfaces/chat-inline.tsx +0 -0
  272. /package/{registry → src/extensions}/nocobase-ai/components/surfaces/chat-page.tsx +0 -0
  273. /package/{registry → src/extensions}/nocobase-ai/components/surfaces/chat-side-panel-layout.tsx +0 -0
  274. /package/{registry → src/extensions}/nocobase-ai/components/surfaces/chat-surface-actions.tsx +0 -0
  275. /package/{registry → src/extensions}/nocobase-ai/components/tools/builtin-tool-renderers.tsx +0 -0
  276. /package/{registry → src/extensions}/nocobase-ai/components/tools/business-report-dialog.tsx +0 -0
  277. /package/{registry → src/extensions}/nocobase-ai/components/tools/business-report-renderer.tsx +0 -0
  278. /package/{registry → src/extensions}/nocobase-ai/components/tools/business-report-utils.tsx +0 -0
  279. /package/{registry → src/extensions}/nocobase-ai/components/tools/chart-renderer.tsx +0 -0
  280. /package/{registry → src/extensions}/nocobase-ai/components/tools/echarts-preview.tsx +0 -0
  281. /package/{registry → src/extensions}/nocobase-ai/components/tools/echarts-runtime-advanced.ts +0 -0
  282. /package/{registry → src/extensions}/nocobase-ai/components/tools/echarts-runtime-common.ts +0 -0
  283. /package/{registry → src/extensions}/nocobase-ai/components/tools/echarts-runtime-components.ts +0 -0
  284. /package/{registry → src/extensions}/nocobase-ai/components/tools/echarts-runtime-hierarchy.ts +0 -0
  285. /package/{registry → src/extensions}/nocobase-ai/components/tools/echarts-runtime.ts +0 -0
  286. /package/{registry → src/extensions}/nocobase-ai/components/tools/sub-agent-renderer.tsx +0 -0
  287. /package/{registry → src/extensions}/nocobase-ai/components/tools/suggestions-renderer.tsx +0 -0
  288. /package/{registry → src/extensions}/nocobase-ai/components/tools/tool-renderer-provider.tsx +0 -0
  289. /package/{registry → src/extensions}/nocobase-ai/components/tools/tool-renderer-utils.ts +0 -0
  290. /package/{registry → src/extensions}/nocobase-ai/components/tools/workflow-renderer.tsx +0 -0
  291. /package/{registry → src/extensions}/nocobase-ai/components/triggers/ai-employee-shortcut.tsx +0 -0
  292. /package/{registry → src/extensions}/nocobase-ai/demo/interaction-showcase.tsx +0 -0
  293. /package/{registry → src/extensions}/nocobase-ai/demo/page-context-prompt-generator.tsx +0 -0
  294. /package/{registry → src/extensions}/nocobase-ai/demo/page-context.tsx +0 -0
  295. /package/{registry → src/extensions}/nocobase-ai/demo/page-element-showcase.tsx +0 -0
  296. /package/{registry → src/extensions}/nocobase-ai/demo/prompt-card.tsx +0 -0
  297. /package/{registry → src/extensions}/nocobase-ai/demo/shortcut.tsx +0 -0
  298. /package/{registry → src/extensions}/nocobase-ai/index.ts +0 -0
  299. /package/{registry → src/extensions}/nocobase-ai/providers/avatars.ts +0 -0
  300. /package/{registry → src/extensions}/nocobase-ai/providers/chat-controller.ts +0 -0
  301. /package/{registry → src/extensions}/nocobase-ai/providers/chat-message-utils.ts +0 -0
  302. /package/{registry → src/extensions}/nocobase-ai/providers/chat-reducer.ts +0 -0
  303. /package/{registry → src/extensions}/nocobase-ai/providers/chat-task-utils.ts +0 -0
  304. /package/{registry → src/extensions}/nocobase-ai/providers/chat-transport.ts +0 -0
  305. /package/{registry → src/extensions}/nocobase-ai/providers/form-registry.tsx +0 -0
  306. /package/{registry → src/extensions}/nocobase-ai/providers/frontend-tool-registry.tsx +0 -0
  307. /package/{registry → src/extensions}/nocobase-ai/providers/index.ts +0 -0
  308. /package/{registry → src/extensions}/nocobase-ai/providers/model.ts +0 -0
  309. /package/{registry → src/extensions}/nocobase-ai/providers/page-context.tsx +0 -0
  310. /package/{registry → src/extensions}/nocobase-ai/providers/stream-coalescer.ts +0 -0
  311. /package/{registry → src/extensions}/nocobase-ai/providers/stream-event-utils.ts +0 -0
  312. /package/{registry → src/extensions}/nocobase-ai/providers/stream-parser.ts +0 -0
  313. /package/{registry → src/extensions}/nocobase-ai/providers/sub-agent-stream.ts +0 -0
  314. /package/{registry → src/extensions}/nocobase-ai/providers/types.ts +0 -0
  315. /package/{registry → src/extensions}/nocobase-ai/providers/ui-message-stream.ts +0 -0
  316. /package/{registry → src/extensions}/nocobase-ai/providers/use-automatic-tool-approval.ts +0 -0
  317. /package/{registry → src/extensions}/nocobase-ai/providers/use-chat-message-actions.ts +0 -0
  318. /package/{registry → src/extensions}/nocobase-ai/providers/use-chat-runtime.ts +0 -0
  319. /package/{registry → src/extensions}/nocobase-ai/providers/use-conversation-catalog.ts +0 -0
  320. /package/{registry → src/extensions}/nocobase-ai/providers/use-conversation-history.ts +0 -0
  321. /package/{registry → src/extensions}/nocobase-ai/services/index.ts +0 -0
  322. /package/{registry → src/extensions}/nocobase-ai/services/nocobase-ai-service.ts +0 -0
  323. /package/{registry → src/extensions}/nocobase-ai/services/types.ts +0 -0
  324. /package/{registry → src/extensions}/nocobase-route-surfaces/demo/lazy-route.tsx +0 -0
  325. /package/{registry → src/extensions}/nocobase-route-surfaces/demo/prompt-generator.tsx +0 -0
  326. /package/{registry → src/extensions}/nocobase-route-surfaces/index.ts +0 -0
  327. /package/{registry → src/extensions}/nocobase-route-surfaces/route-dialog.tsx +0 -0
  328. /package/{registry → src/extensions}/nocobase-route-surfaces/route-drawer.tsx +0 -0
  329. /package/{registry → src/extensions}/nocobase-route-surfaces/route-page.tsx +0 -0
  330. /package/{registry → src/extensions}/nocobase-route-surfaces/route-surface-context.ts +0 -0
  331. /package/{registry → src/extensions}/nocobase-route-surfaces/use-refine-unsaved-changes.tsx +0 -0
  332. /package/{registry → src/extensions}/nocobase-route-surfaces/use-route-surface-close.ts +0 -0
  333. /package/{registry → src/extensions}/nocobase-route-surfaces/use-route-surface-state.ts +0 -0
  334. /package/src/{pages/users → extensions/nocobase-users-example}/form-fields.tsx +0 -0
  335. /package/src/{pages/users → extensions/nocobase-users-example}/index.ts +0 -0
  336. /package/src/{pages/users → extensions/nocobase-users-example}/role-badges.tsx +0 -0
  337. /package/src/{pages/users → extensions/nocobase-users-example}/role-utils.ts +0 -0
  338. /package/src/{pages/users → extensions/nocobase-users-example}/types.ts +0 -0
@@ -0,0 +1 @@
1
+ import{aZ as g,b as t,a_ as d,a$ as i}from"./index-MB-jfQld.js";function w(){return typeof navigator<"u"&&navigator.userAgent.toLowerCase().includes("dingtalk")}function k(n){const[r]=g(),[c,o]=t.useState(!1),[l,s]=t.useState(),u=t.useMemo(()=>{if(r.get("authenticator")!==n.name)return;const e=r.get("error");return e?new Error(e):void 0},[n.name,r]);return{signIn:t.useCallback(async()=>{s(void 0),o(!0);try{const e=d(r.get("to")||r.get("redirect")||"/"),a=await i.action("dingtalk","getAuthUrl",{method:"POST",authenticator:n.name,includeRole:!1,withAclMeta:!1,body:{redirect:e}});if(!(a!=null&&a.url))throw new Error("NocoBase did not return a DingTalk authorization URL.");window.location.replace(i.resolveUrl(a.url))}catch(e){s(e instanceof Error?e:new Error("Unable to start DingTalk sign-in.")),o(!1)}},[n.name,r]),isPending:c,error:l??u}}export{w as i,k as u};
@@ -0,0 +1 @@
1
+ import{aZ as m,b as n,a_ as d,a$ as i}from"./index-MB-jfQld.js";function g(){return typeof navigator<"u"&&navigator.userAgent.toLowerCase().includes("wxwork")}function h(o){const[r]=m(),[c,a]=n.useState(!1),[l,s]=n.useState(),u=n.useMemo(()=>{if(r.get("authenticator")!==o.name)return;const e=r.get("errorMsg");return e?new Error(e):void 0},[o.name,r]);return{signIn:n.useCallback(async()=>{s(void 0),a(!0);try{const e=d(r.get("to")||r.get("redirect")||"/"),t=await i.action("wecom","getAuthUrl",{method:"POST",authenticator:o.name,includeRole:!1,withAclMeta:!1,body:{redirect:e,isWeComBrowser:g()}});if(!(t!=null&&t.url))throw new Error("NocoBase did not return a WeCom authorization URL.");window.location.replace(i.resolveUrl(t.url))}catch(e){s(e instanceof Error?e:new Error("Unable to start WeCom sign-in.")),a(!1)}},[o.name,r]),isPending:c,error:l??u}}export{g as i,h as u};
@@ -0,0 +1 @@
1
+ import{j as s,D as c,b8 as d,r as p,aT as x,aV as m,aW as g,b9 as u,ba as T,bb as j}from"./index-MB-jfQld.js";import{u as b}from"./use-wecom-sign-in-C9j8wfCD.js";function f(e){return typeof e=="string"?e.replace(/<[^>]+>/g," ").replace(/\s+/g," ").trim():""}function W({authenticator:e,onSignIn:i}){var a;const{signIn:o,isPending:t,error:n}=b(e),r=f((a=e.options)==null?void 0:a.btnTooltip),l=s.jsxs(c,{type:"button",variant:"outline",className:"w-full",disabled:!i&&t,onClick:i??o,children:[s.jsx(d,{}),!i&&t?"Redirecting…":p(e.title||e.authTypeTitle||"Sign in via WeCom")]});return s.jsxs("div",{className:"space-y-3",children:[n&&s.jsxs(x,{variant:"destructive",children:[s.jsx(m,{children:"WeCom sign-in failed"}),s.jsx(g,{children:n.message})]}),r?s.jsxs(u,{children:[s.jsx(T,{render:l}),s.jsx(j,{side:"right",className:"max-w-xs",children:r})]}):l]})}export{W as default};
package/dist/index.html CHANGED
@@ -20,8 +20,8 @@
20
20
  content="/logo-mark.png"
21
21
  />
22
22
  <title>NocoBase</title>
23
- <script type="module" crossorigin src="/assets/index-C6xNKxpg.js"></script>
24
- <link rel="stylesheet" crossorigin href="/assets/index-YA7-AUO8.css">
23
+ <script type="module" crossorigin src="/assets/index-MB-jfQld.js"></script>
24
+ <link rel="stylesheet" crossorigin href="/assets/index-NH3aqqQz.css">
25
25
  </head>
26
26
  <body>
27
27
  <noscript>You need to enable JavaScript to run this app.</noscript>
@@ -24,10 +24,13 @@
24
24
  <script>
25
25
  window.NOCOBASE_PORTAL_BASE = "/";
26
26
  window.NOCOBASE_API_URL = "/api";
27
+ window.__nocobase_api_client_storage_prefix__ = window.__nocobase_api_client_storage_prefix__ ?? "NOCOBASE_";
28
+ window.__nocobase_api_client_storage_type__ = window.__nocobase_api_client_storage_type__ ?? "localStorage";
29
+ window.__nocobase_api_client_share_token__ = window.__nocobase_api_client_share_token__ ?? false;
27
30
  </script>
28
31
  <!-- nocobase-runtime-config:end -->
29
- <script type="module" crossorigin src="/assets/index-C6xNKxpg.js"></script>
30
- <link rel="stylesheet" crossorigin href="/assets/index-YA7-AUO8.css">
32
+ <script type="module" crossorigin src="/assets/index-MB-jfQld.js"></script>
33
+ <link rel="stylesheet" crossorigin href="/assets/index-NH3aqqQz.css">
31
34
  </head>
32
35
  <body>
33
36
  <noscript>You need to enable JavaScript to run this app.</noscript>
package/package.json CHANGED
@@ -1,6 +1,7 @@
1
1
  {
2
2
  "name": "@nocobase/portal-template-default",
3
- "version": "1.0.9",
3
+ "version": "1.0.11",
4
+ "packageManager": "pnpm@10.28.0",
4
5
  "type": "module",
5
6
  "devDependencies": {
6
7
  "@ai-sdk/react": "2.0.0",
@@ -77,13 +78,10 @@
77
78
  "url": "git+https://github.com/nocobase/portal-template-default.git"
78
79
  },
79
80
  "scripts": {
80
- "postinstall": "node ./scripts/registry.mjs install-missing",
81
81
  "dev": "vite",
82
82
  "build": "tsc && refine build",
83
83
  "build:html": "node ./scripts/build-html.mjs",
84
- "registry:install": "node ./scripts/registry.mjs install-missing",
85
- "registry:preview": "node ./scripts/registry.mjs preview",
86
- "registry:build": "node ./scripts/registry.mjs build && shadcn build ./registry.json -o ./public/r",
84
+ "test:auth": "node tests/auth-session-regression.mjs",
87
85
  "test:acl": "node registry/nocobase-acl/tests/acl-regression.mjs",
88
86
  "test:i18n": "node registry/nocobase-i18n/tests/i18n-regression.mjs",
89
87
  "start": "refine start",
@@ -65,6 +65,15 @@ const stripExistingRuntimeConfig = (html) => {
65
65
 
66
66
  const portalBase = normalizePortalBase(process.env.NOCOBASE_PORTAL_BASE);
67
67
  const apiUrl = String(process.env.NOCOBASE_API_URL || "/api").trim() || "/api";
68
+ const storagePrefix =
69
+ String(process.env.API_CLIENT_STORAGE_PREFIX || "NOCOBASE_").trim() ||
70
+ "NOCOBASE_";
71
+ const storageType =
72
+ String(process.env.API_CLIENT_STORAGE_TYPE || "localStorage").trim() ||
73
+ "localStorage";
74
+ const shareToken = /^true$/i.test(
75
+ String(process.env.API_CLIENT_SHARE_TOKEN || "false").trim()
76
+ );
68
77
 
69
78
  if (!fs.existsSync(rawIndexPath)) {
70
79
  throw new Error(
@@ -76,6 +85,9 @@ const runtimeConfig = `${startMarker}
76
85
  <script>
77
86
  window.NOCOBASE_PORTAL_BASE = ${JSON.stringify(portalBase)};
78
87
  window.NOCOBASE_API_URL = ${JSON.stringify(apiUrl)};
88
+ window.__nocobase_api_client_storage_prefix__ = ${JSON.stringify(storagePrefix)};
89
+ window.__nocobase_api_client_storage_type__ = ${JSON.stringify(storageType)};
90
+ window.__nocobase_api_client_share_token__ = ${JSON.stringify(shareToken)};
79
91
  </script>
80
92
  ${endMarker}
81
93
  `;
package/src/App.css CHANGED
@@ -1,6 +1,8 @@
1
1
  @import "tailwindcss";
2
2
  @import "tw-animate-css";
3
3
  @import "shadcn/tailwind.css";
4
+ @source "./extensions";
5
+ @source "../registry";
4
6
 
5
7
  @custom-variant dark (&:is(.dark *));
6
8
 
package/src/App.tsx CHANGED
@@ -1,92 +1,32 @@
1
- import { Refine, Authenticated, type ResourceProps } from "@refinedev/core";
1
+ import { Refine, type ResourceProps } from "@refinedev/core";
2
2
 
3
- import { BrowserRouter, Route, Routes, Outlet } from "react-router";
3
+ import { BrowserRouter } from "react-router";
4
4
  import routerProvider, {
5
- CatchAllNavigate,
6
5
  UnsavedChangesNotifier,
7
6
  } from "@refinedev/react-router";
8
- import {
9
- UserCreate,
10
- UserEdit,
11
- UserResourceLayout,
12
- RoleDetailRoute,
13
- userRoutes,
14
- UserShow,
15
- } from "./pages/users";
16
7
  import { dataProvider } from "./providers/data";
17
- import { Login } from "./pages/login";
18
- import { Register } from "./pages/register";
19
- import { ForgotPassword } from "./pages/forgot-password";
20
- import { ErrorComponent } from "./components/app-shell/error-component";
21
- import { Layout } from "./components/app-shell/layout";
22
8
  import { DocumentTitleHandler } from "./components/app-shell/document-title-handler";
23
9
  import { useNotificationProvider } from "./components/notifications/use-notification-provider";
24
10
  import { Toaster } from "./components/notifications/toaster";
25
11
  import { ThemeProvider } from "./components/theme/theme-provider";
26
12
  import { TooltipProvider } from "./components/ui/tooltip";
27
13
  import { BrandLogo } from "./components/app-shell/brand";
28
- import {
29
- AppExtensionProviders,
30
- AppAuthRuntimeProviders,
31
- extensionResources,
32
- extensionRouteElements,
33
- } from "./app/extensions";
14
+ import { AppAuthRuntimeProviders, extensionResources } from "./app/extensions";
34
15
  import "./App.css";
35
16
  import { authProvider } from "./providers/auth";
36
17
  import { accessControlProvider } from "./providers/access-control";
37
- import { AclBootstrap } from "./components/access-control/acl-bootstrap";
38
- import { ResourceAccessGuard } from "./components/access-control/resource-access-guard";
39
- import { NavigateToAccessibleResource } from "./components/access-control/navigate-to-accessible-resource";
40
- import { KeyRound, PanelsTopLeft, UsersRound } from "lucide-react";
41
18
  import { i18nProvider } from "./providers/i18n";
42
19
  import { SystemSettingsProvider } from "./providers/system-settings";
43
- import { AuthDemoPage } from "./components/auth/demo";
44
20
  import { getPortalBase } from "./providers/runtime-config";
21
+ import { AclStoreProvider, aclStore } from "./lib/nocobase/acl";
22
+ import { AppRoutes } from "./app/routes";
45
23
 
46
- const coreResources: ResourceProps[] = [
47
- {
48
- name: "users",
49
- list: userRoutes.list,
50
- create: userRoutes.create,
51
- edit: userRoutes.edit,
52
- show: userRoutes.show,
53
- meta: {
54
- label: "Users",
55
- singularLabel: "User",
56
- i18nKey: "resources.users",
57
- i18nSingularKey: "resources.user",
58
- i18nOptions: { ns: "app" },
59
- descriptionI18nKey: "resources.users.description",
60
- icon: <UsersRound />,
61
- description:
62
- "Manage the people who can sign in and work in this NocoBase application.",
63
- canCreate: true,
64
- canDelete: true,
65
- acl: {
66
- type: "collection",
67
- },
68
- },
69
- },
70
- {
71
- name: "auth-components",
72
- meta: {
73
- label: "Authentication",
74
- icon: <KeyRound />,
75
- description: "NocoBase authentication UI and integration patterns.",
76
- acl: { type: "authenticated" },
77
- },
78
- },
79
- {
80
- name: "auth-patterns",
81
- list: "/auth",
82
- meta: {
83
- parent: "auth-components",
84
- label: "Login composition",
85
- icon: <PanelsTopLeft />,
86
- acl: { type: "authenticated" },
87
- },
88
- },
89
- ];
24
+ const getResourcePriority = (resource: ResourceProps) =>
25
+ typeof resource.meta?.priority === "number" ? resource.meta.priority : 100;
26
+
27
+ const appResources = [...extensionResources].sort(
28
+ (left, right) => getResourcePriority(left) - getResourcePriority(right)
29
+ );
90
30
 
91
31
  const basename = getPortalBase().replace(/\/+$/, "");
92
32
 
@@ -97,123 +37,32 @@ function App() {
97
37
  <ThemeProvider>
98
38
  <TooltipProvider>
99
39
  <SystemSettingsProvider>
100
- <Refine
101
- dataProvider={dataProvider}
102
- notificationProvider={useNotificationProvider()}
103
- routerProvider={routerProvider}
104
- authProvider={authProvider}
105
- accessControlProvider={accessControlProvider}
106
- i18nProvider={i18nProvider}
107
- resources={[...coreResources, ...extensionResources]}
108
- options={{
109
- syncWithLocation: true,
110
- warnWhenUnsavedChanges: true,
111
- disableTelemetry: true,
112
- title: {
113
- text: "NocoBase",
114
- icon: <BrandLogo className="size-14 rounded-2xl" />,
115
- },
116
- }}
117
- >
118
- <Routes>
119
- <Route
120
- element={
121
- <Authenticated
122
- key="authenticated-inner"
123
- fallback={<CatchAllNavigate to="/login" />}
124
- >
125
- <AclBootstrap>
126
- <AppExtensionProviders>
127
- <Layout>
128
- <Outlet />
129
- </Layout>
130
- </AppExtensionProviders>
131
- </AclBootstrap>
132
- </Authenticated>
133
- }
134
- >
135
- <Route index element={<NavigateToAccessibleResource />} />
136
- <Route path="/auth" element={<AuthDemoPage />} />
137
- <Route
138
- path="/users"
139
- element={<UserResourceLayout />}
40
+ <AclStoreProvider store={aclStore}>
41
+ <Refine
42
+ dataProvider={dataProvider}
43
+ notificationProvider={useNotificationProvider()}
44
+ routerProvider={routerProvider}
45
+ authProvider={authProvider}
46
+ accessControlProvider={accessControlProvider}
47
+ i18nProvider={i18nProvider}
48
+ resources={appResources}
49
+ options={{
50
+ syncWithLocation: true,
51
+ warnWhenUnsavedChanges: true,
52
+ disableTelemetry: true,
53
+ title: {
54
+ text: "NocoBase",
55
+ icon: <BrandLogo className="size-14 rounded-2xl" />,
56
+ },
57
+ }}
140
58
  >
141
- <Route
142
- path="create"
143
- element={
144
- <ResourceAccessGuard resource="users" action="create">
145
- <UserCreate />
146
- </ResourceAccessGuard>
147
- }
148
- />
149
- <Route
150
- path="edit/:id"
151
- element={
152
- <ResourceAccessGuard resource="users" action="edit">
153
- <UserEdit />
154
- </ResourceAccessGuard>
155
- }
156
- />
157
- <Route
158
- path="roles/:roleName"
159
- element={
160
- <ResourceAccessGuard resource="roles" action="show">
161
- <RoleDetailRoute returnTo="list" />
162
- </ResourceAccessGuard>
163
- }
164
- />
165
- <Route
166
- path="show/:id"
167
- element={
168
- <ResourceAccessGuard resource="users" action="show">
169
- <UserShow />
170
- </ResourceAccessGuard>
171
- }
172
- >
173
- <Route
174
- path="edit"
175
- element={
176
- <ResourceAccessGuard resource="users" action="edit">
177
- <UserEdit returnTo="show" />
178
- </ResourceAccessGuard>
179
- }
180
- />
181
- <Route
182
- path="roles/:roleName"
183
- element={
184
- <ResourceAccessGuard resource="roles" action="show">
185
- <RoleDetailRoute returnTo="show" />
186
- </ResourceAccessGuard>
187
- }
188
- />
189
- </Route>
190
- </Route>
191
- {extensionRouteElements}
192
- <Route path="*" element={<ErrorComponent />} />
193
- </Route>
194
- <Route
195
- element={
196
- <Authenticated
197
- key="authenticated-outer"
198
- fallback={<Outlet />}
199
- >
200
- <AclBootstrap>
201
- <NavigateToAccessibleResource />
202
- </AclBootstrap>
203
- </Authenticated>
204
- }
205
- >
206
- <Route path="/login" element={<Login />} />
207
- <Route path="/signin" element={<Login />} />
208
- <Route path="/register" element={<Register />} />
209
- <Route path="/forgot-password" element={<ForgotPassword />} />
210
- </Route>
211
- </Routes>
59
+ <AppRoutes />
212
60
 
213
- <Toaster />
214
- <UnsavedChangesNotifier />
215
- <DocumentTitleHandler appName="NocoBase" />
216
- </Refine>
61
+ <Toaster />
62
+ <UnsavedChangesNotifier />
63
+ <DocumentTitleHandler appName="NocoBase" />
64
+ </Refine>
65
+ </AclStoreProvider>
217
66
  </SystemSettingsProvider>
218
67
  </TooltipProvider>
219
68
  </ThemeProvider>
@@ -0,0 +1,154 @@
1
+ import type { ResourceProps, TreeMenuItem } from "@refinedev/core";
2
+ import { KeyRound, PanelsTopLeft } from "lucide-react";
3
+ import type { ReactElement } from "react";
4
+ import { Navigate, Outlet, Route, useLocation } from "react-router";
5
+
6
+ import { AuthDemoPage } from "@/components/auth/demo";
7
+ import { Header } from "@/components/app-shell/header";
8
+ import { SidebarNavigation } from "@/components/app-shell/sidebar";
9
+ import { SidebarInset, SidebarProvider } from "@/components/ui/sidebar";
10
+ import { cn } from "@/lib/utils";
11
+ import type { AppExtension } from "./extension";
12
+
13
+ const coreDevelopmentResources: ResourceProps[] = [
14
+ {
15
+ name: "auth-components",
16
+ meta: {
17
+ label: "Authentication",
18
+ icon: <KeyRound />,
19
+ description: "NocoBase authentication UI and integration patterns.",
20
+ },
21
+ },
22
+ {
23
+ name: "auth-patterns",
24
+ list: "auth",
25
+ meta: {
26
+ parent: "auth-components",
27
+ label: "Login composition",
28
+ icon: <PanelsTopLeft />,
29
+ description:
30
+ "Dynamic login and application-owned customization patterns.",
31
+ },
32
+ },
33
+ ];
34
+
35
+ const toDevelopmentPath = (path: string) =>
36
+ `/dev/${path.replace(/^\/+/, "")}`.replace(/\/+$/, "");
37
+
38
+ function collectDevelopmentMenu(extensions: AppExtension[]) {
39
+ const resources = [
40
+ ...coreDevelopmentResources,
41
+ ...extensions.flatMap((extension) => extension.dev?.resources ?? []),
42
+ ];
43
+ const childrenByParent = new Map<string, ResourceProps[]>();
44
+ const roots: ResourceProps[] = [];
45
+
46
+ for (const resource of resources) {
47
+ const parent = resource.meta?.parent;
48
+ if (typeof parent === "string") {
49
+ const children = childrenByParent.get(parent) ?? [];
50
+ children.push(resource);
51
+ childrenByParent.set(parent, children);
52
+ } else {
53
+ roots.push(resource);
54
+ }
55
+ }
56
+
57
+ const toMenuItem = (
58
+ resource: ResourceProps,
59
+ parentKey?: string
60
+ ): TreeMenuItem => {
61
+ const key = parentKey ? `${parentKey}/${resource.name}` : resource.name;
62
+ const children = childrenByParent
63
+ .get(resource.name)
64
+ ?.map((child) => toMenuItem(child, key));
65
+
66
+ return {
67
+ name: resource.name,
68
+ key,
69
+ route:
70
+ typeof resource.list === "string"
71
+ ? toDevelopmentPath(resource.list)
72
+ : undefined,
73
+ meta: resource.meta,
74
+ children: children ?? [],
75
+ };
76
+ };
77
+
78
+ return roots.map((resource) => toMenuItem(resource));
79
+ }
80
+
81
+ function findFirstRoute(items: TreeMenuItem[]): string | undefined {
82
+ for (const item of items) {
83
+ if (item.route) return item.route;
84
+ const childRoute = item.children && findFirstRoute(item.children);
85
+ if (childRoute) return childRoute;
86
+ }
87
+ }
88
+
89
+ function findSelectedKey(items: TreeMenuItem[], pathname: string) {
90
+ const matches: TreeMenuItem[] = [];
91
+
92
+ const visit = (menuItems: TreeMenuItem[]) => {
93
+ for (const item of menuItems) {
94
+ if (
95
+ item.route &&
96
+ (pathname === item.route || pathname.startsWith(`${item.route}/`))
97
+ ) {
98
+ matches.push(item);
99
+ }
100
+ if (item.children) visit(item.children);
101
+ }
102
+ };
103
+
104
+ visit(items);
105
+ return matches.sort(
106
+ (left, right) => (right.route?.length ?? 0) - (left.route?.length ?? 0)
107
+ )[0]?.key;
108
+ }
109
+
110
+ export function createDevelopmentRoute(
111
+ extensions: AppExtension[]
112
+ ): ReactElement {
113
+ const menuItems = collectDevelopmentMenu(extensions);
114
+ const firstRoute = findFirstRoute(menuItems) ?? "/";
115
+ const routes = extensions
116
+ .map((extension) => extension.dev?.routes)
117
+ .filter((route): route is ReactElement => Boolean(route));
118
+
119
+ return (
120
+ <Route
121
+ key="registry-development"
122
+ path="/dev"
123
+ element={<DevelopmentLayout menuItems={menuItems} />}
124
+ >
125
+ <Route index element={<Navigate to={firstRoute} replace />} />
126
+ <Route path="auth" element={<AuthDemoPage />} />
127
+ {routes}
128
+ </Route>
129
+ );
130
+ }
131
+
132
+ function DevelopmentLayout({ menuItems }: { menuItems: TreeMenuItem[] }) {
133
+ const { pathname } = useLocation();
134
+
135
+ return (
136
+ <SidebarProvider>
137
+ <SidebarNavigation
138
+ menuItems={menuItems}
139
+ selectedKey={findSelectedKey(menuItems, pathname)}
140
+ />
141
+ <SidebarInset className="bg-muted/25">
142
+ <Header />
143
+ <main
144
+ className={cn(
145
+ "@container/main mx-auto flex w-full max-w-[1600px] flex-1 flex-col",
146
+ "relative px-4 py-5 md:p-6 lg:px-8 lg:py-7"
147
+ )}
148
+ >
149
+ <Outlet />
150
+ </main>
151
+ </SidebarInset>
152
+ </SidebarProvider>
153
+ );
154
+ }
@@ -4,8 +4,13 @@ import type { AuthenticatorAdapter } from "@/components/auth/types";
4
4
 
5
5
  export type AppExtension = {
6
6
  id: string;
7
+ priority?: number;
7
8
  resources?: ResourceProps[];
8
9
  routes?: ReactElement;
10
+ dev?: {
11
+ resources?: ResourceProps[];
12
+ routes?: ReactElement;
13
+ };
9
14
  Provider?: ComponentType<PropsWithChildren>;
10
15
  AuthRuntimeProvider?: ComponentType<PropsWithChildren>;
11
16
  authRuntimePriority?: number;
@@ -1,15 +1,25 @@
1
- import { Suspense, type PropsWithChildren, type ReactNode } from "react";
1
+ import {
2
+ Suspense,
3
+ type PropsWithChildren,
4
+ type ReactElement,
5
+ type ReactNode,
6
+ } from "react";
2
7
  import type { AppExtension } from "./extension";
3
8
  import { LoadingState } from "@/components/app-shell/loading-state";
9
+ import { createDevelopmentRoute } from "./development";
4
10
 
5
11
  const extensionModules = import.meta.glob<{ default: AppExtension }>(
6
- "../extensions/*/extension.tsx",
12
+ "@/extensions/*/extension.tsx",
7
13
  { eager: true }
8
14
  );
9
15
 
10
16
  export const appExtensions = Object.values(extensionModules)
11
17
  .map((module) => module.default)
12
- .sort((left, right) => left.id.localeCompare(right.id));
18
+ .sort(
19
+ (left, right) =>
20
+ (left.priority ?? 100) - (right.priority ?? 100) ||
21
+ left.id.localeCompare(right.id)
22
+ );
13
23
 
14
24
  export const extensionResources = appExtensions.flatMap(
15
25
  (extension) => extension.resources ?? []
@@ -17,7 +27,11 @@ export const extensionResources = appExtensions.flatMap(
17
27
 
18
28
  export const extensionRouteElements = appExtensions
19
29
  .map((extension) => extension.routes)
20
- .filter((routes): routes is NonNullable<typeof routes> => Boolean(routes));
30
+ .filter((routes): routes is ReactElement => Boolean(routes));
31
+
32
+ export const extensionStandaloneRouteElements = import.meta.env.DEV
33
+ ? [createDevelopmentRoute(appExtensions)]
34
+ : [];
21
35
 
22
36
  export const extensionUserMenuItems = appExtensions
23
37
  .filter((extension) => extension.UserMenuItems)
@@ -0,0 +1,65 @@
1
+ import { Authenticated } from "@refinedev/core";
2
+ import { CatchAllNavigate } from "@refinedev/react-router";
3
+ import { Outlet, Route, Routes } from "react-router";
4
+
5
+ import { AclBootstrap } from "@/components/access-control/acl-bootstrap";
6
+ import { NavigateToAccessibleResource } from "@/components/access-control/navigate-to-accessible-resource";
7
+ import { ErrorComponent } from "@/components/app-shell/error-component";
8
+ import { Layout } from "@/components/app-shell/layout";
9
+ import { ForgotPassword } from "@/pages/forgot-password";
10
+ import { Login } from "@/pages/login";
11
+ import { Register } from "@/pages/register";
12
+ import {
13
+ AppExtensionProviders,
14
+ extensionRouteElements,
15
+ extensionStandaloneRouteElements,
16
+ } from "./extensions";
17
+
18
+ export function AppRoutes() {
19
+ return (
20
+ <Routes>
21
+ <Route
22
+ element={
23
+ <Authenticated
24
+ key="authenticated-inner"
25
+ fallback={<CatchAllNavigate to="/login" />}
26
+ >
27
+ <AclBootstrap>
28
+ <AppExtensionProviders>
29
+ <Outlet />
30
+ </AppExtensionProviders>
31
+ </AclBootstrap>
32
+ </Authenticated>
33
+ }
34
+ >
35
+ {extensionStandaloneRouteElements}
36
+ <Route
37
+ element={
38
+ <Layout>
39
+ <Outlet />
40
+ </Layout>
41
+ }
42
+ >
43
+ <Route index element={<NavigateToAccessibleResource />} />
44
+ {extensionRouteElements}
45
+ <Route path="*" element={<ErrorComponent />} />
46
+ </Route>
47
+ </Route>
48
+
49
+ <Route
50
+ element={
51
+ <Authenticated key="authenticated-outer" fallback={<Outlet />}>
52
+ <AclBootstrap>
53
+ <NavigateToAccessibleResource />
54
+ </AclBootstrap>
55
+ </Authenticated>
56
+ }
57
+ >
58
+ <Route path="/login" element={<Login />} />
59
+ <Route path="/signin" element={<Login />} />
60
+ <Route path="/register" element={<Register />} />
61
+ <Route path="/forgot-password" element={<ForgotPassword />} />
62
+ </Route>
63
+ </Routes>
64
+ );
65
+ }
@@ -1,9 +1,17 @@
1
- import type { PropsWithChildren } from "react";
1
+ import { useEffect, type PropsWithChildren } from "react";
2
2
 
3
+ import { useAclState, useAclStore } from "@/lib/nocobase/acl";
3
4
  import { AclGate } from "./acl-gate";
4
- import { useAclRuntime } from "./use-acl-runtime";
5
5
 
6
6
  export function AclBootstrap({ children }: PropsWithChildren) {
7
- useAclRuntime();
7
+ const store = useAclStore();
8
+ const state = useAclState();
9
+
10
+ useEffect(() => {
11
+ if (state.status === "idle") {
12
+ store.load();
13
+ }
14
+ }, [state.status, store]);
15
+
8
16
  return <AclGate>{children}</AclGate>;
9
17
  }