@nocobase/portal-template-default 1.0.9 → 1.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (304) 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/package.json +3 -5
  7. package/scripts/build-html.mjs +12 -0
  8. package/src/App.css +2 -0
  9. package/src/App.tsx +35 -186
  10. package/src/app/development.tsx +154 -0
  11. package/src/app/extension.ts +5 -0
  12. package/src/app/extensions.tsx +18 -4
  13. package/src/app/routes.tsx +65 -0
  14. package/src/components/access-control/acl-bootstrap.tsx +11 -3
  15. package/src/components/access-control/acl-gate.tsx +7 -6
  16. package/src/components/access-control/can-access.tsx +17 -0
  17. package/src/components/access-control/navigate-to-accessible-resource.tsx +8 -3
  18. package/src/components/app-shell/sidebar.tsx +21 -5
  19. package/src/components/auth/auto-redirect-provider.tsx +2 -1
  20. package/src/extensions/nocobase-acl/README.md +74 -0
  21. package/{registry → src/extensions}/nocobase-acl/components/acl-boundary.tsx +22 -25
  22. package/{registry → src/extensions}/nocobase-acl/components/role-switcher.tsx +26 -23
  23. package/src/extensions/nocobase-acl/demo/acl-preview-provider.tsx +81 -0
  24. package/{registry → src/extensions}/nocobase-acl/demo/boundary-api.tsx +58 -0
  25. package/{registry → src/extensions}/nocobase-acl/demo/index.tsx +243 -105
  26. package/{registry → src/extensions}/nocobase-acl/demo/prompt-generator.tsx +3 -1
  27. package/src/extensions/nocobase-acl/extension.tsx +73 -0
  28. package/{registry → src/extensions}/nocobase-ai/README.md +21 -5
  29. package/{registry → src/extensions}/nocobase-ai/components/chat/chat-composer.tsx +3 -1
  30. package/{registry → src/extensions}/nocobase-ai/components/chat/chat-messages.tsx +38 -3
  31. package/{registry → src/extensions}/nocobase-ai/components/chat/tool-call-card.tsx +1 -9
  32. package/{registry → src/extensions}/nocobase-ai/components/index.ts +5 -0
  33. package/src/extensions/nocobase-ai/components/surfaces/chat-dialog.tsx +17 -0
  34. package/src/extensions/nocobase-ai/components/surfaces/chat-side-panel.tsx +35 -0
  35. package/src/extensions/nocobase-ai/components/surfaces/chat-surface.tsx +108 -0
  36. package/{registry → src/extensions}/nocobase-ai/components/triggers/ai-chat-floating-trigger.tsx +2 -2
  37. package/{registry → src/extensions}/nocobase-ai/demo/configuration-gate.tsx +4 -1
  38. package/{registry → src/extensions}/nocobase-ai/demo/container-showcase.tsx +2 -2
  39. package/{registry → src/extensions}/nocobase-ai/demo/floating.tsx +45 -15
  40. package/{registry → src/extensions}/nocobase-ai/demo/index.tsx +116 -74
  41. package/{registry → src/extensions}/nocobase-ai/demo/prompt-generator.tsx +3 -3
  42. package/{registry → src/extensions}/nocobase-ai/demo/tool-cards.tsx +2 -3
  43. package/src/extensions/nocobase-ai/extension.tsx +160 -0
  44. package/{registry → src/extensions}/nocobase-ai/global-ai-chat.tsx +12 -28
  45. package/{registry → src/extensions}/nocobase-ai/providers/ai-provider.tsx +14 -1
  46. package/{registry → src/extensions}/nocobase-ai/providers/chat-context.tsx +1 -0
  47. package/{registry → src/extensions}/nocobase-ai/providers/chat-provider.tsx +29 -8
  48. package/{registry → src/extensions}/nocobase-ai/providers/use-chat-attachments.ts +6 -1
  49. package/{registry → src/extensions}/nocobase-ai/providers/use-chat-work-context.ts +4 -1
  50. package/{registry → src/extensions}/nocobase-route-surfaces/README.md +2 -1
  51. package/{registry → src/extensions}/nocobase-route-surfaces/demo/index.tsx +33 -7
  52. package/{registry → src/extensions}/nocobase-route-surfaces/demo/scenarios.ts +20 -14
  53. package/{registry → src/extensions}/nocobase-route-surfaces/extension.tsx +55 -52
  54. package/src/{pages/users → extensions/nocobase-users-example}/create.tsx +4 -4
  55. package/src/{pages/users → extensions/nocobase-users-example}/edit.tsx +5 -9
  56. package/src/extensions/nocobase-users-example/extension.tsx +109 -0
  57. package/src/{pages/users → extensions/nocobase-users-example}/form-context.ts +11 -9
  58. package/src/extensions/nocobase-users-example/layout.tsx +16 -0
  59. package/src/{pages/users → extensions/nocobase-users-example}/list.tsx +1 -1
  60. package/src/extensions/nocobase-users-example/locales/en-US.ts +77 -0
  61. package/src/extensions/nocobase-users-example/locales/index.ts +8 -0
  62. package/src/extensions/nocobase-users-example/locales/zh-CN.ts +73 -0
  63. package/src/extensions/nocobase-users-example/optional-ai.ts +67 -0
  64. package/src/{pages/users → extensions/nocobase-users-example}/role-detail.tsx +4 -15
  65. package/src/{pages/users → extensions/nocobase-users-example}/routes.ts +1 -4
  66. package/src/extensions/nocobase-users-example/show.tsx +266 -0
  67. package/src/lib/nocobase/acl/context.ts +32 -0
  68. package/src/lib/nocobase/acl/evaluator.ts +186 -0
  69. package/src/lib/nocobase/acl/hooks.ts +40 -0
  70. package/src/lib/nocobase/acl/index.ts +4 -1
  71. package/src/lib/nocobase/acl/menu.ts +6 -6
  72. package/src/lib/nocobase/acl/record-permissions.ts +37 -7
  73. package/src/lib/nocobase/acl/store-provider.tsx +14 -0
  74. package/src/lib/nocobase/acl/store.ts +92 -86
  75. package/src/lib/nocobase/acl/types.ts +52 -32
  76. package/src/lib/nocobase/auth-session.ts +128 -0
  77. package/src/lib/nocobase/client.ts +48 -50
  78. package/src/locales/en-US.ts +0 -78
  79. package/src/locales/index.ts +2 -7
  80. package/src/locales/zh-CN.ts +0 -74
  81. package/src/providers/access-control.ts +43 -8
  82. package/src/providers/auth-callback.ts +1 -0
  83. package/src/providers/auth.ts +24 -26
  84. package/src/providers/constants.ts +0 -4
  85. package/src/providers/data.ts +14 -26
  86. package/src/providers/runtime-config.ts +40 -0
  87. package/src/vite-env.d.ts +9 -0
  88. package/tests/auth-session-regression.mjs +101 -0
  89. package/tsconfig.json +2 -1
  90. package/vite.config.ts +9 -1
  91. package/dist/assets/CoordinateSystem-C8P-Cleg.js +0 -1
  92. package/dist/assets/LegendVisualProvider-Bdgkckq-.js +0 -1
  93. package/dist/assets/LineDraw-C0m1GONT.js +0 -1
  94. package/dist/assets/SymbolDraw-CCospe5G.js +0 -1
  95. package/dist/assets/VisualMapping-Cbv1v7Cd.js +0 -1
  96. package/dist/assets/ai-employee-shortcut-B253WWow.js +0 -1
  97. package/dist/assets/calendar-B3dXXyIv.js +0 -1
  98. package/dist/assets/chat-inline-xpQ9iq4p.js +0 -1
  99. package/dist/assets/chat-side-panel-layout-BVWsp5rr.js +0 -1
  100. package/dist/assets/components-ChhJaNRc.js +0 -20
  101. package/dist/assets/configuration-gate-Dwdq_lxf.js +0 -1
  102. package/dist/assets/createClipPathFromCoordSys-uEftn1Mq.js +0 -1
  103. package/dist/assets/createSeriesDataSimply-CI7l7Ufv.js +0 -1
  104. package/dist/assets/customGraphicKeyframeAnimation-DE3jSfMd.js +0 -3
  105. package/dist/assets/echarts-preview-C-cNUtJF.js +0 -1
  106. package/dist/assets/echarts-runtime-CEgJbv68.js +0 -58
  107. package/dist/assets/echarts-runtime-advanced-Buhm2BHz.js +0 -1
  108. package/dist/assets/echarts-runtime-common-DLAdBAIa.js +0 -1
  109. package/dist/assets/echarts-runtime-components-ypnyLkYx.js +0 -1
  110. package/dist/assets/echarts-runtime-hierarchy-ClStquCF.js +0 -1
  111. package/dist/assets/floating-BarTmn-b.js +0 -13
  112. package/dist/assets/index-BJIcYTdc.js +0 -53
  113. package/dist/assets/index-C6xNKxpg.js +0 -656
  114. package/dist/assets/index-D4JQi1TM.js +0 -54
  115. package/dist/assets/index-YA7-AUO8.css +0 -1
  116. package/dist/assets/index-g8zWVpP9.js +0 -23
  117. package/dist/assets/labelHelper-C137W5gU.js +0 -1
  118. package/dist/assets/nocobase-ai-chat-VTMaZFQB.svg +0 -50
  119. package/dist/assets/page-context-Cxx11gzg.js +0 -73
  120. package/dist/assets/prompt-card-BsYMW_rq.js +0 -1
  121. package/dist/assets/sectorHelper-Fqgz3uEk.js +0 -1
  122. package/dist/assets/shortcut-xtghDP63.js +0 -47
  123. package/dist/assets/static.browser-CfQQzERe.js +0 -30
  124. package/dist/assets/switch-DrxImI8F.js +0 -1
  125. package/dist/assets/tool-cards-BGfsY8JF.js +0 -41
  126. package/dist/favicon.ico +0 -0
  127. package/dist/index.html +0 -40
  128. package/dist/index.raw.html +0 -46
  129. package/dist/logo-dark.png +0 -0
  130. package/dist/logo-mark-dark.png +0 -0
  131. package/dist/logo-mark.png +0 -0
  132. package/dist/logo.png +0 -0
  133. package/registry/nocobase-acl/README.md +0 -19
  134. package/registry/nocobase-acl/extension.tsx +0 -71
  135. package/registry/nocobase-acl/tests/acl-regression.mjs +0 -314
  136. package/registry/nocobase-ai/components/surfaces/chat-dialog.tsx +0 -31
  137. package/registry/nocobase-ai/components/surfaces/chat-side-panel.tsx +0 -74
  138. package/registry/nocobase-ai/extension.tsx +0 -158
  139. package/registry/nocobase-ai/tests/business-report-regression.mjs +0 -70
  140. package/registry/nocobase-ai/tests/form-filler-regression.mjs +0 -129
  141. package/registry/nocobase-ai/tests/frontend-tool-regression.mjs +0 -128
  142. package/registry/nocobase-ai/tests/page-context-regression.mjs +0 -48
  143. package/registry/nocobase-ai/tests/stream-regression.mjs +0 -207
  144. package/registry/nocobase-auth-cas/README.md +0 -6
  145. package/registry/nocobase-auth-cas/cas-sign-in-button.tsx +0 -41
  146. package/registry/nocobase-auth-cas/demo.tsx +0 -20
  147. package/registry/nocobase-auth-cas/extension.tsx +0 -46
  148. package/registry/nocobase-auth-cas/index.ts +0 -1
  149. package/registry/nocobase-auth-cas/use-cas-sign-in.ts +0 -29
  150. package/registry/nocobase-auth-dingtalk/README.md +0 -7
  151. package/registry/nocobase-auth-dingtalk/auto-login-provider.tsx +0 -154
  152. package/registry/nocobase-auth-dingtalk/demo.tsx +0 -23
  153. package/registry/nocobase-auth-dingtalk/dingtalk-sign-in-button.tsx +0 -45
  154. package/registry/nocobase-auth-dingtalk/extension.tsx +0 -55
  155. package/registry/nocobase-auth-dingtalk/index.ts +0 -4
  156. package/registry/nocobase-auth-dingtalk/use-dingtalk-sign-in.ts +0 -64
  157. package/registry/nocobase-auth-ldap/README.md +0 -6
  158. package/registry/nocobase-auth-ldap/demo.tsx +0 -21
  159. package/registry/nocobase-auth-ldap/extension.tsx +0 -46
  160. package/registry/nocobase-auth-ldap/index.ts +0 -1
  161. package/registry/nocobase-auth-ldap/ldap-sign-in-form.tsx +0 -69
  162. package/registry/nocobase-auth-ldap/use-ldap-sign-in.ts +0 -5
  163. package/registry/nocobase-auth-oidc/README.md +0 -11
  164. package/registry/nocobase-auth-oidc/auto-redirect-provider.tsx +0 -13
  165. package/registry/nocobase-auth-oidc/demo.tsx +0 -20
  166. package/registry/nocobase-auth-oidc/extension.tsx +0 -51
  167. package/registry/nocobase-auth-oidc/index.ts +0 -1
  168. package/registry/nocobase-auth-oidc/oidc-sign-in-button.tsx +0 -44
  169. package/registry/nocobase-auth-oidc/use-oidc-sign-in.ts +0 -58
  170. package/registry/nocobase-auth-saml/README.md +0 -6
  171. package/registry/nocobase-auth-saml/auto-redirect-provider.tsx +0 -13
  172. package/registry/nocobase-auth-saml/demo.tsx +0 -20
  173. package/registry/nocobase-auth-saml/extension.tsx +0 -51
  174. package/registry/nocobase-auth-saml/index.ts +0 -1
  175. package/registry/nocobase-auth-saml/saml-sign-in-button.tsx +0 -43
  176. package/registry/nocobase-auth-saml/use-saml-sign-in.ts +0 -51
  177. package/registry/nocobase-auth-sms/README.md +0 -7
  178. package/registry/nocobase-auth-sms/demo.tsx +0 -25
  179. package/registry/nocobase-auth-sms/extension.tsx +0 -46
  180. package/registry/nocobase-auth-sms/index.ts +0 -1
  181. package/registry/nocobase-auth-sms/sms-sign-in-form.tsx +0 -107
  182. package/registry/nocobase-auth-sms/use-sms-sign-in.ts +0 -88
  183. package/registry/nocobase-auth-wecom/README.md +0 -6
  184. package/registry/nocobase-auth-wecom/auto-login-provider.tsx +0 -21
  185. package/registry/nocobase-auth-wecom/demo.tsx +0 -23
  186. package/registry/nocobase-auth-wecom/extension.tsx +0 -49
  187. package/registry/nocobase-auth-wecom/index.ts +0 -1
  188. package/registry/nocobase-auth-wecom/use-wecom-sign-in.ts +0 -62
  189. package/registry/nocobase-auth-wecom/wecom-sign-in-button.tsx +0 -70
  190. package/registry/nocobase-i18n/README.md +0 -44
  191. package/registry/nocobase-i18n/components/index.ts +0 -1
  192. package/registry/nocobase-i18n/components/language-switcher.tsx +0 -138
  193. package/registry/nocobase-i18n/demo/index.tsx +0 -209
  194. package/registry/nocobase-i18n/demo/prompt-generator.tsx +0 -132
  195. package/registry/nocobase-i18n/extension.tsx +0 -45
  196. package/registry/nocobase-i18n/index.ts +0 -7
  197. package/registry/nocobase-i18n/locales/en-US.ts +0 -39
  198. package/registry/nocobase-i18n/locales/index.ts +0 -8
  199. package/registry/nocobase-i18n/locales/zh-CN.ts +0 -35
  200. package/registry/nocobase-i18n/provider.tsx +0 -44
  201. package/registry/nocobase-i18n/server-resources.ts +0 -166
  202. package/registry/nocobase-i18n/tests/i18n-regression.mjs +0 -51
  203. package/registry.config.json +0 -302
  204. package/scripts/registry.mjs +0 -164
  205. package/src/components/access-control/resource-access-guard.tsx +0 -21
  206. package/src/components/access-control/use-acl-runtime.ts +0 -28
  207. package/src/lib/nocobase/acl/action.ts +0 -147
  208. package/src/pages/users/layout.tsx +0 -15
  209. package/src/pages/users/show.tsx +0 -278
  210. /package/{registry → src/extensions}/nocobase-acl/components/index.ts +0 -0
  211. /package/{registry → src/extensions}/nocobase-acl/components/role-options.ts +0 -0
  212. /package/{registry → src/extensions}/nocobase-acl/demo/components.tsx +0 -0
  213. /package/{registry → src/extensions}/nocobase-acl/demo/lazy-route.tsx +0 -0
  214. /package/{registry → src/extensions}/nocobase-acl/demo/role-switcher-prompt-generator.tsx +0 -0
  215. /package/{registry → src/extensions}/nocobase-acl/demo/scenario-section.tsx +0 -0
  216. /package/{registry → src/extensions}/nocobase-acl/index.ts +0 -0
  217. /package/{registry → src/extensions}/nocobase-ai/adapters/react-hook-form.ts +0 -0
  218. /package/{registry → src/extensions}/nocobase-ai/assets/nocobase-ai-chat.svg +0 -0
  219. /package/{registry → src/extensions}/nocobase-ai/components/ai-root-provider.tsx +0 -0
  220. /package/{registry → src/extensions}/nocobase-ai/components/chat/ai-employee-avatar.tsx +0 -0
  221. /package/{registry → src/extensions}/nocobase-ai/components/chat/chat-attachment.tsx +0 -0
  222. /package/{registry → src/extensions}/nocobase-ai/components/chat/chat-compact.tsx +0 -0
  223. /package/{registry → src/extensions}/nocobase-ai/components/chat/chat-empty-state.tsx +0 -0
  224. /package/{registry → src/extensions}/nocobase-ai/components/chat/chat-header.tsx +0 -0
  225. /package/{registry → src/extensions}/nocobase-ai/components/chat/chat-history-dialog.tsx +0 -0
  226. /package/{registry → src/extensions}/nocobase-ai/components/chat/chat-message.tsx +0 -0
  227. /package/{registry → src/extensions}/nocobase-ai/components/chat/chat-window.tsx +0 -0
  228. /package/{registry → src/extensions}/nocobase-ai/components/chat/conversation-list.tsx +0 -0
  229. /package/{registry → src/extensions}/nocobase-ai/components/chat/markdown-message.tsx +0 -0
  230. /package/{registry → src/extensions}/nocobase-ai/components/chat/model-select-options.tsx +0 -0
  231. /package/{registry → src/extensions}/nocobase-ai/components/chat/reasoning-panel.tsx +0 -0
  232. /package/{registry → src/extensions}/nocobase-ai/components/chat/sub-agent-conversation.tsx +0 -0
  233. /package/{registry → src/extensions}/nocobase-ai/components/chat/user-prompt-editor.tsx +0 -0
  234. /package/{registry → src/extensions}/nocobase-ai/components/chat/work-context-chip.tsx +0 -0
  235. /package/{registry → src/extensions}/nocobase-ai/components/page-elements/ai-form.tsx +0 -0
  236. /package/{registry → src/extensions}/nocobase-ai/components/page-elements/page-element-provider.tsx +0 -0
  237. /package/{registry → src/extensions}/nocobase-ai/components/surfaces/chat-inline.tsx +0 -0
  238. /package/{registry → src/extensions}/nocobase-ai/components/surfaces/chat-page.tsx +0 -0
  239. /package/{registry → src/extensions}/nocobase-ai/components/surfaces/chat-side-panel-layout.tsx +0 -0
  240. /package/{registry → src/extensions}/nocobase-ai/components/surfaces/chat-surface-actions.tsx +0 -0
  241. /package/{registry → src/extensions}/nocobase-ai/components/tools/builtin-tool-renderers.tsx +0 -0
  242. /package/{registry → src/extensions}/nocobase-ai/components/tools/business-report-dialog.tsx +0 -0
  243. /package/{registry → src/extensions}/nocobase-ai/components/tools/business-report-renderer.tsx +0 -0
  244. /package/{registry → src/extensions}/nocobase-ai/components/tools/business-report-utils.tsx +0 -0
  245. /package/{registry → src/extensions}/nocobase-ai/components/tools/chart-renderer.tsx +0 -0
  246. /package/{registry → src/extensions}/nocobase-ai/components/tools/echarts-preview.tsx +0 -0
  247. /package/{registry → src/extensions}/nocobase-ai/components/tools/echarts-runtime-advanced.ts +0 -0
  248. /package/{registry → src/extensions}/nocobase-ai/components/tools/echarts-runtime-common.ts +0 -0
  249. /package/{registry → src/extensions}/nocobase-ai/components/tools/echarts-runtime-components.ts +0 -0
  250. /package/{registry → src/extensions}/nocobase-ai/components/tools/echarts-runtime-hierarchy.ts +0 -0
  251. /package/{registry → src/extensions}/nocobase-ai/components/tools/echarts-runtime.ts +0 -0
  252. /package/{registry → src/extensions}/nocobase-ai/components/tools/sub-agent-renderer.tsx +0 -0
  253. /package/{registry → src/extensions}/nocobase-ai/components/tools/suggestions-renderer.tsx +0 -0
  254. /package/{registry → src/extensions}/nocobase-ai/components/tools/tool-renderer-provider.tsx +0 -0
  255. /package/{registry → src/extensions}/nocobase-ai/components/tools/tool-renderer-utils.ts +0 -0
  256. /package/{registry → src/extensions}/nocobase-ai/components/tools/workflow-renderer.tsx +0 -0
  257. /package/{registry → src/extensions}/nocobase-ai/components/triggers/ai-employee-shortcut.tsx +0 -0
  258. /package/{registry → src/extensions}/nocobase-ai/demo/interaction-showcase.tsx +0 -0
  259. /package/{registry → src/extensions}/nocobase-ai/demo/page-context-prompt-generator.tsx +0 -0
  260. /package/{registry → src/extensions}/nocobase-ai/demo/page-context.tsx +0 -0
  261. /package/{registry → src/extensions}/nocobase-ai/demo/page-element-showcase.tsx +0 -0
  262. /package/{registry → src/extensions}/nocobase-ai/demo/prompt-card.tsx +0 -0
  263. /package/{registry → src/extensions}/nocobase-ai/demo/shortcut.tsx +0 -0
  264. /package/{registry → src/extensions}/nocobase-ai/index.ts +0 -0
  265. /package/{registry → src/extensions}/nocobase-ai/providers/avatars.ts +0 -0
  266. /package/{registry → src/extensions}/nocobase-ai/providers/chat-controller.ts +0 -0
  267. /package/{registry → src/extensions}/nocobase-ai/providers/chat-message-utils.ts +0 -0
  268. /package/{registry → src/extensions}/nocobase-ai/providers/chat-reducer.ts +0 -0
  269. /package/{registry → src/extensions}/nocobase-ai/providers/chat-task-utils.ts +0 -0
  270. /package/{registry → src/extensions}/nocobase-ai/providers/chat-transport.ts +0 -0
  271. /package/{registry → src/extensions}/nocobase-ai/providers/form-registry.tsx +0 -0
  272. /package/{registry → src/extensions}/nocobase-ai/providers/frontend-tool-registry.tsx +0 -0
  273. /package/{registry → src/extensions}/nocobase-ai/providers/index.ts +0 -0
  274. /package/{registry → src/extensions}/nocobase-ai/providers/model.ts +0 -0
  275. /package/{registry → src/extensions}/nocobase-ai/providers/page-context.tsx +0 -0
  276. /package/{registry → src/extensions}/nocobase-ai/providers/stream-coalescer.ts +0 -0
  277. /package/{registry → src/extensions}/nocobase-ai/providers/stream-event-utils.ts +0 -0
  278. /package/{registry → src/extensions}/nocobase-ai/providers/stream-parser.ts +0 -0
  279. /package/{registry → src/extensions}/nocobase-ai/providers/sub-agent-stream.ts +0 -0
  280. /package/{registry → src/extensions}/nocobase-ai/providers/types.ts +0 -0
  281. /package/{registry → src/extensions}/nocobase-ai/providers/ui-message-stream.ts +0 -0
  282. /package/{registry → src/extensions}/nocobase-ai/providers/use-automatic-tool-approval.ts +0 -0
  283. /package/{registry → src/extensions}/nocobase-ai/providers/use-chat-message-actions.ts +0 -0
  284. /package/{registry → src/extensions}/nocobase-ai/providers/use-chat-runtime.ts +0 -0
  285. /package/{registry → src/extensions}/nocobase-ai/providers/use-conversation-catalog.ts +0 -0
  286. /package/{registry → src/extensions}/nocobase-ai/providers/use-conversation-history.ts +0 -0
  287. /package/{registry → src/extensions}/nocobase-ai/services/index.ts +0 -0
  288. /package/{registry → src/extensions}/nocobase-ai/services/nocobase-ai-service.ts +0 -0
  289. /package/{registry → src/extensions}/nocobase-ai/services/types.ts +0 -0
  290. /package/{registry → src/extensions}/nocobase-route-surfaces/demo/lazy-route.tsx +0 -0
  291. /package/{registry → src/extensions}/nocobase-route-surfaces/demo/prompt-generator.tsx +0 -0
  292. /package/{registry → src/extensions}/nocobase-route-surfaces/index.ts +0 -0
  293. /package/{registry → src/extensions}/nocobase-route-surfaces/route-dialog.tsx +0 -0
  294. /package/{registry → src/extensions}/nocobase-route-surfaces/route-drawer.tsx +0 -0
  295. /package/{registry → src/extensions}/nocobase-route-surfaces/route-page.tsx +0 -0
  296. /package/{registry → src/extensions}/nocobase-route-surfaces/route-surface-context.ts +0 -0
  297. /package/{registry → src/extensions}/nocobase-route-surfaces/use-refine-unsaved-changes.tsx +0 -0
  298. /package/{registry → src/extensions}/nocobase-route-surfaces/use-route-surface-close.ts +0 -0
  299. /package/{registry → src/extensions}/nocobase-route-surfaces/use-route-surface-state.ts +0 -0
  300. /package/src/{pages/users → extensions/nocobase-users-example}/form-fields.tsx +0 -0
  301. /package/src/{pages/users → extensions/nocobase-users-example}/index.ts +0 -0
  302. /package/src/{pages/users → extensions/nocobase-users-example}/role-badges.tsx +0 -0
  303. /package/src/{pages/users → extensions/nocobase-users-example}/role-utils.ts +0 -0
  304. /package/src/{pages/users → extensions/nocobase-users-example}/types.ts +0 -0
@@ -9,7 +9,13 @@ import {
9
9
  } from "../../providers";
10
10
  import { cn } from "@/lib/utils";
11
11
  import { ArrowDown } from "lucide-react";
12
- import { useEffect, useRef, useState, type ReactNode } from "react";
12
+ import {
13
+ useEffect,
14
+ useLayoutEffect,
15
+ useRef,
16
+ useState,
17
+ type ReactNode,
18
+ } from "react";
13
19
  import { ChatEmptyState } from "./chat-empty-state";
14
20
  import { ChatMessage } from "./chat-message";
15
21
 
@@ -81,6 +87,7 @@ export function AIChatMessageList({
81
87
  focusComposer,
82
88
  }: AIChatMessageListProps) {
83
89
  const viewportRef = useRef<HTMLDivElement>(null);
90
+ const bottomOffsetRef = useRef(0);
84
91
  const [atBottom, setAtBottom] = useState(true);
85
92
 
86
93
  const scrollToBottom = (behavior: ScrollBehavior = "smooth") => {
@@ -89,6 +96,31 @@ export function AIChatMessageList({
89
96
  viewport.scrollTo({ top: viewport.scrollHeight, behavior });
90
97
  };
91
98
 
99
+ useLayoutEffect(() => {
100
+ const viewport = viewportRef.current;
101
+ if (!viewport) return;
102
+ viewport.scrollTop = viewport.scrollHeight;
103
+ bottomOffsetRef.current = 0;
104
+ }, []);
105
+
106
+ useEffect(() => {
107
+ const viewport = viewportRef.current;
108
+ if (!viewport || typeof ResizeObserver === "undefined") return;
109
+
110
+ const observer = new ResizeObserver(() => {
111
+ const maxScrollTop = Math.max(
112
+ 0,
113
+ viewport.scrollHeight - viewport.clientHeight
114
+ );
115
+ viewport.scrollTop = Math.max(
116
+ 0,
117
+ maxScrollTop - bottomOffsetRef.current
118
+ );
119
+ });
120
+ observer.observe(viewport);
121
+ return () => observer.disconnect();
122
+ }, []);
123
+
92
124
  useEffect(() => {
93
125
  if (atBottom) scrollToBottom(status === "streaming" ? "auto" : "smooth");
94
126
  }, [atBottom, messages, status]);
@@ -107,9 +139,12 @@ export function AIChatMessageList({
107
139
  className="absolute inset-0 overflow-x-hidden overflow-y-auto overscroll-contain"
108
140
  onScroll={(event) => {
109
141
  const element = event.currentTarget;
110
- setAtBottom(
111
- element.scrollHeight - element.scrollTop - element.clientHeight < 48
142
+ const bottomOffset = Math.max(
143
+ 0,
144
+ element.scrollHeight - element.scrollTop - element.clientHeight
112
145
  );
146
+ bottomOffsetRef.current = bottomOffset;
147
+ setAtBottom(bottomOffset < 48);
113
148
  }}
114
149
  >
115
150
  {loading ? (
@@ -131,9 +131,7 @@ export function ToolCallCard({
131
131
  const [deciding, setDeciding] = useState(false);
132
132
  const renderer = useAIToolRenderer(getToolCallName(part));
133
133
  const Renderer = renderer?.component;
134
- const [open, setOpen] = useState(
135
- part.state === "output-error" || Boolean(Renderer)
136
- );
134
+ const [open, setOpen] = useState(false);
137
135
  const toolStatus = getStatus(part);
138
136
  const approvalRequired =
139
137
  resolvedApproval?.required === true && approvalStatus === "pending";
@@ -152,12 +150,6 @@ export function ToolCallCard({
152
150
  setApprovalStatus(resolvedApproval?.status ?? "pending");
153
151
  }, [resolvedApproval?.status]);
154
152
 
155
- useEffect(() => {
156
- if (part.state === "output-error") {
157
- setOpen(true);
158
- }
159
- }, [part.state]);
160
-
161
153
  const decide = async (
162
154
  decision: "approve" | "reject" | "edit",
163
155
  input?: unknown
@@ -13,6 +13,11 @@ export {
13
13
  } from "./chat/chat-messages";
14
14
  export { AIModelSelectOptions } from "./chat/model-select-options";
15
15
  export { ChatDialog } from "./surfaces/chat-dialog";
16
+ export {
17
+ ChatSurface,
18
+ type ChatSurfaceProps,
19
+ type ChatSurfaceVariant,
20
+ } from "./surfaces/chat-surface";
16
21
  export { ChatSurfaceActions } from "./surfaces/chat-surface-actions";
17
22
  export { ChatInline } from "./surfaces/chat-inline";
18
23
  export { ChatPage } from "./surfaces/chat-page";
@@ -0,0 +1,17 @@
1
+ import type { PropsWithChildren } from "react";
2
+ import { ChatSurface } from "./chat-surface";
3
+
4
+ export function ChatDialog({
5
+ open,
6
+ onOpenChange,
7
+ children,
8
+ }: PropsWithChildren<{
9
+ open: boolean;
10
+ onOpenChange: (open: boolean) => void;
11
+ }>) {
12
+ return (
13
+ <ChatSurface open={open} variant="dialog" onOpenChange={onOpenChange}>
14
+ {children}
15
+ </ChatSurface>
16
+ );
17
+ }
@@ -0,0 +1,35 @@
1
+ import type { PropsWithChildren } from "react";
2
+ import { ChatSurface } from "./chat-surface";
3
+
4
+ export type ChatSidePanelProps = PropsWithChildren<{
5
+ open: boolean;
6
+ onOpenChange: (open: boolean) => void;
7
+ side?: "left" | "right";
8
+ width?: number | string;
9
+ closeOnEscape?: boolean;
10
+ showCloseHandle?: boolean;
11
+ }>;
12
+
13
+ export function ChatSidePanel({
14
+ open,
15
+ onOpenChange,
16
+ side = "right",
17
+ width = 450,
18
+ closeOnEscape = true,
19
+ showCloseHandle = true,
20
+ children,
21
+ }: ChatSidePanelProps) {
22
+ return (
23
+ <ChatSurface
24
+ open={open}
25
+ variant="side-panel"
26
+ onOpenChange={onOpenChange}
27
+ side={side}
28
+ width={width}
29
+ closeOnEscape={closeOnEscape}
30
+ showCloseHandle={showCloseHandle}
31
+ >
32
+ {children}
33
+ </ChatSurface>
34
+ );
35
+ }
@@ -0,0 +1,108 @@
1
+ import { Button } from "@/components/ui/button";
2
+ import { cn } from "@/lib/utils";
3
+ import { Dialog as DialogPrimitive } from "@base-ui/react/dialog";
4
+ import { PanelLeftClose, PanelRightClose } from "lucide-react";
5
+ import type { CSSProperties, PropsWithChildren } from "react";
6
+
7
+ export type ChatSurfaceVariant = "side-panel" | "dialog";
8
+
9
+ export type ChatSurfaceProps = PropsWithChildren<{
10
+ open: boolean;
11
+ variant: ChatSurfaceVariant;
12
+ onOpenChange: (open: boolean) => void;
13
+ side?: "left" | "right";
14
+ width?: number | string;
15
+ closeOnEscape?: boolean;
16
+ showCloseHandle?: boolean;
17
+ }>;
18
+
19
+ export function ChatSurface({
20
+ open,
21
+ variant,
22
+ onOpenChange,
23
+ side = "right",
24
+ width = 450,
25
+ closeOnEscape = true,
26
+ showCloseHandle = false,
27
+ children,
28
+ }: ChatSurfaceProps) {
29
+ const expanded = variant === "dialog";
30
+ const panelWidth = typeof width === "number" ? `${width}px` : width;
31
+
32
+ return (
33
+ <DialogPrimitive.Root
34
+ open={open}
35
+ modal={expanded}
36
+ disablePointerDismissal={!expanded}
37
+ onOpenChange={(nextOpen, eventDetails) => {
38
+ if (
39
+ !nextOpen &&
40
+ eventDetails.reason === "escape-key" &&
41
+ !closeOnEscape
42
+ ) {
43
+ return;
44
+ }
45
+ onOpenChange(nextOpen);
46
+ }}
47
+ >
48
+ <DialogPrimitive.Portal>
49
+ <DialogPrimitive.Backdrop
50
+ className={cn(
51
+ "fixed inset-0 isolate z-50 bg-black/10 supports-backdrop-filter:backdrop-blur-xs data-closed:pointer-events-none",
52
+ !expanded && "pointer-events-none opacity-0"
53
+ )}
54
+ />
55
+ <DialogPrimitive.Popup
56
+ data-variant={variant}
57
+ data-side={side}
58
+ initialFocus={expanded}
59
+ className={cn(
60
+ "fixed z-50 flex max-w-full bg-background text-foreground shadow-2xl outline-none",
61
+ "data-closed:pointer-events-none data-closed:opacity-0",
62
+ expanded
63
+ ? "top-1/2 left-1/2 h-[95svh] w-[95vw] -translate-x-1/2 -translate-y-1/2 overflow-hidden rounded-xl border"
64
+ : cn(
65
+ "inset-y-0 h-svh w-(--chat-surface-width) translate-x-0 translate-y-0 overflow-visible rounded-none",
66
+ side === "right"
67
+ ? "right-0 border-l"
68
+ : "left-0 border-r"
69
+ )
70
+ )}
71
+ style={
72
+ {
73
+ "--chat-surface-width": panelWidth,
74
+ } as CSSProperties
75
+ }
76
+ >
77
+ <DialogPrimitive.Title className="sr-only">
78
+ NocoBase AI employee
79
+ </DialogPrimitive.Title>
80
+ <DialogPrimitive.Description className="sr-only">
81
+ {expanded
82
+ ? "Expanded AI conversation window."
83
+ : "AI conversation side panel."}
84
+ </DialogPrimitive.Description>
85
+ {showCloseHandle && !expanded ? (
86
+ <Button
87
+ variant="outline"
88
+ size="icon-sm"
89
+ className={cn(
90
+ "absolute top-1/2 z-40 size-9 -translate-y-1/2 rounded-full bg-background shadow-md before:absolute before:-inset-2",
91
+ side === "right"
92
+ ? "left-0 -translate-x-1/2"
93
+ : "right-0 translate-x-1/2"
94
+ )}
95
+ aria-label="Close side panel"
96
+ onClick={() => onOpenChange(false)}
97
+ >
98
+ {side === "right" ? <PanelRightClose /> : <PanelLeftClose />}
99
+ </Button>
100
+ ) : null}
101
+ <div className="min-h-0 min-w-0 flex-1 overflow-hidden">
102
+ {children}
103
+ </div>
104
+ </DialogPrimitive.Popup>
105
+ </DialogPrimitive.Portal>
106
+ </DialogPrimitive.Root>
107
+ );
108
+ }
@@ -1,5 +1,5 @@
1
1
  import nocobaseAIChatIcon from "../../assets/nocobase-ai-chat.svg";
2
- import { cn } from "@/lib/utils";
2
+ import { assetUrl, cn } from "@/lib/utils";
3
3
  import {
4
4
  useAI,
5
5
  useAIChatControllerState,
@@ -57,7 +57,7 @@ export function AIChatFloatingTrigger({
57
57
  <span className="relative flex size-[42px] items-center justify-center">
58
58
  <span className="flex size-full overflow-hidden rounded-lg">
59
59
  <img
60
- src={nocobaseAIChatIcon}
60
+ src={assetUrl(nocobaseAIChatIcon)}
61
61
  alt=""
62
62
  className="size-full object-contain"
63
63
  />
@@ -65,7 +65,10 @@ const previewService: AIService = {
65
65
 
66
66
  export function AIConfigurationGate({ children }: { children: ReactNode }) {
67
67
  const { configurationStatus, hasEnabledModels, employees } = useAI();
68
- const configured = configurationStatus === "ready" && hasEnabledModels;
68
+ const configured =
69
+ configurationStatus === "ready" &&
70
+ hasEnabledModels &&
71
+ employees.length > 0;
69
72
 
70
73
  if (configured) return children;
71
74
 
@@ -199,9 +199,9 @@ const containerComponent = (value: ChatContainer) => {
199
199
  case "page":
200
200
  return "<ChatPage />";
201
201
  case "side-panel":
202
- return "<ChatSidePanelLayout />";
202
+ return '<ChatSurface variant="side-panel" />';
203
203
  case "dialog":
204
- return "<ChatDialog />";
204
+ return '<ChatSurface variant="dialog" />';
205
205
  case "mobile":
206
206
  return "<ChatInline /> · 390px";
207
207
  default:
@@ -1,7 +1,8 @@
1
1
  import {
2
2
  AIChatFloatingTrigger,
3
3
  AIChatWindow,
4
- ChatSidePanelLayout,
4
+ ChatSurface,
5
+ ChatSurfaceActions,
5
6
  } from "../components";
6
7
  import { Badge } from "@/components/ui/badge";
7
8
  import { Card } from "@/components/ui/card";
@@ -12,19 +13,22 @@ import {
12
13
  } from "../providers";
13
14
  import { PromptCard } from "./prompt-card";
14
15
  import { AIConfigurationGate } from "./configuration-gate";
16
+ import { useState, type CSSProperties } from "react";
15
17
 
16
18
  const floatingPrompt = `Add the standard NocoBase AI floating chat entry to the application layout.
17
19
 
18
20
  Requirements:
19
21
  - Render AIChatFloatingTrigger at the lower-right edge of the application.
20
22
  - Bind it to the global AI chat controller.
21
- - Clicking the trigger opens a 450px ChatSidePanelLayout on the right.
23
+ - Clicking the trigger opens ChatSurface with variant="side-panel" and a 450px width on the right.
22
24
  - The side panel must push the desktop page narrower instead of blocking page interaction.
23
25
  - Mobile may switch to an overlay presentation.
24
26
  - Hide the floating trigger while the side panel is open.
25
27
  - Support an unread-count badge.
26
28
  - Start a new conversation with the configured default AI employee when opened.
27
- - Keep the trigger and side-panel surface separate from AIChatWindow.
29
+ - Put ChatSurfaceActions in the AIChatWindow header so expand/collapse and close stay in the upper-right corner.
30
+ - Keep one AIChatWindow mounted and change ChatSurface.variant to "dialog" when expanded.
31
+ - Keep the trigger and ChatSurface separate from AIChatWindow.
28
32
  - Use shadcn/Base UI components and the existing AIProvider/AIChatProvider runtime.`;
29
33
 
30
34
  export function FloatingChatPage() {
@@ -38,14 +42,24 @@ export function FloatingChatPage() {
38
42
  function FloatingChatPageContent() {
39
43
  const controller = useAIChatController();
40
44
  const { open } = useAIChatControllerState(controller);
45
+ const [expanded, setExpanded] = useState(false);
46
+
47
+ const handleOpenChange = (nextOpen: boolean) => {
48
+ if (!nextOpen) setExpanded(false);
49
+ controller.setOpen(nextOpen);
50
+ };
41
51
 
42
52
  return (
43
53
  <AIChatProvider id="floating-chat-demo" controller={controller}>
44
- <ChatSidePanelLayout
45
- open={open}
46
- onOpenChange={controller.setOpen}
47
- width={450}
48
- panel={<AIChatWindow />}
54
+ <div
55
+ data-open={open && !expanded}
56
+ data-side="right"
57
+ className="chat-side-panel-layout @container min-w-0"
58
+ style={
59
+ {
60
+ "--chat-side-panel-width": "450px",
61
+ } as CSSProperties
62
+ }
49
63
  >
50
64
  <div className="space-y-12 pb-12">
51
65
  <section className="flex flex-wrap items-start justify-between gap-5 border-b pb-8">
@@ -58,9 +72,9 @@ function FloatingChatPageContent() {
58
72
  Floating AI Chat
59
73
  </h1>
60
74
  <p className="mt-3 max-w-3xl text-sm leading-6 text-muted-foreground">
61
- A global lower-right entry for the shared AI conversation. It is
62
- intentionally coupled to the push side-panel surface rather than
63
- treated as a generic chat container.
75
+ A global lower-right entry for the shared AI conversation. It
76
+ opens as a push side panel and can expand into a focused dialog
77
+ without remounting the chat window.
64
78
  </p>
65
79
  </div>
66
80
  </section>
@@ -71,7 +85,7 @@ function FloatingChatPageContent() {
71
85
  Interactive preview
72
86
  </p>
73
87
  <h2 className="mt-2 text-xl font-semibold tracking-tight">
74
- Global launcher and push side panel
88
+ Global launcher and adaptive chat surface
75
89
  </h2>
76
90
  <p className="mt-1.5 max-w-3xl text-sm leading-6 text-muted-foreground">
77
91
  The trigger is constrained to this simulated application in the
@@ -83,7 +97,7 @@ function FloatingChatPageContent() {
83
97
  <div className="flex h-12 items-center justify-between border-b px-4">
84
98
  <span className="text-sm font-medium">Application shell</span>
85
99
  <code className="rounded-md bg-muted px-2 py-1 text-xs text-muted-foreground">
86
- AIChatFloatingTrigger → ChatSidePanelLayout
100
+ AIChatFloatingTrigger → ChatSurface · side-panel/dialog
87
101
  </code>
88
102
  </div>
89
103
  <div className="relative grid min-h-[560px] grid-cols-[190px_minmax(0,1fr)] overflow-hidden bg-background">
@@ -123,12 +137,28 @@ function FloatingChatPageContent() {
123
137
  </div>
124
138
  <PromptCard
125
139
  title="Add a lower-right AI floating entry"
126
- description="This prompt only configures the global trigger and its side panel."
140
+ description="This prompt configures the global trigger and its switchable side-panel/dialog surface."
127
141
  prompt={floatingPrompt}
128
142
  />
129
143
  </section>
130
144
  </div>
131
- </ChatSidePanelLayout>
145
+ <ChatSurface
146
+ open={open}
147
+ variant={expanded ? "dialog" : "side-panel"}
148
+ onOpenChange={handleOpenChange}
149
+ width={450}
150
+ >
151
+ <AIChatWindow
152
+ headerActions={
153
+ <ChatSurfaceActions
154
+ expanded={expanded}
155
+ onExpandedChange={setExpanded}
156
+ onClose={() => handleOpenChange(false)}
157
+ />
158
+ }
159
+ />
160
+ </ChatSurface>
161
+ </div>
132
162
  </AIChatProvider>
133
163
  );
134
164
  }