@vertesia/ui 1.5.0-dev.20260717.131047Z → 1.5.0-dev.20260722.120446Z

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 (329) hide show
  1. package/lib/core/components/SidePanel.js +1 -1
  2. package/lib/core/components/SidePanel.js.map +1 -1
  3. package/lib/core/components/shadcn/button.d.ts +10 -3
  4. package/lib/core/components/shadcn/button.d.ts.map +1 -1
  5. package/lib/core/components/shadcn/button.js +41 -9
  6. package/lib/core/components/shadcn/button.js.map +1 -1
  7. package/lib/core/components/shadcn/modal/dialog.js +1 -1
  8. package/lib/core/components/shadcn/modal/dialog.js.map +1 -1
  9. package/lib/core/components/shadcn/theme/ThemeSwitcher.js +1 -1
  10. package/lib/core/components/shadcn/theme/ThemeSwitcher.js.map +1 -1
  11. package/lib/features/agent/chat/AgentChatPlaybackControls.d.ts.map +1 -1
  12. package/lib/features/agent/chat/AgentChatPlaybackControls.js +2 -2
  13. package/lib/features/agent/chat/AgentChatPlaybackControls.js.map +1 -1
  14. package/lib/features/agent/chat/AgentRequestInputOverlay.d.ts.map +1 -1
  15. package/lib/features/agent/chat/AgentRequestInputOverlay.js +2 -2
  16. package/lib/features/agent/chat/AgentRequestInputOverlay.js.map +1 -1
  17. package/lib/features/agent/chat/ArtifactsTab.d.ts.map +1 -1
  18. package/lib/features/agent/chat/ArtifactsTab.js +5 -2
  19. package/lib/features/agent/chat/ArtifactsTab.js.map +1 -1
  20. package/lib/features/agent/chat/ImageLightbox.d.ts.map +1 -1
  21. package/lib/features/agent/chat/ImageLightbox.js +1 -1
  22. package/lib/features/agent/chat/ImageLightbox.js.map +1 -1
  23. package/lib/features/agent/chat/ModernAgentConversation.js +1 -1
  24. package/lib/features/agent/chat/ModernAgentConversation.js.map +1 -1
  25. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.d.ts.map +1 -1
  26. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js +5 -5
  27. package/lib/features/agent/chat/ModernAgentOutput/AllMessagesMixed.js.map +1 -1
  28. package/lib/features/agent/chat/ModernAgentOutput/Header.d.ts.map +1 -1
  29. package/lib/features/agent/chat/ModernAgentOutput/Header.js +4 -2
  30. package/lib/features/agent/chat/ModernAgentOutput/Header.js.map +1 -1
  31. package/lib/features/agent/chat/ModernAgentOutput/MessageInput.d.ts.map +1 -1
  32. package/lib/features/agent/chat/ModernAgentOutput/MessageInput.js +2 -2
  33. package/lib/features/agent/chat/ModernAgentOutput/MessageInput.js.map +1 -1
  34. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.d.ts.map +1 -1
  35. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js +2 -1
  36. package/lib/features/agent/chat/ModernAgentOutput/MessageItem.js.map +1 -1
  37. package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.d.ts +6 -0
  38. package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.d.ts.map +1 -1
  39. package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.js +15 -1
  40. package/lib/features/agent/chat/ModernAgentOutput/requestInputMessages.js.map +1 -1
  41. package/lib/features/environment/SelectEnvironment.d.ts +28 -0
  42. package/lib/features/environment/SelectEnvironment.d.ts.map +1 -0
  43. package/lib/features/environment/SelectEnvironment.js +97 -0
  44. package/lib/features/environment/SelectEnvironment.js.map +1 -0
  45. package/lib/features/environment/index.d.ts +2 -0
  46. package/lib/features/environment/index.d.ts.map +1 -0
  47. package/lib/features/environment/index.js +2 -0
  48. package/lib/features/environment/index.js.map +1 -0
  49. package/lib/features/index.d.ts +2 -0
  50. package/lib/features/index.d.ts.map +1 -1
  51. package/lib/features/index.js +2 -0
  52. package/lib/features/index.js.map +1 -1
  53. package/lib/features/magic-pdf/AnnotatedImageSlider.js +12 -12
  54. package/lib/features/magic-pdf/AnnotatedImageSlider.js.map +1 -1
  55. package/lib/features/magic-pdf/DownloadPopover.d.ts.map +1 -1
  56. package/lib/features/magic-pdf/DownloadPopover.js +3 -17
  57. package/lib/features/magic-pdf/DownloadPopover.js.map +1 -1
  58. package/lib/features/magic-pdf/ExtractedContentView.js +2 -6
  59. package/lib/features/magic-pdf/ExtractedContentView.js.map +1 -1
  60. package/lib/features/magic-pdf/GroundedExtractionAssistantPanel.d.ts +25 -0
  61. package/lib/features/magic-pdf/GroundedExtractionAssistantPanel.d.ts.map +1 -0
  62. package/lib/features/magic-pdf/GroundedExtractionAssistantPanel.js +42 -0
  63. package/lib/features/magic-pdf/GroundedExtractionAssistantPanel.js.map +1 -0
  64. package/lib/features/magic-pdf/GroundedExtractionView.d.ts +27 -0
  65. package/lib/features/magic-pdf/GroundedExtractionView.d.ts.map +1 -0
  66. package/lib/features/magic-pdf/GroundedExtractionView.js +377 -0
  67. package/lib/features/magic-pdf/GroundedExtractionView.js.map +1 -0
  68. package/lib/features/magic-pdf/MagicPdfProvider.d.ts +0 -2
  69. package/lib/features/magic-pdf/MagicPdfProvider.d.ts.map +1 -1
  70. package/lib/features/magic-pdf/MagicPdfProvider.js +15 -42
  71. package/lib/features/magic-pdf/MagicPdfProvider.js.map +1 -1
  72. package/lib/features/magic-pdf/MagicPdfView.d.ts.map +1 -1
  73. package/lib/features/magic-pdf/MagicPdfView.js +2 -19
  74. package/lib/features/magic-pdf/MagicPdfView.js.map +1 -1
  75. package/lib/features/magic-pdf/index.d.ts +1 -0
  76. package/lib/features/magic-pdf/index.d.ts.map +1 -1
  77. package/lib/features/magic-pdf/index.js +1 -0
  78. package/lib/features/magic-pdf/index.js.map +1 -1
  79. package/lib/features/magic-pdf/types.d.ts +1 -1
  80. package/lib/features/magic-pdf/types.d.ts.map +1 -1
  81. package/lib/features/oauth/McpConnectionsButton.d.ts.map +1 -1
  82. package/lib/features/oauth/McpConnectionsButton.js +2 -2
  83. package/lib/features/oauth/McpConnectionsButton.js.map +1 -1
  84. package/lib/features/oauth/McpConnectionsDialog.d.ts.map +1 -1
  85. package/lib/features/oauth/McpConnectionsDialog.js +1 -1
  86. package/lib/features/oauth/McpConnectionsDialog.js.map +1 -1
  87. package/lib/features/oauth/RemoteMcpConnectionButton.d.ts.map +1 -1
  88. package/lib/features/oauth/RemoteMcpConnectionButton.js +1 -1
  89. package/lib/features/oauth/RemoteMcpConnectionButton.js.map +1 -1
  90. package/lib/features/pdf-viewer/PdfPageSlider.js +2 -2
  91. package/lib/features/pdf-viewer/PdfPageSlider.js.map +1 -1
  92. package/lib/features/pdf-viewer/SimplePdfViewer.d.ts.map +1 -1
  93. package/lib/features/pdf-viewer/SimplePdfViewer.js +3 -3
  94. package/lib/features/pdf-viewer/SimplePdfViewer.js.map +1 -1
  95. package/lib/features/permissions/UserPermissionsProvider.js +1 -1
  96. package/lib/features/permissions/UserPermissionsProvider.js.map +1 -1
  97. package/lib/features/store/objects/DocumentQuickFilter.d.ts.map +1 -1
  98. package/lib/features/store/objects/DocumentQuickFilter.js +5 -5
  99. package/lib/features/store/objects/DocumentQuickFilter.js.map +1 -1
  100. package/lib/features/store/objects/DocumentSearchResults.d.ts.map +1 -1
  101. package/lib/features/store/objects/DocumentSearchResults.js +2 -2
  102. package/lib/features/store/objects/DocumentSearchResults.js.map +1 -1
  103. package/lib/features/store/objects/components/ContentDispositionButton.d.ts.map +1 -1
  104. package/lib/features/store/objects/components/ContentDispositionButton.js +1 -1
  105. package/lib/features/store/objects/components/ContentDispositionButton.js.map +1 -1
  106. package/lib/features/store/objects/components/ContentOverview.d.ts.map +1 -1
  107. package/lib/features/store/objects/components/ContentOverview.js +78 -21
  108. package/lib/features/store/objects/components/ContentOverview.js.map +1 -1
  109. package/lib/features/store/objects/components/DocumentIcon.js +1 -1
  110. package/lib/features/store/objects/components/VectorSearchWidget.js +1 -1
  111. package/lib/features/store/objects/components/VectorSearchWidget.js.map +1 -1
  112. package/lib/features/store/objects/components/useContentPanelHooks.d.ts +1 -2
  113. package/lib/features/store/objects/components/useContentPanelHooks.d.ts.map +1 -1
  114. package/lib/features/store/objects/components/useContentPanelHooks.js +4 -8
  115. package/lib/features/store/objects/components/useContentPanelHooks.js.map +1 -1
  116. package/lib/features/store/objects/layout/renderers.d.ts.map +1 -1
  117. package/lib/features/store/objects/layout/renderers.js +2 -2
  118. package/lib/features/store/objects/layout/renderers.js.map +1 -1
  119. package/lib/features/store/objects/selection/SelectionActions.js +1 -1
  120. package/lib/features/store/objects/selection/SelectionActions.js.map +1 -1
  121. package/lib/features/store/types/ContentObjectTypesTable.d.ts.map +1 -1
  122. package/lib/features/store/types/ContentObjectTypesTable.js +4 -4
  123. package/lib/features/store/types/ContentObjectTypesTable.js.map +1 -1
  124. package/lib/features/store/types/IntakePolicyEditor.d.ts +15 -0
  125. package/lib/features/store/types/IntakePolicyEditor.d.ts.map +1 -0
  126. package/lib/features/store/types/IntakePolicyEditor.js +455 -0
  127. package/lib/features/store/types/IntakePolicyEditor.js.map +1 -0
  128. package/lib/features/store/types/IntakePolicyForm.d.ts +11 -0
  129. package/lib/features/store/types/IntakePolicyForm.d.ts.map +1 -0
  130. package/lib/features/store/types/IntakePolicyForm.js +91 -0
  131. package/lib/features/store/types/IntakePolicyForm.js.map +1 -0
  132. package/lib/features/store/types/SelectContentTypeModal.js +1 -1
  133. package/lib/features/store/types/SelectContentTypeModal.js.map +1 -1
  134. package/lib/features/store/types/index.d.ts +2 -0
  135. package/lib/features/store/types/index.d.ts.map +1 -1
  136. package/lib/features/store/types/index.js +2 -0
  137. package/lib/features/store/types/index.js.map +1 -1
  138. package/lib/features/store/types/intake-policy-editor.logic.d.ts +7 -0
  139. package/lib/features/store/types/intake-policy-editor.logic.d.ts.map +1 -0
  140. package/lib/features/store/types/intake-policy-editor.logic.js +60 -0
  141. package/lib/features/store/types/intake-policy-editor.logic.js.map +1 -0
  142. package/lib/features/store/types/typeCatalogCache.d.ts +5 -0
  143. package/lib/features/store/types/typeCatalogCache.d.ts.map +1 -0
  144. package/lib/features/store/types/typeCatalogCache.js +40 -0
  145. package/lib/features/store/types/typeCatalogCache.js.map +1 -0
  146. package/lib/features/user/UserInfo.js +7 -3
  147. package/lib/features/user/UserInfo.js.map +1 -1
  148. package/lib/features/views/ViewExperience.d.ts +20 -0
  149. package/lib/features/views/ViewExperience.d.ts.map +1 -0
  150. package/lib/features/views/ViewExperience.js +188 -0
  151. package/lib/features/views/ViewExperience.js.map +1 -0
  152. package/lib/features/views/ViewNavigation.d.ts +3 -0
  153. package/lib/features/views/ViewNavigation.d.ts.map +1 -0
  154. package/lib/features/views/ViewNavigation.js +36 -0
  155. package/lib/features/views/ViewNavigation.js.map +1 -0
  156. package/lib/features/views/ViewResults.d.ts +9 -0
  157. package/lib/features/views/ViewResults.d.ts.map +1 -0
  158. package/lib/features/views/ViewResults.js +229 -0
  159. package/lib/features/views/ViewResults.js.map +1 -0
  160. package/lib/features/views/ViewSearch.d.ts +3 -0
  161. package/lib/features/views/ViewSearch.d.ts.map +1 -0
  162. package/lib/features/views/ViewSearch.js +74 -0
  163. package/lib/features/views/ViewSearch.js.map +1 -0
  164. package/lib/features/views/index.d.ts +7 -0
  165. package/lib/features/views/index.d.ts.map +1 -0
  166. package/lib/features/views/index.js +7 -0
  167. package/lib/features/views/index.js.map +1 -0
  168. package/lib/features/views/types.d.ts +39 -0
  169. package/lib/features/views/types.d.ts.map +1 -0
  170. package/lib/features/views/types.js +2 -0
  171. package/lib/features/views/types.js.map +1 -0
  172. package/lib/features/views/viewState.d.ts +14 -0
  173. package/lib/features/views/viewState.d.ts.map +1 -0
  174. package/lib/features/views/viewState.js +117 -0
  175. package/lib/features/views/viewState.js.map +1 -0
  176. package/lib/i18n/locales/ar.json +16 -0
  177. package/lib/i18n/locales/de.json +12 -0
  178. package/lib/i18n/locales/en.json +245 -33
  179. package/lib/i18n/locales/es.json +13 -0
  180. package/lib/i18n/locales/fr.json +13 -0
  181. package/lib/i18n/locales/it.json +13 -0
  182. package/lib/i18n/locales/ja.json +11 -0
  183. package/lib/i18n/locales/ko.json +11 -0
  184. package/lib/i18n/locales/pt.json +13 -0
  185. package/lib/i18n/locales/ru.json +14 -0
  186. package/lib/i18n/locales/tr.json +12 -0
  187. package/lib/i18n/locales/zh-TW.json +11 -0
  188. package/lib/i18n/locales/zh.json +11 -0
  189. package/lib/router/HistoryNavigator.d.ts.map +1 -1
  190. package/lib/router/HistoryNavigator.js +23 -13
  191. package/lib/router/HistoryNavigator.js.map +1 -1
  192. package/lib/router/Nav.d.ts.map +1 -1
  193. package/lib/router/Nav.js +15 -6
  194. package/lib/router/Nav.js.map +1 -1
  195. package/lib/session/UserSession.d.ts.map +1 -1
  196. package/lib/session/UserSession.js +5 -3
  197. package/lib/session/UserSession.js.map +1 -1
  198. package/lib/vertesia-ui-core.js +4 -4
  199. package/lib/vertesia-ui-core.js.map +1 -1
  200. package/lib/vertesia-ui-features.js +34 -27
  201. package/lib/vertesia-ui-features.js.map +1 -1
  202. package/lib/vertesia-ui-i18n.js +15 -15
  203. package/lib/vertesia-ui-i18n.js.map +1 -1
  204. package/lib/vertesia-ui-router.js +1 -1
  205. package/lib/vertesia-ui-router.js.map +1 -1
  206. package/lib/vertesia-ui-session.js +1 -1
  207. package/lib/vertesia-ui-session.js.map +1 -1
  208. package/lib/vertesia-ui-shell.js +1 -1
  209. package/lib/vertesia-ui-shell.js.map +1 -1
  210. package/lib/vertesia-ui-widgets.js +7 -7
  211. package/lib/vertesia-ui-widgets.js.map +1 -1
  212. package/lib/widgets/form/Form.js +1 -1
  213. package/lib/widgets/form/Form.js.map +1 -1
  214. package/lib/widgets/json-view/JSONSwitcher.js +1 -1
  215. package/lib/widgets/json-view/JSONSwitcher.js.map +1 -1
  216. package/lib/widgets/json-view/JSONView.js +6 -6
  217. package/lib/widgets/json-view/JSONView.js.map +1 -1
  218. package/lib/widgets/monacoEditor/MonacoEditor.d.ts.map +1 -1
  219. package/lib/widgets/monacoEditor/MonacoEditor.js +29 -0
  220. package/lib/widgets/monacoEditor/MonacoEditor.js.map +1 -1
  221. package/lib/widgets/schema-editor/ManagedSchema.d.ts +8 -0
  222. package/lib/widgets/schema-editor/ManagedSchema.d.ts.map +1 -1
  223. package/lib/widgets/schema-editor/ManagedSchema.js +16 -0
  224. package/lib/widgets/schema-editor/ManagedSchema.js.map +1 -1
  225. package/lib/widgets/schema-editor/editor/EditableSchemaProperty.d.ts +2 -0
  226. package/lib/widgets/schema-editor/editor/EditableSchemaProperty.d.ts.map +1 -1
  227. package/lib/widgets/schema-editor/editor/EditableSchemaProperty.js +1 -0
  228. package/lib/widgets/schema-editor/editor/EditableSchemaProperty.js.map +1 -1
  229. package/lib/widgets/schema-editor/editor/PropertyViewer.d.ts.map +1 -1
  230. package/lib/widgets/schema-editor/editor/PropertyViewer.js +4 -1
  231. package/lib/widgets/schema-editor/editor/PropertyViewer.js.map +1 -1
  232. package/lib/widgets/schema-editor/editor/SchemaEditor.d.ts.map +1 -1
  233. package/lib/widgets/schema-editor/editor/SchemaEditor.js +22 -11
  234. package/lib/widgets/schema-editor/editor/SchemaEditor.js.map +1 -1
  235. package/package.json +32 -32
  236. package/src/__tests__/a11y.test.tsx +73 -0
  237. package/src/core/components/SidePanel.tsx +1 -1
  238. package/src/core/components/shadcn/button.tsx +67 -12
  239. package/src/core/components/shadcn/modal/dialog.tsx +1 -1
  240. package/src/core/components/shadcn/theme/ThemeSwitcher.tsx +1 -1
  241. package/src/features/agent/chat/AgentChatPlaybackControls.tsx +0 -5
  242. package/src/features/agent/chat/AgentRequestInputOverlay.test.tsx +31 -0
  243. package/src/features/agent/chat/AgentRequestInputOverlay.tsx +6 -2
  244. package/src/features/agent/chat/ArtifactsTab.tsx +19 -9
  245. package/src/features/agent/chat/ImageLightbox.tsx +0 -1
  246. package/src/features/agent/chat/ModernAgentConversation.test.tsx +48 -0
  247. package/src/features/agent/chat/ModernAgentConversation.tsx +0 -2
  248. package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.test.tsx +6 -1
  249. package/src/features/agent/chat/ModernAgentOutput/AllMessagesMixed.tsx +21 -15
  250. package/src/features/agent/chat/ModernAgentOutput/Header.tsx +3 -3
  251. package/src/features/agent/chat/ModernAgentOutput/MessageInput.tsx +0 -2
  252. package/src/features/agent/chat/ModernAgentOutput/MessageItem.tsx +4 -1
  253. package/src/features/agent/chat/ModernAgentOutput/requestInputMessages.test.ts +80 -0
  254. package/src/features/agent/chat/ModernAgentOutput/requestInputMessages.ts +21 -1
  255. package/src/features/environment/SelectEnvironment.tsx +186 -0
  256. package/src/features/environment/index.ts +1 -0
  257. package/src/features/index.ts +2 -0
  258. package/src/features/magic-pdf/AnnotatedImageSlider.tsx +62 -66
  259. package/src/features/magic-pdf/DownloadPopover.tsx +5 -48
  260. package/src/features/magic-pdf/ExtractedContentView.tsx +2 -14
  261. package/src/features/magic-pdf/GroundedExtractionAssistantPanel.tsx +86 -0
  262. package/src/features/magic-pdf/GroundedExtractionView.test.tsx +65 -0
  263. package/src/features/magic-pdf/GroundedExtractionView.tsx +1055 -0
  264. package/src/features/magic-pdf/MagicPdfProvider.tsx +17 -47
  265. package/src/features/magic-pdf/MagicPdfView.tsx +3 -51
  266. package/src/features/magic-pdf/index.ts +1 -0
  267. package/src/features/magic-pdf/types.ts +1 -1
  268. package/src/features/oauth/McpConnectionsButton.tsx +0 -2
  269. package/src/features/oauth/McpConnectionsDialog.tsx +0 -1
  270. package/src/features/oauth/RemoteMcpConnectionButton.tsx +0 -1
  271. package/src/features/pdf-viewer/PdfPageSlider.tsx +5 -5
  272. package/src/features/pdf-viewer/SimplePdfViewer.tsx +11 -12
  273. package/src/features/permissions/UserPermissionsProvider.tsx +1 -1
  274. package/src/features/store/objects/DocumentQuickFilter.tsx +13 -15
  275. package/src/features/store/objects/DocumentSearchResults.tsx +3 -6
  276. package/src/features/store/objects/components/ContentDispositionButton.tsx +5 -1
  277. package/src/features/store/objects/components/ContentOverview.tsx +144 -44
  278. package/src/features/store/objects/components/DocumentIcon.tsx +1 -1
  279. package/src/features/store/objects/components/VectorSearchWidget.tsx +2 -2
  280. package/src/features/store/objects/components/useContentPanelHooks.ts +3 -15
  281. package/src/features/store/objects/layout/renderers.tsx +1 -2
  282. package/src/features/store/objects/selection/SelectionActions.tsx +1 -1
  283. package/src/features/store/types/ContentObjectTypesTable.tsx +12 -14
  284. package/src/features/store/types/IntakePolicyEditor.tsx +679 -0
  285. package/src/features/store/types/IntakePolicyForm.tsx +838 -0
  286. package/src/features/store/types/SelectContentTypeModal.tsx +2 -2
  287. package/src/features/store/types/index.ts +2 -0
  288. package/src/features/store/types/intake-policy-editor.logic.test.ts +109 -0
  289. package/src/features/store/types/intake-policy-editor.logic.ts +87 -0
  290. package/src/features/store/types/typeCatalogCache.ts +45 -0
  291. package/src/features/user/UserInfo.tsx +7 -7
  292. package/src/features/views/ViewExperience.test.tsx +273 -0
  293. package/src/features/views/ViewExperience.tsx +408 -0
  294. package/src/features/views/ViewNavigation.test.tsx +86 -0
  295. package/src/features/views/ViewNavigation.tsx +187 -0
  296. package/src/features/views/ViewResults.test.ts +82 -0
  297. package/src/features/views/ViewResults.tsx +609 -0
  298. package/src/features/views/ViewSearch.test.tsx +147 -0
  299. package/src/features/views/ViewSearch.tsx +205 -0
  300. package/src/features/views/index.ts +6 -0
  301. package/src/features/views/types.ts +57 -0
  302. package/src/features/views/viewState.test.ts +111 -0
  303. package/src/features/views/viewState.ts +132 -0
  304. package/src/i18n/locales/ar.json +16 -0
  305. package/src/i18n/locales/de.json +12 -0
  306. package/src/i18n/locales/en.json +965 -753
  307. package/src/i18n/locales/es.json +13 -0
  308. package/src/i18n/locales/fr.json +13 -0
  309. package/src/i18n/locales/it.json +13 -0
  310. package/src/i18n/locales/ja.json +11 -0
  311. package/src/i18n/locales/ko.json +11 -0
  312. package/src/i18n/locales/pt.json +13 -0
  313. package/src/i18n/locales/ru.json +14 -0
  314. package/src/i18n/locales/tr.json +12 -0
  315. package/src/i18n/locales/zh-TW.json +11 -0
  316. package/src/i18n/locales/zh.json +11 -0
  317. package/src/router/HistoryNavigator.test.ts +48 -0
  318. package/src/router/HistoryNavigator.ts +24 -13
  319. package/src/router/Nav.tsx +18 -8
  320. package/src/session/UserSession.test.ts +39 -0
  321. package/src/session/UserSession.ts +5 -3
  322. package/src/widgets/form/Form.tsx +1 -1
  323. package/src/widgets/json-view/JSONSwitcher.tsx +2 -2
  324. package/src/widgets/json-view/JSONView.tsx +7 -7
  325. package/src/widgets/monacoEditor/MonacoEditor.tsx +29 -0
  326. package/src/widgets/schema-editor/ManagedSchema.ts +22 -0
  327. package/src/widgets/schema-editor/editor/EditableSchemaProperty.tsx +3 -0
  328. package/src/widgets/schema-editor/editor/PropertyViewer.tsx +14 -3
  329. package/src/widgets/schema-editor/editor/SchemaEditor.tsx +80 -29
@@ -6,7 +6,7 @@ import {
6
6
  type JSONSchema,
7
7
  type Plan,
8
8
  } from '@vertesia/common';
9
- import { Badge, Button, cn, VTooltip } from '@vertesia/ui/core';
9
+ import { Badge, Button, cn } from '@vertesia/ui/core';
10
10
  import { i18nInstance, NAMESPACE, useUITranslation } from '@vertesia/ui/i18n';
11
11
  import { NavLink } from '@vertesia/ui/router';
12
12
  import { MarkdownRenderer, type MarkdownRendererProps } from '@vertesia/ui/widgets';
@@ -49,6 +49,7 @@ import {
49
49
  getRequestInputDisplayText,
50
50
  getRequestInputMessageKey,
51
51
  getResolvedToolApprovalKeys,
52
+ getToolApprovalResponseMetadata,
52
53
  hasRequestInputUx,
53
54
  isRequestInputAnswered,
54
55
  isToolApprovalAnswerHidden,
@@ -763,7 +764,9 @@ function SummaryMessage({
763
764
  options={uxConfig.options}
764
765
  variant={uxConfig.variant}
765
766
  multiSelect={uxConfig.multiSelect}
766
- onSelect={(optionId) => onSendMessage?.(optionId)}
767
+ onSelect={(optionId) =>
768
+ onSendMessage?.(optionId, getToolApprovalResponseMetadata(message, optionId))
769
+ }
767
770
  onMultiSelect={(optionIds) => onSendMessage?.(optionIds.join(', '))}
768
771
  allowFreeResponse={!uxConfig.options?.length || !!uxConfig.free_response}
769
772
  placeholder={uxConfig.free_response?.placeholder}
@@ -2240,7 +2243,12 @@ function SummaryActivityRow({
2240
2243
  options={uxConfig.options}
2241
2244
  variant={uxConfig.variant}
2242
2245
  multiSelect={uxConfig.multiSelect}
2243
- onSelect={(optionId) => onSendMessage?.(optionId)}
2246
+ onSelect={(optionId) =>
2247
+ onSendMessage?.(
2248
+ optionId,
2249
+ getToolApprovalResponseMetadata(message, optionId),
2250
+ )
2251
+ }
2244
2252
  onMultiSelect={(optionIds) => onSendMessage?.(optionIds.join(', '))}
2245
2253
  allowFreeResponse={
2246
2254
  !uxConfig.options?.length || !!uxConfig.free_response
@@ -3246,18 +3254,16 @@ function AllMessagesMixedComponent({
3246
3254
  {isSummaryView && activeWorkstream !== 'all' && activeWorkstreamName && (
3247
3255
  <div className="sticky top-0 z-20 -mx-2 bg-background/95 px-2 pb-2 pt-1 backdrop-blur sm:-mx-4 sm:px-4">
3248
3256
  <div className="mx-auto flex w-full max-w-3xl items-center gap-2 border-b border-border/70 pb-3">
3249
- <VTooltip description={t('agent.backToMainAgent')} asChild>
3250
- <Button
3251
- type="button"
3252
- variant="ghost"
3253
- size="icon"
3254
- className="size-8 shrink-0 text-muted hover:text-foreground"
3255
- aria-label={t('agent.backToMainAgent')}
3256
- onClick={handleShowMainAgentChat}
3257
- >
3258
- <ArrowLeft className="size-4" aria-hidden="true" />
3259
- </Button>
3260
- </VTooltip>
3257
+ <Button
3258
+ type="button"
3259
+ variant="ghost"
3260
+ size="icon"
3261
+ className="size-8 shrink-0 text-muted hover:text-foreground"
3262
+ title={t('agent.backToMainAgent')}
3263
+ onClick={handleShowMainAgentChat}
3264
+ >
3265
+ <ArrowLeft className="size-4" aria-hidden="true" />
3266
+ </Button>
3261
3267
  <div className="min-w-0 flex-1 truncate text-sm font-medium text-foreground">
3262
3268
  {activeWorkstreamName}
3263
3269
  </div>
@@ -100,7 +100,9 @@ export default function Header({
100
100
  const controls = (
101
101
  <div
102
102
  className={cn(
103
- isCompact ? 'flex flex-col items-center gap-1' : 'flex justify-end items-center gap-2 ms-auto',
103
+ isCompact
104
+ ? 'flex flex-row items-center gap-1 lg:flex-col'
105
+ : 'flex justify-end items-center gap-2 ms-auto',
104
106
  )}
105
107
  >
106
108
  {showPlanButton && (
@@ -177,7 +179,6 @@ export default function Header({
177
179
  variant={isPlaybackEnabled ? 'primary' : 'ghost'}
178
180
  onClick={onTogglePlayback}
179
181
  aria-pressed={isPlaybackEnabled}
180
- aria-label={t('agent.rewind.label')}
181
182
  title={t('agent.rewind.label')}
182
183
  className={cn(
183
184
  'transition-all duration-200 rounded-md',
@@ -376,7 +377,6 @@ function MoreDropdown({
376
377
  size={compact ? 'icon' : 'xs'}
377
378
  variant="ghost"
378
379
  title={t('agent.moreActions')}
379
- aria-label={t('agent.moreActions')}
380
380
  className={compact ? 'size-8 rounded-lg' : undefined}
381
381
  >
382
382
  <MoreVertical className="size-4" />
@@ -523,7 +523,6 @@ export default function MessageInput({
523
523
  variant="ghost"
524
524
  size="icon"
525
525
  className="size-8 rounded-full text-muted hover:bg-muted"
526
- aria-label={t('agent.addAttachment')}
527
526
  title={t('agent.addAttachment')}
528
527
  >
529
528
  <PlusIcon className="size-4" />
@@ -654,7 +653,6 @@ export default function MessageInput({
654
653
  '[&_svg]:text-destructive disabled:[&_svg]:text-muted',
655
654
  )}
656
655
  title={t('agent.stopTooltip')}
657
- aria-label={t('agent.stopTooltip')}
658
656
  >
659
657
  {isStopping ? (
660
658
  <Spinner size="sm" />
@@ -35,6 +35,7 @@ import { ThinkingMessages } from '../WaitingMessages';
35
35
  import { AttachmentPreviewList, parseUserMessageAttachments } from './AttachmentPreview';
36
36
  import { MessageDeliveryStatus } from './MessageDeliveryStatus';
37
37
  import { processContentForMarkdown } from './processContentForMarkdown';
38
+ import { getToolApprovalResponseMetadata } from './requestInputMessages';
38
39
  import { getWorkstreamId } from './utils';
39
40
 
40
41
  /** className overrides for MessageItem — single source of truth for all className overrides. */
@@ -649,7 +650,9 @@ function MessageItemComponent({
649
650
  options={askUserUx.options}
650
651
  variant={askUserUx.variant}
651
652
  multiSelect={askUserUx.multiSelect}
652
- onSelect={(optionId) => onSendMessage?.(optionId)}
653
+ onSelect={(optionId) =>
654
+ onSendMessage?.(optionId, getToolApprovalResponseMetadata(message, optionId))
655
+ }
653
656
  onMultiSelect={(optionIds) => onSendMessage?.(optionIds.join(', '))}
654
657
  allowFreeResponse={!askUserUx.options?.length || !!askUserUx.free_response}
655
658
  placeholder={askUserUx.free_response?.placeholder}
@@ -0,0 +1,80 @@
1
+ import { type AgentMessage, AgentMessageType } from '@vertesia/common';
2
+ import { describe, expect, it } from 'vitest';
3
+ import {
4
+ getAnsweredToolApprovalRequestInputKeys,
5
+ getRequestInputMessageKey,
6
+ getToolApprovalResponseMetadata,
7
+ } from './requestInputMessages';
8
+
9
+ const APPROVAL_KEY = 'create_interaction:name:JDE AR Payment Processing Agent';
10
+
11
+ function makeApprovalRequest(): AgentMessage {
12
+ return {
13
+ timestamp: 1,
14
+ type: AgentMessageType.REQUEST_INPUT,
15
+ message: 'Approve Create a new draft interaction: JDE AR Payment Processing Agent?',
16
+ workstream_id: 'main',
17
+ details: {
18
+ tool_approval: { tool_name: 'create_interaction', approval_key: APPROVAL_KEY },
19
+ ux: { options: [{ id: 'allow_once' }, { id: 'allow_for_run' }, { id: 'deny' }] },
20
+ },
21
+ } as unknown as AgentMessage;
22
+ }
23
+
24
+ function makeUserAnswer(message: string, metadata?: Record<string, unknown>): AgentMessage {
25
+ return {
26
+ timestamp: 2,
27
+ type: AgentMessageType.QUESTION,
28
+ message,
29
+ workstream_id: 'main',
30
+ details: metadata ? { metadata } : undefined,
31
+ } as unknown as AgentMessage;
32
+ }
33
+
34
+ describe('getToolApprovalResponseMetadata', () => {
35
+ it('builds structured response metadata for approval options', () => {
36
+ expect(getToolApprovalResponseMetadata(makeApprovalRequest(), 'allow_for_run')).toEqual({
37
+ tool_approval_response: { decision: 'allow_for_run', approval_key: APPROVAL_KEY },
38
+ });
39
+ });
40
+
41
+ it('returns undefined for prompts that are not tool approvals', () => {
42
+ const plainPrompt = {
43
+ timestamp: 1,
44
+ type: AgentMessageType.REQUEST_INPUT,
45
+ message: 'Which environment?',
46
+ workstream_id: 'main',
47
+ details: { ux: { options: [{ id: 'staging' }, { id: 'production' }] } },
48
+ } as unknown as AgentMessage;
49
+ expect(getToolApprovalResponseMetadata(plainPrompt, 'staging')).toBeUndefined();
50
+ });
51
+
52
+ it('returns undefined for unknown option ids', () => {
53
+ expect(getToolApprovalResponseMetadata(makeApprovalRequest(), 'staging')).toBeUndefined();
54
+ });
55
+ });
56
+
57
+ describe('getAnsweredToolApprovalRequestInputKeys', () => {
58
+ it('treats a bare option answer as answered', () => {
59
+ const request = makeApprovalRequest();
60
+ const answer = makeUserAnswer('allow_for_run');
61
+ const answered = getAnsweredToolApprovalRequestInputKeys([request, answer]);
62
+ expect(answered.has(getRequestInputMessageKey(request))).toBe(true);
63
+ });
64
+
65
+ it('treats a metadata-carrying answer as answered regardless of its text', () => {
66
+ const request = makeApprovalRequest();
67
+ const answer = makeUserAnswer('Allow this action for this run\n\nUploaded artifacts:\n[a.png](artifact:a)', {
68
+ tool_approval_response: { decision: 'allow_for_run', approval_key: APPROVAL_KEY },
69
+ });
70
+ const answered = getAnsweredToolApprovalRequestInputKeys([request, answer]);
71
+ expect(answered.has(getRequestInputMessageKey(request))).toBe(true);
72
+ });
73
+
74
+ it('does not treat unrelated prose as an approval answer', () => {
75
+ const request = makeApprovalRequest();
76
+ const answer = makeUserAnswer('please proceed\n\nUploaded artifacts:\n[a.png](artifact:a)');
77
+ const answered = getAnsweredToolApprovalRequestInputKeys([request, answer]);
78
+ expect(answered.size).toBe(0);
79
+ });
80
+ });
@@ -169,6 +169,22 @@ export function isToolApprovalRequestInput(message: AgentMessage): boolean {
169
169
  return message.type === AgentMessageType.REQUEST_INPUT && getToolApprovalKey(message) !== undefined;
170
170
  }
171
171
 
172
+ const TOOL_APPROVAL_OPTION_DECISIONS = new Set(['allow_once', 'allow_for_run', 'deny']);
173
+
174
+ /**
175
+ * Metadata to attach when the user picks an option on a tool-approval prompt, so the workflow
176
+ * reads the decision structurally instead of from the message text (which clients may decorate,
177
+ * e.g. with an attachments footer). Returns undefined for non-approval prompts or unknown options.
178
+ */
179
+ export function getToolApprovalResponseMetadata(
180
+ message: AgentMessage,
181
+ optionId: string,
182
+ ): Record<string, unknown> | undefined {
183
+ const approvalKey = getToolApprovalKey(message);
184
+ if (!approvalKey || !TOOL_APPROVAL_OPTION_DECISIONS.has(optionId)) return undefined;
185
+ return { tool_approval_response: { decision: optionId, approval_key: approvalKey } };
186
+ }
187
+
172
188
  function isToolApprovalOptionResponse(message: AgentMessage): boolean {
173
189
  if (message.type !== AgentMessageType.QUESTION) return false;
174
190
  const normalized = getAgentMessageText(message).trim().toLowerCase();
@@ -181,7 +197,11 @@ function isToolApprovalMetadataResponse(message: AgentMessage): boolean {
181
197
  const metadata = getRecord(details?.metadata);
182
198
  const toolApprovalResponse =
183
199
  getRecord(details?.tool_approval_response) ?? getRecord(metadata?.tool_approval_response);
184
- return toolApprovalResponse?.decision === 'deny_with_feedback';
200
+ const decision = toolApprovalResponse?.decision;
201
+ return (
202
+ decision === 'deny_with_feedback' ||
203
+ (typeof decision === 'string' && TOOL_APPROVAL_OPTION_DECISIONS.has(decision))
204
+ );
185
205
  }
186
206
 
187
207
  function isToolApprovalResponse(message: AgentMessage): boolean {
@@ -0,0 +1,186 @@
1
+ import type { ExecutionEnvironmentRef } from '@vertesia/common';
2
+ import { SelectBox, useFetch, useFetchOnce } from '@vertesia/ui/core';
3
+ import { useUITranslation } from '@vertesia/ui/i18n';
4
+ import { useUserSession } from '@vertesia/ui/session';
5
+ import { useEffect, useState } from 'react';
6
+
7
+ type EnvironmentModel = NonNullable<ExecutionEnvironmentRef['enabled_models']>[number];
8
+
9
+ function environmentLabel(option: ExecutionEnvironmentRef) {
10
+ return option.name;
11
+ }
12
+
13
+ interface SelectEnvironmentProps {
14
+ onChange: (environment?: ExecutionEnvironmentRef) => void;
15
+ isClearable?: boolean;
16
+ ignoreVirtuals?: boolean;
17
+ selectedEnvId?: string;
18
+ disabled?: boolean;
19
+ }
20
+
21
+ export function SelectEnvironment({
22
+ isClearable = false,
23
+ onChange,
24
+ ignoreVirtuals = false,
25
+ selectedEnvId,
26
+ disabled = false,
27
+ }: SelectEnvironmentProps) {
28
+ const { t } = useUITranslation();
29
+ const { client } = useUserSession();
30
+ const [value, setValue] = useState<ExecutionEnvironmentRef | undefined>();
31
+ const { data: environments, isLoading } = useFetchOnce(() =>
32
+ client.environments.list().then((result) => {
33
+ const available = ignoreVirtuals
34
+ ? result.filter((environment) => !environment.provider.startsWith('virtual_'))
35
+ : result;
36
+ return available.slice().sort((left, right) => left.name.localeCompare(right.name));
37
+ }),
38
+ );
39
+
40
+ useEffect(() => {
41
+ setValue(environments?.find((environment) => environment.id === selectedEnvId));
42
+ }, [environments, selectedEnvId]);
43
+
44
+ return (
45
+ <SelectBox
46
+ isClearable={isClearable}
47
+ optionLabel={environmentLabel}
48
+ options={environments ?? []}
49
+ value={value}
50
+ onChange={(environment) => {
51
+ setValue(environment);
52
+ onChange(environment);
53
+ }}
54
+ placeholder={t('intakePolicy.placeholder.environment')}
55
+ filterBy="name"
56
+ disabled={disabled}
57
+ isLoading={isLoading}
58
+ />
59
+ );
60
+ }
61
+
62
+ function modelLabel(option: EnvironmentModel) {
63
+ return option.name;
64
+ }
65
+
66
+ function createModelLabel(greyedModels?: EnvironmentModel[]) {
67
+ if (!greyedModels?.length) {
68
+ return modelLabel;
69
+ }
70
+ return (option: EnvironmentModel) => {
71
+ const isGreyed = greyedModels.some((model) => model.id === option.id);
72
+ return <span className={isGreyed ? 'opacity-50' : ''}>{option.name}</span>;
73
+ };
74
+ }
75
+
76
+ interface SelectModelProps {
77
+ envId: string | undefined;
78
+ onChange: (model?: EnvironmentModel) => void;
79
+ isClearable?: boolean;
80
+ selectedModelId?: string;
81
+ disabled?: boolean;
82
+ greyedModels?: EnvironmentModel[];
83
+ onModelsLoaded?: (models: EnvironmentModel[]) => void;
84
+ }
85
+
86
+ export function SelectModel({
87
+ envId,
88
+ isClearable,
89
+ onChange,
90
+ selectedModelId,
91
+ disabled = false,
92
+ greyedModels,
93
+ onModelsLoaded,
94
+ }: SelectModelProps) {
95
+ const { t } = useUITranslation();
96
+ const { client } = useUserSession();
97
+ const [value, setValue] = useState<EnvironmentModel | undefined>();
98
+ const { data: models, isLoading } = useFetch(async () => {
99
+ if (!envId) {
100
+ return [];
101
+ }
102
+ try {
103
+ const environment = await client.environments.retrieve(envId);
104
+ return [...(environment.enabled_models ?? [])].sort((left, right) => left.name.localeCompare(right.name));
105
+ } catch {
106
+ return [];
107
+ }
108
+ }, [envId]);
109
+
110
+ useEffect(() => {
111
+ if (!selectedModelId) {
112
+ setValue(undefined);
113
+ return;
114
+ }
115
+ const selected = models?.find((model) => model.id === selectedModelId);
116
+ setValue(
117
+ selected ?? {
118
+ id: selectedModelId,
119
+ name: selectedModelId,
120
+ provider: 'unknown',
121
+ },
122
+ );
123
+ }, [models, selectedModelId]);
124
+
125
+ useEffect(() => {
126
+ if (models) {
127
+ onModelsLoaded?.(models);
128
+ }
129
+ }, [models, onModelsLoaded]);
130
+
131
+ return (
132
+ <SelectBox
133
+ isClearable={isClearable}
134
+ by="id"
135
+ optionLabel={createModelLabel(greyedModels)}
136
+ options={models ?? []}
137
+ value={value}
138
+ onChange={(model) => {
139
+ setValue(model);
140
+ onChange(model);
141
+ }}
142
+ placeholder={t('intakePolicy.placeholder.model')}
143
+ disabled={disabled}
144
+ isLoading={isLoading}
145
+ />
146
+ );
147
+ }
148
+
149
+ interface SelectTrainingModelProps {
150
+ env: ExecutionEnvironmentRef | undefined;
151
+ onChange: (model?: EnvironmentModel) => void;
152
+ isClearable?: boolean;
153
+ }
154
+
155
+ export function SelectTrainingModel({ env, isClearable, onChange }: SelectTrainingModelProps) {
156
+ const { t } = useUITranslation();
157
+ const { client } = useUserSession();
158
+ const [value, setValue] = useState<EnvironmentModel | undefined>();
159
+ const { data: models, isLoading } = useFetch(async () => {
160
+ if (!env) {
161
+ return [];
162
+ }
163
+ try {
164
+ return client.environments.listTrainableModels(env.id);
165
+ } catch {
166
+ return [];
167
+ }
168
+ }, [env?.id]);
169
+
170
+ return (
171
+ <SelectBox
172
+ isClearable={isClearable}
173
+ by="id"
174
+ optionLabel={modelLabel}
175
+ options={models ?? []}
176
+ value={value}
177
+ onChange={(model) => {
178
+ setValue(model);
179
+ onChange(model);
180
+ }}
181
+ placeholder={t('intakePolicy.placeholder.model')}
182
+ disabled={!env}
183
+ isLoading={isLoading}
184
+ />
185
+ );
186
+ }
@@ -0,0 +1 @@
1
+ export * from './SelectEnvironment.js';
@@ -1,6 +1,7 @@
1
1
  export * from './activity-doc/index.js';
2
2
  export * from './agent';
3
3
  export * from './document-viewer/index.js';
4
+ export * from './environment/index.js';
4
5
  export * from './errors/index.js';
5
6
  export * from './facets/index.js';
6
7
  export * from './layout/index.js';
@@ -12,3 +13,4 @@ export * from './permissions/index.js';
12
13
  export * from './store/index.js';
13
14
  export * from './user/index.js';
14
15
  export * from './utils/index.js';
16
+ export * from './views/index.js';
@@ -1,4 +1,4 @@
1
- import { Button, Center, VTooltip } from '@vertesia/ui/core';
1
+ import { Button, Center } from '@vertesia/ui/core';
2
2
  import { useUITranslation } from '@vertesia/ui/i18n';
3
3
  import clsx from 'clsx';
4
4
  import { ChevronsDown, ChevronsUp, Image, Loader2, Maximize, Minus, Plus, ScanSearch } from 'lucide-react';
@@ -255,7 +255,7 @@ export function AnnotatedImageSlider({ className, currentPage, onChange }: Annot
255
255
  return (
256
256
  <div ref={ref} className={clsx('flex flex-col items-stretch gap-y-2', className)}>
257
257
  <div className="relative flex items-center justify-center px-2 h-9">
258
- <Button variant="ghost" size="xs" onClick={goPrev} alt={t('pdf.previousPage')}>
258
+ <Button variant="ghost" size="xs" onClick={goPrev} title={t('pdf.previousPage')}>
259
259
  <ChevronsUp className="size-4" />
260
260
  </Button>
261
261
  <div className="absolute start-2 flex items-center gap-x-1">
@@ -301,7 +301,7 @@ export function AnnotatedImageSlider({ className, currentPage, onChange }: Annot
301
301
  ))}
302
302
  </div>
303
303
  <div className="flex items-center justify-center h-9">
304
- <Button variant="ghost" size="xs" onClick={goNext} alt={t('pdf.nextPage')}>
304
+ <Button variant="ghost" size="xs" onClick={goNext} title={t('pdf.nextPage')}>
305
305
  <ChevronsDown className="size-4" />
306
306
  </Button>
307
307
  </div>
@@ -319,22 +319,21 @@ interface ImageTypeButtonProps {
319
319
  function ImageTypeButton({ type, currentType, onClick, icon, tooltip }: ImageTypeButtonProps) {
320
320
  const isSelected = type === currentType;
321
321
  return (
322
- <VTooltip description={tooltip} placement="bottom" size="xs">
323
- <Button
324
- variant="unstyled"
325
- aria-label={tooltip}
326
- aria-pressed={isSelected}
327
- className={clsx(
328
- 'p-1 rounded cursor-pointer transition-colors',
329
- isSelected
330
- ? 'text-primary bg-primary/10'
331
- : 'text-muted-foreground hover:text-foreground hover:bg-muted',
332
- )}
333
- onClick={onClick}
334
- >
335
- {icon}
336
- </Button>
337
- </VTooltip>
322
+ <Button
323
+ title={tooltip}
324
+ tooltipPlacement="bottom"
325
+ variant="unstyled"
326
+ aria-pressed={isSelected}
327
+ className={clsx(
328
+ 'p-1 rounded cursor-pointer transition-colors',
329
+ isSelected
330
+ ? 'text-primary bg-primary/10'
331
+ : 'text-muted-foreground hover:text-foreground hover:bg-muted',
332
+ )}
333
+ onClick={onClick}
334
+ >
335
+ {icon}
336
+ </Button>
338
337
  );
339
338
  }
340
339
 
@@ -350,54 +349,51 @@ function ZoomControls({ zoom, onZoomIn, onZoomOut, onFitToView, canZoomIn, canZo
350
349
  const { t } = useUITranslation();
351
350
  return (
352
351
  <div className="flex items-center gap-x-0.5">
353
- <VTooltip description={t('pdf.zoomOut')} placement="bottom" size="xs">
354
- <Button
355
- variant="unstyled"
356
- aria-label={t('pdf.zoomOut')}
357
- className={clsx(
358
- 'p-1 rounded cursor-pointer transition-colors',
359
- canZoomOut
360
- ? 'text-muted-foreground hover:text-foreground hover:bg-muted'
361
- : 'text-muted-foreground/40 cursor-not-allowed',
362
- )}
363
- onClick={onZoomOut}
364
- disabled={!canZoomOut}
365
- >
366
- <Minus className="size-4" />
367
- </Button>
368
- </VTooltip>
352
+ <Button
353
+ title={t('pdf.zoomOut')}
354
+ tooltipPlacement="bottom"
355
+ variant="unstyled"
356
+ className={clsx(
357
+ 'p-1 rounded cursor-pointer transition-colors',
358
+ canZoomOut
359
+ ? 'text-muted-foreground hover:text-foreground hover:bg-muted'
360
+ : 'text-muted-foreground/40 cursor-not-allowed',
361
+ )}
362
+ onClick={onZoomOut}
363
+ disabled={!canZoomOut}
364
+ >
365
+ <Minus className="size-4" />
366
+ </Button>
369
367
  <span className="text-xs text-muted-foreground min-w-[32px] text-center">{zoom}%</span>
370
- <VTooltip description={t('pdf.zoomIn')} placement="bottom" size="xs">
371
- <Button
372
- variant="unstyled"
373
- aria-label={t('pdf.zoomIn')}
374
- className={clsx(
375
- 'p-1 rounded cursor-pointer transition-colors',
376
- canZoomIn
377
- ? 'text-muted-foreground hover:text-foreground hover:bg-muted'
378
- : 'text-muted-foreground/40 cursor-not-allowed',
379
- )}
380
- onClick={onZoomIn}
381
- disabled={!canZoomIn}
382
- >
383
- <Plus className="size-4" />
384
- </Button>
385
- </VTooltip>
386
- <VTooltip description={t('pdf.fitToWidth')} placement="bottom" size="xs">
387
- <Button
388
- variant="unstyled"
389
- aria-label={t('pdf.fitToWidth')}
390
- className={clsx(
391
- 'p-1 rounded cursor-pointer transition-colors',
392
- zoom !== DEFAULT_ZOOM
393
- ? 'text-muted-foreground hover:text-foreground hover:bg-muted'
394
- : 'text-muted-foreground/40',
395
- )}
396
- onClick={onFitToView}
397
- >
398
- <Maximize className="size-4" />
399
- </Button>
400
- </VTooltip>
368
+ <Button
369
+ title={t('pdf.zoomIn')}
370
+ tooltipPlacement="bottom"
371
+ variant="unstyled"
372
+ className={clsx(
373
+ 'p-1 rounded cursor-pointer transition-colors',
374
+ canZoomIn
375
+ ? 'text-muted-foreground hover:text-foreground hover:bg-muted'
376
+ : 'text-muted-foreground/40 cursor-not-allowed',
377
+ )}
378
+ onClick={onZoomIn}
379
+ disabled={!canZoomIn}
380
+ >
381
+ <Plus className="size-4" />
382
+ </Button>
383
+ <Button
384
+ title={t('pdf.fitToWidth')}
385
+ tooltipPlacement="bottom"
386
+ variant="unstyled"
387
+ className={clsx(
388
+ 'p-1 rounded cursor-pointer transition-colors',
389
+ zoom !== DEFAULT_ZOOM
390
+ ? 'text-muted-foreground hover:text-foreground hover:bg-muted'
391
+ : 'text-muted-foreground/40',
392
+ )}
393
+ onClick={onFitToView}
394
+ >
395
+ <Maximize className="size-4" />
396
+ </Button>
401
397
  </div>
402
398
  );
403
399
  }