@vertesia/ui 1.5.0 → 1.5.1

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 (210) hide show
  1. package/lib/core/components/SelectList.d.ts.map +1 -1
  2. package/lib/core/components/SelectList.js +3 -3
  3. package/lib/core/components/SelectList.js.map +1 -1
  4. package/lib/core/components/SidePanel.d.ts.map +1 -1
  5. package/lib/core/components/SidePanel.js +2 -1
  6. package/lib/core/components/SidePanel.js.map +1 -1
  7. package/lib/features/agent/chat/ModernAgentConversation.d.ts.map +1 -1
  8. package/lib/features/agent/chat/ModernAgentConversation.js +51 -17
  9. package/lib/features/agent/chat/ModernAgentConversation.js.map +1 -1
  10. package/lib/features/agent/chat/ModernAgentOutput/MessageInput.d.ts +5 -1
  11. package/lib/features/agent/chat/ModernAgentOutput/MessageInput.d.ts.map +1 -1
  12. package/lib/features/agent/chat/ModernAgentOutput/MessageInput.js +9 -2
  13. package/lib/features/agent/chat/ModernAgentOutput/MessageInput.js.map +1 -1
  14. package/lib/features/agent/chat/hooks/useAgentPlans.d.ts +1 -1
  15. package/lib/features/agent/chat/hooks/useAgentPlans.d.ts.map +1 -1
  16. package/lib/features/agent/chat/hooks/useAgentPlans.js +5 -5
  17. package/lib/features/agent/chat/hooks/useAgentPlans.js.map +1 -1
  18. package/lib/features/magic-pdf/GroundedExtractionView.js +3 -3
  19. package/lib/features/magic-pdf/GroundedExtractionView.js.map +1 -1
  20. package/lib/features/oauth/McpConnectionsButton.d.ts +2 -2
  21. package/lib/features/oauth/McpConnectionsButton.d.ts.map +1 -1
  22. package/lib/features/oauth/McpConnectionsButton.js +9 -7
  23. package/lib/features/oauth/McpConnectionsButton.js.map +1 -1
  24. package/lib/features/oauth/McpConnectionsDialog.d.ts.map +1 -1
  25. package/lib/features/oauth/McpConnectionsDialog.js +7 -3
  26. package/lib/features/oauth/McpConnectionsDialog.js.map +1 -1
  27. package/lib/features/oauth/useMcpConnections.d.ts +4 -2
  28. package/lib/features/oauth/useMcpConnections.d.ts.map +1 -1
  29. package/lib/features/oauth/useMcpConnections.js +15 -9
  30. package/lib/features/oauth/useMcpConnections.js.map +1 -1
  31. package/lib/features/store/objects/selection/ObjectsActionContext.d.ts.map +1 -1
  32. package/lib/features/store/objects/selection/ObjectsActionContext.js +2 -0
  33. package/lib/features/store/objects/selection/ObjectsActionContext.js.map +1 -1
  34. package/lib/features/store/objects/selection/SelectionActions.d.ts +4 -2
  35. package/lib/features/store/objects/selection/SelectionActions.d.ts.map +1 -1
  36. package/lib/features/store/objects/selection/SelectionActions.js +6 -3
  37. package/lib/features/store/objects/selection/SelectionActions.js.map +1 -1
  38. package/lib/features/store/objects/selection/actions/RunIntakeAction.d.ts +8 -0
  39. package/lib/features/store/objects/selection/actions/RunIntakeAction.d.ts.map +1 -0
  40. package/lib/features/store/objects/selection/actions/RunIntakeAction.js +65 -0
  41. package/lib/features/store/objects/selection/actions/RunIntakeAction.js.map +1 -0
  42. package/lib/features/store/objects/selection/actions/index.d.ts +1 -0
  43. package/lib/features/store/objects/selection/actions/index.d.ts.map +1 -1
  44. package/lib/features/store/objects/selection/actions/index.js +1 -0
  45. package/lib/features/store/objects/selection/actions/index.js.map +1 -1
  46. package/lib/features/store/types/ContentObjectTypesTable.d.ts.map +1 -1
  47. package/lib/features/store/types/ContentObjectTypesTable.js +11 -3
  48. package/lib/features/store/types/ContentObjectTypesTable.js.map +1 -1
  49. package/lib/features/store/types/IntakePolicyEditor.d.ts.map +1 -1
  50. package/lib/features/store/types/IntakePolicyEditor.js +14 -14
  51. package/lib/features/store/types/IntakePolicyEditor.js.map +1 -1
  52. package/lib/features/store/types/TypeRegistry.d.ts +275 -150
  53. package/lib/features/store/types/TypeRegistry.d.ts.map +1 -1
  54. package/lib/features/store/types/search/ObjectTypeSearchContext.d.ts +275 -150
  55. package/lib/features/store/types/search/ObjectTypeSearchContext.d.ts.map +1 -1
  56. package/lib/i18n/locales/ar.json +28 -7
  57. package/lib/i18n/locales/de.json +24 -7
  58. package/lib/i18n/locales/en.json +24 -7
  59. package/lib/i18n/locales/es.json +24 -7
  60. package/lib/i18n/locales/fr.json +25 -7
  61. package/lib/i18n/locales/it.json +24 -7
  62. package/lib/i18n/locales/ja.json +24 -7
  63. package/lib/i18n/locales/ko.json +24 -7
  64. package/lib/i18n/locales/pt.json +24 -7
  65. package/lib/i18n/locales/ru.json +26 -7
  66. package/lib/i18n/locales/tr.json +24 -7
  67. package/lib/i18n/locales/zh-TW.json +24 -7
  68. package/lib/i18n/locales/zh.json +24 -7
  69. package/lib/shell/apps/AppInstallationProvider.d.ts +4 -4
  70. package/lib/shell/login/SignInIcons.d.ts.map +1 -1
  71. package/lib/shell/login/SignInIcons.js +2 -1
  72. package/lib/shell/login/SignInIcons.js.map +1 -1
  73. package/lib/shell/login/SignInPasswordStep.d.ts +9 -0
  74. package/lib/shell/login/SignInPasswordStep.d.ts.map +1 -0
  75. package/lib/shell/login/SignInPasswordStep.js +58 -0
  76. package/lib/shell/login/SignInPasswordStep.js.map +1 -0
  77. package/lib/shell/login/SignInPrimitives.d.ts +13 -0
  78. package/lib/shell/login/SignInPrimitives.d.ts.map +1 -1
  79. package/lib/shell/login/SignInPrimitives.js +11 -1
  80. package/lib/shell/login/SignInPrimitives.js.map +1 -1
  81. package/lib/shell/login/SignInProvidersStep.d.ts +3 -1
  82. package/lib/shell/login/SignInProvidersStep.d.ts.map +1 -1
  83. package/lib/shell/login/SignInProvidersStep.js +4 -2
  84. package/lib/shell/login/SignInProvidersStep.js.map +1 -1
  85. package/lib/shell/login/SignInReturningStep.d.ts +3 -1
  86. package/lib/shell/login/SignInReturningStep.d.ts.map +1 -1
  87. package/lib/shell/login/SignInReturningStep.js +18 -8
  88. package/lib/shell/login/SignInReturningStep.js.map +1 -1
  89. package/lib/shell/login/SignInTenantStep.d.ts +3 -1
  90. package/lib/shell/login/SignInTenantStep.d.ts.map +1 -1
  91. package/lib/shell/login/SignInTenantStep.js +2 -2
  92. package/lib/shell/login/SignInTenantStep.js.map +1 -1
  93. package/lib/shell/login/SignInWithProviderButton.d.ts +5 -3
  94. package/lib/shell/login/SignInWithProviderButton.d.ts.map +1 -1
  95. package/lib/shell/login/SignInWithProviderButton.js +8 -7
  96. package/lib/shell/login/SignInWithProviderButton.js.map +1 -1
  97. package/lib/shell/login/SigninScreen.d.ts.map +1 -1
  98. package/lib/shell/login/SigninScreen.js +13 -4
  99. package/lib/shell/login/SigninScreen.js.map +1 -1
  100. package/lib/shell/login/signInUtils.d.ts +20 -4
  101. package/lib/shell/login/signInUtils.d.ts.map +1 -1
  102. package/lib/shell/login/signInUtils.js +47 -1
  103. package/lib/shell/login/signInUtils.js.map +1 -1
  104. package/lib/vertesia-ui-core.js +1 -1
  105. package/lib/vertesia-ui-core.js.map +1 -1
  106. package/lib/vertesia-ui-features.js +14 -14
  107. package/lib/vertesia-ui-features.js.map +1 -1
  108. package/lib/vertesia-ui-i18n.BoNE1APG.chunk.js +5 -0
  109. package/lib/vertesia-ui-i18n.BoNE1APG.chunk.js.map +1 -0
  110. package/lib/vertesia-ui-i18n.BoPtiSPb.chunk.js +5 -0
  111. package/lib/vertesia-ui-i18n.BoPtiSPb.chunk.js.map +1 -0
  112. package/lib/vertesia-ui-i18n.C4BBW5v5.chunk.js +5 -0
  113. package/lib/vertesia-ui-i18n.C4BBW5v5.chunk.js.map +1 -0
  114. package/lib/vertesia-ui-i18n.C81wuNkY.chunk.js +5 -0
  115. package/lib/vertesia-ui-i18n.C81wuNkY.chunk.js.map +1 -0
  116. package/lib/vertesia-ui-i18n.C9GipKIH.chunk.js +5 -0
  117. package/lib/vertesia-ui-i18n.C9GipKIH.chunk.js.map +1 -0
  118. package/lib/vertesia-ui-i18n.CWsoS0W9.chunk.js +5 -0
  119. package/lib/vertesia-ui-i18n.CWsoS0W9.chunk.js.map +1 -0
  120. package/lib/vertesia-ui-i18n.Cr9NtzZB.chunk.js +5 -0
  121. package/lib/vertesia-ui-i18n.Cr9NtzZB.chunk.js.map +1 -0
  122. package/lib/vertesia-ui-i18n.DEpkHOD5.chunk.js +5 -0
  123. package/lib/vertesia-ui-i18n.DEpkHOD5.chunk.js.map +1 -0
  124. package/lib/vertesia-ui-i18n.DPXaRKFO.chunk.js +5 -0
  125. package/lib/vertesia-ui-i18n.DPXaRKFO.chunk.js.map +1 -0
  126. package/lib/vertesia-ui-i18n.D_QNm1Xg.chunk.js +5 -0
  127. package/lib/vertesia-ui-i18n.D_QNm1Xg.chunk.js.map +1 -0
  128. package/lib/vertesia-ui-i18n.F26Cc0f7.chunk.js +5 -0
  129. package/lib/vertesia-ui-i18n.F26Cc0f7.chunk.js.map +1 -0
  130. package/lib/vertesia-ui-i18n.YkXIESV_.chunk.js +5 -0
  131. package/lib/vertesia-ui-i18n.YkXIESV_.chunk.js.map +1 -0
  132. package/lib/vertesia-ui-i18n.js +3 -3
  133. package/lib/vertesia-ui-i18n.js.map +1 -1
  134. package/lib/vertesia-ui-shell.js +15 -9
  135. package/lib/vertesia-ui-shell.js.map +1 -1
  136. package/lib/widgets/xml-viewer/hooks/useCollapsible.d.ts +1 -1
  137. package/package.json +7 -7
  138. package/src/core/components/SelectList.tsx +5 -2
  139. package/src/core/components/SidePanel.tsx +65 -60
  140. package/src/features/agent/chat/ModernAgentConversation.test.tsx +150 -1
  141. package/src/features/agent/chat/ModernAgentConversation.tsx +59 -21
  142. package/src/features/agent/chat/ModernAgentOutput/MessageInput.tsx +17 -1
  143. package/src/features/agent/chat/hooks/useAgentPlans.test.ts +52 -0
  144. package/src/features/agent/chat/hooks/useAgentPlans.ts +5 -5
  145. package/src/features/magic-pdf/GroundedExtractionView.tsx +3 -3
  146. package/src/features/oauth/McpConnectionsButton.test.tsx +56 -0
  147. package/src/features/oauth/McpConnectionsButton.tsx +9 -6
  148. package/src/features/oauth/McpConnectionsDialog.tsx +14 -5
  149. package/src/features/oauth/useMcpConnections.test.ts +10 -0
  150. package/src/features/oauth/useMcpConnections.ts +18 -10
  151. package/src/features/store/objects/selection/ObjectsActionContext.tsx +2 -0
  152. package/src/features/store/objects/selection/SelectionActions.tsx +13 -6
  153. package/src/features/store/objects/selection/actions/RunIntakeAction.tsx +69 -0
  154. package/src/features/store/objects/selection/actions/index.ts +1 -0
  155. package/src/features/store/types/ContentObjectTypesTable.tsx +20 -3
  156. package/src/features/store/types/IntakePolicyEditor.tsx +33 -28
  157. package/src/i18n/locales/ar.json +28 -7
  158. package/src/i18n/locales/de.json +24 -7
  159. package/src/i18n/locales/en.json +24 -7
  160. package/src/i18n/locales/es.json +24 -7
  161. package/src/i18n/locales/fr.json +25 -7
  162. package/src/i18n/locales/it.json +24 -7
  163. package/src/i18n/locales/ja.json +24 -7
  164. package/src/i18n/locales/ko.json +24 -7
  165. package/src/i18n/locales/pt.json +24 -7
  166. package/src/i18n/locales/ru.json +26 -7
  167. package/src/i18n/locales/tr.json +24 -7
  168. package/src/i18n/locales/zh-TW.json +24 -7
  169. package/src/i18n/locales/zh.json +24 -7
  170. package/src/shell/login/SignInIcons.tsx +2 -1
  171. package/src/shell/login/SignInPasswordRequired.test.tsx +82 -0
  172. package/src/shell/login/SignInPasswordStep.test.tsx +71 -0
  173. package/src/shell/login/SignInPasswordStep.tsx +103 -0
  174. package/src/shell/login/SignInPrimitives.tsx +53 -1
  175. package/src/shell/login/SignInProvidersStep.tsx +8 -4
  176. package/src/shell/login/SignInReturningStep.tsx +20 -8
  177. package/src/shell/login/SignInTenantStep.tsx +6 -2
  178. package/src/shell/login/SignInWithProviderButton.tsx +11 -7
  179. package/src/shell/login/SigninScreen.tsx +32 -3
  180. package/src/shell/login/signInPassword.test.ts +133 -0
  181. package/src/shell/login/signInUtils.ts +60 -7
  182. package/lib/features/store/objects/selection/actions/StartWorkflowButton.d.ts +0 -7
  183. package/lib/features/store/objects/selection/actions/StartWorkflowButton.d.ts.map +0 -1
  184. package/lib/features/store/objects/selection/actions/StartWorkflowButton.js +0 -51
  185. package/lib/features/store/objects/selection/actions/StartWorkflowButton.js.map +0 -1
  186. package/lib/vertesia-ui-i18n.BfN7iOHb.chunk.js +0 -5
  187. package/lib/vertesia-ui-i18n.BfN7iOHb.chunk.js.map +0 -1
  188. package/lib/vertesia-ui-i18n.BjH2zEZw.chunk.js +0 -5
  189. package/lib/vertesia-ui-i18n.BjH2zEZw.chunk.js.map +0 -1
  190. package/lib/vertesia-ui-i18n.BjSwAZXl.chunk.js +0 -5
  191. package/lib/vertesia-ui-i18n.BjSwAZXl.chunk.js.map +0 -1
  192. package/lib/vertesia-ui-i18n.C7PUm5Au.chunk.js +0 -5
  193. package/lib/vertesia-ui-i18n.C7PUm5Au.chunk.js.map +0 -1
  194. package/lib/vertesia-ui-i18n.CF_1mUS5.chunk.js +0 -5
  195. package/lib/vertesia-ui-i18n.CF_1mUS5.chunk.js.map +0 -1
  196. package/lib/vertesia-ui-i18n.ChfUl3_-.chunk.js +0 -5
  197. package/lib/vertesia-ui-i18n.ChfUl3_-.chunk.js.map +0 -1
  198. package/lib/vertesia-ui-i18n.D-Sk-5d1.chunk.js +0 -5
  199. package/lib/vertesia-ui-i18n.D-Sk-5d1.chunk.js.map +0 -1
  200. package/lib/vertesia-ui-i18n.D4rnu1_S.chunk.js +0 -5
  201. package/lib/vertesia-ui-i18n.D4rnu1_S.chunk.js.map +0 -1
  202. package/lib/vertesia-ui-i18n.DDf0-laK.chunk.js +0 -5
  203. package/lib/vertesia-ui-i18n.DDf0-laK.chunk.js.map +0 -1
  204. package/lib/vertesia-ui-i18n.DN79y06J.chunk.js +0 -5
  205. package/lib/vertesia-ui-i18n.DN79y06J.chunk.js.map +0 -1
  206. package/lib/vertesia-ui-i18n.DWLIciYQ.chunk.js +0 -5
  207. package/lib/vertesia-ui-i18n.DWLIciYQ.chunk.js.map +0 -1
  208. package/lib/vertesia-ui-i18n.DvF_YaAJ.chunk.js +0 -5
  209. package/lib/vertesia-ui-i18n.DvF_YaAJ.chunk.js.map +0 -1
  210. package/src/features/store/objects/selection/actions/StartWorkflowButton.tsx +0 -104
@@ -18,14 +18,14 @@ export interface UseAgentPlansResult {
18
18
  * Key improvement: incremental processing. Instead of scanning ALL messages
19
19
  * on every change, tracks `lastProcessedIndex` and only scans new messages.
20
20
  */
21
- export function useAgentPlans(messages: AgentMessage[], interactive: boolean, isModal = false): UseAgentPlansResult {
21
+ export function useAgentPlans(messages: AgentMessage[], interactive: boolean): UseAgentPlansResult {
22
22
  const [plans, setPlans] = useState<Array<{ plan: Plan; timestamp: number }>>([]);
23
23
  const [activePlanIndex, setActivePlanIndex] = useState<number>(0);
24
24
  const [workstreamStatusMap, setWorkstreamStatusMap] = useState<
25
25
  Map<number, Map<string, 'pending' | 'in_progress' | 'completed' | 'skipped'>>
26
26
  >(new Map());
27
27
  const [showInput, setShowInput] = useState(interactive);
28
- const [showSlidingPanel, setShowSlidingPanel] = useState<boolean>(!isModal);
28
+ const [showSlidingPanel, setShowSlidingPanel] = useState<boolean>(false);
29
29
 
30
30
  // Incremental processing: track how far we've scanned
31
31
  const lastProcessedIndex = useRef<number>(-1);
@@ -38,12 +38,12 @@ export function useAgentPlans(messages: AgentMessage[], interactive: boolean, is
38
38
  setPlans([]);
39
39
  setActivePlanIndex(0);
40
40
  setWorkstreamStatusMap(new Map());
41
- // Keep right panel open by default on desktop sessions.
42
- setShowSlidingPanel(!isModal);
41
+ // Open automatically only once a plan is available.
42
+ setShowSlidingPanel(false);
43
43
  lastProcessedIndex.current = -1;
44
44
  knownPlanTimestamps.current.clear();
45
45
  }
46
- }, [messages.length, isModal]);
46
+ }, [messages.length]);
47
47
 
48
48
  // Helper to determine showInput from the latest message
49
49
  const updateShowInput = useCallback(
@@ -659,7 +659,7 @@ function PageWithOverlay({
659
659
  'absolute cursor-pointer border rounded-[1px] transition-colors',
660
660
  citation.misaligned && 'border-dashed',
661
661
  isSelected
662
- ? 'border-2 border-info bg-info z-10'
662
+ ? 'border-2 border-info bg-info/20 z-10'
663
663
  : citation.verified
664
664
  ? 'border-success/70 hover:bg-success/20'
665
665
  : citation.reviewed
@@ -853,7 +853,7 @@ function ArrayTable({
853
853
  className={cn(
854
854
  'text-start rounded px-1 w-full',
855
855
  isSelected
856
- ? 'bg-info ring-1 ring-primary'
856
+ ? 'bg-info/15 ring-1 ring-primary'
857
857
  : citation
858
858
  ? 'hover:bg-muted cursor-pointer'
859
859
  : 'text-muted cursor-default',
@@ -909,7 +909,7 @@ function LeafRow({
909
909
  onClick={() => citation && onSelect(path)}
910
910
  className={cn(
911
911
  'flex items-center gap-2 w-full text-start text-sm rounded px-1.5 py-0.5',
912
- isSelected ? 'bg-info ring-1 ring-primary' : citation ? 'hover:bg-muted' : '',
912
+ isSelected ? 'bg-info/15 ring-1 ring-primary' : citation ? 'hover:bg-muted' : '',
913
913
  !citation && 'cursor-default',
914
914
  )}
915
915
  >
@@ -183,6 +183,62 @@ describe('MCP connection controls', () => {
183
183
  expect(onChange).toHaveBeenCalledWith(['linear']);
184
184
  });
185
185
 
186
+ it.each([{ oauthIds: [] }, { oauthIds: ['anonymous'] }])(
187
+ 'shows anonymous servers without status requests, including stale OAuth ids %j',
188
+ async ({ oauthIds }) => {
189
+ mocks.getInstalledApps.mockResolvedValue([
190
+ {
191
+ id: 'anonymous-app',
192
+ manifest: {
193
+ name: 'anonymous-app',
194
+ tool_collections: [
195
+ {
196
+ type: 'mcp',
197
+ id: 'anonymous',
198
+ name: 'Anonymous MCP',
199
+ namespace: 'anonymous',
200
+ url: 'https://anonymous.example.com/mcp',
201
+ auth: 'none',
202
+ oauth_app: 'stale-oauth-app',
203
+ },
204
+ ],
205
+ },
206
+ oauth_collection_ids: oauthIds,
207
+ },
208
+ ]);
209
+ const onChange = vi.fn();
210
+ const { rerender } = renderWithProviders(
211
+ <McpConnectionsInlineList disabledCollections={['other']} onChange={onChange} />,
212
+ );
213
+
214
+ expect(await screen.findByText('Anonymous MCP')).not.toBeNull();
215
+ expect(screen.getAllByText('No authentication')).toHaveLength(1);
216
+ expect(screen.queryByRole('button', { name: /connect/i })).toBeNull();
217
+ expect(mocks.getStatus).not.toHaveBeenCalled();
218
+ expect(mocks.getCollectionStatus).not.toHaveBeenCalled();
219
+
220
+ fireEvent.click(screen.getByRole('switch', { name: 'Deactivate Anonymous MCP for this conversation' }));
221
+ expect(onChange).toHaveBeenLastCalledWith(['other', 'anonymous']);
222
+ rerender(<McpConnectionsInlineList disabledCollections={['other', 'anonymous']} onChange={onChange} />);
223
+ fireEvent.click(screen.getByRole('switch', { name: 'Activate Anonymous MCP for this conversation' }));
224
+ expect(onChange).toHaveBeenLastCalledWith(['other']);
225
+ rerender(<McpConnectionsInlineList onChange={onChange} readOnly />);
226
+ expect(screen.getByRole('switch')).toHaveProperty('disabled', true);
227
+
228
+ rerender(<McpConnectionsActionMenu onChange={onChange} />);
229
+ fireEvent.pointerDown(await screen.findByRole('button', { name: /settings/i }));
230
+ const menuItem = await screen.findByText('MCP');
231
+ expect(screen.getByText('1')).not.toBeNull();
232
+ fireEvent.click(menuItem);
233
+ expect(await screen.findByText('Anonymous MCP')).not.toBeNull();
234
+ expect(screen.getByText('No authentication')).not.toBeNull();
235
+ expect(screen.queryByRole('button', { name: /connect/i })).toBeNull();
236
+ fireEvent.click(screen.getByRole('switch', { name: 'Deactivate Anonymous MCP for this conversation' }));
237
+ expect(onChange).toHaveBeenLastCalledWith(['anonymous']);
238
+ expect(mocks.getStatus).not.toHaveBeenCalled();
239
+ },
240
+ );
241
+
186
242
  it('renders MCP rows before connection statuses finish loading', async () => {
187
243
  const statusRequest =
188
244
  deferred<
@@ -7,6 +7,7 @@ import { RemoteMcpConnectionButton } from './RemoteMcpConnectionButton.js';
7
7
  import {
8
8
  countConnectedActiveGroups,
9
9
  getConnectedActiveGroupLabels,
10
+ isGroupConnected,
10
11
  isGroupDisabled,
11
12
  toggleGroupDisabled,
12
13
  useMcpConnections,
@@ -29,7 +30,7 @@ export interface McpConnectionsButtonProps {
29
30
  /**
30
31
  * Toolbar button that opens the MCP connections dialog. The badge shows how many MCP
31
32
  * servers are connected and active for this conversation.
32
- * Renders nothing when the project has no OAuth MCP servers installed.
33
+ * Renders nothing when the project has no MCP servers installed.
33
34
  */
34
35
  export function McpConnectionsButton({
35
36
  disabledCollections,
@@ -93,7 +94,7 @@ export function McpConnectionsButton({
93
94
  }
94
95
 
95
96
  /**
96
- * Inline MCP status list for forms. It shows all available authenticated MCP groups
97
+ * Inline MCP status list for forms. It shows all available MCP groups
97
98
  * without requiring the user to open the management dialog.
98
99
  */
99
100
  export function McpConnectionsInlineList({
@@ -127,7 +128,7 @@ export function McpConnectionsInlineList({
127
128
  <div className="space-y-1">
128
129
  {groups.map((group) => {
129
130
  const active = !isGroupDisabled(group, disabledCollections);
130
- const connected = group.authStatus?.authenticated === true;
131
+ const connected = isGroupConnected(group);
131
132
  const interactiveOAuth = group.authType === 'oauth' && group.oauthGrantType !== 'client_credentials';
132
133
  const StatusIcon = connected ? Link2 : Link2Off;
133
134
  return (
@@ -179,9 +180,11 @@ export function McpConnectionsInlineList({
179
180
  />
180
181
  ) : (
181
182
  <Badge variant="outline" className="h-6 w-32 justify-center px-2 text-xs">
182
- {group.authType === 'api_key'
183
- ? t('mcpConnections.apiKey')
184
- : t('mcpConnections.managedByApp')}
183
+ {group.authType === 'none'
184
+ ? t('mcpConnections.noAuthentication')
185
+ : group.authType === 'api_key'
186
+ ? t('mcpConnections.apiKey')
187
+ : t('mcpConnections.managedByApp')}
185
188
  </Badge>
186
189
  )}
187
190
  {onChange && (
@@ -2,7 +2,12 @@ import { useUITranslation } from '@vertesia/ui/i18n';
2
2
  import { Link2, Link2Off } from 'lucide-react';
3
3
  import { Badge, Button, Modal, ModalBody, ModalTitle, Spinner, Switch, VTooltip } from '../../core/index.js';
4
4
  import { RemoteMcpConnectionButton } from './RemoteMcpConnectionButton.js';
5
- import { isGroupDisabled, type McpConnectionGroup, toggleGroupDisabled } from './useMcpConnections.js';
5
+ import {
6
+ isGroupConnected,
7
+ isGroupDisabled,
8
+ type McpConnectionGroup,
9
+ toggleGroupDisabled,
10
+ } from './useMcpConnections.js';
6
11
 
7
12
  export interface McpConnectionsDialogProps {
8
13
  isOpen: boolean;
@@ -61,7 +66,7 @@ export function McpConnectionsDialog({
61
66
  <div className="space-y-1">
62
67
  {groups.map((group) => {
63
68
  const active = !isGroupDisabled(group, disabledCollections);
64
- const connected = group.authStatus?.authenticated === true;
69
+ const connected = isGroupConnected(group);
65
70
  const interactiveOAuth =
66
71
  group.authType === 'oauth' && group.oauthGrantType !== 'client_credentials';
67
72
  const StatusIcon = connected ? Link2 : Link2Off;
@@ -115,11 +120,15 @@ export function McpConnectionsDialog({
115
120
  showDisconnect
116
121
  readOnly={readOnly}
117
122
  />
118
- ) : group.authType === 'oauth' ? (
123
+ ) : (
119
124
  <Badge variant="outline" className="h-6 w-32 justify-center px-2 text-xs">
120
- {t('mcpConnections.managedByApp')}
125
+ {group.authType === 'none'
126
+ ? t('mcpConnections.noAuthentication')
127
+ : group.authType === 'api_key'
128
+ ? t('mcpConnections.apiKey')
129
+ : t('mcpConnections.managedByApp')}
121
130
  </Badge>
122
- ) : null}
131
+ )}
123
132
  {onChange && (
124
133
  <Switch
125
134
  size="sm"
@@ -93,3 +93,13 @@ describe('toggleGroupDisabled', () => {
93
93
  expect(toggleGroupDisabled(g, disabled, true)).toEqual([]);
94
94
  });
95
95
  });
96
+
97
+ describe('anonymous MCP groups', () => {
98
+ it('counts anonymous servers without credential status and respects disabled collections', () => {
99
+ const anonymous = { ...group(['anonymous'], false, 'Anonymous'), authType: 'none' as const };
100
+ expect(countConnectedActiveGroups([anonymous])).toBe(1);
101
+ expect(getConnectedActiveGroupLabels([anonymous])).toEqual(['Anonymous']);
102
+ expect(countConnectedActiveGroups([anonymous], ['anonymous'])).toBe(0);
103
+ expect(getConnectedActiveGroupLabels([anonymous], ['anonymous'])).toEqual([]);
104
+ });
105
+ });
@@ -20,13 +20,13 @@ export interface McpConnectionGroup {
20
20
  memberIds: string[];
21
21
  /** Collection names represented by this row. */
22
22
  memberNames: string[];
23
- authType: 'oauth' | 'api_key';
23
+ authType: 'none' | 'oauth' | 'api_key';
24
24
  oauthGrantType?: 'authorization_code' | 'client_credentials';
25
25
  authStatus?: OAuthAuthStatus;
26
26
  }
27
27
 
28
28
  /**
29
- * Loads the project's installed authenticated MCP tool collections and resolves their status.
29
+ * Loads the project's installed MCP tool collections and resolves their status.
30
30
  *
31
31
  * Shared by the MCP connections button (badge count) and dialog (list) so the data is
32
32
  * fetched once and refreshed together after connect/disconnect.
@@ -57,8 +57,10 @@ export function useMcpConnections() {
57
57
  const mcpCollections = inst.manifest.tool_collections
58
58
  .map((c) => normalizeToolCollection(c))
59
59
  .filter((c): c is MCPToolCollectionObject => c.type === 'mcp');
60
- const oauthCollections = mcpCollections.filter((c) => c.auth !== 'api_key' && oauthIds.includes(c.id));
61
- const apiKeyCollections = mcpCollections.filter((c) => c.auth === 'api_key');
60
+ const oauthCollections = mcpCollections.filter(
61
+ (c) => c.auth !== 'none' && c.auth !== 'api_key' && oauthIds.includes(c.id),
62
+ );
63
+ const directCollections = mcpCollections.filter((c) => c.auth === 'none' || c.auth === 'api_key');
62
64
 
63
65
  const providerMap = new Map<string, MCPToolCollectionObject[]>();
64
66
  const oauthAppMap = new Map<string, MCPToolCollectionObject[]>();
@@ -124,16 +126,16 @@ export function useMcpConnections() {
124
126
  });
125
127
  }
126
128
 
127
- for (const col of apiKeyCollections) {
129
+ for (const col of directCollections) {
128
130
  allGroups.push({
129
- key: `${inst.id}:api-key:${col.id}`,
131
+ key: `${inst.id}:${col.auth}:${col.id}`,
130
132
  appId: inst.id,
131
133
  appName: inst.manifest.title || inst.manifest.name,
132
134
  label: col.name,
133
135
  representativeId: col.id,
134
136
  memberIds: [col.id],
135
137
  memberNames: [col.name],
136
- authType: 'api_key',
138
+ authType: col.auth === 'none' ? 'none' : 'api_key',
137
139
  });
138
140
  }
139
141
  }
@@ -155,6 +157,8 @@ export function useMcpConnections() {
155
157
  const statusRequestsByApp = new Map<string, Promise<OAuthAuthStatus[]>>();
156
158
  const groupsWithStatus = await Promise.all(
157
159
  allGroups.map(async (group) => {
160
+ // Anonymous servers are available without a credential status lookup.
161
+ if (group.authType === 'none') return group;
158
162
  try {
159
163
  let statusRequest = statusRequestsByApp.get(group.appId);
160
164
  if (!statusRequest) {
@@ -219,15 +223,19 @@ export function toggleGroupDisabled(
219
223
  return Array.from(current);
220
224
  }
221
225
 
226
+ /** Anonymous servers are available without authentication; other modes require valid credentials. */
227
+ export function isGroupConnected(group: McpConnectionGroup): boolean {
228
+ return group.authType === 'none' || group.authStatus?.authenticated === true;
229
+ }
230
+
222
231
  /** Count connected MCP groups that are enabled for the current conversation. */
223
232
  export function countConnectedActiveGroups(groups: McpConnectionGroup[], disabled?: string[]): number {
224
- return groups.filter((group) => group.authStatus?.authenticated === true && !isGroupDisabled(group, disabled))
225
- .length;
233
+ return groups.filter((group) => isGroupConnected(group) && !isGroupDisabled(group, disabled)).length;
226
234
  }
227
235
 
228
236
  /** Names of connected MCP groups that are enabled for the current conversation. */
229
237
  export function getConnectedActiveGroupLabels(groups: McpConnectionGroup[], disabled?: string[]): string[] {
230
238
  return groups
231
- .filter((group) => group.authStatus?.authenticated === true && !isGroupDisabled(group, disabled))
239
+ .filter((group) => isGroupConnected(group) && !isGroupDisabled(group, disabled))
232
240
  .map((group) => group.label);
233
241
  }
@@ -10,6 +10,7 @@ import { ChangeTypeAction } from './actions/ChangeTypeAction';
10
10
  import { DeleteObjectsAction, DeleteObjectsFromCollectionsAction } from './actions/DeleteObjectsAction';
11
11
  import { ExportPropertiesAction } from './actions/ExportPropertiesAction';
12
12
  import { RemoveFromCollectionAction } from './actions/RemoveFromCollectionAction';
13
+ import { RunIntakeAction } from './actions/RunIntakeAction';
13
14
  import { ObjectsActionContext } from './ObjectsActionContextClass';
14
15
  import { ObjectsActionContextReact, useObjectsActionContext } from './ObjectsActionHooks';
15
16
  import type { ObjectsActionSpec } from './ObjectsActionSpec';
@@ -18,6 +19,7 @@ const DEFAULT_ACTIONS: ObjectsActionSpec[] = [
18
19
  ExportPropertiesAction,
19
20
  ChangeTypeAction,
20
21
  AddToCollectionAction,
22
+ RunIntakeAction,
21
23
  DeleteObjectsAction,
22
24
  RemoveFromCollectionAction,
23
25
  DeleteObjectsFromCollectionsAction,
@@ -7,7 +7,6 @@ import { useState } from 'react';
7
7
  import { type DocumentSelection, useDocumentSelection } from '../DocumentSelectionProvider.js';
8
8
  import { DocumentUploadModal } from '../upload/DocumentUploadModal.js';
9
9
  import { ExportPropertiesAction } from './actions/ExportPropertiesAction';
10
- import { StartWorkflowButton } from './actions/StartWorkflowButton';
11
10
  import { ObjectsActionContextProvider } from './ObjectsActionContext';
12
11
  import { useObjectsActionContext } from './ObjectsActionHooks';
13
12
  import type { ObjectsActionSpec } from './ObjectsActionSpec';
@@ -17,8 +16,10 @@ interface SelectionActionsProps {
17
16
  allowMutations?: boolean;
18
17
  allowDelete?: boolean;
19
18
  /**
20
- * Opt-in: shows the "Start Workflow" action. Defaults to `false` so it never leaks to read-only
21
- * surfaces — callers must pass a permission-gated value (e.g. `canRunWorkflow(perms)`).
19
+ * Opt-in: shows the "Start Workflow" entry in the actions menu. Defaults to `false` so it never
20
+ * leaks to read-only surfaces — callers must pass a permission-gated value (e.g.
21
+ * `canRunWorkflow(perms)`). Running a workflow is its own permission, so this is deliberately
22
+ * separate from `allowMutations`.
22
23
  */
23
24
  allowWorkflowRun?: boolean;
24
25
  }
@@ -52,11 +53,11 @@ export function SelectionActions({
52
53
  </Button>
53
54
  </div>
54
55
  )}
55
- {allowWorkflowRun && <StartWorkflowButton />}
56
56
  <SelectionActionsPopover
57
57
  selection={selection}
58
58
  allowMutations={allowMutations}
59
59
  allowDelete={allowDelete}
60
+ allowWorkflowRun={allowWorkflowRun}
60
61
  >
61
62
  {(actions) =>
62
63
  actions.length > 0 ? (
@@ -123,7 +124,9 @@ function SelectionActionsPopover({
123
124
  children,
124
125
  allowMutations = true,
125
126
  allowDelete = true,
126
- }: SelectionActionsPopoverProps & Required<Pick<SelectionActionsProps, 'allowMutations' | 'allowDelete'>>) {
127
+ allowWorkflowRun = false,
128
+ }: SelectionActionsPopoverProps &
129
+ Required<Pick<SelectionActionsProps, 'allowMutations' | 'allowDelete' | 'allowWorkflowRun'>>) {
127
130
  const context = useObjectsActionContext();
128
131
  const executeAction = (action: ObjectsActionSpec) => {
129
132
  context.run(action.id);
@@ -131,6 +134,7 @@ function SelectionActionsPopover({
131
134
  const actions = getAvailableActions(context.actions, selection, {
132
135
  allowMutations,
133
136
  allowDelete,
137
+ allowWorkflowRun,
134
138
  });
135
139
  const trigger = children(actions);
136
140
 
@@ -169,7 +173,7 @@ function PopoverBody({ executeAction, actions }: PopoverBodyProps) {
169
173
  function getAvailableActions(
170
174
  actions: ObjectsActionSpec[],
171
175
  selection: DocumentSelection,
172
- permissions: Required<Pick<SelectionActionsProps, 'allowMutations' | 'allowDelete'>>,
176
+ permissions: Required<Pick<SelectionActionsProps, 'allowMutations' | 'allowDelete' | 'allowWorkflowRun'>>,
173
177
  ): ObjectsActionSpec[] {
174
178
  if (!selection?.hasSelection()) {
175
179
  return [ExportPropertiesAction];
@@ -182,6 +186,9 @@ function getAvailableActions(
182
186
  if (action.id === 'delete' || action.id === 'deleteFromCollections') {
183
187
  return permissions.allowDelete;
184
188
  }
189
+ if (action.id === 'runIntake') {
190
+ return permissions.allowWorkflowRun;
191
+ }
185
192
  if (action.id === 'changeType' || action.id === 'addToCollection' || action.id === 'removeFromCollection') {
186
193
  return permissions.allowMutations;
187
194
  }
@@ -0,0 +1,69 @@
1
+ import { errorMessage, useToast } from '@vertesia/ui/core';
2
+ import { i18nInstance, NAMESPACE, useUITranslation } from '@vertesia/ui/i18n';
3
+ import { useUserSession } from '@vertesia/ui/session';
4
+ import { useCallback } from 'react';
5
+ import { useDocumentSearch } from '../../search';
6
+ import { useObjectsActionContext } from '../ObjectsActionHooks';
7
+ import type { ActionComponentTypeProps, ObjectsActionSpec } from '../ObjectsActionSpec';
8
+ import ConfirmAction from './ConfirmAction';
9
+
10
+ /**
11
+ * Re-runs the unified standard intake pipeline over the selected objects. The server resolves each
12
+ * object's nature and starts one run per object — see the `start_workflow` bulk operation.
13
+ */
14
+ export function RunIntakeActionComponent({ action, objectIds }: ActionComponentTypeProps) {
15
+ const { t } = useUITranslation();
16
+ const ctx = useObjectsActionContext();
17
+ const toast = useToast();
18
+ const { store } = useUserSession();
19
+ const search = useDocumentSearch();
20
+
21
+ const callback = useCallback(() => {
22
+ if (!objectIds?.length) {
23
+ toast({
24
+ status: 'error',
25
+ title: t('store.actions.noObjectsSelected'),
26
+ description: t('store.actions.pleaseSelectObjectsToRunIntake'),
27
+ duration: 3000,
28
+ });
29
+ return Promise.resolve(false);
30
+ }
31
+
32
+ return store
33
+ .runOperation({ name: 'start_workflow', ids: objectIds, params: {} })
34
+ .then(() => {
35
+ toast({
36
+ status: 'success',
37
+ title: t('store.actions.intakeStarted'),
38
+ description: t('store.actions.intakeStartedOn', { count: objectIds.length }),
39
+ duration: 3000,
40
+ });
41
+ // Intake rewrites status, type and properties asynchronously, so refresh the list
42
+ // to pick up the `processing` status rather than leaving stale rows selected.
43
+ if (search) {
44
+ ctx.params?.selection?.removeAll();
45
+ search.search();
46
+ }
47
+ })
48
+ .catch((err: unknown) => {
49
+ toast({
50
+ status: 'error',
51
+ title: t('store.actions.errorStartingIntake'),
52
+ description: errorMessage(err),
53
+ duration: 5000,
54
+ });
55
+ });
56
+ }, [ctx.params?.selection?.removeAll, objectIds, search, search?.search, store.runOperation, t, toast]);
57
+
58
+ return <ConfirmAction action={action} callback={callback} />;
59
+ }
60
+
61
+ const t_static = i18nInstance.getFixedT(null, NAMESPACE);
62
+ export const RunIntakeAction: ObjectsActionSpec = {
63
+ id: 'runIntake',
64
+ name: t_static('store.actions.runIntake'),
65
+ description: t_static('store.actions.runIntakeDesc'),
66
+ confirm: true,
67
+ confirmationText: t_static('store.actions.confirmRunIntake'),
68
+ component: RunIntakeActionComponent,
69
+ };
@@ -4,3 +4,4 @@ export * from './ConfirmAction';
4
4
  export * from './DeleteObjectsAction';
5
5
  export * from './ExportPropertiesAction';
6
6
  export * from './RemoveFromCollectionAction';
7
+ export * from './RunIntakeAction';
@@ -1,5 +1,5 @@
1
- import type { ContentObjectTypeItem } from '@vertesia/common';
2
- import { Button, CopyButton, Table, TBody, THead, VTooltip } from '@vertesia/ui/core';
1
+ import type { ContentObjectTypeItem, ContentObjectTypeStatus } from '@vertesia/common';
2
+ import { Badge, Button, CopyButton, Table, TBody, THead, VTooltip } from '@vertesia/ui/core';
3
3
  import { useUITranslation } from '@vertesia/ui/i18n';
4
4
  import { useNavigate } from '@vertesia/ui/router';
5
5
  import clsx from 'clsx';
@@ -46,12 +46,13 @@ export function ContentObjectTypesTable({
46
46
  </th>
47
47
  )}
48
48
  <th>{t('store.name')}</th>
49
+ <th>{t('store.status')}</th>
49
50
  <th>{t('store.strictMode')}</th>
50
51
  <th>{t('store.semanticChunking')}</th>
51
52
  <th>{t('store.updatedAt')}</th>
52
53
  </tr>
53
54
  </THead>
54
- <TBody isLoading={isLoading && (!objects || objects.length === 0)} columns={selectable ? 5 : 4}>
55
+ <TBody isLoading={isLoading && (!objects || objects.length === 0)} columns={selectable ? 6 : 5}>
55
56
  {objects?.map((obj) => (
56
57
  <tr
57
58
  key={obj.id}
@@ -93,6 +94,9 @@ export function ContentObjectTypesTable({
93
94
  )}
94
95
  </div>
95
96
  </td>
97
+ <td>
98
+ <TypeStatusBadge status={obj.status} />
99
+ </td>
96
100
  <td>{obj.strict_mode ? 'Yes' : 'No'}</td>
97
101
  <td>{obj.is_chunkable ? 'Yes' : 'No'}</td>
98
102
  <td>
@@ -106,3 +110,16 @@ export function ContentObjectTypesTable({
106
110
  </Table>
107
111
  );
108
112
  }
113
+
114
+ /** A type stored before `status` existed has none; the stored model defaults it to active. */
115
+ function TypeStatusBadge({ status = 'active' }: { status?: ContentObjectTypeStatus }) {
116
+ const { t } = useUITranslation();
117
+ if (status === 'active') {
118
+ return <Badge variant="success">{t('store.typeStatus.active')}</Badge>;
119
+ }
120
+ return (
121
+ <VTooltip description={t('store.typeStatus.draftHint')}>
122
+ <Badge variant="attention">{t('store.typeStatus.draft')}</Badge>
123
+ </VTooltip>
124
+ );
125
+ }
@@ -511,9 +511,10 @@ export function IntakePolicyEditor({
511
511
  ) : undefined;
512
512
 
513
513
  /** Panel chrome for the policy tabs. Each tab owns its panel now that the switcher is outside. */
514
- const withPolicyPanel = (content: ReactNode) => (
515
- <Panel title={title} className="bg-background! h-full" action={action}>
516
- <div className="flex h-full min-h-0 flex-col gap-3">
514
+ const withPolicyPanel = (content: ReactNode, fill = false) => (
515
+ <Panel title={title} className="bg-background! h-full overflow-hidden" action={action}>
516
+ {/* A fill tab (JSON) sizes itself to the panel and scrolls inside its own panes. */}
517
+ <div className={`flex min-h-0 flex-1 flex-col gap-3 ${fill ? 'overflow-hidden' : 'overflow-auto'}`}>
517
518
  {validationMessage && (
518
519
  <div className="rounded-sm border border-destructive bg-mixer-destructive/10 px-3 py-2 text-sm whitespace-pre-line text-destructive">
519
520
  {validationMessage}
@@ -543,7 +544,7 @@ export function IntakePolicyEditor({
543
544
  );
544
545
 
545
546
  return (
546
- <div className="flex h-full min-h-0 w-full flex-col gap-3">
547
+ <div className="flex h-full min-h-0 w-full flex-col gap-2">
547
548
  <IntakeSummary policy={summaryPolicy} />
548
549
  <Tabs
549
550
  tabs={leadingTabs ? [...leadingTabs, ...policyTabs] : policyTabs}
@@ -554,7 +555,7 @@ export function IntakePolicyEditor({
554
555
  className="px-0 min-h-0 flex-1 flex-row!"
555
556
  >
556
557
  <TabsBar className="py-2 w-48 shrink-0" direction="vertical" />
557
- <TabsPanel className="min-h-0 min-w-0 flex-1 overflow-auto ps-4" />
558
+ <TabsPanel className="min-h-0 min-w-0 flex-1 overflow-auto pb-0!" />
558
559
  </Tabs>
559
560
  </div>
560
561
  );
@@ -572,7 +573,7 @@ function createEditorTabs(
572
573
  onChange: (value: string) => void;
573
574
  theme: string;
574
575
  },
575
- wrap: (content: ReactNode) => ReactNode,
576
+ wrap: (content: ReactNode, fill?: boolean) => ReactNode,
576
577
  ) {
577
578
  const formTab = (name: IntakePolicyFormSection, label: string) => ({
578
579
  name,
@@ -590,30 +591,34 @@ function createEditorTabs(
590
591
  name: 'json',
591
592
  label: t('intakePolicy.tab.json'),
592
593
  content: wrap(
593
- <div className="flex h-full min-h-[36rem] gap-4 py-3">
594
- <div className="min-w-0 flex-1 overflow-hidden rounded-sm border">
595
- <MonacoEditor
596
- value={editorValue}
597
- language="json"
598
- editorRef={json.editorRef}
599
- beforeMount={json.beforeMount}
600
- onChange={(update) => json.onChange(update.state.doc.toString())}
601
- theme={json.theme === 'dark' ? 'vs-dark' : 'vs'}
602
- options={{
603
- readOnly: readonly,
604
- minimap: { enabled: false },
605
- scrollBeyondLastLine: false,
606
- wordWrap: 'on',
607
- lineNumbers: 'on',
608
- automaticLayout: true,
609
- formatOnPaste: true,
610
- formatOnType: true,
611
- tabSize: 2,
612
- }}
613
- />
594
+ <div className="@container flex min-h-0 flex-1 gap-4">
595
+ {/* Absolute child gives Monaco's height="100%" a definite box to fill. */}
596
+ <div className="relative min-w-0 flex-1 overflow-hidden rounded-sm border">
597
+ <div className="absolute inset-0">
598
+ <MonacoEditor
599
+ value={editorValue}
600
+ language="json"
601
+ editorRef={json.editorRef}
602
+ beforeMount={json.beforeMount}
603
+ onChange={(update) => json.onChange(update.state.doc.toString())}
604
+ theme={json.theme === 'dark' ? 'vs-dark' : 'vs'}
605
+ options={{
606
+ readOnly: readonly,
607
+ minimap: { enabled: false },
608
+ scrollBeyondLastLine: false,
609
+ wordWrap: 'on',
610
+ lineNumbers: 'on',
611
+ automaticLayout: true,
612
+ formatOnPaste: true,
613
+ formatOnType: true,
614
+ tabSize: 2,
615
+ }}
616
+ />
617
+ </div>
614
618
  </div>
615
619
  <IntakeHelp />
616
620
  </div>,
621
+ true,
617
622
  ),
618
623
  },
619
624
  ];
@@ -652,7 +657,7 @@ function IntakeSummary({ policy }: { policy: ContentTypeIntakePolicy }) {
652
657
  function IntakeHelp() {
653
658
  const { t } = useUITranslation();
654
659
  return (
655
- <aside className="hidden w-80 shrink-0 overflow-y-auto rounded-sm border bg-mixer-muted/20 p-3 text-sm lg:block">
660
+ <aside className="hidden w-80 shrink-0 overflow-y-auto rounded-sm border bg-mixer-muted/20 p-3 text-sm @3xl:block">
656
661
  <div className="mb-3 font-semibold">{t('intakePolicy.help.title')}</div>
657
662
  <div className="space-y-3 text-muted">
658
663
  <HelpItem label="identification" text={t('intakePolicy.help.identification')} />