@vertesia/ui 1.5.0-dev.20260910.052912Z → 1.6.0-dev.20260912.110338Z

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 (389) hide show
  1. package/README.md +125 -0
  2. package/lib/boot/branding.d.ts +58 -0
  3. package/lib/boot/branding.d.ts.map +1 -0
  4. package/lib/boot/branding.js +62 -0
  5. package/lib/boot/branding.js.map +1 -0
  6. package/lib/boot/index.d.ts +27 -0
  7. package/lib/boot/index.d.ts.map +1 -0
  8. package/lib/boot/index.js +325 -0
  9. package/lib/boot/index.js.map +1 -0
  10. package/lib/boot/vite.d.ts +63 -0
  11. package/lib/boot/vite.d.ts.map +1 -0
  12. package/lib/boot/vite.js +108 -0
  13. package/lib/boot/vite.js.map +1 -0
  14. package/lib/core/components/Link.js +1 -1
  15. package/lib/core/components/Link.js.map +1 -1
  16. package/lib/core/components/Spinner.js +1 -1
  17. package/lib/core/components/Spinner.js.map +1 -1
  18. package/lib/core/components/TagsInput.js +7 -7
  19. package/lib/core/components/TagsInput.js.map +1 -1
  20. package/lib/core/components/shadcn/badge.js +1 -1
  21. package/lib/core/components/shadcn/badge.js.map +1 -1
  22. package/lib/core/components/shadcn/button.d.ts.map +1 -1
  23. package/lib/core/components/shadcn/button.js +3 -4
  24. package/lib/core/components/shadcn/button.js.map +1 -1
  25. package/lib/core/components/shadcn/filters/comboBox/DateCombobox.js +2 -2
  26. package/lib/core/components/shadcn/filters/comboBox/DateCombobox.js.map +1 -1
  27. package/lib/core/components/shadcn/filters/comboBox/SelectCombobox.js +1 -1
  28. package/lib/core/components/shadcn/filters/comboBox/SelectCombobox.js.map +1 -1
  29. package/lib/core/components/shadcn/filters/comboBox/StringListCombobox.js +1 -1
  30. package/lib/core/components/shadcn/filters/comboBox/StringListCombobox.js.map +1 -1
  31. package/lib/core/components/shadcn/filters/comboBox/TextCombobox.js +1 -1
  32. package/lib/core/components/shadcn/filters/comboBox/TextCombobox.js.map +1 -1
  33. package/lib/core/components/shadcn/filters/filter/dateFilter.js +1 -1
  34. package/lib/core/components/shadcn/filters/filter/dateFilter.js.map +1 -1
  35. package/lib/core/components/shadcn/filters/filter-styles.d.ts +1 -1
  36. package/lib/core/components/shadcn/filters/filter-styles.d.ts.map +1 -1
  37. package/lib/core/components/shadcn/filters/filter-styles.js +4 -4
  38. package/lib/core/components/shadcn/filters/filters.js +1 -1
  39. package/lib/core/components/shadcn/filters/filters.js.map +1 -1
  40. package/lib/core/components/shadcn/label.js +1 -1
  41. package/lib/core/components/shadcn/label.js.map +1 -1
  42. package/lib/core/components/shadcn/overflowTabs.js +2 -2
  43. package/lib/core/components/shadcn/overflowTabs.js.map +1 -1
  44. package/lib/core/components/shadcn/tabs.js +1 -1
  45. package/lib/core/components/shadcn/tabs.js.map +1 -1
  46. package/lib/env/index.d.ts +28 -1
  47. package/lib/env/index.d.ts.map +1 -1
  48. package/lib/env/index.js +51 -3
  49. package/lib/env/index.js.map +1 -1
  50. package/lib/features/activity-doc/ActivityDoc.js +1 -1
  51. package/lib/features/activity-doc/ActivityDoc.js.map +1 -1
  52. package/lib/features/agent/PayloadBuilder.d.ts +4 -0
  53. package/lib/features/agent/PayloadBuilder.d.ts.map +1 -1
  54. package/lib/features/agent/PayloadBuilder.js.map +1 -1
  55. package/lib/features/agent/chat/AgentRunFeedback.d.ts +59 -0
  56. package/lib/features/agent/chat/AgentRunFeedback.d.ts.map +1 -0
  57. package/lib/features/agent/chat/AgentRunFeedback.js +286 -0
  58. package/lib/features/agent/chat/AgentRunFeedback.js.map +1 -0
  59. package/lib/features/agent/chat/AskUserWidget.d.ts +1 -0
  60. package/lib/features/agent/chat/AskUserWidget.d.ts.map +1 -1
  61. package/lib/features/agent/chat/AskUserWidget.js +15 -4
  62. package/lib/features/agent/chat/AskUserWidget.js.map +1 -1
  63. package/lib/features/agent/chat/ModernAgentConversation.d.ts.map +1 -1
  64. package/lib/features/agent/chat/ModernAgentConversation.js +3 -2
  65. package/lib/features/agent/chat/ModernAgentConversation.js.map +1 -1
  66. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts +3 -1
  67. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts.map +1 -1
  68. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js +16 -13
  69. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js.map +1 -1
  70. package/lib/features/agent/chat/ModernAgentOutput/Header.d.ts.map +1 -1
  71. package/lib/features/agent/chat/ModernAgentOutput/Header.js.map +1 -1
  72. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.d.ts +3 -1
  73. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.d.ts.map +1 -1
  74. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js +30 -8
  75. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js.map +1 -1
  76. package/lib/features/agent/chat/ModernAgentOutput/SummaryConversation.d.ts.map +1 -1
  77. package/lib/features/agent/chat/ModernAgentOutput/SummaryConversation.js +2 -0
  78. package/lib/features/agent/chat/ModernAgentOutput/SummaryConversation.js.map +1 -1
  79. package/lib/features/agent/chat/index.d.ts +1 -0
  80. package/lib/features/agent/chat/index.d.ts.map +1 -1
  81. package/lib/features/agent/chat/index.js +1 -0
  82. package/lib/features/agent/chat/index.js.map +1 -1
  83. package/lib/features/facets/AgentRunnerFacetsNav.d.ts +8 -0
  84. package/lib/features/facets/AgentRunnerFacetsNav.d.ts.map +1 -1
  85. package/lib/features/facets/AgentRunnerFacetsNav.js +12 -0
  86. package/lib/features/facets/AgentRunnerFacetsNav.js.map +1 -1
  87. package/lib/features/layout/GenericPageNavHeader.js +1 -1
  88. package/lib/features/layout/GenericPageNavHeader.js.map +1 -1
  89. package/lib/features/magic-pdf/AnnotatedImageSlider.js +1 -1
  90. package/lib/features/magic-pdf/AnnotatedImageSlider.js.map +1 -1
  91. package/lib/features/magic-pdf/GroundedExtractionView.js +3 -3
  92. package/lib/features/magic-pdf/GroundedExtractionView.js.map +1 -1
  93. package/lib/features/permissions/UserPermissionsProvider.d.ts +15 -1
  94. package/lib/features/permissions/UserPermissionsProvider.d.ts.map +1 -1
  95. package/lib/features/permissions/UserPermissionsProvider.js +20 -12
  96. package/lib/features/permissions/UserPermissionsProvider.js.map +1 -1
  97. package/lib/features/store/objects/DocumentPreviewPanel.js +5 -5
  98. package/lib/features/store/objects/DocumentPreviewPanel.js.map +1 -1
  99. package/lib/features/store/objects/components/DocumentInput.js +1 -1
  100. package/lib/features/store/objects/components/DocumentInput.js.map +1 -1
  101. package/lib/features/store/objects/selection/SelectionActions.js +1 -1
  102. package/lib/features/store/objects/selection/SelectionActions.js.map +1 -1
  103. package/lib/features/store/objects/upload/DocumentUploadModal.js +1 -1
  104. package/lib/features/store/objects/upload/DocumentUploadModal.js.map +1 -1
  105. package/lib/features/store/types/TypeRegistry.d.ts +130 -0
  106. package/lib/features/store/types/TypeRegistry.d.ts.map +1 -1
  107. package/lib/features/store/types/search/ObjectTypeSearchContext.d.ts +130 -0
  108. package/lib/features/store/types/search/ObjectTypeSearchContext.d.ts.map +1 -1
  109. package/lib/features/user/UserInfo.js +1 -1
  110. package/lib/features/user/UserInfo.js.map +1 -1
  111. package/lib/i18n/index.d.ts +5 -4
  112. package/lib/i18n/index.d.ts.map +1 -1
  113. package/lib/i18n/index.js +16 -2
  114. package/lib/i18n/index.js.map +1 -1
  115. package/lib/i18n/locales/ar.json +30 -0
  116. package/lib/i18n/locales/de.json +30 -0
  117. package/lib/i18n/locales/en.json +30 -0
  118. package/lib/i18n/locales/es.json +30 -0
  119. package/lib/i18n/locales/fr.json +30 -0
  120. package/lib/i18n/locales/it.json +30 -0
  121. package/lib/i18n/locales/ja.json +30 -0
  122. package/lib/i18n/locales/ko.json +30 -0
  123. package/lib/i18n/locales/pt.json +30 -0
  124. package/lib/i18n/locales/ru.json +30 -0
  125. package/lib/i18n/locales/tr.json +30 -0
  126. package/lib/i18n/locales/zh-TW.json +30 -0
  127. package/lib/i18n/locales/zh.json +30 -0
  128. package/lib/layout/ErrorPage.js +1 -1
  129. package/lib/layout/ErrorPage.js.map +1 -1
  130. package/lib/layout/Navbar.d.ts.map +1 -1
  131. package/lib/layout/Navbar.js +3 -2
  132. package/lib/layout/Navbar.js.map +1 -1
  133. package/lib/router/RouteComponent.d.ts.map +1 -1
  134. package/lib/router/RouteComponent.js +15 -12
  135. package/lib/router/RouteComponent.js.map +1 -1
  136. package/lib/session/UserSession.d.ts.map +1 -1
  137. package/lib/session/UserSession.js +6 -3
  138. package/lib/session/UserSession.js.map +1 -1
  139. package/lib/session/UserSessionProvider.d.ts +2 -1
  140. package/lib/session/UserSessionProvider.d.ts.map +1 -1
  141. package/lib/session/UserSessionProvider.js +10 -1
  142. package/lib/session/UserSessionProvider.js.map +1 -1
  143. package/lib/session/auth/composable.d.ts.map +1 -1
  144. package/lib/session/auth/composable.js +88 -3
  145. package/lib/session/auth/composable.js.map +1 -1
  146. package/lib/session/auth/domainRouting.d.ts +22 -12
  147. package/lib/session/auth/domainRouting.d.ts.map +1 -1
  148. package/lib/session/auth/domainRouting.js +35 -21
  149. package/lib/session/auth/domainRouting.js.map +1 -1
  150. package/lib/session/auth/useAuthState.d.ts +9 -4
  151. package/lib/session/auth/useAuthState.d.ts.map +1 -1
  152. package/lib/session/auth/useAuthState.js +9 -4
  153. package/lib/session/auth/useAuthState.js.map +1 -1
  154. package/lib/session/index.d.ts.map +1 -1
  155. package/lib/session/index.js +3 -1
  156. package/lib/session/index.js.map +1 -1
  157. package/lib/shell/AuthScreenPreview.d.ts +12 -0
  158. package/lib/shell/AuthScreenPreview.d.ts.map +1 -0
  159. package/lib/shell/AuthScreenPreview.js +140 -0
  160. package/lib/shell/AuthScreenPreview.js.map +1 -0
  161. package/lib/shell/BrandedAuthScreens.d.ts +19 -0
  162. package/lib/shell/BrandedAuthScreens.d.ts.map +1 -0
  163. package/lib/shell/BrandedAuthScreens.js +64 -0
  164. package/lib/shell/BrandedAuthScreens.js.map +1 -0
  165. package/lib/shell/SplashScreen.d.ts +13 -2
  166. package/lib/shell/SplashScreen.d.ts.map +1 -1
  167. package/lib/shell/SplashScreen.js +21 -20
  168. package/lib/shell/SplashScreen.js.map +1 -1
  169. package/lib/shell/VertesiaShell.d.ts +15 -4
  170. package/lib/shell/VertesiaShell.d.ts.map +1 -1
  171. package/lib/shell/VertesiaShell.js +8 -3
  172. package/lib/shell/VertesiaShell.js.map +1 -1
  173. package/lib/shell/apps/StandaloneApp.js +5 -1
  174. package/lib/shell/apps/StandaloneApp.js.map +1 -1
  175. package/lib/shell/index.d.ts +6 -0
  176. package/lib/shell/index.d.ts.map +1 -1
  177. package/lib/shell/index.js +5 -0
  178. package/lib/shell/index.js.map +1 -1
  179. package/lib/shell/login/SignInFlow.d.ts +68 -0
  180. package/lib/shell/login/SignInFlow.d.ts.map +1 -0
  181. package/lib/shell/login/SignInFlow.js +108 -0
  182. package/lib/shell/login/SignInFlow.js.map +1 -0
  183. package/lib/shell/login/SignInPageShell.d.ts +13 -0
  184. package/lib/shell/login/SignInPageShell.d.ts.map +1 -0
  185. package/lib/shell/login/SignInPageShell.js +14 -0
  186. package/lib/shell/login/SignInPageShell.js.map +1 -0
  187. package/lib/shell/login/SignInPrimitives.d.ts +3 -3
  188. package/lib/shell/login/SignInPrimitives.d.ts.map +1 -1
  189. package/lib/shell/login/SignInPrimitives.js +13 -11
  190. package/lib/shell/login/SignInPrimitives.js.map +1 -1
  191. package/lib/shell/login/SignInRestrictedEnvStep.d.ts +5 -0
  192. package/lib/shell/login/SignInRestrictedEnvStep.d.ts.map +1 -1
  193. package/lib/shell/login/SignInRestrictedEnvStep.js +8 -4
  194. package/lib/shell/login/SignInRestrictedEnvStep.js.map +1 -1
  195. package/lib/shell/login/SigninScreen.d.ts +38 -3
  196. package/lib/shell/login/SigninScreen.d.ts.map +1 -1
  197. package/lib/shell/login/SigninScreen.js +33 -86
  198. package/lib/shell/login/SigninScreen.js.map +1 -1
  199. package/lib/shell/login/SignupForm.d.ts +3 -1
  200. package/lib/shell/login/SignupForm.d.ts.map +1 -1
  201. package/lib/shell/login/SignupForm.js +7 -3
  202. package/lib/shell/login/SignupForm.js.map +1 -1
  203. package/lib/shell/login/signInUtils.d.ts +11 -0
  204. package/lib/shell/login/signInUtils.d.ts.map +1 -1
  205. package/lib/shell/login/signInUtils.js +29 -5
  206. package/lib/shell/login/signInUtils.js.map +1 -1
  207. package/lib/vertesia-ui-boot.js +237 -0
  208. package/lib/vertesia-ui-boot.js.map +1 -0
  209. package/lib/vertesia-ui-core.js +46 -46
  210. package/lib/vertesia-ui-core.js.map +1 -1
  211. package/lib/vertesia-ui-env.js +1 -1
  212. package/lib/vertesia-ui-env.js.map +1 -1
  213. package/lib/vertesia-ui-features.js +222 -208
  214. package/lib/vertesia-ui-features.js.map +1 -1
  215. package/lib/vertesia-ui-i18n.B3NFclwl.chunk.js +5 -0
  216. package/lib/vertesia-ui-i18n.B3NFclwl.chunk.js.map +1 -0
  217. package/lib/vertesia-ui-i18n.BWSrNIxc.chunk.js +5 -0
  218. package/lib/vertesia-ui-i18n.BWSrNIxc.chunk.js.map +1 -0
  219. package/lib/vertesia-ui-i18n.BWvWeB1p.chunk.js +5 -0
  220. package/lib/vertesia-ui-i18n.BWvWeB1p.chunk.js.map +1 -0
  221. package/lib/vertesia-ui-i18n.BZCXvTC1.chunk.js +5 -0
  222. package/lib/vertesia-ui-i18n.BZCXvTC1.chunk.js.map +1 -0
  223. package/lib/vertesia-ui-i18n.BbJMvFZW.chunk.js +5 -0
  224. package/lib/vertesia-ui-i18n.BbJMvFZW.chunk.js.map +1 -0
  225. package/lib/vertesia-ui-i18n.CE5ldwpt.chunk.js +5 -0
  226. package/lib/vertesia-ui-i18n.CE5ldwpt.chunk.js.map +1 -0
  227. package/lib/vertesia-ui-i18n.CMC0IShY.chunk.js +5 -0
  228. package/lib/vertesia-ui-i18n.CMC0IShY.chunk.js.map +1 -0
  229. package/lib/vertesia-ui-i18n.CkcRqBKU.chunk.js +5 -0
  230. package/lib/vertesia-ui-i18n.CkcRqBKU.chunk.js.map +1 -0
  231. package/lib/vertesia-ui-i18n.D-Mq1sw_.chunk.js +5 -0
  232. package/lib/vertesia-ui-i18n.D-Mq1sw_.chunk.js.map +1 -0
  233. package/lib/vertesia-ui-i18n.DkK68-A-.chunk.js +5 -0
  234. package/lib/vertesia-ui-i18n.DkK68-A-.chunk.js.map +1 -0
  235. package/lib/vertesia-ui-i18n.XE_dcCg6.chunk.js +5 -0
  236. package/lib/vertesia-ui-i18n.XE_dcCg6.chunk.js.map +1 -0
  237. package/lib/vertesia-ui-i18n.js +2 -2
  238. package/lib/vertesia-ui-i18n.js.map +1 -1
  239. package/lib/vertesia-ui-i18n.qgNqMPvK.chunk.js +5 -0
  240. package/lib/vertesia-ui-i18n.qgNqMPvK.chunk.js.map +1 -0
  241. package/lib/vertesia-ui-layout.js +13 -13
  242. package/lib/vertesia-ui-layout.js.map +1 -1
  243. package/lib/vertesia-ui-rich-text.js +68 -68
  244. package/lib/vertesia-ui-rich-text.js.map +1 -1
  245. package/lib/vertesia-ui-router.js +1 -1
  246. package/lib/vertesia-ui-router.js.map +1 -1
  247. package/lib/vertesia-ui-session.js +1 -1
  248. package/lib/vertesia-ui-session.js.map +1 -1
  249. package/lib/vertesia-ui-shell.js +58 -33
  250. package/lib/vertesia-ui-shell.js.map +1 -1
  251. package/lib/vertesia-ui-widgets.js +94 -94
  252. package/lib/vertesia-ui-widgets.js.map +1 -1
  253. package/lib/widgets/json-view/JSONCode.js +1 -1
  254. package/lib/widgets/json-view/JSONCode.js.map +1 -1
  255. package/lib/widgets/upload/DropZone.d.ts.map +1 -1
  256. package/lib/widgets/upload/DropZone.js +1 -1
  257. package/lib/widgets/upload/DropZone.js.map +1 -1
  258. package/llms.txt +6 -2
  259. package/package.json +44 -35
  260. package/src/__tests__/a11y.test.tsx +25 -0
  261. package/src/__tests__/theme.test.ts +91 -0
  262. package/src/boot/branding.test.ts +72 -0
  263. package/src/boot/branding.ts +108 -0
  264. package/src/boot/index.test.ts +216 -0
  265. package/src/boot/index.ts +356 -0
  266. package/src/boot/vite.test.ts +93 -0
  267. package/src/boot/vite.ts +118 -0
  268. package/src/core/components/Link.tsx +1 -1
  269. package/src/core/components/Spinner.tsx +1 -1
  270. package/src/core/components/TagsInput.tsx +7 -7
  271. package/src/core/components/shadcn/badge.tsx +1 -1
  272. package/src/core/components/shadcn/button.tsx +3 -5
  273. package/src/core/components/shadcn/filters/comboBox/DateCombobox.tsx +2 -2
  274. package/src/core/components/shadcn/filters/comboBox/SelectCombobox.tsx +1 -1
  275. package/src/core/components/shadcn/filters/comboBox/StringListCombobox.tsx +1 -1
  276. package/src/core/components/shadcn/filters/comboBox/TextCombobox.tsx +1 -1
  277. package/src/core/components/shadcn/filters/filter/dateFilter.tsx +1 -1
  278. package/src/core/components/shadcn/filters/filter-styles.ts +4 -4
  279. package/src/core/components/shadcn/filters/filters.tsx +1 -1
  280. package/src/core/components/shadcn/label.tsx +1 -1
  281. package/src/core/components/shadcn/overflowTabs.tsx +2 -2
  282. package/src/core/components/shadcn/tabs.tsx +1 -1
  283. package/src/css/utilities.css +7 -0
  284. package/src/env/index.test.ts +100 -0
  285. package/src/env/index.ts +66 -3
  286. package/src/features/activity-doc/ActivityDoc.tsx +1 -1
  287. package/src/features/agent/PayloadBuilder.tsx +4 -0
  288. package/src/features/agent/chat/AgentRunFeedback.test.tsx +330 -0
  289. package/src/features/agent/chat/AgentRunFeedback.tsx +452 -0
  290. package/src/features/agent/chat/AskUserWidget.test.tsx +24 -2
  291. package/src/features/agent/chat/AskUserWidget.tsx +19 -4
  292. package/src/features/agent/chat/ModernAgentConversation.tsx +46 -42
  293. package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.test.tsx +207 -0
  294. package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.tsx +50 -31
  295. package/src/features/agent/chat/ModernAgentOutput/Header.tsx +4 -0
  296. package/src/features/agent/chat/ModernAgentOutput/MessageItem.tsx +42 -8
  297. package/src/features/agent/chat/ModernAgentOutput/SummaryConversation.ts +2 -0
  298. package/src/features/agent/chat/ModernAgentOutput/utils.test.ts +14 -0
  299. package/src/features/agent/chat/hooks/useFileProcessing.test.tsx +0 -5
  300. package/src/features/agent/chat/index.ts +6 -0
  301. package/src/features/facets/AgentRunnerFacetsNav.tsx +26 -0
  302. package/src/features/layout/GenericPageNavHeader.test.tsx +36 -0
  303. package/src/features/layout/GenericPageNavHeader.tsx +1 -1
  304. package/src/features/magic-pdf/AnnotatedImageSlider.tsx +1 -1
  305. package/src/features/magic-pdf/GroundedExtractionView.tsx +3 -3
  306. package/src/features/permissions/UserPermissionsProvider.test.tsx +50 -1
  307. package/src/features/permissions/UserPermissionsProvider.tsx +82 -44
  308. package/src/features/store/objects/DocumentPreviewPanel.tsx +10 -10
  309. package/src/features/store/objects/components/DocumentInput.tsx +1 -1
  310. package/src/features/store/objects/selection/SelectionActions.tsx +4 -1
  311. package/src/features/store/objects/upload/DocumentUploadModal.tsx +1 -1
  312. package/src/features/user/UserInfo.tsx +1 -1
  313. package/src/i18n/index.tsx +25 -2
  314. package/src/i18n/locales/ar.json +30 -0
  315. package/src/i18n/locales/de.json +30 -0
  316. package/src/i18n/locales/en.json +30 -0
  317. package/src/i18n/locales/es.json +30 -0
  318. package/src/i18n/locales/fr.json +30 -0
  319. package/src/i18n/locales/it.json +30 -0
  320. package/src/i18n/locales/ja.json +30 -0
  321. package/src/i18n/locales/ko.json +30 -0
  322. package/src/i18n/locales/pt.json +30 -0
  323. package/src/i18n/locales/ru.json +30 -0
  324. package/src/i18n/locales/tr.json +30 -0
  325. package/src/i18n/locales/zh-TW.json +30 -0
  326. package/src/i18n/locales/zh.json +30 -0
  327. package/src/layout/ErrorPage.tsx +1 -1
  328. package/src/layout/Navbar.test.tsx +58 -0
  329. package/src/layout/Navbar.tsx +5 -2
  330. package/src/router/RouteComponent.test.tsx +65 -1
  331. package/src/router/RouteComponent.tsx +18 -15
  332. package/src/session/UserSession.test.ts +65 -0
  333. package/src/session/UserSession.ts +6 -4
  334. package/src/session/UserSessionProvider.strict-mode.test.tsx +44 -0
  335. package/src/session/UserSessionProvider.test.ts +62 -1
  336. package/src/session/UserSessionProvider.tsx +9 -1
  337. package/src/session/auth/composable.renewal.test.ts +170 -0
  338. package/src/session/auth/composable.test.ts +23 -1
  339. package/src/session/auth/composable.ts +101 -2
  340. package/src/session/auth/domainRouting.test.ts +35 -65
  341. package/src/session/auth/domainRouting.ts +51 -34
  342. package/src/session/auth/useAuthState.ts +11 -4
  343. package/src/session/index.ts +3 -1
  344. package/src/shell/AuthScreenPreview.test.tsx +44 -0
  345. package/src/shell/AuthScreenPreview.tsx +228 -0
  346. package/src/shell/BrandedAuthScreens.test.tsx +181 -0
  347. package/src/shell/BrandedAuthScreens.tsx +117 -0
  348. package/src/shell/SplashScreen.test.tsx +37 -0
  349. package/src/shell/SplashScreen.tsx +45 -40
  350. package/src/shell/VertesiaShell.tsx +49 -22
  351. package/src/shell/apps/StandaloneApp.tsx +5 -1
  352. package/src/shell/index.tsx +6 -0
  353. package/src/shell/login/SignInFlow.tsx +213 -0
  354. package/src/shell/login/SignInPageShell.tsx +62 -0
  355. package/src/shell/login/SignInPrimitives.tsx +14 -11
  356. package/src/shell/login/SignInRestrictedEnvStep.tsx +19 -7
  357. package/src/shell/login/SigninScreen.test.tsx +104 -0
  358. package/src/shell/login/SigninScreen.tsx +115 -145
  359. package/src/shell/login/SignupForm.tsx +8 -3
  360. package/src/shell/login/signInUtils.ts +30 -5
  361. package/src/widgets/json-view/JSONCode.test.tsx +2 -2
  362. package/src/widgets/json-view/JSONCode.tsx +1 -1
  363. package/src/widgets/markdown/markdown.css +21 -21
  364. package/src/widgets/upload/DropZone.tsx +2 -4
  365. package/lib/vertesia-ui-i18n.BfN7iOHb.chunk.js +0 -5
  366. package/lib/vertesia-ui-i18n.BfN7iOHb.chunk.js.map +0 -1
  367. package/lib/vertesia-ui-i18n.BjH2zEZw.chunk.js +0 -5
  368. package/lib/vertesia-ui-i18n.BjH2zEZw.chunk.js.map +0 -1
  369. package/lib/vertesia-ui-i18n.BjSwAZXl.chunk.js +0 -5
  370. package/lib/vertesia-ui-i18n.BjSwAZXl.chunk.js.map +0 -1
  371. package/lib/vertesia-ui-i18n.C7PUm5Au.chunk.js +0 -5
  372. package/lib/vertesia-ui-i18n.C7PUm5Au.chunk.js.map +0 -1
  373. package/lib/vertesia-ui-i18n.CF_1mUS5.chunk.js +0 -5
  374. package/lib/vertesia-ui-i18n.CF_1mUS5.chunk.js.map +0 -1
  375. package/lib/vertesia-ui-i18n.ChfUl3_-.chunk.js +0 -5
  376. package/lib/vertesia-ui-i18n.ChfUl3_-.chunk.js.map +0 -1
  377. package/lib/vertesia-ui-i18n.D-Sk-5d1.chunk.js +0 -5
  378. package/lib/vertesia-ui-i18n.D-Sk-5d1.chunk.js.map +0 -1
  379. package/lib/vertesia-ui-i18n.D4rnu1_S.chunk.js +0 -5
  380. package/lib/vertesia-ui-i18n.D4rnu1_S.chunk.js.map +0 -1
  381. package/lib/vertesia-ui-i18n.DDf0-laK.chunk.js +0 -5
  382. package/lib/vertesia-ui-i18n.DDf0-laK.chunk.js.map +0 -1
  383. package/lib/vertesia-ui-i18n.DN79y06J.chunk.js +0 -5
  384. package/lib/vertesia-ui-i18n.DN79y06J.chunk.js.map +0 -1
  385. package/lib/vertesia-ui-i18n.DWLIciYQ.chunk.js +0 -5
  386. package/lib/vertesia-ui-i18n.DWLIciYQ.chunk.js.map +0 -1
  387. package/lib/vertesia-ui-i18n.DvF_YaAJ.chunk.js +0 -5
  388. package/lib/vertesia-ui-i18n.DvF_YaAJ.chunk.js.map +0 -1
  389. package/src/session/auth/authState.test.ts +0 -35
@@ -30,6 +30,10 @@ export interface AgentRunnerFilterQuery {
30
30
  initiated_by?: string;
31
31
  start?: string;
32
32
  end?: string;
33
+ /** Evaluation severity (`high`, `medium`, `low`, `none`) or `unrated` for runs no detector looked at. */
34
+ evaluation?: string;
35
+ /** Last user rating on the run: `up` or `down`. */
36
+ feedback?: string;
33
37
  }
34
38
 
35
39
  const agentRunnerFilterNames = [
@@ -40,6 +44,8 @@ const agentRunnerFilterNames = [
40
44
  'initiated_by',
41
45
  'start',
42
46
  'end',
47
+ 'evaluation',
48
+ 'feedback',
43
49
  ] as const satisfies readonly (keyof AgentRunnerFilterQuery)[];
44
50
  const isAgentRunnerFilterName = createSearchQueryKeyGuard<AgentRunnerFilterQuery>(agentRunnerFilterNames);
45
51
 
@@ -50,6 +56,10 @@ interface AgentRunnerFacetsNavProps {
50
56
  interactions?: EnrichedFacetBucket[];
51
57
  /** `run_kind` buckets — `agent` (autonomous runs) and `process` (process runs). */
52
58
  kinds?: FacetBucket[];
59
+ /** Evaluation severity buckets, `unrated` standing for runs without an evaluation. */
60
+ evaluation?: FacetBucket[];
61
+ /** Last-rating buckets (`up` / `down`). */
62
+ feedback?: FacetBucket[];
53
63
  };
54
64
  search: SearchInterface<AgentRunnerFilterQuery>;
55
65
  actions?: React.ReactNode[];
@@ -108,6 +118,22 @@ export function useAgentRunnerFilterGroups(facets: AgentRunnerFacetsNavProps['fa
108
118
  }),
109
119
  );
110
120
 
121
+ customFilterGroups.push(
122
+ VStringFacet({
123
+ buckets: facets.evaluation || [],
124
+ name: 'evaluation',
125
+ placeholder: 'Evaluation',
126
+ }),
127
+ );
128
+
129
+ customFilterGroups.push(
130
+ VStringFacet({
131
+ buckets: facets.feedback || [],
132
+ name: 'feedback',
133
+ placeholder: 'Feedback',
134
+ }),
135
+ );
136
+
111
137
  customFilterGroups.push({
112
138
  name: 'start',
113
139
  placeholder: 'Started After',
@@ -0,0 +1,36 @@
1
+ import { screen } from '@testing-library/react';
2
+ import type { ComponentProps } from 'react';
3
+ import { describe, expect, it, vi } from 'vitest';
4
+ import { renderWithProviders } from '../../__tests__/test-utils';
5
+ import { GenericPageNavHeader } from './GenericPageNavHeader';
6
+
7
+ vi.mock('@vertesia/ui/router', () => ({ useNavigate: () => vi.fn() }));
8
+
9
+ describe('GenericPageNavHeader breadcrumbs', () => {
10
+ it.each(['Parent', null])('ignores non-array breadcrumbs: %s', (breadcrumbs) => {
11
+ renderWithProviders(
12
+ <GenericPageNavHeader
13
+ title="Page"
14
+ useDynamicBreadcrumbs={false}
15
+ breadcrumbs={breadcrumbs as unknown as ComponentProps<typeof GenericPageNavHeader>['breadcrumbs']}
16
+ />,
17
+ );
18
+ expect(screen.getByText('Page')).toBeDefined();
19
+ expect(screen.queryByText('Parent')).toBeNull();
20
+ });
21
+
22
+ it('preserves breadcrumb elements', () => {
23
+ renderWithProviders(
24
+ <GenericPageNavHeader
25
+ title="Page"
26
+ useDynamicBreadcrumbs={false}
27
+ breadcrumbs={[
28
+ <a key="parent" href="/parent">
29
+ Parent
30
+ </a>,
31
+ ]}
32
+ />,
33
+ );
34
+ expect(screen.getByText('Parent')).toBeDefined();
35
+ });
36
+ });
@@ -124,7 +124,7 @@ export function GenericPageNavHeader({
124
124
  }
125
125
 
126
126
  // Add current page breadcrumbs
127
- if (breadcrumbs && breadcrumbs.length > 0) {
127
+ if (Array.isArray(breadcrumbs)) {
128
128
  breadcrumbs.forEach((breadcrumb) => {
129
129
  // Preserve the entire React element as label
130
130
  const label = breadcrumb.props?.children || breadcrumb;
@@ -326,7 +326,7 @@ function ImageTypeButton({ type, currentType, onClick, icon, tooltip }: ImageTyp
326
326
  aria-pressed={isSelected}
327
327
  className={clsx(
328
328
  'p-1 rounded cursor-pointer transition-colors',
329
- isSelected ? 'text-primary bg-primary/10' : 'text-muted hover:text-foreground hover:bg-muted',
329
+ isSelected ? 'text-info bg-info' : 'text-muted hover:text-foreground hover:bg-muted',
330
330
  )}
331
331
  onClick={onClick}
332
332
  >
@@ -659,7 +659,7 @@ function PageWithOverlay({
659
659
  'absolute cursor-pointer border rounded-[1px] transition-colors',
660
660
  citation.misaligned && 'border-dashed',
661
661
  isSelected
662
- ? 'border-2 border-primary bg-primary/20 z-10'
662
+ ? 'border-2 border-info bg-info z-10'
663
663
  : citation.verified
664
664
  ? 'border-success/70 hover:bg-success/20'
665
665
  : citation.reviewed
@@ -853,7 +853,7 @@ function ArrayTable({
853
853
  className={cn(
854
854
  'text-start rounded px-1 w-full',
855
855
  isSelected
856
- ? 'bg-primary/15 ring-1 ring-primary'
856
+ ? 'bg-info ring-1 ring-primary'
857
857
  : citation
858
858
  ? 'hover:bg-muted cursor-pointer'
859
859
  : 'text-muted cursor-default',
@@ -909,7 +909,7 @@ function LeafRow({
909
909
  onClick={() => citation && onSelect(path)}
910
910
  className={cn(
911
911
  'flex items-center gap-2 w-full text-start text-sm rounded px-1.5 py-0.5',
912
- isSelected ? 'bg-primary/15 ring-1 ring-primary' : citation ? 'hover:bg-muted' : '',
912
+ isSelected ? 'bg-info ring-1 ring-primary' : citation ? 'hover:bg-muted' : '',
913
913
  !citation && 'cursor-default',
914
914
  )}
915
915
  >
@@ -1,8 +1,9 @@
1
1
  import { act, fireEvent, render, screen } from '@testing-library/react';
2
2
  import { VertesiaClient } from '@vertesia/client';
3
3
  import type { AuthTokenPayload, SystemRoleDefinition } from '@vertesia/common';
4
+ import { Button } from '@vertesia/ui/core';
4
5
  import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
5
- import { UserPermissionProvider } from './UserPermissionsProvider';
6
+ import { type PermissionLoadingScreenProps, UserPermissionProvider } from './UserPermissionsProvider';
6
7
 
7
8
  const session = {
8
9
  client: new VertesiaClient({ serverUrl: 'https://studio.example.test', storeUrl: 'https://store.example.test' }),
@@ -169,4 +170,52 @@ describe('role mapping recovery', () => {
169
170
  expect(screen.getByText('Protected workspace')).toBeTruthy();
170
171
  expect(fetch).not.toHaveBeenCalled();
171
172
  });
173
+ it.each([401, 403, 500])('supplies working recovery actions to a custom screen for status %s', async (status) => {
174
+ const fetch = vi
175
+ .spyOn(session.client.iam.roles, 'listSystem')
176
+ .mockRejectedValue(Object.assign(new Error('Request failed'), { status }));
177
+ const CustomScreen = ({ status: phase, onAction, actionLabel }: PermissionLoadingScreenProps) => (
178
+ <main>
179
+ <p>Custom {phase}</p>
180
+ {phase === 'error' && <Button onClick={onAction}>{actionLabel}</Button>}
181
+ </main>
182
+ );
183
+ const view = render(
184
+ <UserPermissionProvider LoadingScreen={CustomScreen}>
185
+ <div>Protected workspace</div>
186
+ </UserPermissionProvider>,
187
+ );
188
+ expect(view.container.firstElementChild?.tagName).toBe('MAIN');
189
+ expect(screen.getByText('Custom loading')).toBeTruthy();
190
+ expect(screen.queryByText('Protected workspace')).toBeNull();
191
+ await advance(0);
192
+ expect(screen.getByText('Custom error')).toBeTruthy();
193
+ expect(screen.queryByText('Protected workspace')).toBeNull();
194
+ fetch.mockResolvedValue([]);
195
+ fireEvent.click(screen.getByRole('button'));
196
+ await advance(0);
197
+ if (status === 401 || status === 403) {
198
+ expect(session.signOut).toHaveBeenCalledOnce();
199
+ expect(screen.queryByText('Protected workspace')).toBeNull();
200
+ } else {
201
+ expect(screen.getByText('Protected workspace')).toBeTruthy();
202
+ expect(screen.queryByText('Custom error')).toBeNull();
203
+ }
204
+ });
205
+
206
+ it('reports automatic retrying to a custom screen before revealing protected content', async () => {
207
+ vi.spyOn(session.client.iam.roles, 'listSystem')
208
+ .mockRejectedValueOnce(Object.assign(new Error('Unavailable'), { status: 503 }))
209
+ .mockResolvedValue([]);
210
+ render(
211
+ <UserPermissionProvider LoadingScreen={({ status }) => <main>Custom {status}</main>}>
212
+ <div>Protected workspace</div>
213
+ </UserPermissionProvider>,
214
+ );
215
+ await advance(0);
216
+ expect(screen.getByText('Custom retrying')).toBeTruthy();
217
+ expect(screen.queryByText('Protected workspace')).toBeNull();
218
+ await advance(1_000);
219
+ expect(screen.getByText('Protected workspace')).toBeTruthy();
220
+ });
172
221
  });
@@ -2,7 +2,7 @@ import { type AuthTokenPayload, type Permission, PrincipalType, type SystemRoleD
2
2
  import { Button, errorMessage, Spinner } from '@vertesia/ui/core';
3
3
  import { useUITranslation } from '@vertesia/ui/i18n';
4
4
  import { useUserSession } from '@vertesia/ui/session';
5
- import { createContext, useContext, useMemo } from 'react';
5
+ import { type ComponentType, createContext, useContext, useMemo } from 'react';
6
6
  import { isAnyOf } from './helpers';
7
7
  import { roleMappingsErrorStatus, useRoleMappings } from './useRoleMappings';
8
8
 
@@ -67,11 +67,23 @@ export function useUserPermissions() {
67
67
  return perms;
68
68
  }
69
69
 
70
+ export interface PermissionLoadingScreenProps {
71
+ status: 'loading' | 'retrying' | 'error';
72
+ error?: unknown;
73
+ title: string;
74
+ description: string;
75
+ loadingIcon?: React.ReactNode;
76
+ /** Localized label and action appropriate to the failure (retry, or sign out for 401/403). */
77
+ actionLabel: string;
78
+ onAction: () => void;
79
+ }
80
+
70
81
  interface UserPermissionProviderProps {
82
+ LoadingScreen?: ComponentType<PermissionLoadingScreenProps>;
71
83
  children: React.ReactNode;
72
84
  loadingIcon?: React.ReactNode;
73
85
  }
74
- export function UserPermissionProvider({ children, loadingIcon }: UserPermissionProviderProps) {
86
+ export function UserPermissionProvider({ children, loadingIcon, LoadingScreen }: UserPermissionProviderProps) {
75
87
  const { t } = useUITranslation();
76
88
  const session = useUserSession();
77
89
  const authToken = session.authToken;
@@ -100,51 +112,77 @@ export function UserPermissionProvider({ children, loadingIcon }: UserPermission
100
112
  : failed
101
113
  ? t('permissions.connectionFailed')
102
114
  : t('permissions.connecting');
115
+ const description = needsSignIn
116
+ ? t('auth.recovery.credential.body')
117
+ : denied
118
+ ? t('permissions.accessDenied')
119
+ : failed
120
+ ? t('permissions.tryAgainLater')
121
+ : state.status === 'retrying'
122
+ ? t('permissions.retrying')
123
+ : t('permissions.loadingPermissions');
124
+ const actionLabel =
125
+ needsSignIn || denied ? t('auth.recovery.useDifferentAccount') : t('auth.recovery.tryAgain');
126
+ const onAction = needsSignIn || denied ? () => session.signOut() : retry;
127
+ const Screen = LoadingScreen ?? DefaultPermissionLoadingScreen;
103
128
  return (
104
- <div className="flex min-h-dvh items-center justify-center bg-background px-6 text-foreground">
105
- <div className="w-full max-w-md space-y-6 text-center">
106
- <div aria-hidden="true" className="flex justify-center">
107
- {loadingIcon || (!failed && <Spinner size="2xl" className="text-primary" />)}
108
- </div>
109
- <div
110
- role={failed ? 'alert' : 'status'}
111
- aria-live={failed ? 'assertive' : 'polite'}
112
- className="space-y-2"
113
- >
114
- <h1 className="text-xl font-semibold">{title}</h1>
115
- <p className="text-muted">
116
- {needsSignIn
117
- ? t('auth.recovery.credential.body')
118
- : denied
119
- ? t('permissions.accessDenied')
120
- : failed
121
- ? t('permissions.tryAgainLater')
122
- : state.status === 'retrying'
123
- ? t('permissions.retrying')
124
- : t('permissions.loadingPermissions')}
125
- </p>
126
- </div>
127
- {failed && (
128
- <>
129
- <Button variant="outline" onClick={needsSignIn || denied ? () => session.signOut() : retry}>
130
- {needsSignIn || denied
131
- ? t('auth.recovery.useDifferentAccount')
132
- : t('auth.recovery.tryAgain')}
133
- </Button>
134
- {state.error != null && (
135
- <details className="text-start text-sm text-muted">
136
- <summary className="cursor-pointer">{t('auth.recovery.technicalDetails')}</summary>
137
- <pre className="mt-2 max-h-48 overflow-auto whitespace-pre-wrap wrap-break-word">
138
- {errorMessage(state.error)}
139
- </pre>
140
- </details>
141
- )}
142
- </>
143
- )}
144
- </div>
145
- </div>
129
+ <Screen
130
+ status={failed ? 'error' : state.status === 'retrying' ? 'retrying' : 'loading'}
131
+ error={failed ? state.error : undefined}
132
+ title={title}
133
+ description={description}
134
+ loadingIcon={loadingIcon}
135
+ actionLabel={actionLabel}
136
+ onAction={onAction}
137
+ />
146
138
  );
147
139
  }
148
140
 
149
141
  return perms && <UserPermissionsContext.Provider value={perms}>{children}</UserPermissionsContext.Provider>;
150
142
  }
143
+
144
+ /** Shared permission-loading and recovery layout. */
145
+ export function DefaultPermissionLoadingScreen({
146
+ status,
147
+ error,
148
+ title,
149
+ description,
150
+ loadingIcon,
151
+ actionLabel,
152
+ onAction,
153
+ }: PermissionLoadingScreenProps) {
154
+ const { t } = useUITranslation();
155
+ const failed = status === 'error';
156
+ return (
157
+ <div className="flex min-h-dvh items-center justify-center bg-background px-6 text-foreground">
158
+ <div className="w-full max-w-md space-y-6 text-center">
159
+ <div aria-hidden="true" className="flex justify-center">
160
+ {loadingIcon || (!failed && <Spinner size="2xl" className="text-info" />)}
161
+ </div>
162
+ <div
163
+ role={failed ? 'alert' : 'status'}
164
+ aria-live={failed ? 'assertive' : 'polite'}
165
+ className="space-y-2"
166
+ >
167
+ <h1 className="text-xl font-semibold">{title}</h1>
168
+ <p className="text-muted">{description}</p>
169
+ </div>
170
+ {failed && (
171
+ <>
172
+ <Button variant="outline" onClick={onAction}>
173
+ {actionLabel}
174
+ </Button>
175
+ {error != null && (
176
+ <details className="text-start text-sm text-muted">
177
+ <summary className="cursor-pointer">{t('auth.recovery.technicalDetails')}</summary>
178
+ <pre className="mt-2 max-h-48 overflow-auto whitespace-pre-wrap wrap-break-word">
179
+ {errorMessage(error)}
180
+ </pre>
181
+ </details>
182
+ )}
183
+ </>
184
+ )}
185
+ </div>
186
+ </div>
187
+ );
188
+ }
@@ -132,7 +132,7 @@ export function DocumentPreviewPanel({ objectId, isOpen, onClose }: DocumentPrev
132
132
  {/* Header */}
133
133
  <div className="flex items-center justify-between px-4 py-3 border-b dark:border-border bg-gradient-to-r from-indigo-50 to-gray-50 dark:from-gray-800 dark:to-gray-900">
134
134
  <div className="flex items-center">
135
- <FileText className="h-5 w-5 text-primary me-2" />
135
+ <FileText className="h-5 w-5 text-info me-2" />
136
136
  <h2 className="text-lg font-semibold text-foreground truncate">
137
137
  {isLoading ? t('store.loadingDocument') : object?.name || t('store.documentPreview')}
138
138
  </h2>
@@ -142,7 +142,7 @@ export function DocumentPreviewPanel({ objectId, isOpen, onClose }: DocumentPrev
142
142
  variant="ghost"
143
143
  size="sm"
144
144
  onClick={handleViewFullDocument}
145
- className="flex items-center gap-1 text-primary hover:text-primary"
145
+ className="flex items-center gap-1 text-info hover:text-info"
146
146
  >
147
147
  <Maximize2 className="h-4 w-4" />
148
148
  <span>{t('store.fullView')}</span>
@@ -162,7 +162,7 @@ export function DocumentPreviewPanel({ objectId, isOpen, onClose }: DocumentPrev
162
162
  {isLoading ? (
163
163
  <div className="flex-1 flex items-center justify-center">
164
164
  <div className="text-center">
165
- <Spinner size="lg" className="text-primary mb-2" />
165
+ <Spinner size="lg" className="text-info mb-2" />
166
166
  <p className="text-muted">{t('store.loadingDocument')}</p>
167
167
  </div>
168
168
  </div>
@@ -175,7 +175,7 @@ export function DocumentPreviewPanel({ objectId, isOpen, onClose }: DocumentPrev
175
175
  variant="unstyled"
176
176
  className={`py-2 px-4 font-medium border-b-2 ${
177
177
  currentTab === 'preview'
178
- ? 'border-primary text-primary'
178
+ ? 'border-primary text-info'
179
179
  : 'border-transparent text-muted hover:text-foreground'
180
180
  }`}
181
181
  onClick={() => setCurrentTab('preview')}
@@ -189,7 +189,7 @@ export function DocumentPreviewPanel({ objectId, isOpen, onClose }: DocumentPrev
189
189
  variant="unstyled"
190
190
  className={`py-2 px-4 font-medium border-b-2 ${
191
191
  currentTab === 'properties'
192
- ? 'border-primary text-primary'
192
+ ? 'border-primary text-info'
193
193
  : 'border-transparent text-muted hover:text-foreground'
194
194
  }`}
195
195
  onClick={() => setCurrentTab('properties')}
@@ -209,12 +209,12 @@ export function DocumentPreviewPanel({ objectId, isOpen, onClose }: DocumentPrev
209
209
  {/* Text/Markdown Content */}
210
210
  {loadingText ? (
211
211
  <div className="flex items-center justify-center h-40">
212
- <Spinner size="md" className="text-primary" />
212
+ <Spinner size="md" className="text-info" />
213
213
  </div>
214
214
  ) : text ? (
215
215
  <div className="shadow rounded-md p-4 border border-border bg-white dark:bg-muted">
216
216
  {seemsMarkdown ? (
217
- <div className="prose prose-sm max-w-none prose-p:my-2 prose-pre:bg-muted prose-pre:my-2 prose-headings:text-primary dark:prose-invert">
217
+ <div className="prose prose-sm max-w-none prose-p:my-2 prose-pre:bg-muted prose-pre:my-2 prose-headings:text-info dark:prose-invert">
218
218
  <MarkdownRenderer>{text}</MarkdownRenderer>
219
219
  </div>
220
220
  ) : (
@@ -238,7 +238,7 @@ export function DocumentPreviewPanel({ objectId, isOpen, onClose }: DocumentPrev
238
238
  </div>
239
239
  ) : (
240
240
  <div className="flex items-center justify-center h-40">
241
- <Spinner size="md" className="text-primary" />
241
+ <Spinner size="md" className="text-info" />
242
242
  </div>
243
243
  )}
244
244
  </div>
@@ -247,7 +247,7 @@ export function DocumentPreviewPanel({ objectId, isOpen, onClose }: DocumentPrev
247
247
  {/* PDF Content Notice */}
248
248
  {isPdf && (
249
249
  <div className="flex flex-col items-center justify-center h-64 border border-border rounded-md p-4 bg-muted">
250
- <FileText className="h-16 w-16 text-primary mb-4" />
250
+ <FileText className="h-16 w-16 text-info mb-4" />
251
251
  <p className="text-muted text-center mb-4">{t('store.pdfPreviewFullView')}</p>
252
252
  <Button
253
253
  onClick={handleViewFullDocument}
@@ -353,7 +353,7 @@ export function DocumentPreviewPanel({ objectId, isOpen, onClose }: DocumentPrev
353
353
  }
354
354
  }}
355
355
  variant="outline"
356
- className="text-primary border-primary hover:bg-info"
356
+ className="text-info border-primary hover:bg-info"
357
357
  >
358
358
  <Download className="h-4 w-4 me-2" />
359
359
  {t('pdf.download')}
@@ -87,7 +87,7 @@ export function DocumentInput({ object }: DocumentInputProps) {
87
87
  <SelectDocumentModal value={actualValue} isOpen={isOn} onClose={onSelect} />
88
88
  </div>
89
89
  {doc && (
90
- <div className="p-1 semibold text-sm text-muted dark:text-foreground">
90
+ <div className="p-1 font-semibold text-sm text-muted dark:text-foreground">
91
91
  {typeof doc.properties?.title === 'string' ? doc.properties.title : doc.name}
92
92
  </div>
93
93
  )}
@@ -110,7 +110,10 @@ export function UploadObjectsButton({
110
110
  function optionLayout(option: ObjectsActionSpec) {
111
111
  return {
112
112
  label: option.name,
113
- className: clsx('flex-1 px-2 py-2 hover:bg-muted nowrap', option.destructive ? 'text-destructive' : ''),
113
+ className: clsx(
114
+ 'flex-1 px-2 py-2 hover:bg-muted whitespace-nowrap',
115
+ option.destructive ? 'text-destructive' : '',
116
+ ),
114
117
  };
115
118
  }
116
119
 
@@ -678,7 +678,7 @@ export function DocumentUploadModal({
678
678
  <div className="grid grid-cols-3 gap-4">
679
679
  <div className="flex flex-col items-center">
680
680
  <div className="flex items-center gap-2">
681
- <UploadIcon className="size-5 text-primary" />
681
+ <UploadIcon className="size-5 text-info" />
682
682
  <span className="font-medium">{t('upload.new')}</span>
683
683
  </div>
684
684
  <div className="text-2xl font-semibold">{processingStats.toCreate}</div>
@@ -466,7 +466,7 @@ function GroupAvatar({ userId, showTitle = false, size = 'md' }: GroupAvatarProp
466
466
  return (
467
467
  <UserPopoverPanel title={group.name || t('user.unnamedGroup')} description={description}>
468
468
  <div className="flex flex-row items-center gap-2">
469
- <Users className="size-6 text-primary" size={size} />
469
+ <Users className="size-6 text-info" size={size} />
470
470
  {showTitle && <div className="text-sm font-semibold ps-2">{group.name || t('user.unnamedGroup')}</div>}
471
471
  </div>
472
472
  </UserPopoverPanel>
@@ -1,4 +1,5 @@
1
- import { type ReactNode, useEffect } from 'react';
1
+ import type { i18n } from 'i18next';
2
+ import { createContext, type ReactNode, useContext, useEffect, useMemo } from 'react';
2
3
  import { I18nextProvider, Trans, useTranslation } from 'react-i18next';
3
4
  import { i18nInstance, NAMESPACE } from './instance.js';
4
5
  import { useLanguage } from './LanguageProvider.js';
@@ -48,8 +49,30 @@ export function LanguageBoundI18nProvider({ children }: { children: ReactNode })
48
49
  * Hook for components inside @vertesia/ui to get translation functions.
49
50
  * Always binds to the 'vertesia.ui' namespace on the scoped instance.
50
51
  */
52
+ const TranslationInstanceContext = createContext<i18n | undefined>(undefined);
53
+
54
+ /** Overrides are scoped to this subtree and never mutate the shared translation resources. */
55
+ export function UITranslationOverrides({
56
+ overrides,
57
+ children,
58
+ }: {
59
+ overrides: Record<string, string>;
60
+ children: ReactNode;
61
+ }) {
62
+ const parent = useContext(TranslationInstanceContext) ?? i18nInstance;
63
+ const { i18n: current } = useTranslation(NAMESPACE, { i18n: parent });
64
+ const language = current.resolvedLanguage ?? current.language;
65
+ const instance = useMemo(() => {
66
+ const clone = parent.cloneInstance({ forkResourceStore: true, lng: language, initAsync: false });
67
+ clone.addResourceBundle(language, NAMESPACE, overrides, true, true);
68
+ return clone;
69
+ }, [parent, language, overrides]);
70
+ return <TranslationInstanceContext.Provider value={instance}>{children}</TranslationInstanceContext.Provider>;
71
+ }
72
+
51
73
  export function useUITranslation() {
52
- return useTranslation(NAMESPACE, { i18n: i18nInstance });
74
+ const instance = useContext(TranslationInstanceContext) ?? i18nInstance;
75
+ return useTranslation(NAMESPACE, { i18n: instance });
53
76
  }
54
77
 
55
78
  export { i18nInstance, NAMESPACE } from './instance.js';
@@ -101,6 +101,35 @@
101
101
  "agent.failedToInterrupt": "فشل الإيقاف",
102
102
  "agent.failedToLoadDocument": "فشل تحميل المستند",
103
103
  "agent.failedToSend": "فشل إرسال الرسالة",
104
+ "agent.feedback.commentHelp": "يُحتسب فقط ما إذا كنت قد تركت تعليقًا؛ أما النص نفسه فيبقى داخل مشروعك.",
105
+ "agent.feedback.commentLabel": "تعليق",
106
+ "agent.feedback.commentPlaceholder": "ما الذي سار على ما يرام، وما الذي حدث فيه خلل؟",
107
+ "agent.feedback.detailHelp": "تم حفظ تقييمك. أضف سببًا إذا أردت قول المزيد.",
108
+ "agent.feedback.detailTitle": "أخبرنا المزيد",
109
+ "agent.feedback.failed": "تعذّر إرسال تقييمك",
110
+ "agent.feedback.notRecorded": "لم يتم تسجيل تقييمك",
111
+ "agent.feedback.rateMessageDown": "تقييم هذه الإجابة بالسلب",
112
+ "agent.feedback.rateMessageUp": "تقييم هذه الإجابة بالإيجاب",
113
+ "agent.feedback.rateRunDown": "تقييم هذا التشغيل بالسلب",
114
+ "agent.feedback.rateRunUp": "تقييم هذا التشغيل بالإيجاب",
115
+ "agent.feedback.reason.accurate": "دقيق",
116
+ "agent.feedback.reason.fast": "سريع",
117
+ "agent.feedback.reason.helpful": "مفيد",
118
+ "agent.feedback.reason.incomplete": "غير مكتمل",
119
+ "agent.feedback.reason.misunderstood_request": "أساء فهم طلبي",
120
+ "agent.feedback.reason.other": "شيء آخر",
121
+ "agent.feedback.reason.too_slow": "بطيء جدًا",
122
+ "agent.feedback.reason.tool_failure": "فشلت إحدى الأدوات",
123
+ "agent.feedback.reason.unsafe_action": "قام بإجراء غير آمن",
124
+ "agent.feedback.reason.well_explained": "شرح جيد",
125
+ "agent.feedback.reason.wrong_result": "نتيجة خاطئة",
126
+ "agent.feedback.reasonLabel": "السبب",
127
+ "agent.feedback.reasonPlaceholder": "اختر سببًا (اختياري)",
128
+ "agent.feedback.skip": "ليس الآن",
129
+ "agent.feedback.status.disabled": "لا يتم جمع التقييمات في هذه البيئة.",
130
+ "agent.feedback.submit": "إرسال",
131
+ "agent.feedback.tellUsMore": "أخبرنا المزيد",
132
+ "agent.feedback.thanks": "شكرًا على ملاحظاتك",
104
133
  "agent.filesProcessing": "لا تزال الملفات قيد المعالجة",
105
134
  "agent.fileStagedTooltip": "ملف مُعدّ - سيتم رفعه عند بدء المحادثة",
106
135
  "agent.fullscreen": "ملء الشاشة",
@@ -333,6 +362,7 @@
333
362
  "layout.pageNotFound": "الصفحة غير موجودة",
334
363
  "layout.search": "بحث",
335
364
  "layout.searchPlaceholder": "بحث...",
365
+ "layout.toggleNavigationMenu": "تبديل قائمة التنقل",
336
366
  "login.accept": "قبول",
337
367
  "login.reject": "رفض",
338
368
  "login.reviewInvites": "مراجعة الدعوات",
@@ -93,6 +93,35 @@
93
93
  "agent.failedToInterrupt": "Unterbrechung fehlgeschlagen",
94
94
  "agent.failedToLoadDocument": "Dokument konnte nicht geladen werden",
95
95
  "agent.failedToSend": "Nachricht konnte nicht gesendet werden",
96
+ "agent.feedback.commentHelp": "Gezählt wird nur, ob Sie einen Kommentar hinterlassen haben; der Text selbst bleibt in Ihrem Projekt.",
97
+ "agent.feedback.commentLabel": "Kommentar",
98
+ "agent.feedback.commentPlaceholder": "Was lief gut, was lief schief?",
99
+ "agent.feedback.detailHelp": "Ihre Bewertung wurde gespeichert. Fügen Sie einen Grund hinzu, wenn Sie mehr sagen möchten.",
100
+ "agent.feedback.detailTitle": "Erzählen Sie uns mehr",
101
+ "agent.feedback.failed": "Bewertung konnte nicht gesendet werden",
102
+ "agent.feedback.notRecorded": "Ihre Bewertung wurde nicht erfasst",
103
+ "agent.feedback.rateMessageDown": "Diese Antwort negativ bewerten",
104
+ "agent.feedback.rateMessageUp": "Diese Antwort positiv bewerten",
105
+ "agent.feedback.rateRunDown": "Diesen Lauf negativ bewerten",
106
+ "agent.feedback.rateRunUp": "Diesen Lauf positiv bewerten",
107
+ "agent.feedback.reason.accurate": "Korrekt",
108
+ "agent.feedback.reason.fast": "Schnell",
109
+ "agent.feedback.reason.helpful": "Hilfreich",
110
+ "agent.feedback.reason.incomplete": "Unvollständig",
111
+ "agent.feedback.reason.misunderstood_request": "Hat meine Anfrage missverstanden",
112
+ "agent.feedback.reason.other": "Etwas anderes",
113
+ "agent.feedback.reason.too_slow": "Zu langsam",
114
+ "agent.feedback.reason.tool_failure": "Ein Tool ist fehlgeschlagen",
115
+ "agent.feedback.reason.unsafe_action": "Hat etwas Unsicheres getan",
116
+ "agent.feedback.reason.well_explained": "Gut erklärt",
117
+ "agent.feedback.reason.wrong_result": "Falsches Ergebnis",
118
+ "agent.feedback.reasonLabel": "Grund",
119
+ "agent.feedback.reasonPlaceholder": "Grund auswählen (optional)",
120
+ "agent.feedback.skip": "Jetzt nicht",
121
+ "agent.feedback.status.disabled": "In dieser Umgebung werden keine Bewertungen erfasst.",
122
+ "agent.feedback.submit": "Senden",
123
+ "agent.feedback.tellUsMore": "Erzählen Sie uns mehr",
124
+ "agent.feedback.thanks": "Danke für Ihr Feedback",
96
125
  "agent.filesProcessing": "Dateien werden noch verarbeitet",
97
126
  "agent.fileStagedTooltip": "Datei bereitgestellt - wird beim Start der Konversation hochgeladen",
98
127
  "agent.fullscreen": "Vollbild",
@@ -321,6 +350,7 @@
321
350
  "layout.pageNotFound": "Seite nicht gefunden",
322
351
  "layout.search": "Suche",
323
352
  "layout.searchPlaceholder": "Suchen...",
353
+ "layout.toggleNavigationMenu": "Navigationsmenü umschalten",
324
354
  "login.accept": "Akzeptieren",
325
355
  "login.reject": "Ablehnen",
326
356
  "login.reviewInvites": "Einladungen überprüfen",