@vertesia/ui 1.5.0 → 1.6.0-dev.20260918.061604Z

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 (336) 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/shadcn/button.d.ts.map +1 -1
  15. package/lib/core/components/shadcn/button.js +1 -2
  16. package/lib/core/components/shadcn/button.js.map +1 -1
  17. package/lib/core/components/shadcn/filters/filter-styles.d.ts +1 -1
  18. package/lib/core/components/shadcn/filters/filter-styles.d.ts.map +1 -1
  19. package/lib/core/components/shadcn/filters/filter-styles.js +4 -4
  20. package/lib/core/components/shadcn/label.js +1 -1
  21. package/lib/core/components/shadcn/label.js.map +1 -1
  22. package/lib/env/index.d.ts +32 -1
  23. package/lib/env/index.d.ts.map +1 -1
  24. package/lib/env/index.js +55 -3
  25. package/lib/env/index.js.map +1 -1
  26. package/lib/features/agent/PayloadBuilder.d.ts +4 -0
  27. package/lib/features/agent/PayloadBuilder.d.ts.map +1 -1
  28. package/lib/features/agent/PayloadBuilder.js +6 -1
  29. package/lib/features/agent/PayloadBuilder.js.map +1 -1
  30. package/lib/features/agent/chat/AgentRunFeedback.d.ts +66 -0
  31. package/lib/features/agent/chat/AgentRunFeedback.d.ts.map +1 -0
  32. package/lib/features/agent/chat/AgentRunFeedback.js +298 -0
  33. package/lib/features/agent/chat/AgentRunFeedback.js.map +1 -0
  34. package/lib/features/agent/chat/ModernAgentConversation.d.ts.map +1 -1
  35. package/lib/features/agent/chat/ModernAgentConversation.js +7 -5
  36. package/lib/features/agent/chat/ModernAgentConversation.js.map +1 -1
  37. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts +3 -1
  38. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts.map +1 -1
  39. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js +11 -10
  40. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js.map +1 -1
  41. package/lib/features/agent/chat/ModernAgentOutput/Header.d.ts.map +1 -1
  42. package/lib/features/agent/chat/ModernAgentOutput/Header.js.map +1 -1
  43. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.d.ts +3 -1
  44. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.d.ts.map +1 -1
  45. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js +28 -7
  46. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js.map +1 -1
  47. package/lib/features/agent/chat/ModernAgentOutput/SummaryConversation.d.ts.map +1 -1
  48. package/lib/features/agent/chat/ModernAgentOutput/SummaryConversation.js +2 -0
  49. package/lib/features/agent/chat/ModernAgentOutput/SummaryConversation.js.map +1 -1
  50. package/lib/features/agent/chat/hooks/useAgentPlans.d.ts +1 -1
  51. package/lib/features/agent/chat/hooks/useAgentPlans.d.ts.map +1 -1
  52. package/lib/features/agent/chat/hooks/useAgentPlans.js +5 -5
  53. package/lib/features/agent/chat/hooks/useAgentPlans.js.map +1 -1
  54. package/lib/features/agent/chat/index.d.ts +1 -0
  55. package/lib/features/agent/chat/index.d.ts.map +1 -1
  56. package/lib/features/agent/chat/index.js +1 -0
  57. package/lib/features/agent/chat/index.js.map +1 -1
  58. package/lib/features/facets/AgentRunnerFacetsNav.d.ts +8 -0
  59. package/lib/features/facets/AgentRunnerFacetsNav.d.ts.map +1 -1
  60. package/lib/features/facets/AgentRunnerFacetsNav.js +12 -0
  61. package/lib/features/facets/AgentRunnerFacetsNav.js.map +1 -1
  62. package/lib/features/permissions/UserPermissionsProvider.d.ts +15 -1
  63. package/lib/features/permissions/UserPermissionsProvider.d.ts.map +1 -1
  64. package/lib/features/permissions/UserPermissionsProvider.js +20 -12
  65. package/lib/features/permissions/UserPermissionsProvider.js.map +1 -1
  66. package/lib/features/store/objects/search/DocumentSearchContext.d.ts.map +1 -1
  67. package/lib/features/store/objects/search/DocumentSearchContext.js +6 -1
  68. package/lib/features/store/objects/search/DocumentSearchContext.js.map +1 -1
  69. package/lib/features/store/objects/selection/SelectionActions.js +1 -1
  70. package/lib/features/store/objects/selection/SelectionActions.js.map +1 -1
  71. package/lib/features/store/types/TypeRegistry.d.ts +130 -0
  72. package/lib/features/store/types/TypeRegistry.d.ts.map +1 -1
  73. package/lib/features/store/types/search/ObjectTypeSearchContext.d.ts +130 -0
  74. package/lib/features/store/types/search/ObjectTypeSearchContext.d.ts.map +1 -1
  75. package/lib/i18n/index.d.ts +5 -4
  76. package/lib/i18n/index.d.ts.map +1 -1
  77. package/lib/i18n/index.js +16 -2
  78. package/lib/i18n/index.js.map +1 -1
  79. package/lib/i18n/locales/ar.json +30 -0
  80. package/lib/i18n/locales/de.json +30 -0
  81. package/lib/i18n/locales/en.json +30 -0
  82. package/lib/i18n/locales/es.json +30 -0
  83. package/lib/i18n/locales/fr.json +30 -0
  84. package/lib/i18n/locales/it.json +30 -0
  85. package/lib/i18n/locales/ja.json +30 -0
  86. package/lib/i18n/locales/ko.json +30 -0
  87. package/lib/i18n/locales/pt.json +30 -0
  88. package/lib/i18n/locales/ru.json +30 -0
  89. package/lib/i18n/locales/tr.json +30 -0
  90. package/lib/i18n/locales/zh-TW.json +30 -0
  91. package/lib/i18n/locales/zh.json +30 -0
  92. package/lib/layout/ErrorPage.js +1 -1
  93. package/lib/layout/ErrorPage.js.map +1 -1
  94. package/lib/layout/Navbar.d.ts.map +1 -1
  95. package/lib/layout/Navbar.js +3 -2
  96. package/lib/layout/Navbar.js.map +1 -1
  97. package/lib/session/UserSession.d.ts.map +1 -1
  98. package/lib/session/UserSession.js +2 -3
  99. package/lib/session/UserSession.js.map +1 -1
  100. package/lib/session/UserSessionProvider.d.ts +2 -1
  101. package/lib/session/UserSessionProvider.d.ts.map +1 -1
  102. package/lib/session/UserSessionProvider.js +13 -4
  103. package/lib/session/UserSessionProvider.js.map +1 -1
  104. package/lib/session/auth/composable.d.ts.map +1 -1
  105. package/lib/session/auth/composable.js +88 -3
  106. package/lib/session/auth/composable.js.map +1 -1
  107. package/lib/session/auth/domainRouting.d.ts +22 -12
  108. package/lib/session/auth/domainRouting.d.ts.map +1 -1
  109. package/lib/session/auth/domainRouting.js +35 -21
  110. package/lib/session/auth/domainRouting.js.map +1 -1
  111. package/lib/session/auth/firebase.d.ts.map +1 -1
  112. package/lib/session/auth/firebase.js +10 -0
  113. package/lib/session/auth/firebase.js.map +1 -1
  114. package/lib/session/auth/useAuthState.d.ts +9 -4
  115. package/lib/session/auth/useAuthState.d.ts.map +1 -1
  116. package/lib/session/auth/useAuthState.js +9 -4
  117. package/lib/session/auth/useAuthState.js.map +1 -1
  118. package/lib/session/index.d.ts.map +1 -1
  119. package/lib/session/index.js +3 -1
  120. package/lib/session/index.js.map +1 -1
  121. package/lib/shell/AuthScreenPreview.d.ts +12 -0
  122. package/lib/shell/AuthScreenPreview.d.ts.map +1 -0
  123. package/lib/shell/AuthScreenPreview.js +140 -0
  124. package/lib/shell/AuthScreenPreview.js.map +1 -0
  125. package/lib/shell/BrandedAuthScreens.d.ts +19 -0
  126. package/lib/shell/BrandedAuthScreens.d.ts.map +1 -0
  127. package/lib/shell/BrandedAuthScreens.js +64 -0
  128. package/lib/shell/BrandedAuthScreens.js.map +1 -0
  129. package/lib/shell/SplashScreen.d.ts +13 -2
  130. package/lib/shell/SplashScreen.d.ts.map +1 -1
  131. package/lib/shell/SplashScreen.js +20 -19
  132. package/lib/shell/SplashScreen.js.map +1 -1
  133. package/lib/shell/VertesiaShell.d.ts +15 -4
  134. package/lib/shell/VertesiaShell.d.ts.map +1 -1
  135. package/lib/shell/VertesiaShell.js +8 -3
  136. package/lib/shell/VertesiaShell.js.map +1 -1
  137. package/lib/shell/apps/StandaloneApp.js +5 -1
  138. package/lib/shell/apps/StandaloneApp.js.map +1 -1
  139. package/lib/shell/index.d.ts +6 -0
  140. package/lib/shell/index.d.ts.map +1 -1
  141. package/lib/shell/index.js +5 -0
  142. package/lib/shell/index.js.map +1 -1
  143. package/lib/shell/login/SignInAuthPending.js +1 -1
  144. package/lib/shell/login/SignInAuthPending.js.map +1 -1
  145. package/lib/shell/login/SignInEmailStep.d.ts.map +1 -1
  146. package/lib/shell/login/SignInEmailStep.js +2 -2
  147. package/lib/shell/login/SignInEmailStep.js.map +1 -1
  148. package/lib/shell/login/SignInFlow.d.ts +68 -0
  149. package/lib/shell/login/SignInFlow.d.ts.map +1 -0
  150. package/lib/shell/login/SignInFlow.js +108 -0
  151. package/lib/shell/login/SignInFlow.js.map +1 -0
  152. package/lib/shell/login/SignInIcons.d.ts +1 -1
  153. package/lib/shell/login/SignInIcons.d.ts.map +1 -1
  154. package/lib/shell/login/SignInPageShell.d.ts +13 -0
  155. package/lib/shell/login/SignInPageShell.d.ts.map +1 -0
  156. package/lib/shell/login/SignInPageShell.js +14 -0
  157. package/lib/shell/login/SignInPageShell.js.map +1 -0
  158. package/lib/shell/login/SignInPrimitives.d.ts +3 -3
  159. package/lib/shell/login/SignInPrimitives.d.ts.map +1 -1
  160. package/lib/shell/login/SignInPrimitives.js +13 -11
  161. package/lib/shell/login/SignInPrimitives.js.map +1 -1
  162. package/lib/shell/login/SignInRestrictedEnvStep.d.ts +5 -0
  163. package/lib/shell/login/SignInRestrictedEnvStep.d.ts.map +1 -1
  164. package/lib/shell/login/SignInRestrictedEnvStep.js +8 -4
  165. package/lib/shell/login/SignInRestrictedEnvStep.js.map +1 -1
  166. package/lib/shell/login/SigninScreen.d.ts +38 -3
  167. package/lib/shell/login/SigninScreen.d.ts.map +1 -1
  168. package/lib/shell/login/SigninScreen.js +33 -86
  169. package/lib/shell/login/SigninScreen.js.map +1 -1
  170. package/lib/shell/login/SignupForm.d.ts +3 -1
  171. package/lib/shell/login/SignupForm.d.ts.map +1 -1
  172. package/lib/shell/login/SignupForm.js +7 -3
  173. package/lib/shell/login/SignupForm.js.map +1 -1
  174. package/lib/shell/login/signInUtils.d.ts +12 -1
  175. package/lib/shell/login/signInUtils.d.ts.map +1 -1
  176. package/lib/shell/login/signInUtils.js +34 -11
  177. package/lib/shell/login/signInUtils.js.map +1 -1
  178. package/lib/vertesia-ui-boot.js +237 -0
  179. package/lib/vertesia-ui-boot.js.map +1 -0
  180. package/lib/vertesia-ui-core.js +88 -46
  181. package/lib/vertesia-ui-core.js.map +1 -1
  182. package/lib/vertesia-ui-env.js +1 -1
  183. package/lib/vertesia-ui-env.js.map +1 -1
  184. package/lib/vertesia-ui-features.js +350 -317
  185. package/lib/vertesia-ui-features.js.map +1 -1
  186. package/lib/vertesia-ui-i18n.B3NFclwl.chunk.js +5 -0
  187. package/lib/vertesia-ui-i18n.B3NFclwl.chunk.js.map +1 -0
  188. package/lib/vertesia-ui-i18n.BWSrNIxc.chunk.js +5 -0
  189. package/lib/vertesia-ui-i18n.BWSrNIxc.chunk.js.map +1 -0
  190. package/lib/vertesia-ui-i18n.BWvWeB1p.chunk.js +5 -0
  191. package/lib/vertesia-ui-i18n.BWvWeB1p.chunk.js.map +1 -0
  192. package/lib/vertesia-ui-i18n.BZCXvTC1.chunk.js +5 -0
  193. package/lib/vertesia-ui-i18n.BZCXvTC1.chunk.js.map +1 -0
  194. package/lib/vertesia-ui-i18n.BbJMvFZW.chunk.js +5 -0
  195. package/lib/vertesia-ui-i18n.BbJMvFZW.chunk.js.map +1 -0
  196. package/lib/vertesia-ui-i18n.CE5ldwpt.chunk.js +5 -0
  197. package/lib/vertesia-ui-i18n.CE5ldwpt.chunk.js.map +1 -0
  198. package/lib/vertesia-ui-i18n.CMC0IShY.chunk.js +5 -0
  199. package/lib/vertesia-ui-i18n.CMC0IShY.chunk.js.map +1 -0
  200. package/lib/vertesia-ui-i18n.CkcRqBKU.chunk.js +5 -0
  201. package/lib/vertesia-ui-i18n.CkcRqBKU.chunk.js.map +1 -0
  202. package/lib/vertesia-ui-i18n.D-Mq1sw_.chunk.js +5 -0
  203. package/lib/vertesia-ui-i18n.D-Mq1sw_.chunk.js.map +1 -0
  204. package/lib/vertesia-ui-i18n.DkK68-A-.chunk.js +5 -0
  205. package/lib/vertesia-ui-i18n.DkK68-A-.chunk.js.map +1 -0
  206. package/lib/vertesia-ui-i18n.XE_dcCg6.chunk.js +5 -0
  207. package/lib/vertesia-ui-i18n.XE_dcCg6.chunk.js.map +1 -0
  208. package/lib/vertesia-ui-i18n.js +2 -2
  209. package/lib/vertesia-ui-i18n.js.map +1 -1
  210. package/lib/vertesia-ui-i18n.qgNqMPvK.chunk.js +5 -0
  211. package/lib/vertesia-ui-i18n.qgNqMPvK.chunk.js.map +1 -0
  212. package/lib/vertesia-ui-layout.js +43 -19
  213. package/lib/vertesia-ui-layout.js.map +1 -1
  214. package/lib/vertesia-ui-rich-text.js +123 -74
  215. package/lib/vertesia-ui-rich-text.js.map +1 -1
  216. package/lib/vertesia-ui-router.js.map +1 -1
  217. package/lib/vertesia-ui-session.js +1 -1
  218. package/lib/vertesia-ui-session.js.map +1 -1
  219. package/lib/vertesia-ui-shell.js +87 -33
  220. package/lib/vertesia-ui-shell.js.map +1 -1
  221. package/lib/vertesia-ui-widgets.js +154 -98
  222. package/lib/vertesia-ui-widgets.js.map +1 -1
  223. package/lib/widgets/xml-viewer/hooks/useCollapsible.d.ts +1 -1
  224. package/llms.txt +6 -2
  225. package/package.json +45 -36
  226. package/src/__tests__/a11y.test.tsx +25 -0
  227. package/src/__tests__/theme.test.ts +91 -0
  228. package/src/boot/branding.test.ts +72 -0
  229. package/src/boot/branding.ts +108 -0
  230. package/src/boot/index.test.ts +216 -0
  231. package/src/boot/index.ts +356 -0
  232. package/src/boot/vite.test.ts +93 -0
  233. package/src/boot/vite.ts +118 -0
  234. package/src/core/components/shadcn/button.tsx +1 -2
  235. package/src/core/components/shadcn/filters/filter-styles.ts +4 -4
  236. package/src/core/components/shadcn/label.tsx +1 -1
  237. package/src/env/index.test.ts +127 -0
  238. package/src/env/index.ts +73 -3
  239. package/src/features/agent/PayloadBuilder.tsx +10 -1
  240. package/src/features/agent/chat/AgentRunFeedback.test.tsx +347 -0
  241. package/src/features/agent/chat/AgentRunFeedback.tsx +465 -0
  242. package/src/features/agent/chat/ModernAgentConversation.test.tsx +1 -1
  243. package/src/features/agent/chat/ModernAgentConversation.tsx +52 -47
  244. package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.test.tsx +145 -0
  245. package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.tsx +42 -24
  246. package/src/features/agent/chat/ModernAgentOutput/Header.tsx +4 -0
  247. package/src/features/agent/chat/ModernAgentOutput/MessageItem.tsx +38 -5
  248. package/src/features/agent/chat/ModernAgentOutput/SummaryConversation.ts +2 -0
  249. package/src/features/agent/chat/ModernAgentOutput/utils.test.ts +14 -0
  250. package/src/features/agent/chat/hooks/useAgentPlans.test.ts +52 -0
  251. package/src/features/agent/chat/hooks/useAgentPlans.ts +5 -5
  252. package/src/features/agent/chat/hooks/useFileProcessing.test.tsx +0 -5
  253. package/src/features/agent/chat/index.ts +6 -0
  254. package/src/features/facets/AgentRunnerFacetsNav.tsx +26 -0
  255. package/src/features/permissions/UserPermissionsProvider.test.tsx +50 -1
  256. package/src/features/permissions/UserPermissionsProvider.tsx +82 -44
  257. package/src/features/store/objects/search/DocumentSearchContext.ts +8 -3
  258. package/src/features/store/objects/selection/SelectionActions.tsx +4 -1
  259. package/src/i18n/index.tsx +25 -2
  260. package/src/i18n/locales/ar.json +30 -0
  261. package/src/i18n/locales/de.json +30 -0
  262. package/src/i18n/locales/en.json +30 -0
  263. package/src/i18n/locales/es.json +30 -0
  264. package/src/i18n/locales/fr.json +30 -0
  265. package/src/i18n/locales/it.json +30 -0
  266. package/src/i18n/locales/ja.json +30 -0
  267. package/src/i18n/locales/ko.json +30 -0
  268. package/src/i18n/locales/pt.json +30 -0
  269. package/src/i18n/locales/ru.json +30 -0
  270. package/src/i18n/locales/tr.json +30 -0
  271. package/src/i18n/locales/zh-TW.json +30 -0
  272. package/src/i18n/locales/zh.json +30 -0
  273. package/src/layout/ErrorPage.tsx +1 -1
  274. package/src/layout/Navbar.test.tsx +58 -0
  275. package/src/layout/Navbar.tsx +5 -2
  276. package/src/router/path.test.ts +5 -5
  277. package/src/session/UserSession.ts +2 -4
  278. package/src/session/UserSessionProvider.strict-mode.test.tsx +44 -0
  279. package/src/session/UserSessionProvider.test.ts +62 -1
  280. package/src/session/UserSessionProvider.tsx +12 -4
  281. package/src/session/auth/composable.renewal.test.ts +170 -0
  282. package/src/session/auth/composable.test.ts +23 -1
  283. package/src/session/auth/composable.ts +101 -2
  284. package/src/session/auth/domainRouting.test.ts +35 -65
  285. package/src/session/auth/domainRouting.ts +51 -34
  286. package/src/session/auth/firebase.test.ts +25 -0
  287. package/src/session/auth/firebase.ts +10 -0
  288. package/src/session/auth/useAuthState.ts +11 -4
  289. package/src/session/index.ts +3 -1
  290. package/src/shell/AuthScreenPreview.test.tsx +44 -0
  291. package/src/shell/AuthScreenPreview.tsx +228 -0
  292. package/src/shell/BrandedAuthScreens.test.tsx +181 -0
  293. package/src/shell/BrandedAuthScreens.tsx +117 -0
  294. package/src/shell/SplashScreen.test.tsx +37 -0
  295. package/src/shell/SplashScreen.tsx +44 -39
  296. package/src/shell/VertesiaShell.tsx +49 -22
  297. package/src/shell/apps/StandaloneApp.tsx +5 -1
  298. package/src/shell/index.tsx +6 -0
  299. package/src/shell/login/SignInAuthPending.tsx +3 -3
  300. package/src/shell/login/SignInEmailStep.test.tsx +32 -0
  301. package/src/shell/login/SignInEmailStep.tsx +13 -9
  302. package/src/shell/login/SignInFlow.tsx +213 -0
  303. package/src/shell/login/SignInPageShell.tsx +62 -0
  304. package/src/shell/login/SignInPrimitives.tsx +14 -11
  305. package/src/shell/login/SignInRestrictedEnvStep.tsx +19 -7
  306. package/src/shell/login/SigninScreen.test.tsx +104 -0
  307. package/src/shell/login/SigninScreen.tsx +115 -145
  308. package/src/shell/login/SignupForm.tsx +8 -3
  309. package/src/shell/login/signInUtils.ts +42 -9
  310. package/src/widgets/markdown/CollaborativeMarkdownRenderer.test.tsx +11 -3
  311. package/src/widgets/markdown/markdown.css +21 -21
  312. package/lib/vertesia-ui-i18n.BfN7iOHb.chunk.js +0 -5
  313. package/lib/vertesia-ui-i18n.BfN7iOHb.chunk.js.map +0 -1
  314. package/lib/vertesia-ui-i18n.BjH2zEZw.chunk.js +0 -5
  315. package/lib/vertesia-ui-i18n.BjH2zEZw.chunk.js.map +0 -1
  316. package/lib/vertesia-ui-i18n.BjSwAZXl.chunk.js +0 -5
  317. package/lib/vertesia-ui-i18n.BjSwAZXl.chunk.js.map +0 -1
  318. package/lib/vertesia-ui-i18n.C7PUm5Au.chunk.js +0 -5
  319. package/lib/vertesia-ui-i18n.C7PUm5Au.chunk.js.map +0 -1
  320. package/lib/vertesia-ui-i18n.CF_1mUS5.chunk.js +0 -5
  321. package/lib/vertesia-ui-i18n.CF_1mUS5.chunk.js.map +0 -1
  322. package/lib/vertesia-ui-i18n.ChfUl3_-.chunk.js +0 -5
  323. package/lib/vertesia-ui-i18n.ChfUl3_-.chunk.js.map +0 -1
  324. package/lib/vertesia-ui-i18n.D-Sk-5d1.chunk.js +0 -5
  325. package/lib/vertesia-ui-i18n.D-Sk-5d1.chunk.js.map +0 -1
  326. package/lib/vertesia-ui-i18n.D4rnu1_S.chunk.js +0 -5
  327. package/lib/vertesia-ui-i18n.D4rnu1_S.chunk.js.map +0 -1
  328. package/lib/vertesia-ui-i18n.DDf0-laK.chunk.js +0 -5
  329. package/lib/vertesia-ui-i18n.DDf0-laK.chunk.js.map +0 -1
  330. package/lib/vertesia-ui-i18n.DN79y06J.chunk.js +0 -5
  331. package/lib/vertesia-ui-i18n.DN79y06J.chunk.js.map +0 -1
  332. package/lib/vertesia-ui-i18n.DWLIciYQ.chunk.js +0 -5
  333. package/lib/vertesia-ui-i18n.DWLIciYQ.chunk.js.map +0 -1
  334. package/lib/vertesia-ui-i18n.DvF_YaAJ.chunk.js +0 -5
  335. package/lib/vertesia-ui-i18n.DvF_YaAJ.chunk.js.map +0 -1
  336. package/src/session/auth/authState.test.ts +0 -35
@@ -93,6 +93,35 @@
93
93
  "agent.failedToInterrupt": "중단에 실패했습니다",
94
94
  "agent.failedToLoadDocument": "문서 로드 실패",
95
95
  "agent.failedToSend": "메시지 전송에 실패했습니다",
96
+ "agent.feedback.commentHelp": "댓글을 남겼는지 여부만 집계되며, 내용 자체는 프로젝트에 남습니다.",
97
+ "agent.feedback.commentLabel": "의견",
98
+ "agent.feedback.commentPlaceholder": "무엇이 좋았거나 무엇이 잘못되었나요?",
99
+ "agent.feedback.detailHelp": "평가가 저장되었습니다. 더 말하고 싶다면 이유를 추가하세요.",
100
+ "agent.feedback.detailTitle": "자세히 알려주세요",
101
+ "agent.feedback.failed": "평가를 보낼 수 없습니다",
102
+ "agent.feedback.notRecorded": "평가가 기록되지 않았습니다",
103
+ "agent.feedback.rateMessageDown": "이 답변에 낮은 평가하기",
104
+ "agent.feedback.rateMessageUp": "이 답변에 높은 평가하기",
105
+ "agent.feedback.rateRunDown": "이 실행에 낮은 평가하기",
106
+ "agent.feedback.rateRunUp": "이 실행에 높은 평가하기",
107
+ "agent.feedback.reason.accurate": "정확함",
108
+ "agent.feedback.reason.fast": "빠름",
109
+ "agent.feedback.reason.helpful": "도움이 됨",
110
+ "agent.feedback.reason.incomplete": "불완전함",
111
+ "agent.feedback.reason.misunderstood_request": "요청을 잘못 이해함",
112
+ "agent.feedback.reason.other": "기타",
113
+ "agent.feedback.reason.too_slow": "너무 느림",
114
+ "agent.feedback.reason.tool_failure": "도구가 실패함",
115
+ "agent.feedback.reason.unsafe_action": "안전하지 않은 작업을 수행함",
116
+ "agent.feedback.reason.well_explained": "설명이 명확함",
117
+ "agent.feedback.reason.wrong_result": "결과가 잘못됨",
118
+ "agent.feedback.reasonLabel": "이유",
119
+ "agent.feedback.reasonPlaceholder": "이유 선택 (선택 사항)",
120
+ "agent.feedback.skip": "나중에",
121
+ "agent.feedback.status.disabled": "이 환경에서는 평가를 수집하지 않습니다.",
122
+ "agent.feedback.submit": "보내기",
123
+ "agent.feedback.tellUsMore": "자세히 알려주세요",
124
+ "agent.feedback.thanks": "의견 감사합니다",
96
125
  "agent.filesProcessing": "파일 처리 중",
97
126
  "agent.fileStagedTooltip": "파일이 준비됨 - 대화 시작 시 업로드됩니다",
98
127
  "agent.fullscreen": "전체 화면",
@@ -321,6 +350,7 @@
321
350
  "layout.pageNotFound": "페이지를 찾을 수 없음",
322
351
  "layout.search": "검색",
323
352
  "layout.searchPlaceholder": "검색...",
353
+ "layout.toggleNavigationMenu": "탐색 메뉴 전환",
324
354
  "login.accept": "수락",
325
355
  "login.reject": "거부",
326
356
  "login.reviewInvites": "초대 검토",
@@ -94,6 +94,35 @@
94
94
  "agent.failedToInterrupt": "Falha ao interromper",
95
95
  "agent.failedToLoadDocument": "Falha ao carregar documento",
96
96
  "agent.failedToSend": "Falha ao enviar a mensagem",
97
+ "agent.feedback.commentHelp": "Apenas se você deixou um comentário é contabilizado; o texto em si permanece no seu projeto.",
98
+ "agent.feedback.commentLabel": "Comentário",
99
+ "agent.feedback.commentPlaceholder": "O que funcionou bem, ou o que deu errado?",
100
+ "agent.feedback.detailHelp": "Sua avaliação foi salva. Adicione um motivo se quiser dizer mais.",
101
+ "agent.feedback.detailTitle": "Conte-nos mais",
102
+ "agent.feedback.failed": "Não foi possível enviar sua avaliação",
103
+ "agent.feedback.notRecorded": "Sua avaliação não foi registrada",
104
+ "agent.feedback.rateMessageDown": "Avaliar esta resposta negativamente",
105
+ "agent.feedback.rateMessageUp": "Avaliar esta resposta positivamente",
106
+ "agent.feedback.rateRunDown": "Avaliar esta execução negativamente",
107
+ "agent.feedback.rateRunUp": "Avaliar esta execução positivamente",
108
+ "agent.feedback.reason.accurate": "Preciso",
109
+ "agent.feedback.reason.fast": "Rápido",
110
+ "agent.feedback.reason.helpful": "Útil",
111
+ "agent.feedback.reason.incomplete": "Incompleto",
112
+ "agent.feedback.reason.misunderstood_request": "Entendeu mal meu pedido",
113
+ "agent.feedback.reason.other": "Outra coisa",
114
+ "agent.feedback.reason.too_slow": "Muito lento",
115
+ "agent.feedback.reason.tool_failure": "Uma ferramenta falhou",
116
+ "agent.feedback.reason.unsafe_action": "Fez algo inseguro",
117
+ "agent.feedback.reason.well_explained": "Bem explicado",
118
+ "agent.feedback.reason.wrong_result": "Resultado errado",
119
+ "agent.feedback.reasonLabel": "Motivo",
120
+ "agent.feedback.reasonPlaceholder": "Escolha um motivo (opcional)",
121
+ "agent.feedback.skip": "Agora não",
122
+ "agent.feedback.status.disabled": "Avaliações não são coletadas neste ambiente.",
123
+ "agent.feedback.submit": "Enviar",
124
+ "agent.feedback.tellUsMore": "Conte-nos mais",
125
+ "agent.feedback.thanks": "Obrigado pelo feedback",
97
126
  "agent.filesProcessing": "Arquivos ainda em processamento",
98
127
  "agent.fileStagedTooltip": "Arquivo preparado - será enviado quando a conversa iniciar",
99
128
  "agent.fullscreen": "Tela cheia",
@@ -323,6 +352,7 @@
323
352
  "layout.pageNotFound": "Página não encontrada",
324
353
  "layout.search": "Pesquisar",
325
354
  "layout.searchPlaceholder": "Pesquisar...",
355
+ "layout.toggleNavigationMenu": "Alternar menu de navegação",
326
356
  "login.accept": "Aceitar",
327
357
  "login.reject": "Rejeitar",
328
358
  "login.reviewInvites": "Revisar convites",
@@ -97,6 +97,35 @@
97
97
  "agent.failedToInterrupt": "Не удалось прервать",
98
98
  "agent.failedToLoadDocument": "Не удалось загрузить документ",
99
99
  "agent.failedToSend": "Не удалось отправить сообщение",
100
+ "agent.feedback.commentHelp": "Учитывается только сам факт комментария; его текст остаётся в вашем проекте.",
101
+ "agent.feedback.commentLabel": "Комментарий",
102
+ "agent.feedback.commentPlaceholder": "Что получилось хорошо, а что пошло не так?",
103
+ "agent.feedback.detailHelp": "Ваша оценка сохранена. Добавьте причину, если хотите сказать больше.",
104
+ "agent.feedback.detailTitle": "Расскажите подробнее",
105
+ "agent.feedback.failed": "Не удалось отправить оценку",
106
+ "agent.feedback.notRecorded": "Ваша оценка не была записана",
107
+ "agent.feedback.rateMessageDown": "Оценить этот ответ отрицательно",
108
+ "agent.feedback.rateMessageUp": "Оценить этот ответ положительно",
109
+ "agent.feedback.rateRunDown": "Оценить этот запуск отрицательно",
110
+ "agent.feedback.rateRunUp": "Оценить этот запуск положительно",
111
+ "agent.feedback.reason.accurate": "Точно",
112
+ "agent.feedback.reason.fast": "Быстро",
113
+ "agent.feedback.reason.helpful": "Полезно",
114
+ "agent.feedback.reason.incomplete": "Неполно",
115
+ "agent.feedback.reason.misunderstood_request": "Неправильно понял запрос",
116
+ "agent.feedback.reason.other": "Другое",
117
+ "agent.feedback.reason.too_slow": "Слишком медленно",
118
+ "agent.feedback.reason.tool_failure": "Инструмент не сработал",
119
+ "agent.feedback.reason.unsafe_action": "Выполнил небезопасное действие",
120
+ "agent.feedback.reason.well_explained": "Хорошо объяснено",
121
+ "agent.feedback.reason.wrong_result": "Неверный результат",
122
+ "agent.feedback.reasonLabel": "Причина",
123
+ "agent.feedback.reasonPlaceholder": "Выберите причину (необязательно)",
124
+ "agent.feedback.skip": "Не сейчас",
125
+ "agent.feedback.status.disabled": "В этой среде оценки не собираются.",
126
+ "agent.feedback.submit": "Отправить",
127
+ "agent.feedback.tellUsMore": "Расскажите подробнее",
128
+ "agent.feedback.thanks": "Спасибо за отзыв",
100
129
  "agent.filesProcessing": "Файлы ещё обрабатываются",
101
130
  "agent.fileStagedTooltip": "Файл подготовлен - будет загружен при начале разговора",
102
131
  "agent.fullscreen": "Полноэкранный режим",
@@ -327,6 +356,7 @@
327
356
  "layout.pageNotFound": "Страница не найдена",
328
357
  "layout.search": "Поиск",
329
358
  "layout.searchPlaceholder": "Поиск...",
359
+ "layout.toggleNavigationMenu": "Переключить меню навигации",
330
360
  "login.accept": "Принять",
331
361
  "login.reject": "Отклонить",
332
362
  "login.reviewInvites": "Просмотреть приглашения",
@@ -93,6 +93,35 @@
93
93
  "agent.failedToInterrupt": "Durdurulamadı",
94
94
  "agent.failedToLoadDocument": "Belge yüklenemedi",
95
95
  "agent.failedToSend": "Mesaj gönderilemedi",
96
+ "agent.feedback.commentHelp": "Yalnızca yorum bırakıp bırakmadığınız sayılır; metnin kendisi projenizde kalır.",
97
+ "agent.feedback.commentLabel": "Yorum",
98
+ "agent.feedback.commentPlaceholder": "Ne iyi gitti veya ne ters gitti?",
99
+ "agent.feedback.detailHelp": "Değerlendirmeniz kaydedildi. Daha fazlasını söylemek isterseniz bir neden ekleyin.",
100
+ "agent.feedback.detailTitle": "Bize daha fazlasını anlatın",
101
+ "agent.feedback.failed": "Değerlendirmeniz gönderilemedi",
102
+ "agent.feedback.notRecorded": "Değerlendirmeniz kaydedilmedi",
103
+ "agent.feedback.rateMessageDown": "Bu yanıtı olumsuz değerlendir",
104
+ "agent.feedback.rateMessageUp": "Bu yanıtı olumlu değerlendir",
105
+ "agent.feedback.rateRunDown": "Bu çalıştırmayı olumsuz değerlendir",
106
+ "agent.feedback.rateRunUp": "Bu çalıştırmayı olumlu değerlendir",
107
+ "agent.feedback.reason.accurate": "Doğru",
108
+ "agent.feedback.reason.fast": "Hızlı",
109
+ "agent.feedback.reason.helpful": "Yararlı",
110
+ "agent.feedback.reason.incomplete": "Eksik",
111
+ "agent.feedback.reason.misunderstood_request": "İsteğimi yanlış anladı",
112
+ "agent.feedback.reason.other": "Başka bir şey",
113
+ "agent.feedback.reason.too_slow": "Çok yavaş",
114
+ "agent.feedback.reason.tool_failure": "Bir araç başarısız oldu",
115
+ "agent.feedback.reason.unsafe_action": "Güvenli olmayan bir şey yaptı",
116
+ "agent.feedback.reason.well_explained": "İyi açıklanmış",
117
+ "agent.feedback.reason.wrong_result": "Yanlış sonuç",
118
+ "agent.feedback.reasonLabel": "Neden",
119
+ "agent.feedback.reasonPlaceholder": "Bir neden seçin (isteğe bağlı)",
120
+ "agent.feedback.skip": "Şimdi değil",
121
+ "agent.feedback.status.disabled": "Bu ortamda değerlendirmeler toplanmaz.",
122
+ "agent.feedback.submit": "Gönder",
123
+ "agent.feedback.tellUsMore": "Bize daha fazlasını anlatın",
124
+ "agent.feedback.thanks": "Geri bildiriminiz için teşekkürler",
96
125
  "agent.filesProcessing": "Dosyalar hâlâ işleniyor",
97
126
  "agent.fileStagedTooltip": "Dosya hazırlandı - konuşma başladığında yüklenecek",
98
127
  "agent.fullscreen": "Tam ekran",
@@ -321,6 +350,7 @@
321
350
  "layout.pageNotFound": "Sayfa Bulunamadı",
322
351
  "layout.search": "Ara",
323
352
  "layout.searchPlaceholder": "Ara...",
353
+ "layout.toggleNavigationMenu": "Gezinme menüsünü aç veya kapat",
324
354
  "login.accept": "Kabul Et",
325
355
  "login.reject": "Reddet",
326
356
  "login.reviewInvites": "Davetleri İncele",
@@ -93,6 +93,35 @@
93
93
  "agent.failedToInterrupt": "中斷失敗",
94
94
  "agent.failedToLoadDocument": "載入文件失敗",
95
95
  "agent.failedToSend": "傳送訊息失敗",
96
+ "agent.feedback.commentHelp": "只會統計你是否留下了評論;評論內容本身仍保留在你的專案中。",
97
+ "agent.feedback.commentLabel": "評論",
98
+ "agent.feedback.commentPlaceholder": "哪裡做得好,或者哪裡出了問題?",
99
+ "agent.feedback.detailHelp": "你的評分已儲存。如果想補充說明,可以新增原因。",
100
+ "agent.feedback.detailTitle": "告訴我們更多",
101
+ "agent.feedback.failed": "無法送出你的評分",
102
+ "agent.feedback.notRecorded": "你的評分未被記錄",
103
+ "agent.feedback.rateMessageDown": "對此回答按倒讚",
104
+ "agent.feedback.rateMessageUp": "對此回答按讚",
105
+ "agent.feedback.rateRunDown": "對此執行按倒讚",
106
+ "agent.feedback.rateRunUp": "對此執行按讚",
107
+ "agent.feedback.reason.accurate": "準確",
108
+ "agent.feedback.reason.fast": "快速",
109
+ "agent.feedback.reason.helpful": "有幫助",
110
+ "agent.feedback.reason.incomplete": "不完整",
111
+ "agent.feedback.reason.misunderstood_request": "誤解了我的請求",
112
+ "agent.feedback.reason.other": "其他原因",
113
+ "agent.feedback.reason.too_slow": "太慢",
114
+ "agent.feedback.reason.tool_failure": "工具執行失敗",
115
+ "agent.feedback.reason.unsafe_action": "執行了不安全的操作",
116
+ "agent.feedback.reason.well_explained": "解釋清楚",
117
+ "agent.feedback.reason.wrong_result": "結果錯誤",
118
+ "agent.feedback.reasonLabel": "原因",
119
+ "agent.feedback.reasonPlaceholder": "選擇原因(選填)",
120
+ "agent.feedback.skip": "暫不填寫",
121
+ "agent.feedback.status.disabled": "此環境不會收集評分。",
122
+ "agent.feedback.submit": "送出",
123
+ "agent.feedback.tellUsMore": "告訴我們更多",
124
+ "agent.feedback.thanks": "感謝你的意見回饋",
96
125
  "agent.filesProcessing": "檔案處理中",
97
126
  "agent.fileStagedTooltip": "檔案已暫存 - 對話開始時將上傳",
98
127
  "agent.fullscreen": "全螢幕",
@@ -321,6 +350,7 @@
321
350
  "layout.pageNotFound": "頁面未找到",
322
351
  "layout.search": "搜尋",
323
352
  "layout.searchPlaceholder": "搜尋...",
353
+ "layout.toggleNavigationMenu": "切換導覽選單",
324
354
  "login.accept": "接受",
325
355
  "login.reject": "拒絕",
326
356
  "login.reviewInvites": "查看邀請",
@@ -93,6 +93,35 @@
93
93
  "agent.failedToInterrupt": "中断失败",
94
94
  "agent.failedToLoadDocument": "加载文档失败",
95
95
  "agent.failedToSend": "发送消息失败",
96
+ "agent.feedback.commentHelp": "只会统计你是否留下了评论;评论内容本身仍保留在你的项目中。",
97
+ "agent.feedback.commentLabel": "评论",
98
+ "agent.feedback.commentPlaceholder": "哪里做得好,或者哪里出了问题?",
99
+ "agent.feedback.detailHelp": "你的评分已保存。如果想补充说明,可以添加原因。",
100
+ "agent.feedback.detailTitle": "告诉我们更多",
101
+ "agent.feedback.failed": "无法发送你的评分",
102
+ "agent.feedback.notRecorded": "你的评分未被记录",
103
+ "agent.feedback.rateMessageDown": "对该回答点踩",
104
+ "agent.feedback.rateMessageUp": "对该回答点赞",
105
+ "agent.feedback.rateRunDown": "对该运行点踩",
106
+ "agent.feedback.rateRunUp": "对该运行点赞",
107
+ "agent.feedback.reason.accurate": "准确",
108
+ "agent.feedback.reason.fast": "快速",
109
+ "agent.feedback.reason.helpful": "有帮助",
110
+ "agent.feedback.reason.incomplete": "不完整",
111
+ "agent.feedback.reason.misunderstood_request": "误解了我的请求",
112
+ "agent.feedback.reason.other": "其他原因",
113
+ "agent.feedback.reason.too_slow": "太慢",
114
+ "agent.feedback.reason.tool_failure": "工具执行失败",
115
+ "agent.feedback.reason.unsafe_action": "执行了不安全的操作",
116
+ "agent.feedback.reason.well_explained": "解释清晰",
117
+ "agent.feedback.reason.wrong_result": "结果错误",
118
+ "agent.feedback.reasonLabel": "原因",
119
+ "agent.feedback.reasonPlaceholder": "选择原因(可选)",
120
+ "agent.feedback.skip": "暂不填写",
121
+ "agent.feedback.status.disabled": "此环境不收集评分。",
122
+ "agent.feedback.submit": "发送",
123
+ "agent.feedback.tellUsMore": "告诉我们更多",
124
+ "agent.feedback.thanks": "感谢你的反馈",
96
125
  "agent.filesProcessing": "文件处理中",
97
126
  "agent.fileStagedTooltip": "文件已暂存 - 对话开始时将上传",
98
127
  "agent.fullscreen": "全屏",
@@ -321,6 +350,7 @@
321
350
  "layout.pageNotFound": "页面未找到",
322
351
  "layout.search": "搜索",
323
352
  "layout.searchPlaceholder": "搜索...",
353
+ "layout.toggleNavigationMenu": "切换导航菜单",
324
354
  "login.accept": "接受",
325
355
  "login.reject": "拒绝",
326
356
  "login.reviewInvites": "查看邀请",
@@ -14,7 +14,7 @@ export function ErrorPage({
14
14
  onAction,
15
15
  }: ErrorPageProps) {
16
16
  return (
17
- <div className="flex min-h-screen items-center justify-center bg-white px-6 py-12 text-center">
17
+ <div className="flex min-h-screen items-center justify-center bg-background text-foreground px-6 py-12 text-center">
18
18
  <div className="max-w-md space-y-6">
19
19
  <div className="mx-auto flex h-16 w-16 items-center justify-center rounded-full bg-destructive text-3xl font-semibold text-destructive">
20
20
  !
@@ -0,0 +1,58 @@
1
+ import { fireEvent, render, screen } from '@testing-library/react';
2
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
3
+ import { I18nProvider } from '../i18n/index.js';
4
+ import { HamburgerButton } from './Navbar.js';
5
+ import { SidebarContext } from './SidebarContext.js';
6
+
7
+ function renderHamburger(options: { isOpen?: boolean; toggleDesktop?: () => void; toggleMobile?: () => void } = {}) {
8
+ const toggleDesktop = options.toggleDesktop ?? vi.fn();
9
+ const toggleMobile = options.toggleMobile ?? vi.fn();
10
+
11
+ render(
12
+ <I18nProvider lng="en">
13
+ <SidebarContext.Provider
14
+ value={{
15
+ isOpen: options.isOpen ?? false,
16
+ toggleDesktop,
17
+ toggleMobile,
18
+ }}
19
+ >
20
+ <HamburgerButton />
21
+ </SidebarContext.Provider>
22
+ </I18nProvider>,
23
+ );
24
+
25
+ return { toggleDesktop, toggleMobile };
26
+ }
27
+
28
+ describe('HamburgerButton', () => {
29
+ beforeEach(() => {
30
+ Object.defineProperty(window, 'innerWidth', { configurable: true, value: 1280 });
31
+ });
32
+
33
+ it('exposes an accessible name and the current expanded state', () => {
34
+ renderHamburger({ isOpen: true });
35
+
36
+ const button = screen.getByRole('button', { name: 'Toggle navigation menu' });
37
+ expect(button.getAttribute('aria-expanded')).toBe('true');
38
+ });
39
+
40
+ it('uses the desktop toggle at a desktop viewport', () => {
41
+ const { toggleDesktop, toggleMobile } = renderHamburger();
42
+
43
+ fireEvent.click(screen.getByRole('button', { name: 'Toggle navigation menu' }));
44
+
45
+ expect(toggleDesktop).toHaveBeenCalledOnce();
46
+ expect(toggleMobile).not.toHaveBeenCalled();
47
+ });
48
+
49
+ it('uses the mobile toggle at a narrow viewport', () => {
50
+ Object.defineProperty(window, 'innerWidth', { configurable: true, value: 640 });
51
+ const { toggleDesktop, toggleMobile } = renderHamburger();
52
+
53
+ fireEvent.click(screen.getByRole('button', { name: 'Toggle navigation menu' }));
54
+
55
+ expect(toggleMobile).toHaveBeenCalledOnce();
56
+ expect(toggleDesktop).not.toHaveBeenCalled();
57
+ });
58
+ });
@@ -57,7 +57,8 @@ function SearchBox(_props: SearchBoxProps) {
57
57
  }
58
58
 
59
59
  export function HamburgerButton() {
60
- const { toggleDesktop, toggleMobile } = useSidebarToggle();
60
+ const { isOpen, toggleDesktop, toggleMobile } = useSidebarToggle();
61
+ const { t } = useUITranslation();
61
62
  const toggle = () => {
62
63
  if (window.innerWidth < 1024) {
63
64
  toggleMobile();
@@ -69,7 +70,9 @@ export function HamburgerButton() {
69
70
  <Button
70
71
  variant="ghost"
71
72
  size="icon"
72
- onClick={() => toggle()} //alt='sidebar toggle'
73
+ aria-expanded={isOpen}
74
+ aria-label={t('layout.toggleNavigationMenu')}
75
+ onClick={toggle}
73
76
  className="p-2 rounded-full transition-colors w-full text-center "
74
77
  >
75
78
  <Menu aria-hidden="true" size={24} />
@@ -1,20 +1,20 @@
1
- import { afterEach, describe, expect, it } from 'vitest';
1
+ import { afterEach, describe, expect, it, vi } from 'vitest';
2
2
  import { getMountBasename, joinPath, stripMountBasename, withMountBasename } from './path';
3
3
 
4
4
  // Simulate a served `<base href>` (or its absence) by stubbing document.querySelector + document.URL.
5
5
  function setBaseHref(href: string | null, docUrl = 'https://gw.example.com/x') {
6
- (globalThis as { document?: unknown }).document = {
6
+ vi.stubGlobal('document', {
7
7
  URL: docUrl,
8
8
  querySelector: (sel: string) =>
9
9
  sel === 'base[href]' && href ? ({ href: new URL(href, docUrl).href } as unknown) : null,
10
- };
10
+ });
11
11
  }
12
12
 
13
13
  const MOUNT = '/tenants/05948c_5ed5f4/apps/furniture-catalog/versions/20260620T064257113Z/app';
14
14
 
15
15
  describe('mount basename helpers', () => {
16
16
  afterEach(() => {
17
- delete (globalThis as { document?: unknown }).document;
17
+ vi.unstubAllGlobals();
18
18
  });
19
19
 
20
20
  describe('getMountBasename', () => {
@@ -31,7 +31,7 @@ describe('mount basename helpers', () => {
31
31
  expect(getMountBasename()).toBe('');
32
32
  });
33
33
  it('returns "" when there is no document (SSR)', () => {
34
- delete (globalThis as { document?: unknown }).document;
34
+ vi.stubGlobal('document', undefined);
35
35
  expect(getMountBasename()).toBe('');
36
36
  });
37
37
  });
@@ -5,15 +5,13 @@ import { jwtDecode } from 'jwt-decode';
5
5
  import { createContext, useContext } from 'react';
6
6
 
7
7
  import { getComposableToken } from './auth/composable';
8
- import { authReturnUrl, mountRootUrl, shouldRedirectToCentralAuth } from './auth/domainRouting';
8
+ import { authReturnUrl, centralAuthUrl, mountRootUrl, shouldRedirectToCentralAuth } from './auth/domainRouting';
9
9
  import { getFirebaseAuth } from './auth/firebase';
10
10
 
11
11
  import { LastSelectedAccountId_KEY, LastSelectedProjectId_KEY } from './constants';
12
12
 
13
13
  export { LastSelectedAccountId_KEY, LastSelectedProjectId_KEY };
14
14
 
15
- const CENTRAL_AUTH_REDIRECT = 'https://internal-auth.vertesia.app/';
16
-
17
15
  export interface UserSessionLoginOptions {
18
16
  loadOnboardingStatus?: boolean;
19
17
  }
@@ -152,7 +150,7 @@ class UserSession {
152
150
  this.setSession = undefined;
153
151
  this.client.withAuthCallback(undefined);
154
152
 
155
- const logoutUrl = new URL(CENTRAL_AUTH_REDIRECT);
153
+ const logoutUrl = new URL(centralAuthUrl());
156
154
  const currentUrl = authReturnUrl();
157
155
  logoutUrl.pathname = '/logout';
158
156
  logoutUrl.searchParams.set('redirect_uri', currentUrl.toString());
@@ -0,0 +1,44 @@
1
+ import { cleanup, render, waitFor } from '@testing-library/react';
2
+ import { Env } from '@vertesia/ui/env';
3
+ import { StrictMode } from 'react';
4
+ import { afterEach, expect, it, vi } from 'vitest';
5
+ import { redirectToCentralAuth } from './auth/domainRouting';
6
+ import { UserSessionProvider } from './UserSessionProvider';
7
+
8
+ vi.mock('./auth/useAuthState', () => ({ useAuthState: () => ({}) }));
9
+ vi.mock('./auth/domainRouting', async (importOriginal) => ({
10
+ ...(await importOriginal<typeof import('./auth/domainRouting')>()),
11
+ shouldRedirectToCentralAuth: () => true,
12
+ redirectToCentralAuth: vi.fn(),
13
+ }));
14
+
15
+ afterEach(() => {
16
+ cleanup();
17
+ vi.clearAllMocks();
18
+ });
19
+
20
+ it('continues authentication after StrictMode cancels the first host-token attempt', async () => {
21
+ const authTokenProvider = vi.fn(async () => undefined);
22
+ Env.init({
23
+ name: 'test',
24
+ version: '1',
25
+ type: 'development',
26
+ isLocalDev: true,
27
+ isDocker: false,
28
+ endpoints: {
29
+ studio: 'https://api.example.com',
30
+ zeno: 'https://api.example.com',
31
+ sts: 'https://sts.example.com',
32
+ },
33
+ authTokenProvider,
34
+ });
35
+ render(
36
+ <StrictMode>
37
+ <UserSessionProvider>
38
+ <span>App</span>
39
+ </UserSessionProvider>
40
+ </StrictMode>,
41
+ );
42
+ await waitFor(() => expect(redirectToCentralAuth).toHaveBeenCalledTimes(1));
43
+ expect(authTokenProvider).toHaveBeenCalledTimes(2);
44
+ });
@@ -1,6 +1,6 @@
1
1
  import { describe, expect, it } from 'vitest';
2
2
  import { RequestedScopeUnavailableError } from './auth/composable';
3
- import { sanitizeRejectedScopeUrl } from './UserSessionProvider';
3
+ import { buildCentralAuthRedirectUrl, sanitizeRejectedScopeUrl } from './UserSessionProvider';
4
4
 
5
5
  describe('sanitizeRejectedScopeUrl', () => {
6
6
  it.each([
@@ -67,3 +67,64 @@ describe('sanitizeRejectedScopeUrl', () => {
67
67
  expect(error.requestedScope).toBe('project');
68
68
  });
69
69
  });
70
+
71
+ describe('buildCentralAuthRedirectUrl', () => {
72
+ const RETURN_URL = new URL('https://app.example.test/studio/dashboard?tab=runs');
73
+ const STS = 'https://sts.example.test';
74
+
75
+ it('carries the sts, redirect_uri and state parameters', () => {
76
+ const url = buildCentralAuthRedirectUrl('https://auth.example.test/', STS, RETURN_URL, 'state-123');
77
+
78
+ expect(url.origin).toBe('https://auth.example.test');
79
+ expect(url.pathname).toBe('/');
80
+ expect(url.searchParams.get('sts')).toBe(STS);
81
+ expect(url.searchParams.get('redirect_uri')).toBe(RETURN_URL.toString());
82
+ expect(url.searchParams.get('state')).toBe('state-123');
83
+ });
84
+
85
+ it('carries the selected account and project through a gateway-mounted app redirect', () => {
86
+ const returnUrl = new URL('https://apps.example.test/tenants/t/apps/a/versions/v/app/?view=grid');
87
+ const url = buildCentralAuthRedirectUrl('https://auth.example.test/', STS, returnUrl, 'state-123', {
88
+ accountId: 'account-1',
89
+ projectId: 'project-1',
90
+ });
91
+
92
+ expect(url.searchParams.get('redirect_uri')).toBe(
93
+ 'https://apps.example.test/tenants/t/apps/a/versions/v/app/?view=grid&p=project-1&a=account-1',
94
+ );
95
+ });
96
+
97
+ // The endpoint is configurable, so it can arrive with a query of its own. Concatenating
98
+ // `?sts=...` onto it folds the parameter into the existing value and Central Auth sees no sts.
99
+ it('preserves a query already present on the configured endpoint', () => {
100
+ const url = buildCentralAuthRedirectUrl('https://auth.example.test/?tenant=acme', STS, RETURN_URL, 'state-123');
101
+
102
+ expect(url.searchParams.get('tenant')).toBe('acme');
103
+ expect(url.searchParams.get('sts')).toBe(STS);
104
+ expect(url.searchParams.get('redirect_uri')).toBe(RETURN_URL.toString());
105
+ expect(url.searchParams.get('state')).toBe('state-123');
106
+ });
107
+
108
+ // Same hazard from the other side: appended after a fragment, the parameters land inside it.
109
+ it('keeps the parameters out of a fragment on the configured endpoint', () => {
110
+ const url = buildCentralAuthRedirectUrl('https://auth.example.test/#section', STS, RETURN_URL, 'state-123');
111
+
112
+ expect(url.hash).toBe('#section');
113
+ expect(url.searchParams.get('sts')).toBe(STS);
114
+ expect(url.searchParams.get('state')).toBe('state-123');
115
+ });
116
+
117
+ it('preserves a path prefix on the configured endpoint', () => {
118
+ const url = buildCentralAuthRedirectUrl('https://auth.example.test/signin', STS, RETURN_URL, 'state-123');
119
+
120
+ expect(url.pathname).toBe('/signin');
121
+ expect(url.searchParams.get('sts')).toBe(STS);
122
+ });
123
+
124
+ it('percent-encodes the parameter values', () => {
125
+ const url = buildCentralAuthRedirectUrl('https://auth.example.test/', STS, RETURN_URL, 'a b&c=d');
126
+
127
+ expect(url.search).toContain('sts=https%3A%2F%2Fsts.example.test');
128
+ expect(url.searchParams.get('state')).toBe('a b&c=d');
129
+ });
130
+ });
@@ -12,7 +12,7 @@ import {
12
12
  resolveAuthSelection,
13
13
  UserNotFoundError,
14
14
  } from './auth/composable';
15
- import { redirectToCentralAuth, shouldRedirectToCentralAuth } from './auth/domainRouting';
15
+ import { buildCentralAuthRedirectUrl, redirectToCentralAuth, shouldRedirectToCentralAuth } from './auth/domainRouting';
16
16
  import { getFirebaseAuth } from './auth/firebase';
17
17
  import { useAuthState } from './auth/useAuthState';
18
18
  import { UserSession, UserSessionContext } from './UserSession';
@@ -23,6 +23,10 @@ function clearAuthHash() {
23
23
  window.history.replaceState(window.history.state, '', `${url.pathname}${url.search}`);
24
24
  }
25
25
 
26
+ // Re-exported from its new home in ./auth/domainRouting, which the token layer can import without
27
+ // a cycle -- it renews an expired Central Auth session through the same URL.
28
+ export { buildCentralAuthRedirectUrl };
29
+
26
30
  export function sanitizeRejectedScopeUrl(
27
31
  currentUrl: URL,
28
32
  error: RequestedScopeUnavailableError,
@@ -130,7 +134,7 @@ export function UserSessionProvider({ children, loadOnboardingStatus = true }: U
130
134
  session.setSession = setSession;
131
135
  getComposableToken(selectedAccount, selectedProject, Env.devAuthToken)
132
136
  .then((res) => {
133
- session.login(res.rawToken).then(() => setSession(session.clone()));
137
+ return session.login(res.rawToken).then(() => setSession(session.clone()));
134
138
  })
135
139
  .catch((err) => {
136
140
  if (surfaceAuthError(err)) return;
@@ -165,7 +169,7 @@ export function UserSessionProvider({ children, loadOnboardingStatus = true }: U
165
169
  }
166
170
  getComposableToken(selectedAccount, selectedProject, token, false, shouldRedirectToCentralAuth())
167
171
  .then((res) => {
168
- session.login(res.rawToken, { loadOnboardingStatus }).then(() => {
172
+ return session.login(res.rawToken, { loadOnboardingStatus }).then(() => {
169
173
  setSession(session.clone());
170
174
  clearAuthHash();
171
175
  });
@@ -234,7 +238,7 @@ export function UserSessionProvider({ children, loadOnboardingStatus = true }: U
234
238
  shouldRedirectToCentralAuth(),
235
239
  )
236
240
  .then((res) => {
237
- session
241
+ return session
238
242
  .login(res.rawToken, { loadOnboardingStatus })
239
243
  .then(() => setSession(session.clone()));
240
244
  })
@@ -268,6 +272,7 @@ export function UserSessionProvider({ children, loadOnboardingStatus = true }: U
268
272
  session.setSession = setSession;
269
273
  void Env.authTokenProvider()
270
274
  .then(async (injectedToken) => {
275
+ if (cancelled) return;
271
276
  if (!injectedToken) {
272
277
  startFirebaseOrCentralAuth();
273
278
  return;
@@ -283,6 +288,7 @@ export function UserSessionProvider({ children, loadOnboardingStatus = true }: U
283
288
  if (!cancelled) setSession(session.clone());
284
289
  })
285
290
  .catch((err: unknown) => {
291
+ if (cancelled) return;
286
292
  if (surfaceAuthError(err)) return;
287
293
  console.warn('Auth: failed to initialize injected auth token', err);
288
294
  Env.logger.warn('Failed to initialize injected auth token', {
@@ -298,6 +304,7 @@ export function UserSessionProvider({ children, loadOnboardingStatus = true }: U
298
304
  });
299
305
  return () => {
300
306
  cancelled = true;
307
+ hasInitiatedAuthRef.current = false;
301
308
  unsubscribe?.();
302
309
  };
303
310
  }
@@ -305,6 +312,7 @@ export function UserSessionProvider({ children, loadOnboardingStatus = true }: U
305
312
  startFirebaseOrCentralAuth();
306
313
  return () => {
307
314
  cancelled = true;
315
+ hasInitiatedAuthRef.current = false;
308
316
  unsubscribe?.();
309
317
  };
310
318
  };