@vertesia/ui 1.5.0-dev.20260901.052906Z → 1.5.0-dev.20260910.051115Z

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 (563) hide show
  1. package/lib/core/components/Avatar.d.ts.map +1 -1
  2. package/lib/core/components/Avatar.js +3 -3
  3. package/lib/core/components/Avatar.js.map +1 -1
  4. package/lib/core/components/ComboBox.js +1 -1
  5. package/lib/core/components/ComboBox.js.map +1 -1
  6. package/lib/core/components/FileUpload.js +1 -1
  7. package/lib/core/components/FileUpload.js.map +1 -1
  8. package/lib/core/components/Link.js +1 -1
  9. package/lib/core/components/Link.js.map +1 -1
  10. package/lib/core/components/SelectList.js +1 -1
  11. package/lib/core/components/SelectList.js.map +1 -1
  12. package/lib/core/components/SidePanel.js +1 -1
  13. package/lib/core/components/SidePanel.js.map +1 -1
  14. package/lib/core/components/Spinner.js +1 -1
  15. package/lib/core/components/Spinner.js.map +1 -1
  16. package/lib/core/components/TagsInput.js +8 -8
  17. package/lib/core/components/TagsInput.js.map +1 -1
  18. package/lib/core/components/shadcn/MessageBox.js +1 -1
  19. package/lib/core/components/shadcn/MessageBox.js.map +1 -1
  20. package/lib/core/components/shadcn/button.js +1 -1
  21. package/lib/core/components/shadcn/button.js.map +1 -1
  22. package/lib/core/components/shadcn/card.d.ts.map +1 -1
  23. package/lib/core/components/shadcn/card.js +1 -1
  24. package/lib/core/components/shadcn/card.js.map +1 -1
  25. package/lib/core/components/shadcn/command.js +5 -5
  26. package/lib/core/components/shadcn/command.js.map +1 -1
  27. package/lib/core/components/shadcn/filters/DynamicLabel.js +1 -1
  28. package/lib/core/components/shadcn/filters/DynamicLabel.js.map +1 -1
  29. package/lib/core/components/shadcn/filters/comboBox/DateCombobox.js +3 -3
  30. package/lib/core/components/shadcn/filters/comboBox/DateCombobox.js.map +1 -1
  31. package/lib/core/components/shadcn/input.js +3 -3
  32. package/lib/core/components/shadcn/input.js.map +1 -1
  33. package/lib/core/components/shadcn/modal/ConfirmModal.js +1 -1
  34. package/lib/core/components/shadcn/modal/ConfirmModal.js.map +1 -1
  35. package/lib/core/components/shadcn/modal/dialog.d.ts.map +1 -1
  36. package/lib/core/components/shadcn/modal/dialog.js +2 -2
  37. package/lib/core/components/shadcn/modal/dialog.js.map +1 -1
  38. package/lib/core/components/shadcn/overflowTabs.js +2 -2
  39. package/lib/core/components/shadcn/overflowTabs.js.map +1 -1
  40. package/lib/core/components/shadcn/popover.js +1 -1
  41. package/lib/core/components/shadcn/popover.js.map +1 -1
  42. package/lib/core/components/shadcn/radioGroup.d.ts.map +1 -1
  43. package/lib/core/components/shadcn/radioGroup.js +3 -3
  44. package/lib/core/components/shadcn/radioGroup.js.map +1 -1
  45. package/lib/core/components/shadcn/selectBox.js +1 -1
  46. package/lib/core/components/shadcn/selectBox.js.map +1 -1
  47. package/lib/core/components/shadcn/tabs.d.ts.map +1 -1
  48. package/lib/core/components/shadcn/tabs.js +5 -2
  49. package/lib/core/components/shadcn/tabs.js.map +1 -1
  50. package/lib/core/components/styles.js +1 -1
  51. package/lib/core/components/styles.js.map +1 -1
  52. package/lib/core/components/table/index.js +1 -1
  53. package/lib/core/hooks/useFetch.d.ts.map +1 -1
  54. package/lib/core/hooks/useFetch.js +2 -0
  55. package/lib/core/hooks/useFetch.js.map +1 -1
  56. package/lib/features/activity-doc/ActivityDoc.js +8 -8
  57. package/lib/features/activity-doc/ActivityDoc.js.map +1 -1
  58. package/lib/features/agent/chat/AgentChart.js +1 -1
  59. package/lib/features/agent/chat/AgentChart.js.map +1 -1
  60. package/lib/features/agent/chat/AgentRightPanel.d.ts +2 -3
  61. package/lib/features/agent/chat/AgentRightPanel.d.ts.map +1 -1
  62. package/lib/features/agent/chat/AgentRightPanel.js +3 -3
  63. package/lib/features/agent/chat/AgentRightPanel.js.map +1 -1
  64. package/lib/features/agent/chat/AskUserWidget.d.ts.map +1 -1
  65. package/lib/features/agent/chat/AskUserWidget.js +13 -13
  66. package/lib/features/agent/chat/AskUserWidget.js.map +1 -1
  67. package/lib/features/agent/chat/DocumentPanel.d.ts +7 -7
  68. package/lib/features/agent/chat/DocumentPanel.d.ts.map +1 -1
  69. package/lib/features/agent/chat/DocumentPanel.js +6 -12
  70. package/lib/features/agent/chat/DocumentPanel.js.map +1 -1
  71. package/lib/features/agent/chat/DocumentsTab.d.ts +15 -0
  72. package/lib/features/agent/chat/DocumentsTab.d.ts.map +1 -0
  73. package/lib/features/agent/chat/DocumentsTab.js +33 -0
  74. package/lib/features/agent/chat/DocumentsTab.js.map +1 -0
  75. package/lib/features/agent/chat/JumpingDots.js +1 -1
  76. package/lib/features/agent/chat/JumpingDots.js.map +1 -1
  77. package/lib/features/agent/chat/ModernAgentConversation.js +3 -3
  78. package/lib/features/agent/chat/ModernAgentConversation.js.map +1 -1
  79. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts.map +1 -1
  80. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js +22 -9
  81. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js.map +1 -1
  82. package/lib/features/agent/chat/ModernAgentOutput/BatchProgressPanel.js +5 -5
  83. package/lib/features/agent/chat/ModernAgentOutput/BatchProgressPanel.js.map +1 -1
  84. package/lib/features/agent/chat/ModernAgentOutput/Header.d.ts.map +1 -1
  85. package/lib/features/agent/chat/ModernAgentOutput/Header.js +16 -11
  86. package/lib/features/agent/chat/ModernAgentOutput/Header.js.map +1 -1
  87. package/lib/features/agent/chat/ModernAgentOutput/InlineSlideInPanel.js +1 -1
  88. package/lib/features/agent/chat/ModernAgentOutput/InlineSlideInPanel.js.map +1 -1
  89. package/lib/features/agent/chat/ModernAgentOutput/MessageInput.js +1 -1
  90. package/lib/features/agent/chat/ModernAgentOutput/MessageInput.js.map +1 -1
  91. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.d.ts.map +1 -1
  92. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js +7 -7
  93. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js.map +1 -1
  94. package/lib/features/agent/chat/ModernAgentOutput/MessagesContainer.js +1 -1
  95. package/lib/features/agent/chat/ModernAgentOutput/MessagesContainer.js.map +1 -1
  96. package/lib/features/agent/chat/ModernAgentOutput/PlanPanel.d.ts.map +1 -1
  97. package/lib/features/agent/chat/ModernAgentOutput/PlanPanel.js +10 -10
  98. package/lib/features/agent/chat/ModernAgentOutput/PlanPanel.js.map +1 -1
  99. package/lib/features/agent/chat/ModernAgentOutput/SlideInPanel.js +1 -1
  100. package/lib/features/agent/chat/ModernAgentOutput/SlideInPanel.js.map +1 -1
  101. package/lib/features/agent/chat/ModernAgentOutput/SlidingMessages.d.ts.map +1 -1
  102. package/lib/features/agent/chat/ModernAgentOutput/SlidingMessages.js +1 -1
  103. package/lib/features/agent/chat/ModernAgentOutput/SlidingMessages.js.map +1 -1
  104. package/lib/features/agent/chat/ModernAgentOutput/SlidingPlanPanel.js +17 -17
  105. package/lib/features/agent/chat/ModernAgentOutput/SlidingPlanPanel.js.map +1 -1
  106. package/lib/features/agent/chat/ModernAgentOutput/StreamingMessage.js +1 -1
  107. package/lib/features/agent/chat/ModernAgentOutput/StreamingMessage.js.map +1 -1
  108. package/lib/features/agent/chat/ModernAgentOutput/SummaryConversation.d.ts.map +1 -1
  109. package/lib/features/agent/chat/ModernAgentOutput/SummaryConversation.js +14 -2
  110. package/lib/features/agent/chat/ModernAgentOutput/SummaryConversation.js.map +1 -1
  111. package/lib/features/agent/chat/ModernAgentOutput/ToolCallGroup.d.ts.map +1 -1
  112. package/lib/features/agent/chat/ModernAgentOutput/ToolCallGroup.js +15 -15
  113. package/lib/features/agent/chat/ModernAgentOutput/ToolCallGroup.js.map +1 -1
  114. package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.d.ts.map +1 -1
  115. package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.js +18 -0
  116. package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.js.map +1 -1
  117. package/lib/features/agent/chat/SlidingThinkingIndicator.d.ts.map +1 -1
  118. package/lib/features/agent/chat/SlidingThinkingIndicator.js +5 -2
  119. package/lib/features/agent/chat/SlidingThinkingIndicator.js.map +1 -1
  120. package/lib/features/agent/chat/VegaLiteChart.d.ts.map +1 -1
  121. package/lib/features/agent/chat/VegaLiteChart.js +6 -2
  122. package/lib/features/agent/chat/VegaLiteChart.js.map +1 -1
  123. package/lib/features/agent/chat/hooks/useDocumentPanel.d.ts +2 -2
  124. package/lib/features/agent/chat/hooks/useDocumentPanel.d.ts.map +1 -1
  125. package/lib/features/agent/chat/hooks/useDocumentPanel.js +0 -18
  126. package/lib/features/agent/chat/hooks/useDocumentPanel.js.map +1 -1
  127. package/lib/features/errors/RowErrorBoundary.js +1 -1
  128. package/lib/features/errors/RowErrorBoundary.js.map +1 -1
  129. package/lib/features/facets/AgentRunnerFacetsNav.js +1 -1
  130. package/lib/features/facets/AgentRunnerFacetsNav.js.map +1 -1
  131. package/lib/features/facets/utils/VInteractionFacet.d.ts +3 -5
  132. package/lib/features/facets/utils/VInteractionFacet.d.ts.map +1 -1
  133. package/lib/features/facets/utils/VInteractionFacet.js +10 -23
  134. package/lib/features/facets/utils/VInteractionFacet.js.map +1 -1
  135. package/lib/features/facets/utils/VUserFacet.js +1 -1
  136. package/lib/features/facets/utils/VUserFacet.js.map +1 -1
  137. package/lib/features/layout/GenericPageNavHeader.d.ts.map +1 -1
  138. package/lib/features/layout/GenericPageNavHeader.js +4 -1
  139. package/lib/features/layout/GenericPageNavHeader.js.map +1 -1
  140. package/lib/features/layout/NotFoundView.js +1 -1
  141. package/lib/features/layout/NotFoundView.js.map +1 -1
  142. package/lib/features/magic-pdf/AnnotatedImageSlider.js +4 -12
  143. package/lib/features/magic-pdf/AnnotatedImageSlider.js.map +1 -1
  144. package/lib/features/magic-pdf/ExtractedContentView.js +4 -4
  145. package/lib/features/magic-pdf/ExtractedContentView.js.map +1 -1
  146. package/lib/features/magic-pdf/MagicPdfView.js +1 -1
  147. package/lib/features/magic-pdf/MagicPdfView.js.map +1 -1
  148. package/lib/features/oauth/McpConnectionsButton.d.ts.map +1 -1
  149. package/lib/features/oauth/McpConnectionsButton.js +4 -1
  150. package/lib/features/oauth/McpConnectionsButton.js.map +1 -1
  151. package/lib/features/oauth/McpConnectionsDialog.d.ts.map +1 -1
  152. package/lib/features/oauth/McpConnectionsDialog.js +3 -2
  153. package/lib/features/oauth/McpConnectionsDialog.js.map +1 -1
  154. package/lib/features/oauth/useMcpConnections.d.ts +6 -7
  155. package/lib/features/oauth/useMcpConnections.d.ts.map +1 -1
  156. package/lib/features/oauth/useMcpConnections.js +27 -20
  157. package/lib/features/oauth/useMcpConnections.js.map +1 -1
  158. package/lib/features/pdf-viewer/PdfPageRenderer.js +2 -2
  159. package/lib/features/pdf-viewer/PdfPageRenderer.js.map +1 -1
  160. package/lib/features/pdf-viewer/PdfPageSlider.js +3 -3
  161. package/lib/features/pdf-viewer/PdfPageSlider.js.map +1 -1
  162. package/lib/features/pdf-viewer/SimplePdfViewer.js +1 -1
  163. package/lib/features/pdf-viewer/SimplePdfViewer.js.map +1 -1
  164. package/lib/features/permissions/UserPermissionsProvider.d.ts +2 -1
  165. package/lib/features/permissions/UserPermissionsProvider.d.ts.map +1 -1
  166. package/lib/features/permissions/UserPermissionsProvider.js +35 -22
  167. package/lib/features/permissions/UserPermissionsProvider.js.map +1 -1
  168. package/lib/features/permissions/useRoleMappings.d.ts +19 -0
  169. package/lib/features/permissions/useRoleMappings.d.ts.map +1 -0
  170. package/lib/features/permissions/useRoleMappings.js +87 -0
  171. package/lib/features/permissions/useRoleMappings.js.map +1 -0
  172. package/lib/features/store/collections/SelectCollection.js +1 -1
  173. package/lib/features/store/collections/SelectCollection.js.map +1 -1
  174. package/lib/features/store/objects/DocumentPreviewPanel.d.ts.map +1 -1
  175. package/lib/features/store/objects/DocumentPreviewPanel.js +9 -9
  176. package/lib/features/store/objects/DocumentPreviewPanel.js.map +1 -1
  177. package/lib/features/store/objects/DocumentTable.js +1 -1
  178. package/lib/features/store/objects/DocumentTable.js.map +1 -1
  179. package/lib/features/store/objects/components/DocumentIcon.js +2 -2
  180. package/lib/features/store/objects/components/DocumentIcon.js.map +1 -1
  181. package/lib/features/store/objects/components/DocumentInput.js +1 -1
  182. package/lib/features/store/objects/components/DocumentInput.js.map +1 -1
  183. package/lib/features/store/objects/components/PropertiesEditorModal.js +1 -1
  184. package/lib/features/store/objects/components/PropertiesEditorModal.js.map +1 -1
  185. package/lib/features/store/objects/components/SaveVersionConfirmModal.js +1 -1
  186. package/lib/features/store/objects/components/SaveVersionConfirmModal.js.map +1 -1
  187. package/lib/features/store/objects/layout/documentLayout.d.ts.map +1 -1
  188. package/lib/features/store/objects/layout/documentLayout.js +2 -2
  189. package/lib/features/store/objects/layout/documentLayout.js.map +1 -1
  190. package/lib/features/store/objects/selection/SelectionActions.js +1 -1
  191. package/lib/features/store/objects/selection/SelectionActions.js.map +1 -1
  192. package/lib/features/store/types/IntakePolicyEditor.d.ts +10 -1
  193. package/lib/features/store/types/IntakePolicyEditor.d.ts.map +1 -1
  194. package/lib/features/store/types/IntakePolicyEditor.js +29 -19
  195. package/lib/features/store/types/IntakePolicyEditor.js.map +1 -1
  196. package/lib/features/store/types/IntakePolicyForm.d.ts +1 -1
  197. package/lib/features/store/types/IntakePolicyForm.d.ts.map +1 -1
  198. package/lib/features/store/types/IntakePolicyForm.js +5 -3
  199. package/lib/features/store/types/IntakePolicyForm.js.map +1 -1
  200. package/lib/features/store/types/SelectContentTypeModal.js +1 -1
  201. package/lib/features/store/types/SelectContentTypeModal.js.map +1 -1
  202. package/lib/features/store/types/TypeRegistry.d.ts +10 -5
  203. package/lib/features/store/types/TypeRegistry.d.ts.map +1 -1
  204. package/lib/features/store/types/search/ObjectTypeSearchContext.d.ts +10 -5
  205. package/lib/features/store/types/search/ObjectTypeSearchContext.d.ts.map +1 -1
  206. package/lib/features/user/UserAvatar.js +2 -2
  207. package/lib/features/user/UserAvatar.js.map +1 -1
  208. package/lib/features/user/UserInfo.d.ts.map +1 -1
  209. package/lib/features/user/UserInfo.js +7 -7
  210. package/lib/features/user/UserInfo.js.map +1 -1
  211. package/lib/features/utils/index.d.ts +1 -0
  212. package/lib/features/utils/index.d.ts.map +1 -1
  213. package/lib/features/utils/index.js +1 -0
  214. package/lib/features/utils/index.js.map +1 -1
  215. package/lib/features/utils/interaction.d.ts +55 -0
  216. package/lib/features/utils/interaction.d.ts.map +1 -0
  217. package/lib/features/utils/interaction.js +77 -0
  218. package/lib/features/utils/interaction.js.map +1 -0
  219. package/lib/features/views/ViewResults.js +2 -2
  220. package/lib/features/views/ViewResults.js.map +1 -1
  221. package/lib/i18n/locales/ar.json +17 -1
  222. package/lib/i18n/locales/de.json +13 -1
  223. package/lib/i18n/locales/en.json +13 -1
  224. package/lib/i18n/locales/es.json +13 -1
  225. package/lib/i18n/locales/fr.json +13 -1
  226. package/lib/i18n/locales/it.json +13 -1
  227. package/lib/i18n/locales/ja.json +13 -1
  228. package/lib/i18n/locales/ko.json +13 -1
  229. package/lib/i18n/locales/pt.json +13 -1
  230. package/lib/i18n/locales/ru.json +15 -1
  231. package/lib/i18n/locales/tr.json +13 -1
  232. package/lib/i18n/locales/zh-TW.json +13 -1
  233. package/lib/i18n/locales/zh.json +13 -1
  234. package/lib/layout/FullHeightLayout.js +2 -2
  235. package/lib/layout/FullHeightLayout.js.map +1 -1
  236. package/lib/layout/Navbar.js +4 -4
  237. package/lib/layout/Navbar.js.map +1 -1
  238. package/lib/layout/Sidebar.js +1 -1
  239. package/lib/layout/Sidebar.js.map +1 -1
  240. package/lib/router/NestedNavigationContext.d.ts +3 -1
  241. package/lib/router/NestedNavigationContext.d.ts.map +1 -1
  242. package/lib/router/NestedNavigationContext.js +2 -2
  243. package/lib/router/NestedNavigationContext.js.map +1 -1
  244. package/lib/session/UserSessionProvider.d.ts.map +1 -1
  245. package/lib/session/UserSessionProvider.js +2 -13
  246. package/lib/session/UserSessionProvider.js.map +1 -1
  247. package/lib/session/auth/authState.d.ts +13 -0
  248. package/lib/session/auth/authState.d.ts.map +1 -0
  249. package/lib/session/auth/authState.js +37 -0
  250. package/lib/session/auth/authState.js.map +1 -0
  251. package/lib/session/auth/domainRouting.d.ts +39 -0
  252. package/lib/session/auth/domainRouting.d.ts.map +1 -1
  253. package/lib/session/auth/domainRouting.js +85 -0
  254. package/lib/session/auth/domainRouting.js.map +1 -1
  255. package/lib/session/auth/useAuthState.d.ts +4 -7
  256. package/lib/session/auth/useAuthState.d.ts.map +1 -1
  257. package/lib/session/auth/useAuthState.js +5 -41
  258. package/lib/session/auth/useAuthState.js.map +1 -1
  259. package/lib/session/index.d.ts +1 -0
  260. package/lib/session/index.d.ts.map +1 -1
  261. package/lib/session/index.js +2 -0
  262. package/lib/session/index.js.map +1 -1
  263. package/lib/shell/SplashScreen.d.ts +1 -1
  264. package/lib/shell/SplashScreen.d.ts.map +1 -1
  265. package/lib/shell/SplashScreen.js +6 -2
  266. package/lib/shell/SplashScreen.js.map +1 -1
  267. package/lib/shell/VertesiaShell.js +1 -1
  268. package/lib/shell/VertesiaShell.js.map +1 -1
  269. package/lib/shell/apps/AppProjectSelector.js +1 -1
  270. package/lib/shell/apps/AppProjectSelector.js.map +1 -1
  271. package/lib/shell/apps/StandaloneApp.js +2 -2
  272. package/lib/shell/apps/StandaloneApp.js.map +1 -1
  273. package/lib/shell/login/SignInPrimitives.js +2 -2
  274. package/lib/shell/login/SignInPrimitives.js.map +1 -1
  275. package/lib/shell/login/SigninScreen.js +1 -1
  276. package/lib/shell/login/SigninScreen.js.map +1 -1
  277. package/lib/shell/login/SignupForm.js +1 -1
  278. package/lib/shell/login/SignupForm.js.map +1 -1
  279. package/lib/shell/login/TerminalLogin.js +2 -2
  280. package/lib/shell/login/TerminalLogin.js.map +1 -1
  281. package/lib/shell/login/UserInfo.d.ts.map +1 -1
  282. package/lib/shell/login/UserInfo.js +1 -1
  283. package/lib/shell/login/UserInfo.js.map +1 -1
  284. package/lib/shell/login/UserSessionMenu.js +1 -1
  285. package/lib/shell/login/UserSessionMenu.js.map +1 -1
  286. package/lib/vertesia-ui-core.js +7 -7
  287. package/lib/vertesia-ui-core.js.map +1 -1
  288. package/lib/vertesia-ui-features.js +179 -182
  289. package/lib/vertesia-ui-features.js.map +1 -1
  290. package/lib/vertesia-ui-i18n.BfN7iOHb.chunk.js +5 -0
  291. package/lib/vertesia-ui-i18n.BfN7iOHb.chunk.js.map +1 -0
  292. package/lib/vertesia-ui-i18n.BjH2zEZw.chunk.js +5 -0
  293. package/lib/vertesia-ui-i18n.BjH2zEZw.chunk.js.map +1 -0
  294. package/lib/vertesia-ui-i18n.BjSwAZXl.chunk.js +5 -0
  295. package/lib/vertesia-ui-i18n.BjSwAZXl.chunk.js.map +1 -0
  296. package/lib/vertesia-ui-i18n.C7PUm5Au.chunk.js +5 -0
  297. package/lib/vertesia-ui-i18n.C7PUm5Au.chunk.js.map +1 -0
  298. package/lib/vertesia-ui-i18n.CF_1mUS5.chunk.js +5 -0
  299. package/lib/vertesia-ui-i18n.CF_1mUS5.chunk.js.map +1 -0
  300. package/lib/vertesia-ui-i18n.ChfUl3_-.chunk.js +5 -0
  301. package/lib/vertesia-ui-i18n.ChfUl3_-.chunk.js.map +1 -0
  302. package/lib/vertesia-ui-i18n.D-Sk-5d1.chunk.js +5 -0
  303. package/lib/vertesia-ui-i18n.D-Sk-5d1.chunk.js.map +1 -0
  304. package/lib/vertesia-ui-i18n.D4rnu1_S.chunk.js +5 -0
  305. package/lib/vertesia-ui-i18n.D4rnu1_S.chunk.js.map +1 -0
  306. package/lib/vertesia-ui-i18n.DDf0-laK.chunk.js +5 -0
  307. package/lib/vertesia-ui-i18n.DDf0-laK.chunk.js.map +1 -0
  308. package/lib/vertesia-ui-i18n.DN79y06J.chunk.js +5 -0
  309. package/lib/vertesia-ui-i18n.DN79y06J.chunk.js.map +1 -0
  310. package/lib/vertesia-ui-i18n.DWLIciYQ.chunk.js +5 -0
  311. package/lib/vertesia-ui-i18n.DWLIciYQ.chunk.js.map +1 -0
  312. package/lib/vertesia-ui-i18n.DvF_YaAJ.chunk.js +5 -0
  313. package/lib/vertesia-ui-i18n.DvF_YaAJ.chunk.js.map +1 -0
  314. package/lib/vertesia-ui-i18n.js +2 -2
  315. package/lib/vertesia-ui-layout.js +1 -1
  316. package/lib/vertesia-ui-layout.js.map +1 -1
  317. package/lib/vertesia-ui-rich-text.js +24 -24
  318. package/lib/vertesia-ui-rich-text.js.map +1 -1
  319. package/lib/vertesia-ui-router.js +1 -1
  320. package/lib/vertesia-ui-router.js.map +1 -1
  321. package/lib/vertesia-ui-session.js +1 -1
  322. package/lib/vertesia-ui-session.js.map +1 -1
  323. package/lib/vertesia-ui-shell.js +3 -3
  324. package/lib/vertesia-ui-shell.js.map +1 -1
  325. package/lib/vertesia-ui-widgets.js +54 -54
  326. package/lib/vertesia-ui-widgets.js.map +1 -1
  327. package/lib/widgets/Progress.js +1 -1
  328. package/lib/widgets/Progress.js.map +1 -1
  329. package/lib/widgets/form/Form.js +2 -2
  330. package/lib/widgets/form/Form.js.map +1 -1
  331. package/lib/widgets/form/fields.js +2 -2
  332. package/lib/widgets/form/fields.js.map +1 -1
  333. package/lib/widgets/json-view/JSONView.js +1 -1
  334. package/lib/widgets/json-view/JSONView.js.map +1 -1
  335. package/lib/widgets/markdown/MermaidDiagram.js +1 -1
  336. package/lib/widgets/markdown/MermaidDiagram.js.map +1 -1
  337. package/lib/widgets/markdown/remarkDirectiveHandler.d.ts +7 -2
  338. package/lib/widgets/markdown/remarkDirectiveHandler.d.ts.map +1 -1
  339. package/lib/widgets/markdown/remarkDirectiveHandler.js +19 -4
  340. package/lib/widgets/markdown/remarkDirectiveHandler.js.map +1 -1
  341. package/lib/widgets/monacoEditor/MonacoEditor.d.ts.map +1 -1
  342. package/lib/widgets/monacoEditor/MonacoEditor.js +4 -2
  343. package/lib/widgets/monacoEditor/MonacoEditor.js.map +1 -1
  344. package/lib/widgets/monacoEditor/index.d.ts +1 -0
  345. package/lib/widgets/monacoEditor/index.d.ts.map +1 -1
  346. package/lib/widgets/monacoEditor/index.js +1 -0
  347. package/lib/widgets/monacoEditor/index.js.map +1 -1
  348. package/lib/widgets/monacoEditor/loadMonaco.d.ts +45 -0
  349. package/lib/widgets/monacoEditor/loadMonaco.d.ts.map +1 -0
  350. package/lib/widgets/monacoEditor/loadMonaco.js +62 -0
  351. package/lib/widgets/monacoEditor/loadMonaco.js.map +1 -0
  352. package/lib/widgets/properties/PropertiesView.js +1 -1
  353. package/lib/widgets/properties/PropertiesView.js.map +1 -1
  354. package/lib/widgets/schema-editor/editor/Editable.js +2 -2
  355. package/lib/widgets/schema-editor/editor/Editable.js.map +1 -1
  356. package/lib/widgets/schema-editor/editor/PropertyEditor.js +1 -1
  357. package/lib/widgets/schema-editor/editor/PropertyEditor.js.map +1 -1
  358. package/lib/widgets/schema-editor/editor/SchemaEditor.js +2 -2
  359. package/lib/widgets/schema-editor/editor/SchemaEditor.js.map +1 -1
  360. package/lib/widgets/upload/DropZone.js +1 -1
  361. package/lib/widgets/upload/DropZone.js.map +1 -1
  362. package/lib/widgets/upload/UploadResultCategory.d.ts +1 -1
  363. package/lib/widgets/upload/UploadResultCategory.d.ts.map +1 -1
  364. package/lib/widgets/upload/UploadResultCategory.js +3 -3
  365. package/lib/widgets/upload/UploadResultCategory.js.map +1 -1
  366. package/lib/widgets/upload/UploadSummary.js +1 -1
  367. package/lib/widgets/upload/UploadSummary.js.map +1 -1
  368. package/lib/widgets/xml-viewer/components/XMLViewer.d.ts.map +1 -1
  369. package/lib/widgets/xml-viewer/components/XMLViewer.js +7 -3
  370. package/lib/widgets/xml-viewer/components/XMLViewer.js.map +1 -1
  371. package/lib/widgets/xml-viewer/hooks/useCollapsible.d.ts +1 -1
  372. package/lib/widgets/xml-viewer/hooks/useXMLViewer.d.ts +11 -13
  373. package/lib/widgets/xml-viewer/hooks/useXMLViewer.d.ts.map +1 -1
  374. package/lib/widgets/xml-viewer/hooks/useXMLViewer.js +41 -14
  375. package/lib/widgets/xml-viewer/hooks/useXMLViewer.js.map +1 -1
  376. package/package.json +7 -7
  377. package/src/__tests__/contrast.test.ts +1 -0
  378. package/src/core/components/Avatar.tsx +3 -3
  379. package/src/core/components/ComboBox.tsx +1 -1
  380. package/src/core/components/FileUpload.tsx +4 -4
  381. package/src/core/components/Link.tsx +1 -1
  382. package/src/core/components/SelectList.tsx +1 -1
  383. package/src/core/components/SidePanel.tsx +1 -1
  384. package/src/core/components/Spinner.tsx +1 -1
  385. package/src/core/components/TagsInput.tsx +8 -8
  386. package/src/core/components/shadcn/MessageBox.tsx +1 -1
  387. package/src/core/components/shadcn/button.tsx +1 -1
  388. package/src/core/components/shadcn/card.tsx +1 -3
  389. package/src/core/components/shadcn/command.tsx +5 -5
  390. package/src/core/components/shadcn/filters/DynamicLabel.tsx +1 -1
  391. package/src/core/components/shadcn/filters/comboBox/DateCombobox.tsx +3 -3
  392. package/src/core/components/shadcn/input.tsx +3 -3
  393. package/src/core/components/shadcn/modal/ConfirmModal.tsx +3 -3
  394. package/src/core/components/shadcn/modal/dialog.tsx +2 -4
  395. package/src/core/components/shadcn/overflowTabs.tsx +2 -2
  396. package/src/core/components/shadcn/popover.tsx +1 -1
  397. package/src/core/components/shadcn/radioGroup.tsx +5 -7
  398. package/src/core/components/shadcn/selectBox.tsx +1 -1
  399. package/src/core/components/shadcn/tabs.tsx +4 -2
  400. package/src/core/components/styles.ts +1 -1
  401. package/src/core/components/table/index.tsx +1 -1
  402. package/src/core/hooks/useFetch.test.ts +20 -0
  403. package/src/core/hooks/useFetch.ts +2 -0
  404. package/src/css/base.css +1 -1
  405. package/src/css/color.css +4 -0
  406. package/src/css/theme.css +1 -0
  407. package/src/css/typography.css +2 -2
  408. package/src/features/activity-doc/ActivityDoc.tsx +11 -11
  409. package/src/features/agent/chat/AgentChart.tsx +1 -1
  410. package/src/features/agent/chat/AgentRightPanel.tsx +4 -8
  411. package/src/features/agent/chat/AskUserWidget.tsx +19 -23
  412. package/src/features/agent/chat/DocumentPanel.tsx +39 -48
  413. package/src/features/agent/chat/DocumentsTab.test.tsx +87 -0
  414. package/src/features/agent/chat/DocumentsTab.tsx +124 -0
  415. package/src/features/agent/chat/JumpingDots.tsx +3 -3
  416. package/src/features/agent/chat/ModernAgentConversation.test.tsx +0 -1
  417. package/src/features/agent/chat/ModernAgentConversation.tsx +3 -5
  418. package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.test.tsx +60 -1
  419. package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.tsx +44 -24
  420. package/src/features/agent/chat/ModernAgentOutput/BatchProgressPanel.tsx +12 -12
  421. package/src/features/agent/chat/ModernAgentOutput/Header.tsx +28 -15
  422. package/src/features/agent/chat/ModernAgentOutput/InlineSlideInPanel.tsx +4 -4
  423. package/src/features/agent/chat/ModernAgentOutput/MessageInput.tsx +2 -2
  424. package/src/features/agent/chat/ModernAgentOutput/MessageItem.tsx +7 -12
  425. package/src/features/agent/chat/ModernAgentOutput/MessagesContainer.tsx +1 -1
  426. package/src/features/agent/chat/ModernAgentOutput/PlanPanel.tsx +16 -22
  427. package/src/features/agent/chat/ModernAgentOutput/SlideInPanel.tsx +4 -4
  428. package/src/features/agent/chat/ModernAgentOutput/SlidingMessages.tsx +2 -4
  429. package/src/features/agent/chat/ModernAgentOutput/SlidingPlanPanel.tsx +21 -21
  430. package/src/features/agent/chat/ModernAgentOutput/StreamingMessage.tsx +4 -4
  431. package/src/features/agent/chat/ModernAgentOutput/SummaryConversation.ts +16 -1
  432. package/src/features/agent/chat/ModernAgentOutput/ToolCallGroup.tsx +19 -40
  433. package/src/features/agent/chat/ModernAgentOutput/requestInputMessages.test.ts +41 -0
  434. package/src/features/agent/chat/ModernAgentOutput/requestInputMessages.ts +19 -0
  435. package/src/features/agent/chat/ModernAgentOutput/utils.test.ts +93 -0
  436. package/src/features/agent/chat/SlidingThinkingIndicator.tsx +5 -2
  437. package/src/features/agent/chat/VegaLiteChart.tsx +6 -2
  438. package/src/features/agent/chat/hooks/useDocumentPanel.test.tsx +33 -0
  439. package/src/features/agent/chat/hooks/useDocumentPanel.ts +3 -20
  440. package/src/features/errors/RowErrorBoundary.tsx +1 -1
  441. package/src/features/facets/AgentRunnerFacetsNav.tsx +1 -1
  442. package/src/features/facets/utils/VInteractionFacet.tsx +22 -34
  443. package/src/features/facets/utils/VUserFacet.tsx +1 -1
  444. package/src/features/layout/GenericPageNavHeader.tsx +9 -1
  445. package/src/features/layout/NotFoundView.tsx +1 -1
  446. package/src/features/magic-pdf/AnnotatedImageSlider.tsx +8 -16
  447. package/src/features/magic-pdf/ExtractedContentView.tsx +4 -4
  448. package/src/features/magic-pdf/MagicPdfView.tsx +1 -1
  449. package/src/features/oauth/McpConnectionsButton.test.tsx +79 -8
  450. package/src/features/oauth/McpConnectionsButton.tsx +6 -3
  451. package/src/features/oauth/McpConnectionsDialog.tsx +9 -3
  452. package/src/features/oauth/useMcpConnections.ts +33 -27
  453. package/src/features/pdf-viewer/PdfPageRenderer.tsx +2 -2
  454. package/src/features/pdf-viewer/PdfPageSlider.tsx +4 -4
  455. package/src/features/pdf-viewer/SimplePdfViewer.tsx +1 -1
  456. package/src/features/permissions/UserPermissionsProvider.test.tsx +172 -0
  457. package/src/features/permissions/UserPermissionsProvider.tsx +68 -21
  458. package/src/features/permissions/useRoleMappings.ts +105 -0
  459. package/src/features/store/collections/SelectCollection.tsx +1 -1
  460. package/src/features/store/objects/DocumentPreviewPanel.tsx +43 -53
  461. package/src/features/store/objects/DocumentTable.tsx +2 -2
  462. package/src/features/store/objects/components/DocumentIcon.tsx +4 -4
  463. package/src/features/store/objects/components/DocumentInput.tsx +3 -3
  464. package/src/features/store/objects/components/PropertiesEditorModal.tsx +2 -2
  465. package/src/features/store/objects/components/SaveVersionConfirmModal.tsx +2 -2
  466. package/src/features/store/objects/layout/documentLayout.tsx +2 -4
  467. package/src/features/store/objects/selection/SelectionActions.tsx +1 -1
  468. package/src/features/store/types/IntakePolicyEditor.tsx +70 -36
  469. package/src/features/store/types/IntakePolicyForm.tsx +11 -3
  470. package/src/features/store/types/SelectContentTypeModal.tsx +1 -1
  471. package/src/features/user/UserAvatar.tsx +3 -3
  472. package/src/features/user/UserInfo.tsx +11 -16
  473. package/src/features/utils/index.ts +1 -0
  474. package/src/features/utils/interaction.test.tsx +93 -0
  475. package/src/features/utils/interaction.tsx +125 -0
  476. package/src/features/views/ViewResults.tsx +3 -3
  477. package/src/i18n/locales/ar.json +17 -1
  478. package/src/i18n/locales/de.json +13 -1
  479. package/src/i18n/locales/en.json +13 -1
  480. package/src/i18n/locales/es.json +13 -1
  481. package/src/i18n/locales/fr.json +13 -1
  482. package/src/i18n/locales/it.json +13 -1
  483. package/src/i18n/locales/ja.json +13 -1
  484. package/src/i18n/locales/ko.json +13 -1
  485. package/src/i18n/locales/pt.json +13 -1
  486. package/src/i18n/locales/ru.json +15 -1
  487. package/src/i18n/locales/tr.json +13 -1
  488. package/src/i18n/locales/zh-TW.json +13 -1
  489. package/src/i18n/locales/zh.json +13 -1
  490. package/src/layout/FullHeightLayout.tsx +2 -2
  491. package/src/layout/Navbar.tsx +5 -5
  492. package/src/layout/Sidebar.tsx +1 -1
  493. package/src/router/NestedNavigationContext.test.tsx +54 -0
  494. package/src/router/NestedNavigationContext.tsx +9 -2
  495. package/src/session/UserSessionProvider.tsx +2 -15
  496. package/src/session/auth/authState.test.ts +35 -0
  497. package/src/session/auth/authState.ts +42 -0
  498. package/src/session/auth/domainRouting.test.ts +169 -1
  499. package/src/session/auth/domainRouting.ts +89 -0
  500. package/src/session/auth/useAuthState.ts +5 -49
  501. package/src/session/index.ts +6 -0
  502. package/src/shell/SplashScreen.test.tsx +22 -0
  503. package/src/shell/SplashScreen.tsx +6 -2
  504. package/src/shell/VertesiaShell.tsx +1 -1
  505. package/src/shell/apps/AppProjectSelector.tsx +1 -1
  506. package/src/shell/apps/StandaloneApp.tsx +9 -9
  507. package/src/shell/login/SignInPrimitives.tsx +2 -2
  508. package/src/shell/login/SigninScreen.tsx +1 -1
  509. package/src/shell/login/SignupForm.tsx +2 -2
  510. package/src/shell/login/TerminalLogin.tsx +5 -5
  511. package/src/shell/login/UserInfo.tsx +2 -5
  512. package/src/shell/login/UserSessionMenu.tsx +2 -2
  513. package/src/widgets/Progress.tsx +2 -2
  514. package/src/widgets/form/Form.tsx +4 -4
  515. package/src/widgets/form/fields.tsx +2 -2
  516. package/src/widgets/json-view/JSONView.tsx +1 -6
  517. package/src/widgets/markdown/ArtifactEditingSurface.test.tsx +33 -29
  518. package/src/widgets/markdown/MarkdownRenderer.test.tsx +52 -0
  519. package/src/widgets/markdown/MermaidDiagram.tsx +2 -2
  520. package/src/widgets/markdown/remarkDirectiveHandler.ts +21 -5
  521. package/src/widgets/monacoEditor/MonacoEditor.tsx +4 -2
  522. package/src/widgets/monacoEditor/index.ts +1 -0
  523. package/src/widgets/monacoEditor/loadMonaco.test.ts +63 -0
  524. package/src/widgets/monacoEditor/loadMonaco.ts +70 -0
  525. package/src/widgets/properties/PropertiesView.tsx +1 -1
  526. package/src/widgets/schema-editor/editor/Editable.tsx +2 -2
  527. package/src/widgets/schema-editor/editor/PropertyEditor.tsx +1 -1
  528. package/src/widgets/schema-editor/editor/SchemaEditor.tsx +2 -2
  529. package/src/widgets/upload/DropZone.tsx +1 -1
  530. package/src/widgets/upload/UploadResultCategory.tsx +7 -7
  531. package/src/widgets/upload/UploadSummary.tsx +4 -4
  532. package/src/widgets/xml-viewer/components/XMLViewer.tsx +7 -3
  533. package/src/widgets/xml-viewer/hooks/useXMLViewer.test.ts +60 -7
  534. package/src/widgets/xml-viewer/hooks/useXMLViewer.ts +70 -16
  535. package/lib/features/agent/chat/DocumentTabBar.d.ts +0 -9
  536. package/lib/features/agent/chat/DocumentTabBar.d.ts.map +0 -1
  537. package/lib/features/agent/chat/DocumentTabBar.js +0 -9
  538. package/lib/features/agent/chat/DocumentTabBar.js.map +0 -1
  539. package/lib/vertesia-ui-i18n.BJBGsq-8.chunk.js +0 -5
  540. package/lib/vertesia-ui-i18n.BJBGsq-8.chunk.js.map +0 -1
  541. package/lib/vertesia-ui-i18n.BY5YG5cX.chunk.js +0 -5
  542. package/lib/vertesia-ui-i18n.BY5YG5cX.chunk.js.map +0 -1
  543. package/lib/vertesia-ui-i18n.Bd5_1BXO.chunk.js +0 -5
  544. package/lib/vertesia-ui-i18n.Bd5_1BXO.chunk.js.map +0 -1
  545. package/lib/vertesia-ui-i18n.Bvwej2HH.chunk.js +0 -5
  546. package/lib/vertesia-ui-i18n.Bvwej2HH.chunk.js.map +0 -1
  547. package/lib/vertesia-ui-i18n.CMT3f4gf.chunk.js +0 -5
  548. package/lib/vertesia-ui-i18n.CMT3f4gf.chunk.js.map +0 -1
  549. package/lib/vertesia-ui-i18n.D56DNPJW.chunk.js +0 -5
  550. package/lib/vertesia-ui-i18n.D56DNPJW.chunk.js.map +0 -1
  551. package/lib/vertesia-ui-i18n.DDzKLNx6.chunk.js +0 -5
  552. package/lib/vertesia-ui-i18n.DDzKLNx6.chunk.js.map +0 -1
  553. package/lib/vertesia-ui-i18n.D_Am1LpF.chunk.js +0 -5
  554. package/lib/vertesia-ui-i18n.D_Am1LpF.chunk.js.map +0 -1
  555. package/lib/vertesia-ui-i18n.DrZizgGV.chunk.js +0 -5
  556. package/lib/vertesia-ui-i18n.DrZizgGV.chunk.js.map +0 -1
  557. package/lib/vertesia-ui-i18n.DwHsq86z.chunk.js +0 -5
  558. package/lib/vertesia-ui-i18n.DwHsq86z.chunk.js.map +0 -1
  559. package/lib/vertesia-ui-i18n.PLpo0Bbz.chunk.js +0 -5
  560. package/lib/vertesia-ui-i18n.PLpo0Bbz.chunk.js.map +0 -1
  561. package/lib/vertesia-ui-i18n.xVbXALqz.chunk.js +0 -5
  562. package/lib/vertesia-ui-i18n.xVbXALqz.chunk.js.map +0 -1
  563. package/src/features/agent/chat/DocumentTabBar.tsx +0 -41
@@ -0,0 +1,172 @@
1
+ import { act, fireEvent, render, screen } from '@testing-library/react';
2
+ import { VertesiaClient } from '@vertesia/client';
3
+ import type { AuthTokenPayload, SystemRoleDefinition } from '@vertesia/common';
4
+ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
5
+ import { UserPermissionProvider } from './UserPermissionsProvider';
6
+
7
+ const session = {
8
+ client: new VertesiaClient({ serverUrl: 'https://studio.example.test', storeUrl: 'https://store.example.test' }),
9
+ authToken: { sub: 'user-a', account_roles: [] } as unknown as AuthTokenPayload,
10
+ signOut: vi.fn(),
11
+ };
12
+ vi.mock('@vertesia/ui/session', () => ({ useUserSession: () => session }));
13
+
14
+ function renderProvider() {
15
+ return render(
16
+ <UserPermissionProvider>
17
+ <div>Protected workspace</div>
18
+ </UserPermissionProvider>,
19
+ );
20
+ }
21
+
22
+ async function advance(ms: number) {
23
+ await act(async () => {
24
+ await vi.advanceTimersByTimeAsync(ms);
25
+ });
26
+ }
27
+
28
+ describe('role mapping recovery', () => {
29
+ beforeEach(() => {
30
+ vi.useFakeTimers();
31
+ vi.spyOn(Math, 'random').mockReturnValue(1);
32
+ session.authToken = { sub: 'user-a', account_roles: [] } as unknown as AuthTokenPayload;
33
+ session.signOut.mockClear();
34
+ });
35
+ afterEach(() => {
36
+ vi.useRealTimers();
37
+ vi.restoreAllMocks();
38
+ });
39
+
40
+ it.each([0, 502, 503, 504])(
41
+ 'recovers automatically from status %s without rendering protected content early',
42
+ async (status) => {
43
+ const fetch = vi
44
+ .spyOn(session.client.iam.roles, 'listSystem')
45
+ .mockRejectedValueOnce(Object.assign(new Error('JWKSTimeout'), { status }))
46
+ .mockResolvedValue([]);
47
+ renderProvider();
48
+ expect(screen.queryByText('Protected workspace')).toBeNull();
49
+ await advance(0);
50
+ expect(screen.getByRole('status').textContent).toContain('automatically');
51
+ expect(screen.queryByText('JWKSTimeout')).toBeNull();
52
+ await advance(1_000);
53
+ expect(screen.getByText('Protected workspace')).toBeTruthy();
54
+ expect(fetch).toHaveBeenCalledTimes(2);
55
+ expect(screen.queryByRole('alert')).toBeNull();
56
+ },
57
+ );
58
+
59
+ it('stops after one minute and lets a manual retry recover without navigating', async () => {
60
+ const fetch = vi
61
+ .spyOn(session.client.iam.roles, 'listSystem')
62
+ .mockRejectedValue(Object.assign(new Error('JWKSTimeout'), { status: 503 }));
63
+ const location = window.location.href;
64
+ renderProvider();
65
+ await advance(60_000);
66
+ expect(screen.getByRole('alert').textContent).toContain('couldn’t connect');
67
+ const calls = fetch.mock.calls.length;
68
+ await advance(60_000);
69
+ expect(fetch).toHaveBeenCalledTimes(calls);
70
+ fetch.mockResolvedValue([]);
71
+ fireEvent.click(screen.getByRole('button', { name: 'Try again' }));
72
+ await advance(0);
73
+ expect(screen.getByText('Protected workspace')).toBeTruthy();
74
+ expect(window.location.href).toBe(location);
75
+ });
76
+
77
+ it('does not restart recovery when authentication re-decodes the same JWT', async () => {
78
+ const fetch = vi.spyOn(session.client.iam.roles, 'listSystem').mockImplementation(async () => {
79
+ session.authToken = { ...session.authToken };
80
+ throw Object.assign(new Error('Unavailable'), { status: 503 });
81
+ });
82
+ renderProvider();
83
+ await advance(60_000);
84
+ expect(screen.getByRole('button', { name: 'Try again' })).toBeTruthy();
85
+ const calls = fetch.mock.calls.length;
86
+ await advance(10_000);
87
+ expect(fetch).toHaveBeenCalledTimes(calls);
88
+ fetch.mockImplementation(async () => {
89
+ session.authToken = { ...session.authToken };
90
+ return [];
91
+ });
92
+ fireEvent.click(screen.getByRole('button', { name: 'Try again' }));
93
+ await advance(0);
94
+ expect(screen.getByText('Protected workspace')).toBeTruthy();
95
+ expect(fetch).toHaveBeenCalledTimes(calls + 1);
96
+ });
97
+
98
+ it('bounds a hung request and ignores its late success', async () => {
99
+ let resolve!: (roles: SystemRoleDefinition[]) => void;
100
+ const fetch = vi.spyOn(session.client.iam.roles, 'listSystem').mockImplementation(
101
+ () =>
102
+ new Promise((done) => {
103
+ resolve = done;
104
+ }),
105
+ );
106
+ renderProvider();
107
+ await advance(60_000);
108
+ expect(fetch.mock.calls[0][0]?.signal?.aborted).toBe(true);
109
+ await act(async () => resolve([]));
110
+ expect(screen.queryByText('Protected workspace')).toBeNull();
111
+ expect(screen.getByRole('button', { name: 'Try again' })).toBeTruthy();
112
+ });
113
+
114
+ it.each([401, 403, 400, 500])('does not automatically retry status %s', async (status) => {
115
+ const fetch = vi
116
+ .spyOn(session.client.iam.roles, 'listSystem')
117
+ .mockRejectedValue(Object.assign(new Error('Request failed'), { status }));
118
+ renderProvider();
119
+ await advance(60_000);
120
+ expect(fetch).toHaveBeenCalledTimes(1);
121
+ expect(screen.queryByText('Protected workspace')).toBeNull();
122
+ if (status === 401 || status === 403) {
123
+ fireEvent.click(screen.getByRole('button', { name: 'Use a different account' }));
124
+ expect(session.signOut).toHaveBeenCalledOnce();
125
+ }
126
+ });
127
+
128
+ it('cancels retries on unmount', async () => {
129
+ const fetch = vi
130
+ .spyOn(session.client.iam.roles, 'listSystem')
131
+ .mockRejectedValue(Object.assign(new Error('Unavailable'), { status: 503 }));
132
+ const view = renderProvider();
133
+ await advance(0);
134
+ view.unmount();
135
+ await advance(60_000);
136
+ expect(fetch).toHaveBeenCalledTimes(1);
137
+ expect(fetch.mock.calls[0][0]?.signal?.aborted).toBe(true);
138
+ });
139
+
140
+ it('ignores the previous session’s pending response after a token change', async () => {
141
+ let resolveOld!: (roles: SystemRoleDefinition[]) => void;
142
+ const fetch = vi
143
+ .spyOn(session.client.iam.roles, 'listSystem')
144
+ .mockImplementationOnce(
145
+ () =>
146
+ new Promise((done) => {
147
+ resolveOld = done;
148
+ }),
149
+ )
150
+ .mockRejectedValue(Object.assign(new Error('Forbidden'), { status: 403 }));
151
+ const view = renderProvider();
152
+ session.authToken = { sub: 'user-b', account_roles: [] } as unknown as AuthTokenPayload;
153
+ view.rerender(
154
+ <UserPermissionProvider>
155
+ <div>Protected workspace</div>
156
+ </UserPermissionProvider>,
157
+ );
158
+ await advance(0);
159
+ await act(async () => resolveOld([]));
160
+ expect(fetch.mock.calls[0][0]?.signal?.aborted).toBe(true);
161
+ expect(screen.queryByText('Protected workspace')).toBeNull();
162
+ expect(screen.getByRole('alert').textContent).toContain('Access Denied');
163
+ });
164
+
165
+ it('uses permissions embedded in the token without fetching mappings', () => {
166
+ session.authToken = { ...session.authToken, permissions: [] };
167
+ const fetch = vi.spyOn(session.client.iam.roles, 'listSystem');
168
+ renderProvider();
169
+ expect(screen.getByText('Protected workspace')).toBeTruthy();
170
+ expect(fetch).not.toHaveBeenCalled();
171
+ });
172
+ });
@@ -1,9 +1,10 @@
1
1
  import { type AuthTokenPayload, type Permission, PrincipalType, type SystemRoleDefinition } from '@vertesia/common';
2
- import { ErrorBox, errorMessage, useFetch } from '@vertesia/ui/core';
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
5
  import { createContext, useContext, useMemo } from 'react';
6
6
  import { isAnyOf } from './helpers';
7
+ import { roleMappingsErrorStatus, useRoleMappings } from './useRoleMappings';
7
8
 
8
9
  type ListRolesResponse = SystemRoleDefinition[];
9
10
 
@@ -68,35 +69,81 @@ export function useUserPermissions() {
68
69
 
69
70
  interface UserPermissionProviderProps {
70
71
  children: React.ReactNode;
72
+ loadingIcon?: React.ReactNode;
71
73
  }
72
- export function UserPermissionProvider({ children }: UserPermissionProviderProps) {
74
+ export function UserPermissionProvider({ children, loadingIcon }: UserPermissionProviderProps) {
73
75
  const { t } = useUITranslation();
74
76
  const session = useUserSession();
75
77
  const authToken = session.authToken;
76
- const shouldFetchRoleMappings = Boolean(authToken && !authToken.permissions);
77
- const { data, error, isLoading } = useFetch<ListRolesResponse | undefined>(() => {
78
- if (shouldFetchRoleMappings) {
79
- return session.client.iam.roles.listSystem();
80
- }
81
- return Promise.resolve(undefined);
82
- }, [session.client, authToken, shouldFetchRoleMappings]);
78
+ const { state, retry } = useRoleMappings(session.client, authToken);
83
79
 
84
80
  const perms = useMemo(() => {
85
- if (authToken) {
86
- if (authToken.permissions || !shouldFetchRoleMappings) {
87
- return new UserPermissions(authToken);
88
- }
89
- if (data && !isLoading) {
90
- return new UserPermissions(authToken, data);
91
- }
92
- } else {
93
- return undefined;
81
+ if (!authToken) return undefined;
82
+ if (authToken.permissions) {
83
+ return new UserPermissions(authToken);
84
+ }
85
+ if (state.status === 'ready') {
86
+ return new UserPermissions(authToken, state.roles);
94
87
  }
95
88
  return undefined;
96
- }, [authToken, data, isLoading, shouldFetchRoleMappings]);
89
+ }, [authToken, state]);
97
90
 
98
- if (error) {
99
- return <ErrorBox title={t('store.failedToFetchRoleMappings')}>{errorMessage(error)}</ErrorBox>;
91
+ if (authToken && !perms) {
92
+ const failed = state.status === 'error';
93
+ const status = failed ? roleMappingsErrorStatus(state.error) : undefined;
94
+ const needsSignIn = status === 401;
95
+ const denied = status === 403;
96
+ const title = needsSignIn
97
+ ? t('auth.recovery.credential.title')
98
+ : denied
99
+ ? t('shell.accessDenied')
100
+ : failed
101
+ ? t('permissions.connectionFailed')
102
+ : t('permissions.connecting');
103
+ 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>
146
+ );
100
147
  }
101
148
 
102
149
  return perms && <UserPermissionsContext.Provider value={perms}>{children}</UserPermissionsContext.Provider>;
@@ -0,0 +1,105 @@
1
+ import type { VertesiaClient } from '@vertesia/client';
2
+ import type { AuthTokenPayload, SystemRoleDefinition } from '@vertesia/common';
3
+ import { useCallback, useEffect, useMemo, useState } from 'react';
4
+
5
+ type RoleMappingsState =
6
+ | { status: 'loading' | 'retrying' }
7
+ | { status: 'ready'; roles: SystemRoleDefinition[] }
8
+ | { status: 'error'; error?: unknown };
9
+
10
+ export function roleMappingsErrorStatus(error: unknown): number | undefined {
11
+ if (error && typeof error === 'object' && 'status' in error && typeof error.status === 'number') {
12
+ return error.status;
13
+ }
14
+ return undefined;
15
+ }
16
+
17
+ function isTransient(error: unknown): boolean {
18
+ const status = roleMappingsErrorStatus(error);
19
+ return (
20
+ status === 0 ||
21
+ status === 502 ||
22
+ status === 503 ||
23
+ status === 504 ||
24
+ (error instanceof Error && error.name === 'TimeoutError')
25
+ );
26
+ }
27
+
28
+ /** Each session gets an independent, cancellable recovery window. Never reuse another session's roles. */
29
+ export function useRoleMappings(client: VertesiaClient, authToken?: AuthTokenPayload) {
30
+ // UserSession.rawAuthToken decodes the cached JWT on each authenticated request.
31
+ // Object identity would restart recovery on every failure (or success), forever.
32
+ // Preserve all claims in the identity: subject/account/expiry can stay the same
33
+ // when project, roles, or other authorization claims change.
34
+ const tokenKey = useMemo(() => (authToken ? JSON.stringify(authToken) : undefined), [authToken]);
35
+ const needsMappings = Boolean(authToken && !authToken.permissions);
36
+ const [attempt, setAttempt] = useState(0);
37
+ const [result, setResult] = useState<{
38
+ client: VertesiaClient;
39
+ tokenKey: string | undefined;
40
+ attempt: number;
41
+ state: RoleMappingsState;
42
+ }>();
43
+ const retry = useCallback(() => setAttempt((value) => value + 1), []);
44
+
45
+ useEffect(() => {
46
+ if (!needsMappings) return;
47
+
48
+ const controller = new AbortController();
49
+ let stopped = false;
50
+ let failures = 0;
51
+ let lastError: unknown;
52
+ let retryTimer: ReturnType<typeof setTimeout> | undefined;
53
+ const update = (state: RoleMappingsState) => setResult({ client, tokenKey, attempt, state });
54
+ const stop = () => {
55
+ stopped = true;
56
+ clearTimeout(slowTimer);
57
+ clearTimeout(deadlineTimer);
58
+ clearTimeout(retryTimer);
59
+ controller.abort();
60
+ };
61
+ const slowTimer = setTimeout(() => update({ status: 'retrying' }), 5_000);
62
+ // Bound the whole recovery window, including requests that never settle.
63
+ const deadlineTimer = setTimeout(() => {
64
+ stop();
65
+ update({ status: 'error', error: lastError });
66
+ }, 60_000);
67
+
68
+ const fetchRoles = async () => {
69
+ try {
70
+ const roles = await client.iam.roles.listSystem({
71
+ signal: controller.signal,
72
+ timeoutMs: 15_000,
73
+ // This hook owns backoff and the overall deadline, not the client's retry policy.
74
+ retryPolicy: false,
75
+ });
76
+ if (stopped) return;
77
+ stop();
78
+ update({ status: 'ready', roles });
79
+ } catch (error) {
80
+ if (stopped) return;
81
+ lastError = error;
82
+ if (!isTransient(error)) {
83
+ stop();
84
+ update({ status: 'error', error });
85
+ return;
86
+ }
87
+ update({ status: 'retrying' });
88
+ const delay = Math.min(1_000 * 2 ** failures++, 8_000) * (0.5 + Math.random() * 0.5);
89
+ retryTimer = setTimeout(() => {
90
+ void fetchRoles();
91
+ }, delay);
92
+ }
93
+ };
94
+
95
+ update({ status: 'loading' });
96
+ void fetchRoles();
97
+ return stop;
98
+ }, [client, tokenKey, needsMappings, attempt]);
99
+
100
+ const state: RoleMappingsState =
101
+ result?.client === client && result.tokenKey === tokenKey && result.attempt === attempt
102
+ ? result.state
103
+ : { status: 'loading' };
104
+ return { state, retry };
105
+ }
@@ -217,7 +217,7 @@ export function SelectCollection({
217
217
  placeholder={resolvedSearchPlaceholder}
218
218
  value={searchQuery}
219
219
  onValueChange={handleSearchChange}
220
- className="flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted-foreground disabled:cursor-not-allowed disabled:opacity-50"
220
+ className="flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none placeholder:text-muted disabled:cursor-not-allowed disabled:opacity-50"
221
221
  />
222
222
  {isSearching && (
223
223
  <div className="me-2 h-4 w-4 animate-spin rounded-full border-2 border-current border-t-transparent" />
@@ -127,13 +127,13 @@ export function DocumentPreviewPanel({ objectId, isOpen, onClose }: DocumentPrev
127
127
 
128
128
  return (
129
129
  <div
130
- className={`fixed inset-y-0 end-0 w-2/5 dark:bg-slate-900 shadow-xl z-50 flex flex-col transition-transform duration-300 transform ${panelTranslateClass}`}
130
+ className={`fixed inset-y-0 end-0 w-2/5 dark:bg-muted shadow-xl z-50 flex flex-col transition-transform duration-300 transform ${panelTranslateClass}`}
131
131
  >
132
132
  {/* Header */}
133
- <div className="flex items-center justify-between px-4 py-3 border-b dark:border-gray-700 bg-gradient-to-r from-indigo-50 to-gray-50 dark:from-gray-800 dark:to-gray-900">
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-indigo-600 me-2" />
136
- <h2 className="text-lg font-semibold text-gray-800 dark:text-gray-200 truncate">
135
+ <FileText className="h-5 w-5 text-primary me-2" />
136
+ <h2 className="text-lg font-semibold text-foreground truncate">
137
137
  {isLoading ? t('store.loadingDocument') : object?.name || t('store.documentPreview')}
138
138
  </h2>
139
139
  </div>
@@ -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-indigo-600 hover:text-indigo-800"
145
+ className="flex items-center gap-1 text-primary hover:text-primary"
146
146
  >
147
147
  <Maximize2 className="h-4 w-4" />
148
148
  <span>{t('store.fullView')}</span>
@@ -151,7 +151,7 @@ export function DocumentPreviewPanel({ objectId, isOpen, onClose }: DocumentPrev
151
151
  variant="ghost"
152
152
  size="sm"
153
153
  onClick={onClose}
154
- className="flex items-center text-gray-600 hover:text-gray-800 dark:text-gray-300 dark:hover:text-gray-100"
154
+ className="flex items-center text-muted hover:text-foreground dark:text-foreground"
155
155
  >
156
156
  <X className="h-5 w-5" />
157
157
  </Button>
@@ -162,8 +162,8 @@ 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-indigo-600 dark:text-indigo-400 mb-2" />
166
- <p className="text-gray-600 dark:text-gray-400">{t('store.loadingDocument')}</p>
165
+ <Spinner size="lg" className="text-primary mb-2" />
166
+ <p className="text-muted">{t('store.loadingDocument')}</p>
167
167
  </div>
168
168
  </div>
169
169
  ) : (
@@ -175,8 +175,8 @@ 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-indigo-600 text-indigo-700 dark:text-indigo-300'
179
- : 'border-transparent text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200'
178
+ ? 'border-primary text-primary'
179
+ : 'border-transparent text-muted hover:text-foreground'
180
180
  }`}
181
181
  onClick={() => setCurrentTab('preview')}
182
182
  >
@@ -189,8 +189,8 @@ 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-indigo-600 text-indigo-700 dark:text-indigo-300'
193
- : 'border-transparent text-gray-500 hover:text-gray-700 dark:text-gray-400 dark:hover:text-gray-200'
192
+ ? 'border-primary text-primary'
193
+ : 'border-transparent text-muted hover:text-foreground'
194
194
  }`}
195
195
  onClick={() => setCurrentTab('properties')}
196
196
  >
@@ -209,16 +209,16 @@ 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-indigo-600 dark:text-indigo-400" />
212
+ <Spinner size="md" className="text-primary" />
213
213
  </div>
214
214
  ) : text ? (
215
- <div className="shadow rounded-md p-4 border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800">
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-gray-800 prose-pre:my-2 prose-headings:text-indigo-700 dark:prose-invert dark:prose-headings:text-indigo-300">
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">
218
218
  <MarkdownRenderer>{text}</MarkdownRenderer>
219
219
  </div>
220
220
  ) : (
221
- <pre className="text-wrap whitespace-pre-wrap dark:text-gray-200">
221
+ <pre className="text-wrap whitespace-pre-wrap dark:text-foreground">
222
222
  {text}
223
223
  </pre>
224
224
  )}
@@ -229,7 +229,7 @@ export function DocumentPreviewPanel({ objectId, isOpen, onClose }: DocumentPrev
229
229
  {isImage && (
230
230
  <div className="mt-4">
231
231
  {imageUrl ? (
232
- <div className="border border-gray-200 dark:border-gray-700 rounded-md p-2 bg-white dark:bg-gray-800">
232
+ <div className="border border-border rounded-md p-2 bg-white dark:bg-muted">
233
233
  <img
234
234
  src={imageUrl}
235
235
  alt={object?.name}
@@ -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-indigo-600 dark:text-indigo-400" />
241
+ <Spinner size="md" className="text-primary" />
242
242
  </div>
243
243
  )}
244
244
  </div>
@@ -246,14 +246,12 @@ export function DocumentPreviewPanel({ objectId, isOpen, onClose }: DocumentPrev
246
246
 
247
247
  {/* PDF Content Notice */}
248
248
  {isPdf && (
249
- <div className="flex flex-col items-center justify-center h-64 border border-gray-200 dark:border-gray-700 rounded-md p-4 bg-gray-50 dark:bg-gray-800">
250
- <FileText className="h-16 w-16 text-indigo-300 dark:text-indigo-400 mb-4" />
251
- <p className="text-gray-600 dark:text-gray-400 text-center mb-4">
252
- {t('store.pdfPreviewFullView')}
253
- </p>
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" />
251
+ <p className="text-muted text-center mb-4">{t('store.pdfPreviewFullView')}</p>
254
252
  <Button
255
253
  onClick={handleViewFullDocument}
256
- className="bg-indigo-600 hover:bg-indigo-700 text-white"
254
+ className="bg-primary hover:bg-primary text-white"
257
255
  >
258
256
  {t('store.openFullDocumentView')}
259
257
  </Button>
@@ -262,11 +260,9 @@ export function DocumentPreviewPanel({ objectId, isOpen, onClose }: DocumentPrev
262
260
 
263
261
  {/* No Content Notice */}
264
262
  {!isImage && !text && !isPdf && !loadingText && (
265
- <div className="flex flex-col items-center justify-center h-64 border border-gray-200 dark:border-gray-700 rounded-md p-4 bg-gray-50 dark:bg-gray-800">
266
- <FileText className="h-16 w-16 text-gray-300 dark:text-gray-600 mb-4" />
267
- <p className="text-gray-600 dark:text-gray-400 text-center">
268
- {t('store.noPreviewAvailable')}
269
- </p>
263
+ <div className="flex flex-col items-center justify-center h-64 border border-border rounded-md p-4 bg-muted">
264
+ <FileText className="h-16 w-16 text-foreground dark:text-muted mb-4" />
265
+ <p className="text-muted text-center">{t('store.noPreviewAvailable')}</p>
270
266
  </div>
271
267
  )}
272
268
  </div>
@@ -275,56 +271,50 @@ export function DocumentPreviewPanel({ objectId, isOpen, onClose }: DocumentPrev
275
271
  {currentTab === 'properties' && object && (
276
272
  <div className="h-full">
277
273
  {object.properties ? (
278
- <div className="shadow rounded-md p-4 border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800">
274
+ <div className="shadow rounded-md p-4 border border-border bg-white dark:bg-muted">
279
275
  <JSONDisplay value={object.properties} />
280
276
  </div>
281
277
  ) : (
282
- <div className="flex flex-col items-center justify-center h-64 border border-gray-200 dark:border-gray-700 rounded-md p-4 bg-gray-50 dark:bg-gray-800">
283
- <Info className="h-16 w-16 text-gray-300 dark:text-gray-600 mb-4" />
284
- <p className="text-gray-600 dark:text-gray-400 text-center">
285
- {t('store.noPropertiesAvailable')}
286
- </p>
278
+ <div className="flex flex-col items-center justify-center h-64 border border-border rounded-md p-4 bg-muted">
279
+ <Info className="h-16 w-16 text-foreground dark:text-muted mb-4" />
280
+ <p className="text-muted text-center">{t('store.noPropertiesAvailable')}</p>
287
281
  </div>
288
282
  )}
289
283
 
290
284
  <div className="mt-4">
291
- <h3 className="text-sm font-semibold text-gray-700 dark:text-gray-300 mb-2">
285
+ <h3 className="text-sm font-semibold text-foreground mb-2">
292
286
  {t('store.documentInformation')}
293
287
  </h3>
294
- <div className="shadow rounded-md p-4 border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-800">
288
+ <div className="shadow rounded-md p-4 border border-border bg-white dark:bg-muted">
295
289
  <div className="grid grid-cols-2 gap-y-2 gap-x-4 text-sm">
296
- <div className="text-gray-500 dark:text-gray-400">{t('store.id')}</div>
297
- <div className="font-medium dark:text-gray-200">{object.id}</div>
290
+ <div className="text-muted">{t('store.id')}</div>
291
+ <div className="font-medium dark:text-foreground">{object.id}</div>
298
292
 
299
- <div className="text-gray-500 dark:text-gray-400">
300
- {t('store.contentType')}
301
- </div>
302
- <div className="font-medium dark:text-gray-200">
293
+ <div className="text-muted">{t('store.contentType')}</div>
294
+ <div className="font-medium dark:text-foreground">
303
295
  {object.type?.name || t('store.unknown')}
304
296
  </div>
305
297
 
306
- <div className="text-gray-500 dark:text-gray-400">
307
- {t('store.contentType')}
308
- </div>
309
- <div className="font-medium dark:text-gray-200">
298
+ <div className="text-muted">{t('store.contentType')}</div>
299
+ <div className="font-medium dark:text-foreground">
310
300
  {object.content?.type || t('store.na')}
311
301
  </div>
312
302
 
313
- <div className="text-gray-500">{t('store.size')}</div>
303
+ <div className="text-muted">{t('store.size')}</div>
314
304
  <div className="font-medium">
315
305
  {object.content && 'size' in object.content
316
306
  ? formatFileSize(object.content.size as number)
317
307
  : t('store.unknown')}
318
308
  </div>
319
309
 
320
- <div className="text-gray-500">{t('store.created')}</div>
310
+ <div className="text-muted">{t('store.created')}</div>
321
311
  <div className="font-medium">
322
312
  {object.created_at
323
313
  ? new Date(object.created_at).toLocaleString()
324
314
  : t('store.na')}
325
315
  </div>
326
316
 
327
- <div className="text-gray-500">{t('store.updated')}</div>
317
+ <div className="text-muted">{t('store.updated')}</div>
328
318
  <div className="font-medium">
329
319
  {object.updated_at
330
320
  ? new Date(object.updated_at).toLocaleString()
@@ -340,7 +330,7 @@ export function DocumentPreviewPanel({ objectId, isOpen, onClose }: DocumentPrev
340
330
  )}
341
331
 
342
332
  {/* Footer actions */}
343
- <div className="flex items-center justify-between p-4 border-t bg-gray-50 dark:bg-gray-800 dark:border-gray-700">
333
+ <div className="flex items-center justify-between p-4 border-t bg-muted dark:border-border">
344
334
  <div>
345
335
  {object?.content?.source && (
346
336
  <Button
@@ -363,14 +353,14 @@ export function DocumentPreviewPanel({ objectId, isOpen, onClose }: DocumentPrev
363
353
  }
364
354
  }}
365
355
  variant="outline"
366
- className="text-indigo-600 border-indigo-300 hover:bg-indigo-50"
356
+ className="text-primary border-primary hover:bg-info"
367
357
  >
368
358
  <Download className="h-4 w-4 me-2" />
369
359
  {t('pdf.download')}
370
360
  </Button>
371
361
  )}
372
362
  </div>
373
- <Button onClick={handleViewFullDocument} className="bg-indigo-600 hover:bg-indigo-700 text-white">
363
+ <Button onClick={handleViewFullDocument} className="bg-primary hover:bg-primary text-white">
374
364
  {t('store.openFullDocument')}
375
365
  <ChevronRight className="h-4 w-4 ms-2 cn-rtl-flip" />
376
366
  </Button>