@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
@@ -74,8 +74,11 @@ export function useChatWorkContext(activeConversationId: string) {
74
74
  );
75
75
 
76
76
  const clearWorkContext = useCallback(() => setDrafts({}), []);
77
+ // Shared EMPTY_CONTEXT rather than a fresh `[]` — see getConversationAttachments: the send path
78
+ // compares this by identity across an await, so a new array each call would read as "the user
79
+ // changed the work context" and silently abort every send.
77
80
  const getConversationWorkContext = useCallback(
78
- (conversationId: string) => draftsRef.current[conversationId] ?? [],
81
+ (conversationId: string) => draftsRef.current[conversationId] ?? EMPTY_CONTEXT,
79
82
  []
80
83
  );
81
84
  const workContext = drafts[activeConversationId] ?? EMPTY_CONTEXT;
@@ -3,7 +3,8 @@
3
3
  Route surfaces keep URL navigation separate from visual presentation. The same
4
4
  business content can be hosted by a routed drawer, dialog, or full page.
5
5
 
6
- The Registry also installs a lazy-loaded Demo route at `/route-surfaces` with
6
+ In development, the Registry also installs a lazy-loaded Demo route at
7
+ `/dev/route-surfaces` with
7
8
  live drawer, dialog, child-page, nested-drawer, and mixed page/drawer/dialog
8
9
  scenarios plus a Prompt generator.
9
10
 
@@ -1,9 +1,15 @@
1
1
  import { ArrowLeft, ArrowRight, Layers3 } from "lucide-react";
2
- import { useOutlet, useNavigate } from "react-router";
2
+ import { useLocation, useOutlet, useNavigate } from "react-router";
3
3
 
4
4
  import { Badge } from "@/components/ui/badge";
5
5
  import { Button } from "@/components/ui/button";
6
- import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card";
6
+ import {
7
+ Card,
8
+ CardContent,
9
+ CardDescription,
10
+ CardHeader,
11
+ CardTitle,
12
+ } from "@/components/ui/card";
7
13
  import {
8
14
  RouteDialog,
9
15
  RouteDrawer,
@@ -13,7 +19,16 @@ import {
13
19
  import { RouteSurfacePromptGenerator } from "./prompt-generator";
14
20
  import { routeSurfaceScenarios } from "./scenarios";
15
21
 
16
- const demoBase = "/route-surfaces";
22
+ const routeSurfaceRoot = "/route-surfaces";
23
+
24
+ function useRouteSurfaceDemoBase() {
25
+ const { pathname } = useLocation();
26
+ const rootIndex = pathname.indexOf(routeSurfaceRoot);
27
+
28
+ return rootIndex >= 0
29
+ ? pathname.slice(0, rootIndex + routeSurfaceRoot.length)
30
+ : routeSurfaceRoot;
31
+ }
17
32
 
18
33
  export function RouteSurfacesDemoHome() {
19
34
  const navigate = useNavigate();
@@ -29,8 +44,8 @@ export function RouteSurfacesDemoHome() {
29
44
  </h1>
30
45
  <p className="max-w-3xl text-muted-foreground">
31
46
  Keep business content independent from whether it appears as a page,
32
- drawer, dialog, or nested combination. Every preview below supports a
33
- direct URL and browser history.
47
+ drawer, dialog, or nested combination. Every preview below supports
48
+ a direct URL and browser history.
34
49
  </p>
35
50
  </div>
36
51
 
@@ -72,6 +87,7 @@ export function RouteSurfacesDemoHome() {
72
87
  export function DemoDrawerRoute() {
73
88
  const navigate = useNavigate();
74
89
  const nested = useOutlet();
90
+ const demoBase = useRouteSurfaceDemoBase();
75
91
 
76
92
  return (
77
93
  <RouteDrawer
@@ -96,6 +112,8 @@ export function DemoDrawerRoute() {
96
112
  }
97
113
 
98
114
  export function DemoSecondDrawerRoute() {
115
+ const demoBase = useRouteSurfaceDemoBase();
116
+
99
117
  return (
100
118
  <RouteDrawer
101
119
  title="Renewal activity"
@@ -113,6 +131,8 @@ export function DemoSecondDrawerRoute() {
113
131
  }
114
132
 
115
133
  export function DemoDialogRoute() {
134
+ const demoBase = useRouteSurfaceDemoBase();
135
+
116
136
  return (
117
137
  <RouteDialog
118
138
  title="Approve renewal"
@@ -131,6 +151,7 @@ export function DemoDialogRoute() {
131
151
 
132
152
  export function DemoPageRoute() {
133
153
  const nested = useOutlet();
154
+ const demoBase = useRouteSurfaceDemoBase();
134
155
 
135
156
  return (
136
157
  <RoutePage closeTo={demoBase}>
@@ -153,7 +174,8 @@ function DemoPageContent({ nested }: { nested: React.ReactNode }) {
153
174
  Customer workspace
154
175
  </h1>
155
176
  <p className="text-muted-foreground">
156
- This route replaces the Demo home instead of rendering inside its Outlet.
177
+ This route replaces the Demo home instead of rendering inside its
178
+ Outlet.
157
179
  </p>
158
180
  </div>
159
181
  <Button variant="outline" onClick={() => void close()}>
@@ -169,7 +191,8 @@ function DemoPageContent({ nested }: { nested: React.ReactNode }) {
169
191
  <CardTitle>Page-owned workflow</CardTitle>
170
192
  </div>
171
193
  <CardDescription>
172
- A page can still host routed overlays without becoming coupled to their content.
194
+ A page can still host routed overlays without becoming coupled to
195
+ their content.
173
196
  </CardDescription>
174
197
  </CardHeader>
175
198
  <CardContent>
@@ -185,6 +208,7 @@ function DemoPageContent({ nested }: { nested: React.ReactNode }) {
185
208
  export function DemoPageDrawerRoute() {
186
209
  const navigate = useNavigate();
187
210
  const nested = useOutlet();
211
+ const demoBase = useRouteSurfaceDemoBase();
188
212
 
189
213
  return (
190
214
  <RouteDrawer
@@ -209,6 +233,8 @@ export function DemoPageDrawerRoute() {
209
233
  }
210
234
 
211
235
  export function DemoPageDrawerDialogRoute() {
236
+ const demoBase = useRouteSurfaceDemoBase();
237
+
212
238
  return (
213
239
  <RouteDialog
214
240
  title="Confirm follow-up"
@@ -19,40 +19,45 @@ export const routeSurfaceScenarios: RouteSurfaceScenario[] = [
19
19
  id: "drawer",
20
20
  number: "1",
21
21
  title: "Drawer route",
22
- description: "Keep the current page mounted and open one URL-backed drawer.",
23
- path: "/route-surfaces/drawer",
22
+ description:
23
+ "Keep the current page mounted and open one URL-backed drawer.",
24
+ path: "drawer",
24
25
  routeShape: "Page → Drawer",
25
26
  },
26
27
  {
27
28
  id: "dialog",
28
29
  number: "2",
29
30
  title: "Dialog route",
30
- description: "Open focused content in a modal while preserving the page URL history.",
31
- path: "/route-surfaces/dialog",
31
+ description:
32
+ "Open focused content in a modal while preserving the page URL history.",
33
+ path: "dialog",
32
34
  routeShape: "Page → Dialog",
33
35
  },
34
36
  {
35
37
  id: "page",
36
38
  number: "3",
37
39
  title: "Child page",
38
- description: "Replace the current page instead of rendering the child inside an overlay.",
39
- path: "/route-surfaces/page",
40
+ description:
41
+ "Replace the current page instead of rendering the child inside an overlay.",
42
+ path: "page",
40
43
  routeShape: "Page → Child page",
41
44
  },
42
45
  {
43
46
  id: "nested-drawers",
44
47
  number: "4",
45
48
  title: "Second-level drawer",
46
- description: "Push the lower drawer outward and keep the top drawer at a stable size.",
47
- path: "/route-surfaces/drawer/second",
49
+ description:
50
+ "Push the lower drawer outward and keep the top drawer at a stable size.",
51
+ path: "drawer/second",
48
52
  routeShape: "Page → Drawer → Drawer",
49
53
  },
50
54
  {
51
55
  id: "page-drawer-dialog",
52
56
  number: "5",
53
57
  title: "Page, drawer, and dialog",
54
- description: "Compose different presentation types without coupling business content to them.",
55
- path: "/route-surfaces/page/drawer/dialog",
58
+ description:
59
+ "Compose different presentation types without coupling business content to them.",
60
+ path: "page/drawer/dialog",
56
61
  routeShape: "Child page → Drawer → Dialog",
57
62
  },
58
63
  ];
@@ -66,15 +71,16 @@ export function getRouteSurfacePrompt(
66
71
  "Keep the current page mounted and open the target content with RouteDrawer. Closing the drawer returns to the page route.",
67
72
  dialog:
68
73
  "Keep the current page mounted and open the target content with RouteDialog. The dialog route must be directly addressable and dismissible through the shared close lifecycle.",
69
- page:
70
- "Render the target content as a real child page with RoutePage. Register it as a page route branch rather than placing it inside a drawer outlet.",
74
+ page: "Render the target content as a real child page with RoutePage. Register it as a page route branch rather than placing it inside a drawer outlet.",
71
75
  "nested-drawers":
72
76
  "Create a parent RouteDrawer with an Outlet and pass the rendered child outlet through its nested prop. The second RouteDrawer must push the lower drawer outward, keep equal widths, and close back to the parent route.",
73
77
  "page-drawer-dialog":
74
78
  "Render a RoutePage first, place a RouteDrawer route inside that page, then render a RouteDialog as the drawer's nested route. Closing each layer must return to the immediately lower URL.",
75
79
  }[scenario.id];
76
80
 
77
- return `Build ${target || "the requested workflow"} with the installed NocoBase route surfaces.
81
+ return `Build ${
82
+ target || "the requested workflow"
83
+ } with the installed NocoBase route surfaces.
78
84
 
79
85
  Scenario:
80
86
  - ${scenario.routeShape}
@@ -89,7 +95,7 @@ Implementation requirements:
89
95
  - A full child page must be a page route branch, not an Outlet rendered inside a drawer.
90
96
  - For editable forms, use useRefineUnsavedChangesGuard, pass its beforeClose callback to the surface, render its confirmation node, and use useRouteSurfaceClose for Cancel and successful submission.
91
97
  - Direct URL entry, refresh, browser back/forward, Escape, the close button, and backdrop dismissal must all restore the correct layer stack.
92
- - Apply ResourceAccessGuard to each business resource/action independently; do not rely on a parent list permission for unrelated child pages.
98
+ - Apply Refine CanAccess with an AccessDenied fallback to each business resource/action independently; do not rely on a parent list permission for unrelated child pages.
93
99
 
94
100
  Deliver the complete route definitions and React components using the application's existing design system.`;
95
101
  }
@@ -36,84 +36,87 @@ const DemoPageDrawerDialog = lazy(() =>
36
36
 
37
37
  const routeSurfacesExtension: AppExtension = {
38
38
  id: "nocobase-route-surfaces",
39
- resources: [
40
- {
41
- name: "route-surfaces",
42
- list: "/route-surfaces",
43
- meta: {
44
- label: "Route surfaces",
45
- icon: <Layers3 />,
46
- description: "URL-backed drawer, dialog, page, and nested route patterns.",
47
- acl: { type: "authenticated" },
39
+ dev: {
40
+ resources: [
41
+ {
42
+ name: "route-surfaces",
43
+ list: "route-surfaces",
44
+ meta: {
45
+ label: "Route surfaces",
46
+ icon: <Layers3 />,
47
+ description:
48
+ "URL-backed drawer, dialog, page, and nested route patterns.",
49
+ acl: { type: "authenticated" },
50
+ },
48
51
  },
49
- },
50
- ],
51
- routes: (
52
- <>
53
- <Route
54
- key="route-surfaces-overlays"
55
- path="/route-surfaces"
56
- element={
57
- <LazyRouteSurfaceDemo>
58
- <DemoHome />
59
- </LazyRouteSurfaceDemo>
60
- }
61
- >
52
+ ],
53
+ routes: (
54
+ <>
62
55
  <Route
63
- path="drawer"
56
+ key="route-surfaces-overlays"
57
+ path="route-surfaces"
64
58
  element={
65
59
  <LazyRouteSurfaceDemo>
66
- <DemoDrawer />
60
+ <DemoHome />
67
61
  </LazyRouteSurfaceDemo>
68
62
  }
69
63
  >
70
64
  <Route
71
- path="second"
65
+ path="drawer"
72
66
  element={
73
67
  <LazyRouteSurfaceDemo>
74
- <DemoSecondDrawer />
68
+ <DemoDrawer />
69
+ </LazyRouteSurfaceDemo>
70
+ }
71
+ >
72
+ <Route
73
+ path="second"
74
+ element={
75
+ <LazyRouteSurfaceDemo>
76
+ <DemoSecondDrawer />
77
+ </LazyRouteSurfaceDemo>
78
+ }
79
+ />
80
+ </Route>
81
+ <Route
82
+ path="dialog"
83
+ element={
84
+ <LazyRouteSurfaceDemo>
85
+ <DemoDialog />
75
86
  </LazyRouteSurfaceDemo>
76
87
  }
77
88
  />
78
89
  </Route>
79
90
  <Route
80
- path="dialog"
91
+ key="route-surfaces-page"
92
+ path="route-surfaces/page"
81
93
  element={
82
94
  <LazyRouteSurfaceDemo>
83
- <DemoDialog />
84
- </LazyRouteSurfaceDemo>
85
- }
86
- />
87
- </Route>
88
- <Route
89
- key="route-surfaces-page"
90
- path="/route-surfaces/page"
91
- element={
92
- <LazyRouteSurfaceDemo>
93
- <DemoPage />
94
- </LazyRouteSurfaceDemo>
95
- }
96
- >
97
- <Route
98
- path="drawer"
99
- element={
100
- <LazyRouteSurfaceDemo>
101
- <DemoPageDrawer />
95
+ <DemoPage />
102
96
  </LazyRouteSurfaceDemo>
103
97
  }
104
98
  >
105
99
  <Route
106
- path="dialog"
100
+ path="drawer"
107
101
  element={
108
102
  <LazyRouteSurfaceDemo>
109
- <DemoPageDrawerDialog />
103
+ <DemoPageDrawer />
110
104
  </LazyRouteSurfaceDemo>
111
105
  }
112
- />
106
+ >
107
+ <Route
108
+ path="dialog"
109
+ element={
110
+ <LazyRouteSurfaceDemo>
111
+ <DemoPageDrawerDialog />
112
+ </LazyRouteSurfaceDemo>
113
+ }
114
+ />
115
+ </Route>
113
116
  </Route>
114
- </Route>
115
- </>
116
- ),
117
+ </>
118
+ ),
119
+ },
117
120
  };
118
121
 
119
122
  export default routeSurfacesExtension;
@@ -4,7 +4,7 @@ import { useMemo } from "react";
4
4
 
5
5
  import { Button } from "@/components/ui/button";
6
6
  import { Form } from "@/components/ui/form";
7
- import { useAIForm, type AIFormField } from "@/extensions/nocobase-ai";
7
+ import { useAIForm, type AIFormField } from "./optional-ai";
8
8
  import {
9
9
  RouteDrawer,
10
10
  RouteDrawerFooter,
@@ -60,7 +60,7 @@ function UserCreateForm() {
60
60
  action: "create",
61
61
  redirect: false,
62
62
  onMutationSuccess: () => {
63
- void close({ skipBeforeClose: true });
63
+ close({ skipBeforeClose: true });
64
64
  },
65
65
  },
66
66
  defaultValues: {
@@ -90,11 +90,11 @@ function UserCreateForm() {
90
90
  onSubmit={form.handleSubmit((values) => onFinish(values))}
91
91
  className="flex min-h-0 flex-1 flex-col"
92
92
  >
93
- <div className="resource-form min-h-0 flex-1 overflow-y-auto px-5 py-5">
93
+ <div className="min-h-0 flex-1 space-y-6 overflow-y-auto px-5 py-5 [&_[data-slot=input]]:h-10 [&_[data-slot=select-trigger]]:h-10 [&_[data-slot=textarea]]:min-h-56">
94
94
  <UserFormFields form={form} includePassword translate={translate} />
95
95
  </div>
96
96
  <RouteDrawerFooter className="flex-row justify-end">
97
- <Button type="button" variant="outline" onClick={() => void close()}>
97
+ <Button type="button" variant="outline" onClick={() => close()}>
98
98
  {translate("users.form.cancel", { ns: "app" }, "Cancel")}
99
99
  </Button>
100
100
  <Button
@@ -5,7 +5,7 @@ import { useParams } from "react-router";
5
5
 
6
6
  import { Button } from "@/components/ui/button";
7
7
  import { Form } from "@/components/ui/form";
8
- import { useAIForm, type AIFormField } from "@/extensions/nocobase-ai";
8
+ import { useAIForm, type AIFormField } from "./optional-ai";
9
9
  import {
10
10
  RouteDrawer,
11
11
  RouteDrawerFooter,
@@ -35,11 +35,7 @@ export const UserEdit = ({
35
35
  return (
36
36
  <>
37
37
  <RouteDrawer
38
- title={translate(
39
- "users.drawer.edit.title",
40
- { ns: "app" },
41
- "Edit user"
42
- )}
38
+ title={translate("users.drawer.edit.title", { ns: "app" }, "Edit user")}
43
39
  description={translate(
44
40
  "users.drawer.edit.description",
45
41
  { ns: "app" },
@@ -69,7 +65,7 @@ function UserEditForm({ id }: { id?: string }) {
69
65
  id,
70
66
  redirect: false,
71
67
  onMutationSuccess: () => {
72
- void close({ skipBeforeClose: true });
68
+ close({ skipBeforeClose: true });
73
69
  },
74
70
  },
75
71
  });
@@ -92,11 +88,11 @@ function UserEditForm({ id }: { id?: string }) {
92
88
  onSubmit={form.handleSubmit((values) => onFinish(values))}
93
89
  className="flex min-h-0 flex-1 flex-col"
94
90
  >
95
- <div className="resource-form min-h-0 flex-1 overflow-y-auto px-5 py-5">
91
+ <div className="min-h-0 flex-1 space-y-6 overflow-y-auto px-5 py-5 [&_[data-slot=input]]:h-10 [&_[data-slot=select-trigger]]:h-10 [&_[data-slot=textarea]]:min-h-56">
96
92
  <UserFormFields form={form} translate={translate} />
97
93
  </div>
98
94
  <RouteDrawerFooter className="flex-row justify-end">
99
- <Button type="button" variant="outline" onClick={() => void close()}>
95
+ <Button type="button" variant="outline" onClick={() => close()}>
100
96
  {translate("users.form.cancel", { ns: "app" }, "Cancel")}
101
97
  </Button>
102
98
  <Button
@@ -0,0 +1,109 @@
1
+ import { CanAccess } from "@/components/access-control/can-access";
2
+ import { UsersRound } from "lucide-react";
3
+ import { Route } from "react-router";
4
+
5
+ import type { AppExtension } from "@/app/extension";
6
+ import { AccessDenied } from "@/components/access-control/access-denied";
7
+ import { UserCreate } from "./create";
8
+ import { UserEdit } from "./edit";
9
+ import { UserResourceLayout } from "./layout";
10
+ import { RoleDetailRoute } from "./role-detail";
11
+ import { userRoutes } from "./routes";
12
+ import { UserShow } from "./show";
13
+ import "./locales";
14
+
15
+ const usersExampleExtension: AppExtension = {
16
+ id: "nocobase-users-example",
17
+ priority: 0,
18
+ resources: [
19
+ {
20
+ name: "users",
21
+ list: userRoutes.list,
22
+ create: userRoutes.create,
23
+ edit: userRoutes.edit,
24
+ show: userRoutes.show,
25
+ meta: {
26
+ label: "Users",
27
+ priority: 1,
28
+ singularLabel: "User",
29
+ i18nKey: "resources.users",
30
+ i18nSingularKey: "resources.user",
31
+ i18nOptions: { ns: "app" },
32
+ descriptionI18nKey: "resources.users.description",
33
+ icon: <UsersRound />,
34
+ description:
35
+ "Manage the people who can sign in and work in this NocoBase application.",
36
+ canCreate: true,
37
+ canDelete: true,
38
+ acl: { type: "collection" },
39
+ },
40
+ },
41
+ ],
42
+ routes: (
43
+ <Route path="/users" element={<UserResourceLayout />}>
44
+ <Route
45
+ path="create"
46
+ element={
47
+ <CanAccess
48
+ resource="users"
49
+ action="create"
50
+ fallback={<AccessDenied />}
51
+ >
52
+ <UserCreate />
53
+ </CanAccess>
54
+ }
55
+ />
56
+ <Route
57
+ path="edit/:id"
58
+ element={
59
+ <CanAccess resource="users" action="edit" fallback={<AccessDenied />}>
60
+ <UserEdit />
61
+ </CanAccess>
62
+ }
63
+ />
64
+ <Route
65
+ path="roles/:roleName"
66
+ element={
67
+ <CanAccess resource="roles" action="show" fallback={<AccessDenied />}>
68
+ <RoleDetailRoute returnTo="list" />
69
+ </CanAccess>
70
+ }
71
+ />
72
+ <Route
73
+ path="show/:id"
74
+ element={
75
+ <CanAccess resource="users" action="show" fallback={<AccessDenied />}>
76
+ <UserShow />
77
+ </CanAccess>
78
+ }
79
+ >
80
+ <Route
81
+ path="edit"
82
+ element={
83
+ <CanAccess
84
+ resource="users"
85
+ action="edit"
86
+ fallback={<AccessDenied />}
87
+ >
88
+ <UserEdit returnTo="show" />
89
+ </CanAccess>
90
+ }
91
+ />
92
+ <Route
93
+ path="roles/:roleName"
94
+ element={
95
+ <CanAccess
96
+ resource="roles"
97
+ action="show"
98
+ fallback={<AccessDenied />}
99
+ >
100
+ <RoleDetailRoute returnTo="show" />
101
+ </CanAccess>
102
+ }
103
+ />
104
+ </Route>
105
+ </Route>
106
+ ),
107
+ };
108
+
109
+ export default usersExampleExtension;
@@ -1,7 +1,6 @@
1
1
  import type { useTranslate } from "@refinedev/core";
2
- import type { UseFormReturn } from "react-hook-form";
2
+ import type { Path, PathValue, UseFormReturn } from "react-hook-form";
3
3
 
4
- import { applyReactHookFormValues } from "@/extensions/nocobase-ai/adapters/react-hook-form";
5
4
  import type { UserFormValues } from "./types";
6
5
 
7
6
  type Translate = ReturnType<typeof useTranslate>;
@@ -18,14 +17,17 @@ export function applyAIUserFormValues(
18
17
  form: Pick<UseFormReturn<UserFormValues>, "setValue">,
19
18
  values: Record<string, unknown>
20
19
  ) {
21
- applyReactHookFormValues(
22
- form,
23
- Object.fromEntries(
24
- Object.entries(values).filter(([name]) =>
25
- AI_EDITABLE_FIELDS.includes(name as (typeof AI_EDITABLE_FIELDS)[number])
26
- )
27
- )
20
+ const editableValues = Object.entries(values).filter(([name]) =>
21
+ AI_EDITABLE_FIELDS.includes(name as (typeof AI_EDITABLE_FIELDS)[number])
28
22
  );
23
+ for (const [name, value] of editableValues) {
24
+ const path = name as Path<UserFormValues>;
25
+ form.setValue(path, value as PathValue<UserFormValues, typeof path>, {
26
+ shouldDirty: true,
27
+ shouldTouch: true,
28
+ shouldValidate: true,
29
+ });
30
+ }
29
31
  }
30
32
 
31
33
  export function getAIUserFormFields(translate: Translate) {
@@ -0,0 +1,16 @@
1
+ import { CanAccess } from "@/components/access-control/can-access";
2
+ import { Outlet } from "react-router";
3
+
4
+ import { AccessDenied } from "@/components/access-control/access-denied";
5
+ import { UserList } from "./list";
6
+
7
+ export function UserResourceLayout() {
8
+ return (
9
+ <>
10
+ <CanAccess resource="users" action="list" fallback={<AccessDenied />}>
11
+ <UserList />
12
+ </CanAccess>
13
+ <Outlet />
14
+ </>
15
+ );
16
+ }
@@ -15,7 +15,7 @@ import { DeleteButton } from "@/components/resources/buttons/delete";
15
15
  import { EditButton } from "@/components/resources/buttons/edit";
16
16
  import { ShowButton } from "@/components/resources/buttons/show";
17
17
  import { ListView } from "@/components/resources/views/list-view";
18
- import { useAIPageElementHandle } from "@/extensions/nocobase-ai";
18
+ import { useAIPageElementHandle } from "./optional-ai";
19
19
  import type { Role } from "@/lib/nocobase/acl";
20
20
  import { RoleBadges } from "./role-badges";
21
21
  import { resolveRoleLabel } from "./role-utils";