@kortix/ui 0.14.5 → 0.14.7

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 (236) hide show
  1. package/dist/_vendor/kortix-shared.js +489 -381
  2. package/dist/access/access/access-dialog.js +8 -5
  3. package/dist/access/access/copy-row.js +2 -2
  4. package/dist/access/sharing-picker.js +2 -1
  5. package/dist/browser/app-in-browser.js +5 -3
  6. package/dist/browser/browser-panel.js +6 -6
  7. package/dist/browser/sandbox-browser-chrome.d.ts +4 -1
  8. package/dist/browser/sandbox-browser-chrome.js +4 -3
  9. package/dist/customize/agents/agent-access.d.ts +20 -0
  10. package/dist/customize/agents/agent-access.js +17 -0
  11. package/dist/customize/agents/agent-authority-card.js +1 -2
  12. package/dist/customize/agents/agent-detail-aside.js +15 -14
  13. package/dist/customize/agents/agent-drives-section.js +5 -6
  14. package/dist/customize/agents/agent-grant-pages.js +73 -76
  15. package/dist/customize/agents/agent-nav.prototype.d.ts +35 -0
  16. package/dist/customize/agents/agent-nav.prototype.js +95 -0
  17. package/dist/customize/agents/agent-page.js +59 -23
  18. package/dist/customize/agents/agent-people-section.js +18 -17
  19. package/dist/customize/agents/agent-triggers-section.js +6 -5
  20. package/dist/customize/agents/agents-page.js +18 -1
  21. package/dist/customize/connectors/add-mcp/add-mcp-server.js +4 -2
  22. package/dist/customize/connectors/catalog/catalog-entry.d.ts +14 -0
  23. package/dist/customize/connectors/catalog/catalog-entry.js +18 -1
  24. package/dist/customize/connectors/catalog/connector-browse.d.ts +28 -0
  25. package/dist/customize/connectors/catalog/connector-browse.js +18 -5
  26. package/dist/customize/connectors/connector-routes.d.ts +3 -1
  27. package/dist/customize/connectors/connector-routes.js +18 -0
  28. package/dist/customize/connectors/connectors-page.js +23 -4
  29. package/dist/customize/connectors/detail/app-page.js +19 -5
  30. package/dist/customize/connectors/detail/connector-advanced-tools.js +4 -6
  31. package/dist/customize/connectors/detail/connector-modal.d.ts +10 -13
  32. package/dist/customize/connectors/detail/connector-modal.js +18 -101
  33. package/dist/customize/connectors/detail/connector-notice.js +6 -2
  34. package/dist/customize/connectors/detail/connector-page.d.ts +30 -0
  35. package/dist/customize/connectors/detail/connector-page.js +26 -13
  36. package/dist/customize/providers/provider-accordion.js +2 -1
  37. package/dist/customize/providers/provider-connect.js +2 -1
  38. package/dist/customize/sections/component/telegram-channel-row.js +1 -1
  39. package/dist/customize/sections/connector-connection-modal.js +11 -9
  40. package/dist/customize/sections/connectors-view.js +11 -13
  41. package/dist/customize/sections/llm-provider/custom-provider-form.js +24 -7
  42. package/dist/customize/sections/llm-provider/custom-provider-panel.js +44 -8
  43. package/dist/customize/sections/llm-provider/types.d.ts +3 -0
  44. package/dist/customize/sections/llm-provider/utils.js +2 -2
  45. package/dist/customize/sections/view/agent-editor-access-fields.d.ts +9 -16
  46. package/dist/customize/sections/view/agent-editor-access-fields.js +30 -30
  47. package/dist/customize/sections/view/agent-editor-basics-fields.js +3 -10
  48. package/dist/customize/sections/view/agent-editor-primitives.d.ts +28 -10
  49. package/dist/customize/sections/view/agent-editor-primitives.js +32 -19
  50. package/dist/customize/sections/view/agent-editor.js +3 -3
  51. package/dist/customize/sections/view/gateway/gateway-routing.js +18 -21
  52. package/dist/customize/sections/view/grant-mode-field.d.ts +2 -5
  53. package/dist/customize/sections/view/grant-mode-field.js +10 -18
  54. package/dist/customize/sections/view/permission-editor.js +11 -8
  55. package/dist/customize/sections/view/secrets-view.js +2 -1
  56. package/dist/customize/settings/rail-copy-context.js +5 -3
  57. package/dist/customize/settings/tabs/general-tab.d.ts +9 -2
  58. package/dist/customize/settings/tabs/general-tab.js +33 -11
  59. package/dist/customize/settings/tabs/sandbox-template-form.js +9 -12
  60. package/dist/customize/settings/tabs/transfer-workspace-dialog.d.ts +4 -0
  61. package/dist/customize/settings/tabs/transfer-workspace-dialog.js +82 -0
  62. package/dist/customize/shared/capability-tabs.js +2 -1
  63. package/dist/customize/skills/skills-page.js +3 -5
  64. package/dist/customize/triggers/schedule/event-trigger-copy.js +3 -2
  65. package/dist/customize/triggers/schedule/schedule-builder.js +7 -4
  66. package/dist/customize/triggers/schedule/trigger-composer.js +5 -2
  67. package/dist/customize/triggers/schedule/when-event.js +1 -1
  68. package/dist/diff/diff-view.js +9 -10
  69. package/dist/files/editor/code-editor.js +2 -3
  70. package/dist/files/project/api/runtime-files.js +3 -2
  71. package/dist/files/project/components/change-request-detail-dialog.d.ts +3 -1
  72. package/dist/files/project/components/change-request-detail-dialog.js +3 -5
  73. package/dist/files/project/components/change-request-status-badge.d.ts +12 -0
  74. package/dist/files/project/components/change-request-status-badge.js +27 -0
  75. package/dist/files/project/components/change-requests-panel.js +1 -1
  76. package/dist/files/project/components/drive-explorer.js +2 -1
  77. package/dist/files/project/components/drive-grid-view.js +11 -7
  78. package/dist/files/project/components/drive-list-view.js +4 -4
  79. package/dist/files/project/components/file-breadcrumbs.js +1 -1
  80. package/dist/files/project/components/file-explorer-page.js +1 -1
  81. package/dist/files/project/components/file-history-popover.js +1 -6
  82. package/dist/files/project/components/file-search.js +6 -1
  83. package/dist/files/project/components/open-change-request-dialog.js +2 -1
  84. package/dist/files/project/components/version-selector-logic.d.ts +11 -0
  85. package/dist/files/project/components/version-selector-logic.js +26 -0
  86. package/dist/files/project/components/version-selector.js +11 -20
  87. package/dist/files/project/file-source.js +18 -1
  88. package/dist/files/project/hooks/use-file-content.js +2 -0
  89. package/dist/files/project/hooks/use-server-health.js +17 -15
  90. package/dist/files/renderers/docx/docx-viewer.js +0 -5
  91. package/dist/files/renderers/image-renderer.js +6 -24
  92. package/dist/files/renderers/pdf/pdf-viewer.js +1 -1
  93. package/dist/files/renderers/presentation/FullScreenPresentationViewer.js +2 -11
  94. package/dist/files/renderers/show-content-renderer.js +1 -1
  95. package/dist/files/renderers/sqlite-renderer.js +8 -3
  96. package/dist/files/renderers/xlsx/xlsx-viewer.js +15 -16
  97. package/dist/files/tree/components/file-tree-item.js +1 -1
  98. package/dist/files/viewer/file-header.js +1 -1
  99. package/dist/files/viewer/file-preview-modal.d.ts +1 -1
  100. package/dist/files/viewer/file-preview-modal.js +13 -3
  101. package/dist/files/viewer/file-source.d.ts +3 -1
  102. package/dist/files/viewer/use-file-content-state.js +27 -8
  103. package/dist/files/viewer/viewer-actions.js +2 -2
  104. package/dist/i18n/en.d.ts +355 -12
  105. package/dist/i18n/en.js +360 -17
  106. package/dist/internal/desktop/desktop-back-button.js +5 -3
  107. package/dist/internal/files/types.d.ts +2 -0
  108. package/dist/internal/goals/goal-meta.d.ts +30 -0
  109. package/dist/internal/goals/goal-meta.js +55 -0
  110. package/dist/internal/hooks/use-auto-scroll.js +5 -3
  111. package/dist/internal/lib/query-client-singleton.d.ts +9 -3
  112. package/dist/internal/lib/query-client-singleton.js +18 -12
  113. package/dist/internal/notifications/notification-rows.js +2 -1
  114. package/dist/internal/outcomes/outcome-types.d.ts +5 -0
  115. package/dist/internal/share/session-shares-modal.js +3 -7
  116. package/dist/internal/stores/kortix-computer-store.js +14 -2
  117. package/dist/internal/stores/session-hover-store.d.ts +32 -0
  118. package/dist/internal/stores/session-hover-store.js +38 -0
  119. package/dist/internal/stores/sidebar-nav-store.d.ts +1 -1
  120. package/dist/internal/stores/sidebar-nav-store.js +3 -1
  121. package/dist/lib/routes.d.ts +2 -0
  122. package/dist/lib/routes.js +1 -0
  123. package/dist/markdown/code/inline-code.js +8 -0
  124. package/dist/markdown/code/output-paths-context.d.ts +18 -0
  125. package/dist/markdown/code/output-paths-context.js +35 -0
  126. package/dist/markdown/genui/components/charts.js +6 -5
  127. package/dist/primitives/map.js +2 -1
  128. package/dist/primitives/preview-image.js +4 -2
  129. package/dist/primitives/settings-section-header.d.ts +1 -1
  130. package/dist/primitives/textarea.js +1 -1
  131. package/dist/primitives/typed-title.js +12 -14
  132. package/dist/primitives/typing-animation.js +4 -2
  133. package/dist/session/composer/agent-selector.js +6 -1
  134. package/dist/session/composer/attachment-tile.d.ts +0 -2
  135. package/dist/session/composer/attachment-tile.js +0 -8
  136. package/dist/session/composer/clipboard-files.d.ts +2 -1
  137. package/dist/session/composer/composer-chat-input.js +5 -3
  138. package/dist/session/composer/composer-draft-recovery.d.ts +1 -2
  139. package/dist/session/composer/composer-draft-recovery.js +0 -13
  140. package/dist/session/composer/composer-logic.js +8 -7
  141. package/dist/session/composer/context-ring.d.ts +1 -1
  142. package/dist/session/composer/context-ring.js +2 -2
  143. package/dist/session/composer/context-usage.d.ts +3 -6
  144. package/dist/session/composer/context-usage.js +3 -6
  145. package/dist/session/composer/draft/composer-draft.js +4 -4
  146. package/dist/session/composer/inbox-row-claims.d.ts +2 -2
  147. package/dist/session/composer/inbox-row-claims.js +1 -1
  148. package/dist/session/composer/pasted-text.js +3 -2
  149. package/dist/session/composer/queue-projection.d.ts +3 -2
  150. package/dist/session/composer/queued-prompt-edit.d.ts +1 -1
  151. package/dist/session/composer/reasoning-effort-selector.d.ts +2 -1
  152. package/dist/session/composer/session-composer-readiness.d.ts +7 -22
  153. package/dist/session/composer/session-composer-readiness.js +12 -40
  154. package/dist/session/composer/stores/queued-draft-store.js +3 -2
  155. package/dist/session/composer/token-progress.d.ts +1 -1
  156. package/dist/session/composer/token-progress.js +2 -2
  157. package/dist/session/header/reminder-parts.d.ts +11 -2
  158. package/dist/session/header/reminder-parts.js +9 -4
  159. package/dist/session/header/session-goal-indicator.d.ts +1 -0
  160. package/dist/session/header/session-goal-indicator.js +41 -0
  161. package/dist/session/header/session-site-header.js +2 -1
  162. package/dist/session/media/sandbox-url-detector.js +0 -7
  163. package/dist/session/outcomes/change-request-outcomes.js +24 -3
  164. package/dist/session/overrides/provider-secret-pool-editor.js +2 -1
  165. package/dist/session/panel/advanced/advanced-panel.js +3 -7
  166. package/dist/session/panel/easy/app-preview.js +12 -2
  167. package/dist/session/panel/easy/easy-panel-logic.d.ts +1 -1
  168. package/dist/session/panel/easy/easy-panel-logic.js +1 -1
  169. package/dist/session/panel/easy/outputs-card.js +2 -1
  170. package/dist/session/panel/easy/panel-card.js +5 -3
  171. package/dist/session/panel/easy/preview-load.d.ts +14 -0
  172. package/dist/session/panel/easy/preview-load.js +15 -0
  173. package/dist/session/panel/easy/step-detail-body.js +2 -7
  174. package/dist/session/panel/session-action-panel-column.js +11 -1
  175. package/dist/session/panel/session-audit-shared.d.ts +0 -4
  176. package/dist/session/panel/session-audit-shared.js +1 -1
  177. package/dist/session/panel/session-changes-shared.d.ts +2 -1
  178. package/dist/session/panel/session-panel-provider.js +6 -2
  179. package/dist/session/panel/shared/use-panel-derivations.js +6 -4
  180. package/dist/session/panel/use-session-panel-layout.js +7 -5
  181. package/dist/session/print/session-print-header.js +9 -8
  182. package/dist/session/prompts/session-permission-prompt.js +6 -3
  183. package/dist/session/status/provisioning-failure.d.ts +2 -1
  184. package/dist/session/status/session-error-banner.js +8 -6
  185. package/dist/session/status/session-starting-loader.d.ts +24 -31
  186. package/dist/session/status/session-starting-loader.js +32 -81
  187. package/dist/session/thread/chat-minimap-items.d.ts +4 -4
  188. package/dist/session/thread/first-prompt-handover.d.ts +3 -2
  189. package/dist/session/thread/message-parsing.d.ts +3 -3
  190. package/dist/session/thread/session-chat.js +15 -19
  191. package/dist/session/thread/session-history-scroll.d.ts +2 -1
  192. package/dist/session/thread/session-history.js +3 -1
  193. package/dist/session/thread/session-thread.js +1 -1
  194. package/dist/session/thread/transcript.js +13 -7
  195. package/dist/session/tool/shared/file-list.js +19 -2
  196. package/dist/session/tool/shared/infrastructure-contexts.d.ts +7 -0
  197. package/dist/session/tool/shared/infrastructure-contexts.js +7 -0
  198. package/dist/session/tool/shared/infrastructure-output.js +9 -5
  199. package/dist/session/tool/shared/infrastructure-row-header.js +9 -1
  200. package/dist/session/tool/shared/infrastructure-rows.js +7 -5
  201. package/dist/session/tool/tools/bash-tool.js +10 -6
  202. package/dist/session/tool/tools/web-search-tool.js +25 -3
  203. package/dist/session/turn/recovered-failures.d.ts +8 -0
  204. package/dist/session/turn/recovered-failures.js +32 -0
  205. package/dist/session/turn/streaming-cadence.js +5 -8
  206. package/dist/styles.css +1 -1
  207. package/dist/terminal/pty-connection.d.ts +5 -4
  208. package/dist/terminal/session-terminal-panel.js +3 -5
  209. package/dist/theme/theme.js +2 -1
  210. package/dist/workspace/index.d.ts +1 -0
  211. package/dist/workspace/index.js +1 -0
  212. package/dist/workspace/projects/modal/github-import-pickers.js +7 -6
  213. package/dist/workspace/review/review-center.js +13 -10
  214. package/dist/workspace/saved-session-skeleton-shape.d.ts +4 -3
  215. package/dist/workspace/saved-session-skeleton.d.ts +5 -1
  216. package/dist/workspace/saved-session-skeleton.js +5 -4
  217. package/dist/workspace/session-workspace.js +9 -14
  218. package/dist/workspace/sessions/deleted-session-row.js +5 -2
  219. package/dist/workspace/sidebar/footer/project-computer-nav.js +6 -4
  220. package/dist/workspace/sidebar/footer/project-goals-nav.d.ts +6 -0
  221. package/dist/workspace/sidebar/footer/project-goals-nav.js +26 -0
  222. package/dist/workspace/sidebar/footer/project-mcp-nav.js +6 -2
  223. package/dist/workspace/sidebar/modal/rename-session-modal.js +8 -3
  224. package/dist/workspace/sidebar/modal/session-embed-section.d.ts +25 -0
  225. package/dist/workspace/sidebar/modal/session-embed-section.js +71 -0
  226. package/dist/workspace/sidebar/modal/share-session-modal.js +2 -2
  227. package/dist/workspace/sidebar/nav-row-meta.js +14 -2
  228. package/dist/workspace/sidebar/project-nav-items.js +3 -0
  229. package/dist/workspace/sidebar/project-session-list.js +12 -3
  230. package/dist/workspace/sidebar/session-brief-hover-card.js +5 -8
  231. package/package.json +4 -4
  232. package/skills/kortix-ui/references/modules.md +2 -0
  233. package/dist/session/status/use-readiness-settling.d.ts +0 -18
  234. package/dist/session/status/use-readiness-settling.js +0 -43
  235. package/dist/workspace/sidebar/modal/session-public-link-section.d.ts +0 -13
  236. package/dist/workspace/sidebar/modal/session-public-link-section.js +0 -66
@@ -84,7 +84,7 @@ function ListRow({ node, onClick, onDoubleClick, onDownload, onRename, onDelete,
84
84
  (isCut || isCopied || selected) && 'ring-ring bg-ring/15 ring-1 ring-inset', isDragging && 'opacity-30', isDragOver && 'bg-primary/8'), children: [_jsx(TableCell, { children: _jsxs("div", { className: "flex min-w-0 items-center gap-2.5", children: [selectMode ? _jsx(SelectionCheck, { selected: selected, className: "shrink-0" }) : null, isDir ? (_jsx(Folder, { className: "text-muted-foreground size-4 shrink-0" })) : (getFileIcon(node.name, {
85
85
  className: 'size-4 shrink-0 text-muted-foreground',
86
86
  variant: 'monochrome',
87
- })), isRenaming ? (_jsx("input", { ref: renameInputRef, type: "text", value: renameName, onChange: (e) => setRenameName(e.target.value), onKeyDown: (e) => {
87
+ })), isRenaming ? (_jsx("input", { ref: renameInputRef, type: "text", "aria-label": tHardcodedUi.raw('i18nComplete.text3064d79a295c'), value: renameName, onChange: (e) => setRenameName(e.target.value), onKeyDown: (e) => {
88
88
  if (e.key === 'Enter') {
89
89
  if (e.nativeEvent.isComposing)
90
90
  return;
@@ -92,7 +92,7 @@ function ListRow({ node, onClick, onDoubleClick, onDownload, onRename, onDelete,
92
92
  }
93
93
  if (e.key === 'Escape')
94
94
  setIsRenaming(false);
95
- }, onBlur: confirmRename, onClick: (e) => e.stopPropagation(), className: "border-border min-w-0 flex-1 border-b bg-transparent py-0.5 text-sm outline-none" })) : (_jsx("span", { className: cn('truncate text-sm font-medium', node.ignored && 'opacity-50', node.name.startsWith('.') && 'text-muted-foreground'), children: node.name })), uploading ? (_jsx("span", { role: "status", "aria-label": tDrives('uploadingFile', { name: node.name }), className: "shrink-0", children: _jsx(Loading, { variant: "spokes", className: "size-3.5" }) })) : null] }) }), _jsx(TableCell, { children: isDir ? (_jsx(ChalkBadge, { label: tHardcodedUi.raw('i18nComplete.text74ccd4330384') })) : ext ? (_jsx(ChalkBadge, { label: ext })) : (_jsx("span", { className: "text-muted-foreground text-sm", children: "\u2014" })) }), _jsx(TableCell, { children: !isRenaming && (_jsx("div", { className: "flex justify-end", children: _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { onClick: (e) => e.stopPropagation(), variant: "ghost", size: "icon-xs", className: "shrink-0 opacity-0 group-hover:opacity-100", children: _jsx(MoreVertical, { className: "text-muted-foreground size-3.5" }) }) }), _jsx(DropdownMenuContent, { align: "end", className: "w-48", children: isDir ? (_jsx(FolderDriveMenuItems, { Item: DropdownMenuItem, Separator: DropdownMenuSeparator, ...folderMenuProps })) : (_jsx(FileDriveMenuItems, { Item: DropdownMenuItem, Separator: DropdownMenuSeparator, ...fileMenuProps })) })] }) })) })] }) }), _jsx(ContextMenuContent, { className: "w-48", children: selection?.selectionMenu(node, ContextMenuItem, ContextMenuSeparator) ?? (_jsxs(_Fragment, { children: [_jsx(SelectMenuItem, { selection: selection, node: node, Item: ContextMenuItem, Separator: ContextMenuSeparator }), isDir ? (_jsx(FolderDriveMenuItems, { Item: ContextMenuItem, Separator: ContextMenuSeparator, ...folderMenuProps })) : (_jsx(FileDriveMenuItems, { Item: ContextMenuItem, Separator: ContextMenuSeparator, ...fileMenuProps }))] })) })] }));
95
+ }, onBlur: confirmRename, onClick: (e) => e.stopPropagation(), className: "border-border min-w-0 flex-1 border-b bg-transparent py-0.5 text-sm outline-none" })) : (_jsx("span", { className: cn('truncate text-sm font-medium', node.ignored && 'opacity-50', node.name.startsWith('.') && 'text-muted-foreground'), children: node.name })), uploading ? (_jsx("span", { role: "status", "aria-label": tDrives('uploadingFile', { name: node.name }), className: "shrink-0", children: _jsx(Loading, { variant: "spokes", className: "size-3.5" }) })) : null] }) }), _jsx(TableCell, { children: isDir ? (_jsx(ChalkBadge, { label: tHardcodedUi.raw('i18nComplete.text74ccd4330384') })) : ext ? (_jsx(ChalkBadge, { label: ext })) : (_jsx("span", { className: "text-muted-foreground text-sm", children: "\u2014" })) }), _jsx(TableCell, { children: !isRenaming && (_jsx("div", { className: "flex justify-end", children: _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { onClick: (e) => e.stopPropagation(), "aria-label": tHardcodedUi.raw('i18nComplete.textf8d46c2570e7'), variant: "ghost", size: "icon-xs", className: "shrink-0 opacity-0 group-hover:opacity-100", children: _jsx(MoreVertical, { className: "text-muted-foreground size-3.5" }) }) }), _jsx(DropdownMenuContent, { align: "end", className: "w-48", children: isDir ? (_jsx(FolderDriveMenuItems, { Item: DropdownMenuItem, Separator: DropdownMenuSeparator, ...folderMenuProps })) : (_jsx(FileDriveMenuItems, { Item: DropdownMenuItem, Separator: DropdownMenuSeparator, ...fileMenuProps })) })] }) })) })] }) }), _jsx(ContextMenuContent, { className: "w-48", children: selection?.selectionMenu(node, ContextMenuItem, ContextMenuSeparator) ?? (_jsxs(_Fragment, { children: [_jsx(SelectMenuItem, { selection: selection, node: node, Item: ContextMenuItem, Separator: ContextMenuSeparator }), isDir ? (_jsx(FolderDriveMenuItems, { Item: ContextMenuItem, Separator: ContextMenuSeparator, ...folderMenuProps })) : (_jsx(FileDriveMenuItems, { Item: ContextMenuItem, Separator: ContextMenuSeparator, ...fileMenuProps }))] })) })] }));
96
96
  }
97
97
  function ElevatedDirRow({ node, onNavigate }) {
98
98
  const tI18nComplete = useTranslations('hardcodedUi.i18nComplete');
@@ -119,10 +119,10 @@ export function DriveListView({ elevatedDirs, dirs, files, onNavigateToDir, onOp
119
119
  setSortBy(field);
120
120
  }
121
121
  };
122
- const SortIcon = ({ field }) => {
122
+ const renderSortIcon = (field) => {
123
123
  if (sortDisabled || sortBy !== field)
124
124
  return null;
125
125
  return sortOrder === 'asc' ? (_jsx(ArrowUp, { className: "ml-1 size-3" })) : (_jsx(ArrowDown, { className: "ml-1 size-3" }));
126
126
  };
127
- return (_jsx("div", { className: "space-y-7 p-5", children: _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { className: "hover:bg-transparent", children: [_jsx(TableHead, { children: _jsxs(Button, { onClick: () => handleHeaderClick('name'), disabled: sortDisabled, variant: "transparent", className: "text-muted-foreground hover:text-foreground m-0 h-fit w-fit p-0 font-normal has-[>svg]:p-0", children: [tI18nComplete.raw('textdcd1d5223f73'), _jsx(SortIcon, { field: "name" })] }) }), _jsx(TableHead, { children: _jsxs(Button, { onClick: () => handleHeaderClick('type'), disabled: sortDisabled, variant: "transparent", className: "text-muted-foreground hover:text-foreground m-0 h-fit w-fit p-0 font-normal has-[>svg]:p-0", children: [tI18nComplete.raw('textbaaddf70fb5d'), _jsx(SortIcon, { field: "type" })] }) }), _jsx(TableHead, { className: "w-[52px]", children: _jsx("span", { className: "sr-only", children: tI18nComplete.raw('textff8059dc6752') }) })] }) }), _jsxs(TableBody, { children: [elevatedDirs.map((node) => (_jsx(ElevatedDirRow, { node: node, onNavigate: () => onNavigateToDir(node) }, node.path))), dirs.map((node) => (_jsx(ListRow, { node: node, onClick: () => onNavigateToDir(node), onDownload: onDownloadDir, isDownloadingItem: isDirDownloading(node.path), onRename: isFixed?.(node.path) ? undefined : onRename, onDelete: isFixed?.(node.path) ? undefined : onDelete, onCopy: onCopy, onCut: isFixed?.(node.path) ? undefined : onCut, onDropMove: onDropMove, onDropUpload: onDropUpload, isCut: clipboardOperation === 'cut' && clipboardPath === node.path, isCopied: clipboardOperation === 'copy' && clipboardPath === node.path }, node.path))), files.map((node) => (_jsx(ListRow, { node: node, onClick: () => onPreviewFile(node), onDoubleClick: () => onOpenFile(node), onDownload: onDownload, onRename: onRename, onDelete: onDelete, onHistory: onHistory, onCopy: onCopy, onCut: onCut, gitStatus: gitStatusMap.get(node.path), isCut: clipboardOperation === 'cut' && clipboardPath === node.path, isCopied: clipboardOperation === 'copy' && clipboardPath === node.path, uploading: uploadingPaths?.has(node.path) }, node.path)))] })] }) }));
127
+ return (_jsx("div", { className: "space-y-7 p-5", children: _jsxs(Table, { children: [_jsx(TableHeader, { children: _jsxs(TableRow, { className: "hover:bg-transparent", children: [_jsx(TableHead, { children: _jsxs(Button, { onClick: () => handleHeaderClick('name'), disabled: sortDisabled, variant: "transparent", className: "text-muted-foreground hover:text-foreground m-0 h-fit w-fit p-0 font-normal has-[>svg]:p-0", children: [tI18nComplete.raw('textdcd1d5223f73'), renderSortIcon('name')] }) }), _jsx(TableHead, { children: _jsxs(Button, { onClick: () => handleHeaderClick('type'), disabled: sortDisabled, variant: "transparent", className: "text-muted-foreground hover:text-foreground m-0 h-fit w-fit p-0 font-normal has-[>svg]:p-0", children: [tI18nComplete.raw('textbaaddf70fb5d'), renderSortIcon('type')] }) }), _jsx(TableHead, { className: "w-[52px]", children: _jsx("span", { className: "sr-only", children: tI18nComplete.raw('textff8059dc6752') }) })] }) }), _jsxs(TableBody, { children: [elevatedDirs.map((node) => (_jsx(ElevatedDirRow, { node: node, onNavigate: () => onNavigateToDir(node) }, node.path))), dirs.map((node) => (_jsx(ListRow, { node: node, onClick: () => onNavigateToDir(node), onDownload: onDownloadDir, isDownloadingItem: isDirDownloading(node.path), onRename: isFixed?.(node.path) ? undefined : onRename, onDelete: isFixed?.(node.path) ? undefined : onDelete, onCopy: onCopy, onCut: isFixed?.(node.path) ? undefined : onCut, onDropMove: onDropMove, onDropUpload: onDropUpload, isCut: clipboardOperation === 'cut' && clipboardPath === node.path, isCopied: clipboardOperation === 'copy' && clipboardPath === node.path }, node.path))), files.map((node) => (_jsx(ListRow, { node: node, onClick: () => onPreviewFile(node), onDoubleClick: () => onOpenFile(node), onDownload: onDownload, onRename: onRename, onDelete: onDelete, onHistory: onHistory, onCopy: onCopy, onCut: onCut, gitStatus: gitStatusMap.get(node.path), isCut: clipboardOperation === 'cut' && clipboardPath === node.path, isCopied: clipboardOperation === 'copy' && clipboardPath === node.path, uploading: uploadingPaths?.has(node.path) }, node.path)))] })] }) }));
128
128
  }
@@ -12,7 +12,7 @@ function BreadcrumbSegments({ segments, onSegmentClick, onHomeClick, fileMode, f
12
12
  // When rootPath is set, only show segments at or below it
13
13
  const rootSegmentCount = useMemo(() => (rootPath ? rootPath.split('/').filter(Boolean).length : 0), [rootPath]);
14
14
  const visibleSegments = useMemo(() => (rootPath ? segments.slice(rootSegmentCount) : segments), [rootPath, segments, rootSegmentCount]);
15
- return (_jsxs("nav", { className: "flex min-w-0 flex-1 items-center gap-0.5 overflow-x-auto", onDoubleClick: onDoubleClick, title: onDoubleClick ? tI18nComplete.raw('text5efd0bed7735') : undefined, children: [_jsx("button", { onClick: onHomeClick, className: cn('flex shrink-0 cursor-pointer items-center gap-1 rounded-lg px-2 py-1 transition-colors', 'hover:bg-muted', visibleSegments.length === 0
15
+ return (_jsxs("nav", { className: "flex min-w-0 flex-1 items-center gap-0.5 overflow-x-auto", onDoubleClick: onDoubleClick, title: onDoubleClick ? tI18nComplete.raw('text5efd0bed7735') : undefined, children: [_jsx("button", { onClick: onHomeClick, "aria-label": tI18nComplete.raw('text3a78695388b3'), className: cn('flex shrink-0 cursor-pointer items-center gap-1 rounded-lg px-2 py-1 transition-colors', 'hover:bg-muted', visibleSegments.length === 0
16
16
  ? 'text-foreground bg-muted/50 font-medium'
17
17
  : 'text-muted-foreground'), children: _jsx(FolderRoot, { className: "h-3.5 w-3.5" }) }), visibleSegments.map((segment, visibleIndex) => {
18
18
  // Skip 'workspace' when not sandboxed (rootPath null)
@@ -357,7 +357,7 @@ export function FileExplorerPage({ embedded = false } = {}) {
357
357
  gridTemplateColumns: "repeat(auto-fill, minmax(150px, 1fr))",
358
358
  }, children: Array.from({ length: 8 }).map((_, i) => (_jsx(Skeleton, { className: "h-[138px] rounded-lg" }, `fi${i}`))) })] })] })) : (_jsx("div", { className: "space-y-1", children: Array.from({ length: 10 }).map((_, i) => (_jsx(Skeleton, { className: "h-10 w-full rounded" }, i))) })) })), !!error && !isLoading && (_jsx(ErrorState, { title: tHardcodedUi.raw('featuresProjectFilesComponentsFileExplorerPage.line658JsxTextFailedToLoadFiles'), description: error instanceof Error
359
359
  ? error.message
360
- : tHardcodedUi.raw('i18nComplete.text27c2ccd962c2'), action: _jsx(Button, { variant: "outline", size: "sm", onClick: () => refetchFiles(), children: tHardcodedUi.raw('i18nComplete.text942087cc2d41') }) })), isEmpty && (_jsx(EmptyState, { icon: FolderOpen, title: tHardcodedUi.raw('featuresProjectFilesComponentsDriveListView.line396JsxTextThisFolderIsEmpty'), description: tHardcodedUi.raw('featuresProjectFilesComponentsDriveListView.line398JsxTextNoFilesOrSubfoldersAtThisPathIn') })), !isLoading && !error && files && !isEmpty && (_jsxs(_Fragment, { children: [viewMode === 'grid' ? (_jsx(DriveGridView, { elevatedDirs: elevatedDirs, dirs: dirs, files: fileItems, onNavigateToDir: handleNavigateToDir, onOpenFile: handleOpenFile, onPreviewFile: handlePreviewFile, onDownload: handleDownload, onDownloadDir: handleDownloadDir, onRename: handleRename, onDelete: handleDelete, onHistory: handleHistory, onCopy: handleCopy, onCut: handleCut, onDropMove: handleDropMove, gitStatusMap: gitStatusMap, clipboardPath: clipboard?.path, clipboardOperation: clipboard?.operation, isDirDownloading: isDirDownloading, readOnly: true })) : (_jsx(DriveListView, { elevatedDirs: elevatedDirs, dirs: dirs, files: fileItems, sortDisabled: partial, onNavigateToDir: handleNavigateToDir, onOpenFile: handleOpenFile, onPreviewFile: handlePreviewFile, onDownload: handleDownload, onDownloadDir: handleDownloadDir, onRename: handleRename, onDelete: handleDelete, onHistory: handleHistory, onCopy: handleCopy, onCut: handleCut, onDropMove: handleDropMove, gitStatusMap: gitStatusMap, clipboardPath: clipboard?.path, clipboardOperation: clipboard?.operation, isDirDownloading: isDirDownloading, readOnly: true })), _jsx(LoadMoreRow, { listing: listing })] }))] }), _jsx(CheckpointsPanel, { open: rightPanel === 'history', onClose: () => setRightPanel(null) }), _jsx(ChangeRequestsPanel, { open: rightPanel === 'proposed-changes', onClose: () => setRightPanel(null) })] }), _jsx(ChangeRequestDetailDialog, { crId: createdCrId, onClose: () => setCreatedCrId(null) }), _jsx(ExplorerFilePreview, {}), searchEnabled && isSearchOpen && _jsx(FileSearch, {}), historyPopoverPath && (_jsx("div", { className: "bg-popover border-border animate-in slide-in-from-bottom-4 fade-in-0 fixed right-4 bottom-4 z-50 overflow-hidden rounded-md border shadow-2xl duration-200", children: _jsx(FileHistoryPopoverContent, { filePath: historyPopoverPath, onClose: () => setHistoryPopoverPath(null) }) })), _jsx(AlertDialog, { open: !!deleteTarget, onOpenChange: () => setDeleteTarget(null), children: _jsxs(AlertDialogContent, { className: "sm:max-w-md", onOpenAutoFocus: (e) => {
360
+ : tHardcodedUi.raw('i18nComplete.text27c2ccd962c2'), action: _jsx(Button, { variant: "outline", size: "sm", onClick: () => refetchFiles(), children: tHardcodedUi.raw('i18nComplete.text942087cc2d41') }) })), isEmpty && (_jsx(EmptyState, { icon: FolderOpen, title: tHardcodedUi.raw('featuresProjectFilesComponentsDriveListView.line396JsxTextThisFolderIsEmpty'), description: tHardcodedUi.raw('featuresProjectFilesComponentsDriveListView.line398JsxTextNoFilesOrSubfoldersAtThisPathIn') })), !isLoading && !error && files && !isEmpty && (_jsxs(_Fragment, { children: [viewMode === 'grid' ? (_jsx(DriveGridView, { elevatedDirs: elevatedDirs, dirs: dirs, files: fileItems, onNavigateToDir: handleNavigateToDir, onOpenFile: handleOpenFile, onPreviewFile: handlePreviewFile, onDownload: handleDownload, onDownloadDir: handleDownloadDir, onRename: handleRename, onDelete: handleDelete, onHistory: handleHistory, onCopy: handleCopy, onCut: handleCut, onDropMove: handleDropMove, gitStatusMap: gitStatusMap, clipboardPath: clipboard?.path, clipboardOperation: clipboard?.operation, isDirDownloading: isDirDownloading, readOnly: true })) : (_jsx(DriveListView, { elevatedDirs: elevatedDirs, dirs: dirs, files: fileItems, sortDisabled: partial, onNavigateToDir: handleNavigateToDir, onOpenFile: handleOpenFile, onPreviewFile: handlePreviewFile, onDownload: handleDownload, onDownloadDir: handleDownloadDir, onRename: handleRename, onDelete: handleDelete, onHistory: handleHistory, onCopy: handleCopy, onCut: handleCut, onDropMove: handleDropMove, gitStatusMap: gitStatusMap, clipboardPath: clipboard?.path, clipboardOperation: clipboard?.operation, isDirDownloading: isDirDownloading, readOnly: true })), _jsx(LoadMoreRow, { listing: listing })] }))] }), _jsx(CheckpointsPanel, { open: rightPanel === 'history', onClose: () => setRightPanel(null) }), _jsx(ChangeRequestsPanel, { open: rightPanel === 'proposed-changes', onClose: () => setRightPanel(null) })] }), _jsx(ChangeRequestDetailDialog, { crId: createdCrId, onClose: () => setCreatedCrId(null), onOpenChangeRequest: setCreatedCrId }), _jsx(ExplorerFilePreview, {}), searchEnabled && isSearchOpen && _jsx(FileSearch, {}), historyPopoverPath && (_jsx("div", { className: "bg-popover border-border animate-in slide-in-from-bottom-4 fade-in-0 fixed right-4 bottom-4 z-50 overflow-hidden rounded-md border shadow-2xl duration-200", children: _jsx(FileHistoryPopoverContent, { filePath: historyPopoverPath, onClose: () => setHistoryPopoverPath(null) }) })), _jsx(AlertDialog, { open: !!deleteTarget, onOpenChange: () => setDeleteTarget(null), children: _jsxs(AlertDialogContent, { className: "sm:max-w-md", onOpenAutoFocus: (e) => {
361
361
  e.preventDefault();
362
362
  deleteButtonRef.current?.focus();
363
363
  }, children: [_jsxs(AlertDialogHeader, { children: [_jsxs(AlertDialogTitle, { children: [tHardcodedUi.raw('i18nComplete.texte2d0a54968ea'), ' ', deleteTarget?.type === 'directory' ? 'folder' : 'file'] }), _jsxs(AlertDialogDescription, { children: [tHardcodedUi.raw('featuresProjectFilesComponentsFileExplorerPage.line806JsxTextAreYouSureYouWantToDelete'), ' ', _jsxs("span", { className: "text-foreground font-semibold", children: [tHardcodedUi.raw('featuresProjectFilesComponentsFileExplorerPage.line807JsxTextQuot'), deleteTarget?.name, tHardcodedUi.raw('featuresProjectFilesComponentsFileExplorerPage.line807JsxTextQuot32c14d98')] }), tHardcodedUi.raw('featuresProjectFilesComponentsFileExplorerPage.line807JsxTextThisActionCannotBeUndone')] })] }), _jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, { disabled: deleteMutation.isPending, children: tHardcodedUi.raw('i18nComplete.text19766ed6ccb2') }), _jsx(AlertDialogAction, { ref: deleteButtonRef, onClick: (e) => {
@@ -83,12 +83,7 @@ function CompactCommitRow({ commit, filePath }) {
83
83
  setTimeout(() => setCopied(false), 2000);
84
84
  }, [commit.hash]);
85
85
  const toggle = () => setExpanded((v) => !v);
86
- return (_jsxs("li", { className: cn('relative rounded-md', expanded && 'bg-muted'), children: [_jsxs("div", { role: "button", tabIndex: 0, "aria-expanded": expanded, onClick: toggle, onKeyDown: (e) => {
87
- if (e.key === 'Enter' || e.key === ' ') {
88
- e.preventDefault();
89
- toggle();
90
- }
91
- }, className: cn('group/row focus-visible:ring-ring flex w-full cursor-pointer items-start gap-3 rounded-md px-2 py-2 text-left outline-none focus-visible:ring-1', !expanded && 'hover:bg-muted'), children: [_jsx("span", { className: "border-muted-foreground bg-background relative z-10 mt-[5px] size-2.5 shrink-0 rounded-full border" }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("p", { className: "text-foreground truncate text-sm font-medium", children: commit.subject }), _jsxs(InlineMeta, { className: "mt-0.5", children: [commit.author, _jsx("time", { title: formatFullDate(commit.timestamp), children: formatRelativeDate(commit.timestamp) })] })] }), _jsxs("button", { type: "button", onClick: handleCopyHash, className: "text-muted-foreground hover:text-foreground flex shrink-0 items-center gap-1 rounded-sm px-1 font-mono text-xs leading-5", title: tHardcodedUi.raw('featuresProjectFilesComponentsFileHistoryPopover.line160JsxAttrTitleCopyCheckpointId'), children: [copied ? (_jsx(SolidCheckIcon, { className: "text-kortix-green size-3" })) : (_jsx(Copy, { className: "size-3 opacity-0 group-hover/row:opacity-100" })), commit.shortHash] })] }), expanded && _jsx(CompactCommitDiff, { filePath: filePath, commitHash: commit.hash })] }));
86
+ return (_jsxs("li", { className: cn('relative rounded-md', expanded && 'bg-muted'), children: [_jsxs("div", { className: cn('group/row has-[button[aria-expanded]:focus-visible]:ring-ring flex w-full items-start gap-3 rounded-md has-[button[aria-expanded]:focus-visible]:ring-1', !expanded && 'hover:bg-muted'), children: [_jsxs("button", { type: "button", "aria-expanded": expanded, onClick: toggle, className: "flex min-w-0 flex-1 cursor-pointer items-start gap-3 py-2 pl-2 text-left outline-none", children: [_jsx("span", { className: "border-muted-foreground bg-background relative z-10 mt-[5px] size-2.5 shrink-0 rounded-full border" }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("p", { className: "text-foreground truncate text-sm font-medium", children: commit.subject }), _jsxs(InlineMeta, { className: "mt-0.5", children: [commit.author, _jsx("time", { title: formatFullDate(commit.timestamp), children: formatRelativeDate(commit.timestamp) })] })] })] }), _jsxs("button", { type: "button", onClick: handleCopyHash, className: "text-muted-foreground hover:text-foreground my-2 mr-2 flex shrink-0 items-center gap-1 rounded-sm px-1 font-mono text-xs leading-5", title: tHardcodedUi.raw('featuresProjectFilesComponentsFileHistoryPopover.line160JsxAttrTitleCopyCheckpointId'), children: [copied ? (_jsx(SolidCheckIcon, { className: "text-kortix-green size-3" })) : (_jsx(Copy, { className: "size-3 opacity-0 group-hover/row:opacity-100" })), commit.shortHash] })] }), expanded && _jsx(CompactCommitDiff, { filePath: filePath, commitHash: commit.hash })] }));
92
87
  }
93
88
  export function FileHistoryPopoverContent({ filePath, onClose }) {
94
89
  const tHardcodedUi = useTranslations('hardcodedUi');
@@ -112,7 +112,12 @@ export function FileSearch() {
112
112
  }
113
113
  }
114
114
  }, [closeSearch, results, selectedIndex, handleSelect, scrollItemIntoView]);
115
- return (_jsx("div", { className: "absolute inset-0 z-50 bg-black/60 backdrop-blur-sm", onClick: closeSearch, children: _jsx("div", { className: "mx-auto mt-4 max-w-lg px-4", onClick: (e) => e.stopPropagation(), children: _jsxs("div", { className: "border-border bg-card overflow-hidden rounded-2xl border shadow-2xl", children: [_jsxs("div", { className: "flex items-center gap-2 border-b px-3", children: [_jsx(Search, { className: "text-muted-foreground h-4 w-4 shrink-0" }), _jsx(Input, { type: "text", ref: inputRef, value: query, onChange: (e) => setQuery(e.target.value), onKeyDown: handleInputKeyDown, placeholder: tHardcodedUi.raw(searchContents
115
+ return (_jsx("div", { role: "presentation", className: "absolute inset-0 z-50 bg-black/60 backdrop-blur-sm", onClick: (e) => {
116
+ if (e.target === e.currentTarget)
117
+ closeSearch();
118
+ else
119
+ e.stopPropagation();
120
+ }, children: _jsx("div", { className: "mx-auto mt-4 max-w-lg px-4", children: _jsxs("div", { className: "border-border bg-card overflow-hidden rounded-2xl border shadow-2xl", children: [_jsxs("div", { className: "flex items-center gap-2 border-b px-3", children: [_jsx(Search, { className: "text-muted-foreground h-4 w-4 shrink-0" }), _jsx(Input, { type: "text", ref: inputRef, value: query, onChange: (e) => setQuery(e.target.value), onKeyDown: handleInputKeyDown, placeholder: tHardcodedUi.raw(searchContents
116
121
  ? 'featuresProjectFilesComponentsFileSearch.searchContentsPlaceholder'
117
122
  : 'featuresProjectFilesComponentsFileSearch.line109JsxAttrPlaceholderSearchFiles'), className: "h-10 border-0 px-0 shadow-none focus-visible:ring-0" }), _jsx("button", { onClick: closeSearch, "aria-label": tI18nHardcoded.raw('autoFeaturesProjectFilesComponentsFileSearchJsxAttrAriaLabel732c1816'), className: "hover:bg-muted rounded p-1", children: _jsx(X, { className: "text-muted-foreground h-4 w-4" }) })] }), canSearchContents && (_jsx("div", { className: "flex items-center border-b", children: _jsx(Switch, { label: tHardcodedUi.raw('featuresProjectFilesComponentsFileSearch.searchContents'), "aria-label": tHardcodedUi.raw('featuresProjectFilesComponentsFileSearch.searchContents'), checked: contentMode, onCheckedChange: (checked) => {
118
123
  setContentMode(checked);
@@ -30,6 +30,7 @@ function BranchRow({ branch }) {
30
30
  const tI18nComplete = useTranslations('hardcodedUi.i18nComplete');
31
31
  return (_jsxs("div", { className: "flex items-center justify-start gap-2 py-0.5", children: [_jsx(Layers, { className: "text-muted-foreground size-4 shrink-0" }), _jsxs("div", { className: "flex flex-col items-start gap-0", children: [branch.subject && (_jsx("span", { className: "text-muted-foreground/80 truncate text-xs", children: branch.subject })), _jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx("span", { className: "text-foreground truncate font-mono text-xs", children: displayBranchName(branch.name) }), branch.is_default && (_jsx(Badge, { variant: "kortix", size: "xs", className: "shrink-0 text-[11px]", children: tI18nComplete.raw('text37a8eec1ce19') }))] })] })] }));
32
32
  }
33
+ const NO_BRANCHES = [];
33
34
  const PICKER_TRIGGER_CLASS = 'py-2 flex-1 min-w-0 rounded-sm border-0 bg-transparent px-2 hover:bg-muted/40 focus:ring-0';
34
35
  export function OpenChangeRequestDialog({ open, onOpenChange, projectId, defaultBranch, session = null, initialHeadRef, onCreated, }) {
35
36
  const tHardcodedUi = useTranslations('hardcodedUi');
@@ -41,7 +42,7 @@ export function OpenChangeRequestDialog({ open, onOpenChange, projectId, default
41
42
  const activeSession = session ?? lastSessionRef.current;
42
43
  const sessionMode = activeSession !== null;
43
44
  const branchesQuery = useBranches({ enabled: open && !sessionMode, projectId });
44
- const branches = branchesQuery.data?.branches ?? [];
45
+ const branches = branchesQuery.data?.branches ?? NO_BRANCHES;
45
46
  const branchMap = useMemo(() => {
46
47
  const m = new Map();
47
48
  for (const b of branches)
@@ -0,0 +1,11 @@
1
+ import type { ProjectBranch } from '@kortix/sdk';
2
+ /** A session branch is named by its session id. A person knows it by the session's title (KRTX-3020). */
3
+ export declare function versionTitle(branch: ProjectBranch): string;
4
+ /** Search reads the title, the agent, the branch name and the last commit. */
5
+ export declare function versionMatches(branch: ProjectBranch, query: string): boolean;
6
+ /** The default branch, live work, then what the person archived or deleted, each in served order. */
7
+ export declare function groupVersions(branches: ProjectBranch[]): {
8
+ primary: ProjectBranch[];
9
+ others: ProjectBranch[];
10
+ archived: ProjectBranch[];
11
+ };
@@ -0,0 +1,26 @@
1
+ /** A session branch is named by its session id. A person knows it by the session's title (KRTX-3020). */
2
+ export function versionTitle(branch) {
3
+ return branch.session?.title?.trim() || branch.name;
4
+ }
5
+ /** Search reads the title, the agent, the branch name and the last commit. */
6
+ export function versionMatches(branch, query) {
7
+ const q = query.trim().toLowerCase();
8
+ if (!q)
9
+ return true;
10
+ return [branch.session?.title, branch.session?.agent_name, branch.name, branch.subject].some((value) => value?.toLowerCase().includes(q));
11
+ }
12
+ /** The default branch, live work, then what the person archived or deleted, each in served order. */
13
+ export function groupVersions(branches) {
14
+ const primary = [];
15
+ const others = [];
16
+ const archived = [];
17
+ for (const b of branches) {
18
+ if (b.is_default)
19
+ primary.push(b);
20
+ else if (b.session?.archived || b.session?.deleted)
21
+ archived.push(b);
22
+ else
23
+ others.push(b);
24
+ }
25
+ return { primary, others, archived };
26
+ }
@@ -13,6 +13,7 @@ import { useMemo, useState } from 'react';
13
13
  import { useProjectContext } from '../context.js';
14
14
  import { useBranches } from '../hooks/use-branches.js';
15
15
  import { useVersionStore } from '../store/version-store.js';
16
+ import { groupVersions, versionMatches, versionTitle } from './version-selector-logic.js';
16
17
  /** Shared formatter, hoisted so each row render does not rebuild the Intl
17
18
  * machinery. Same options as the old `toLocaleDateString` call — identical output. */
18
19
  const commitDateFormatter = new Intl.DateTimeFormat(undefined, {
@@ -30,24 +31,10 @@ export function VersionSelector() {
30
31
  const { data, isLoading, error } = useBranches({ enabled: open || activeRef !== '' });
31
32
  const defaultBranch = data?.default_branch ?? activeRef;
32
33
  const isOnMain = activeRef === defaultBranch;
33
- const filtered = useMemo(() => {
34
- const branches = data?.branches ?? [];
35
- const trimmed = query.trim().toLowerCase();
36
- if (!trimmed)
37
- return branches;
38
- return branches.filter((b) => b.name.toLowerCase().includes(trimmed) || b.subject.toLowerCase().includes(trimmed));
39
- }, [data?.branches, query]);
40
- const { primary, others } = useMemo(() => {
41
- const primary = [];
42
- const others = [];
43
- for (const b of filtered) {
44
- if (b.is_default)
45
- primary.push(b);
46
- else
47
- others.push(b);
48
- }
49
- return { primary, others };
50
- }, [filtered]);
34
+ const filtered = useMemo(() => (data?.branches ?? []).filter((b) => versionMatches(b, query)), [data?.branches, query]);
35
+ const { primary, others, archived } = useMemo(() => groupVersions(filtered), [filtered]);
36
+ const activeBranch = data?.branches.find((b) => b.name === activeRef);
37
+ const activeLabel = activeBranch ? versionTitle(activeBranch) : activeRef;
51
38
  const handleSelect = (branchName) => {
52
39
  setVersion(projectId, branchName === defaultBranch ? null : branchName);
53
40
  setOpen(false);
@@ -57,10 +44,14 @@ export function VersionSelector() {
57
44
  setOpen(v);
58
45
  if (!v)
59
46
  setQuery('');
60
- }, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(Button, { variant: "outline-ghost", type: "button", size: "sm", className: cn('w-30 max-w-[300px] min-w-0 shrink-0 justify-between'), title: tHardcodedUi.raw('featuresProjectFilesComponentsVersionSelector.line88JsxAttrTitleSwitchVersion'), children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Layers, { className: "text-muted-foreground size-3.5 shrink-0" }), _jsx("span", { className: "truncate", children: activeRef || 'Version' })] }), _jsx(ChevronsUpDown, { className: "text-muted-foreground size-3 shrink-0" })] }) }), _jsxs(PopoverContent, { align: "start", sideOffset: 6, className: "flex w-[340px] flex-col overflow-hidden p-0", children: [_jsxs("div", { className: "border-border flex shrink-0 items-center gap-1.5 border-b px-3 py-2", children: [_jsx(Search, { className: "text-muted-foreground/60 h-3.5 w-3.5 shrink-0" }), _jsx("input", { type: "text", value: query, onChange: (e) => setQuery(e.target.value), placeholder: tHardcodedUi.raw('featuresProjectFilesComponentsVersionSelector.line112JsxAttrPlaceholderFindAVersion'), className: "text-foreground placeholder:text-muted-foreground/50 h-7 min-w-0 flex-1 border-0 bg-transparent px-0 text-sm outline-none", autoFocus: true })] }), _jsx("div", { className: "h-[520px] max-h-[calc(100vh-8rem)] min-h-0 shrink", children: _jsxs(FadedScrollArea, { fadeColor: "from-popover", className: "h-full overscroll-contain", children: [isLoading && (_jsxs("div", { className: "text-muted-foreground flex items-center justify-center gap-2 py-8 text-xs", children: [_jsx(Loading, { className: "size-3.5" }), tHardcodedUi.raw('featuresProjectFilesComponentsVersionSelector.line122JsxTextLoadingVersions')] })), error && !isLoading && (_jsx("div", { className: "text-muted-foreground px-4 py-8 text-center text-xs", children: tHardcodedUi.raw('featuresProjectFilesComponentsVersionSelector.line128JsxTextFailedToLoadVersions') })), !isLoading && !error && filtered.length === 0 && (_jsxs("div", { className: "text-muted-foreground px-4 py-8 text-center text-xs", children: [tHardcodedUi.raw('featuresProjectFilesComponentsVersionSelector.line134JsxTextNoVersionsMatch'), ' ', query ? `“${query}”` : ''] })), primary.length > 0 && (_jsxs("div", { className: cn('space-y-3 p-3', others.length > 0 ? 'pb-0' : 'pb-3'), children: [_jsx(Label, { children: tHardcodedUi.raw('featuresProjectFilesComponentsVersionSelector.line140JsxTextMainVersion') }), primary.map((b) => (_jsx(VersionRow, { branch: b, isActive: activeRef === b.name, onClick: () => handleSelect(b.name) }, b.name)))] })), others.length > 0 && (_jsxs("div", { className: "space-y-3 p-3 pb-3", children: [_jsx(Label, { children: tHardcodedUi.raw('featuresProjectFilesComponentsVersionSelector.line154JsxTextOtherVersions') }), others.map((b) => (_jsx(VersionRow, { branch: b, isActive: activeRef === b.name, onClick: () => handleSelect(b.name) }, b.name)))] }))] }) })] })] }));
47
+ }, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs(Button, { variant: "outline-ghost", type: "button", size: "sm", className: "max-w-48 min-w-30 shrink-0 justify-between", title: tHardcodedUi.raw('featuresProjectFilesComponentsVersionSelector.line88JsxAttrTitleSwitchVersion'), children: [_jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [_jsx(Layers, { className: "text-muted-foreground size-3.5 shrink-0" }), _jsx("span", { className: "truncate", children: activeLabel || 'Version' })] }), _jsx(ChevronsUpDown, { className: "text-muted-foreground size-3 shrink-0" })] }) }), _jsxs(PopoverContent, { align: "start", sideOffset: 6, className: "flex w-[340px] flex-col overflow-hidden p-0", children: [_jsxs("div", { className: "border-border flex shrink-0 items-center gap-1.5 border-b px-3 py-2", children: [_jsx(Search, { className: "text-muted-foreground h-3.5 w-3.5 shrink-0" }), _jsx("input", { type: "text", value: query, onChange: (e) => setQuery(e.target.value), placeholder: tHardcodedUi.raw('featuresProjectFilesComponentsVersionSelector.line112JsxAttrPlaceholderFindAVersion'), className: "text-foreground placeholder:text-muted-foreground h-7 min-w-0 flex-1 border-0 bg-transparent px-0 text-sm outline-none" })] }), _jsx("div", { className: "h-[520px] max-h-[calc(100vh-8rem)] min-h-0 shrink", children: _jsxs(FadedScrollArea, { fadeColor: "from-popover", className: "h-full overscroll-contain", children: [isLoading && (_jsxs("div", { className: "text-muted-foreground flex items-center justify-center gap-2 py-8 text-xs", children: [_jsx(Loading, { className: "size-3.5" }), tHardcodedUi.raw('featuresProjectFilesComponentsVersionSelector.line122JsxTextLoadingVersions')] })), error && !isLoading && (_jsx("div", { className: "text-muted-foreground px-4 py-8 text-center text-xs", children: tHardcodedUi.raw('featuresProjectFilesComponentsVersionSelector.line128JsxTextFailedToLoadVersions') })), !isLoading && !error && filtered.length === 0 && (_jsxs("div", { className: "text-muted-foreground px-4 py-8 text-center text-xs", children: [tHardcodedUi.raw('featuresProjectFilesComponentsVersionSelector.line134JsxTextNoVersionsMatch'), ' ', query ? `“${query}”` : ''] })), primary.length > 0 && (_jsxs("div", { className: cn('space-y-3 p-3', others.length + archived.length > 0 ? 'pb-0' : 'pb-3'), children: [_jsx(Label, { children: tHardcodedUi.raw('featuresProjectFilesComponentsVersionSelector.line140JsxTextMainVersion') }), primary.map((b) => (_jsx(VersionRow, { branch: b, isActive: activeRef === b.name, onClick: () => handleSelect(b.name) }, b.name)))] })), others.length > 0 && (_jsxs("div", { className: cn('space-y-3 p-3', archived.length > 0 ? 'pb-0' : 'pb-3'), children: [_jsx(Label, { children: tHardcodedUi.raw('featuresProjectFilesComponentsVersionSelector.line154JsxTextOtherVersions') }), others.map((b) => (_jsx(VersionRow, { branch: b, isActive: activeRef === b.name, onClick: () => handleSelect(b.name) }, b.name)))] })), archived.length > 0 && (_jsxs("div", { className: "space-y-3 p-3 pb-3", children: [_jsx(Label, { children: tHardcodedUi.raw('i18nComplete.textbdb86505f806') }), archived.map((b) => (_jsx(VersionRow, { branch: b, isActive: activeRef === b.name, onClick: () => handleSelect(b.name) }, b.name)))] }))] }) })] })] }));
61
48
  }
62
49
  function VersionRow({ branch, isActive, onClick, }) {
63
50
  const tHardcodedUi = useTranslations('hardcodedUi');
64
51
  const date = branch.committed_at ? commitDateFormatter.format(new Date(branch.committed_at)) : '';
65
- return (_jsxs("button", { type: "button", onClick: onClick, className: cn('border-border bg-popover hover:bg-foreground/4 flex w-full cursor-pointer items-start gap-2.5 rounded-md px-3 py-2 text-left', isActive && 'bg-primary/5'), children: [_jsx("div", { className: "mt-0.5 flex size-4 shrink-0 items-center justify-center", children: isActive ? (_jsx(Check, { className: "text-primary size-3.5" })) : (_jsx(Layers, { className: "text-muted-foreground size-3.5" })) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx("span", { className: "text-foreground truncate text-sm font-medium", children: branch.name }), branch.is_default && (_jsx(Badge, { variant: "kortix", size: "xs", children: tHardcodedUi.raw('i18nComplete.texteb814be3ca3b') }))] }), _jsxs("div", { className: "text-muted-foreground/80 mt-0.5 flex items-center gap-1.5 text-xs", children: [date && (_jsxs("span", { children: [tHardcodedUi.raw('i18nComplete.text3a5ecca188c0'), " ", date] })), !branch.is_default && branch.ahead != null && branch.behind != null && (_jsxs(_Fragment, { children: [date && _jsx("span", { className: "text-muted-foreground/40", children: "\u00B7" }), _jsxs("span", { className: "inline-flex items-center gap-1 tabular-nums", title: tHardcodedUi.raw('featuresProjectFilesComponentsVersionSelector.line234JsxAttrTitleAheadBehindMainVersion'), children: [_jsxs("span", { className: "text-kortix-green inline-flex items-center gap-0.5", children: [_jsx(ArrowUpRight, { className: "h-2.5 w-2.5" }), branch.ahead] }), _jsxs("span", { className: "text-kortix-red inline-flex items-center gap-0.5", children: [_jsx(ArrowDownLeft, { className: "h-2.5 w-2.5" }), branch.behind] })] })] }))] }), branch.subject && (_jsx("div", { className: "text-muted-foreground/70 mt-0.5 truncate text-xs", children: branch.subject }))] })] }));
52
+ const title = versionTitle(branch);
53
+ const agent = branch.session?.agent_name;
54
+ return (_jsxs("button", { type: "button", onClick: onClick,
55
+ // The id stays one hover away, and search still finds it.
56
+ title: title === branch.name ? undefined : branch.name, className: cn('border-border bg-popover hover:bg-foreground/4 flex w-full cursor-pointer items-start gap-2.5 rounded-md px-3 py-2 text-left', isActive && 'bg-primary/5'), children: [_jsx("div", { className: "mt-0.5 flex size-4 shrink-0 items-center justify-center", children: isActive ? (_jsx(Check, { className: "text-primary size-3.5" })) : (_jsx(Layers, { className: "text-muted-foreground size-3.5" })) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsxs("div", { className: "flex items-center gap-1.5", children: [_jsx("span", { className: "text-foreground truncate text-sm font-medium", children: title }), branch.is_default && (_jsx(Badge, { variant: "kortix", size: "xs", children: tHardcodedUi.raw('i18nComplete.texteb814be3ca3b') })), branch.session?.deleted && (_jsx(Badge, { variant: "outline", size: "xs", children: tHardcodedUi.raw('i18nComplete.textb48ff39c2e0f') }))] }), _jsxs("div", { className: "text-muted-foreground mt-0.5 flex items-center gap-1.5 text-xs", children: [agent && _jsx("span", { className: "truncate", children: agent }), agent && date && _jsx("span", { className: "text-muted-foreground", children: "\u00B7" }), date && (_jsxs("span", { children: [tHardcodedUi.raw('i18nComplete.text3a5ecca188c0'), " ", date] })), !branch.is_default && branch.ahead != null && branch.behind != null && (_jsxs(_Fragment, { children: [date && _jsx("span", { className: "text-muted-foreground", children: "\u00B7" }), _jsxs("span", { className: "inline-flex items-center gap-1 tabular-nums", title: tHardcodedUi.raw('featuresProjectFilesComponentsVersionSelector.line234JsxAttrTitleAheadBehindMainVersion'), children: [_jsxs("span", { className: "text-kortix-green inline-flex items-center gap-0.5", children: [_jsx(ArrowUpRight, { className: "h-2.5 w-2.5" }), branch.ahead] }), _jsxs("span", { className: "text-kortix-red inline-flex items-center gap-0.5", children: [_jsx(ArrowDownLeft, { className: "h-2.5 w-2.5" }), branch.behind] })] })] }))] }), branch.subject && (_jsx("div", { className: "text-muted-foreground mt-0.5 truncate text-xs", children: branch.subject }))] })] }));
66
57
  }
@@ -1,4 +1,9 @@
1
1
  'use client';
2
+ import { useQueryClient } from '@tanstack/react-query';
3
+ import { writeProjectFile } from '@kortix/sdk';
4
+ import { fileContentKeys } from './hooks/use-file-content.js';
5
+ import { useProjectCan } from '../../internal/lib/use-project-can.js';
6
+ import { PROJECT_ACTIONS } from '../../internal/lib/project-actions.js';
2
7
  import { useMemo } from 'react';
3
8
  import { downloadFile, uploadFile } from './api/runtime-files.js';
4
9
  import { FilePathBreadcrumbs } from './components/file-breadcrumbs.js';
@@ -16,6 +21,8 @@ import { useBinaryBlob } from './hooks/use-binary-blob.js';
16
21
  */
17
22
  export function useProjectFileSource() {
18
23
  const ctx = useProjectContext();
24
+ const queryClient = useQueryClient();
25
+ const canWrite = useProjectCan(ctx?.projectId ?? '', PROJECT_ACTIONS.PROJECT_FILE_WRITE).allowed === true;
19
26
  return useMemo(() => ({
20
27
  id: 'project-ref',
21
28
  useFileContent,
@@ -25,6 +32,16 @@ export function useProjectFileSource() {
25
32
  ? downloadFile(ctx.projectId, ctx.ref, filePath, fileName)
26
33
  : Promise.reject(new Error('No project context for download')),
27
34
  upload: uploadFile,
35
+ editablePreview: canWrite,
36
+ save: ctx && canWrite ? async (filePath, file, revision) => {
37
+ if (!revision)
38
+ throw new Error('Reload the file before saving.');
39
+ await writeProjectFile(ctx.projectId, {
40
+ path: filePath.replace(/^\/workspace\//, '').replace(/^\//, ''), ref: ctx.ref,
41
+ content: await file.text(), expected_revision: revision,
42
+ });
43
+ await queryClient.invalidateQueries({ queryKey: fileContentKeys.all });
44
+ } : undefined,
28
45
  Breadcrumbs: FilePathBreadcrumbs,
29
- }), [ctx]);
46
+ }), [ctx, canWrite, queryClient]);
30
47
  }
@@ -20,6 +20,8 @@ export function useFileContent(filePath, options) {
20
20
  staleTime: options?.staleTime ?? 10_000,
21
21
  gcTime: 5 * 60_000,
22
22
  refetchOnWindowFocus: false,
23
+ // A revision used for edits must remain paired with the displayed text.
24
+ refetchOnMount: false,
23
25
  retry: (failureCount, error) => {
24
26
  const msg = error.message.toLowerCase();
25
27
  if (msg.includes('404') ||
@@ -18,19 +18,21 @@ export function useServerHealth(_options) {
18
18
  * git-status gate (`project?.vcs === 'git'`) continues to behave correctly.
19
19
  */
20
20
  export function useCurrentProject(_options) {
21
- const data = {
22
- id: 'project-files',
23
- worktree: '/workspace',
24
- vcs: 'git',
25
- name: 'project',
26
- time: { created: Date.now(), updated: Date.now() },
27
- sandboxes: [],
28
- };
29
- return useMemo(() => ({
30
- data,
31
- isLoading: false,
32
- isError: false,
33
- error: null,
34
- refetch: async () => ({ data }),
35
- }), []);
21
+ return useMemo(() => {
22
+ const data = {
23
+ id: 'project-files',
24
+ worktree: '/workspace',
25
+ vcs: 'git',
26
+ name: 'project',
27
+ time: { created: Date.now(), updated: Date.now() },
28
+ sandboxes: [],
29
+ };
30
+ return {
31
+ data,
32
+ isLoading: false,
33
+ isError: false,
34
+ error: null,
35
+ refetch: async () => ({ data }),
36
+ };
37
+ }, []);
36
38
  }
@@ -196,11 +196,6 @@ function DocxPageNumberControl({ activePageStore, controlsDisabled, onPageChange
196
196
  const displayPage = pageCount ? activePage : 1;
197
197
  const [isEditing, setIsEditing] = React.useState(false);
198
198
  const [draftPage, setDraftPage] = React.useState(() => String(displayPage));
199
- React.useEffect(() => {
200
- if (!isEditing) {
201
- setDraftPage(String(displayPage));
202
- }
203
- }, [displayPage, isEditing]);
204
199
  React.useEffect(() => {
205
200
  if (!isEditing)
206
201
  return;
@@ -55,11 +55,10 @@ export function ImageRenderer({ url, className, fileName, controls = 'hover', ba
55
55
  const [rotation, setRotation] = useState(0);
56
56
  const [isPanning, setIsPanning] = useState(false);
57
57
  const [position, setPosition] = useState({ x: 0, y: 0 });
58
- const [startPanPosition, setStartPanPosition] = useState({ x: 0, y: 0 });
58
+ const startPanPositionRef = useRef({ x: 0, y: 0 });
59
59
  const [backdrop, setBackdrop] = useState('transparent');
60
60
  const [imgLoaded, setImgLoaded] = useState(false);
61
61
  const [imgError, setImgError] = useState(false);
62
- const [imgInfo, setImgInfo] = useState(null);
63
62
  // ── Retry state ──────────────────────────────────────────────────────
64
63
  const [retryCount, setRetryCount] = useState(0);
65
64
  const [imgSrc, setImgSrc] = useState(url);
@@ -71,18 +70,6 @@ export function ImageRenderer({ url, className, fileName, controls = 'hover', ba
71
70
  const isSvg = fileName?.toLowerCase().endsWith('.svg') ||
72
71
  url?.toLowerCase().endsWith('.svg') ||
73
72
  url?.includes('image/svg');
74
- // Derive the display file type for the info panel
75
- const displayFileType = (() => {
76
- if (isSvg)
77
- return 'SVG';
78
- if (fileName) {
79
- const ext = fileName.split('.').pop()?.toUpperCase();
80
- if (ext)
81
- return ext;
82
- }
83
- const ext = url.split('.').pop()?.toUpperCase();
84
- return ext || 'Image';
85
- })();
86
73
  // When the parent passes a new URL, reset everything. The reset runs during
87
74
  // render, not in an effect: an effect also ran on mount, after a cached
88
75
  // image had already fired `load`, and set `imgLoaded` back to false. The
@@ -123,17 +110,12 @@ export function ImageRenderer({ url, className, fileName, controls = 'hover', ba
123
110
  setImgError(false);
124
111
  setRetryCount(0); // reset on success
125
112
  if (imageRef.current) {
126
- setImgInfo({
127
- width: imageRef.current.naturalWidth,
128
- height: imageRef.current.naturalHeight,
129
- type: displayFileType,
130
- });
131
113
  previewFit?.report({
132
114
  width: imageRef.current.naturalWidth,
133
115
  height: imageRef.current.naturalHeight,
134
116
  });
135
117
  }
136
- }, [displayFileType, previewFit]);
118
+ }, [previewFit]);
137
119
  // Retries exhausted: these bytes are never going to decode, so there will be
138
120
  // no `report` for this image. Say "never" rather than staying silent — a
139
121
  // consumer reads silence as "still loading" and keeps whatever width it last
@@ -213,17 +195,17 @@ export function ImageRenderer({ url, className, fileName, controls = 'hover', ba
213
195
  const handleMouseDown = (e) => {
214
196
  if (canPan) {
215
197
  setIsPanning(true);
216
- setStartPanPosition({
198
+ startPanPositionRef.current = {
217
199
  x: e.clientX - position.x,
218
200
  y: e.clientY - position.y,
219
- });
201
+ };
220
202
  }
221
203
  };
222
204
  const handleMouseMove = (e) => {
223
205
  if (isPanning && canPan) {
224
206
  setPosition({
225
- x: e.clientX - startPanPosition.x,
226
- y: e.clientY - startPanPosition.y,
207
+ x: e.clientX - startPanPositionRef.current.x,
208
+ y: e.clientY - startPanPositionRef.current.y,
227
209
  });
228
210
  }
229
211
  };
@@ -240,7 +240,7 @@ function PDFViewerFileActionsMenu({ onUploadFile, showUpload = false, }) {
240
240
  const inputRef = React.useRef(null);
241
241
  if (!showUpload || !onUploadFile)
242
242
  return null;
243
- return (_jsxs(_Fragment, { children: [_jsx("input", { ref: inputRef, type: "file", accept: "application/pdf,.pdf", className: "sr-only", tabIndex: -1, onChange: (event) => {
243
+ return (_jsxs(_Fragment, { children: [_jsx("input", { ref: inputRef, type: "file", accept: "application/pdf,.pdf", "aria-label": tI18nComplete.raw('text865e89de78d9'), className: "sr-only", tabIndex: -1, onChange: (event) => {
244
244
  const nextFile = event.target.files?.[0];
245
245
  if (nextFile) {
246
246
  onUploadFile(nextFile);
@@ -19,11 +19,9 @@ export function FullScreenPresentationViewer({ isOpen, onClose, presentationName
19
19
  const [metadata, setMetadata] = useState(null);
20
20
  const [currentSlide, setCurrentSlide] = useState(initialSlide);
21
21
  const [isLoading, setIsLoading] = useState(false);
22
- const [error, setError] = useState(null);
23
22
  const [retryAttempt, setRetryAttempt] = useState(0);
24
23
  const retryTimeoutRef = useRef(null);
25
24
  const hasLoadedRef = useRef(false);
26
- const [showControls, setShowControls] = useState(true);
27
25
  const [showEditor, setShowEditor] = useState(false);
28
26
  const [isDownloadingPDF, setIsDownloadingPDF] = useState(false);
29
27
  const [isDownloadingPPTX, setIsDownloadingPPTX] = useState(false);
@@ -57,7 +55,6 @@ export function FullScreenPresentationViewer({ isOpen, onClose, presentationName
57
55
  return;
58
56
  }
59
57
  setIsLoading(true);
60
- setError(null);
61
58
  setRetryAttempt(retryCount);
62
59
  try {
63
60
  // Sanitize the presentation name to match backend directory creation
@@ -218,12 +215,6 @@ export function FullScreenPresentationViewer({ isOpen, onClose, presentationName
218
215
  document.addEventListener('keydown', handleKeyDown, true);
219
216
  return () => document.removeEventListener('keydown', handleKeyDown, true);
220
217
  }, [isOpen, goToNextSlide, goToPreviousSlide, totalSlides, onClose, showEditor]);
221
- // Always show controls
222
- useEffect(() => {
223
- if (isOpen) {
224
- setShowControls(true);
225
- }
226
- }, [isOpen]);
227
218
  // Download handlers
228
219
  const handleDownload = async (format) => {
229
220
  if (isDownloadRestricted) {
@@ -322,7 +313,7 @@ export function FullScreenPresentationViewer({ isOpen, onClose, presentationName
322
313
  });
323
314
  SlideIframeComponent.displayName = 'SlideIframeComponent';
324
315
  return SlideIframeComponent;
325
- }, [sandboxUrl, refreshTimestamp, showEditor, subdomainOpts, tHardcodedUi]);
316
+ }, [sandboxUrl, refreshTimestamp, showEditor, subdomainOpts, tHardcodedUi, tI18nComplete]);
326
317
  if (!isOpen)
327
318
  return null;
328
319
  // Render slide iframe with proper scaling
@@ -331,7 +322,7 @@ export function FullScreenPresentationViewer({ isOpen, onClose, presentationName
331
322
  ? tHardcodedUi.raw('i18nComplete.textbd0b7be215ce')
332
323
  : tHardcodedUi.raw('i18nComplete.text8268dd9ea939'), onClick: () => setShowEditor(!showEditor), children: showEditor ? (_jsx(Presentation, { className: "h-3.5 w-3.5" })) : (_jsx(Edit, { className: "h-3.5 w-3.5" })) }), _jsxs(DropdownMenu, { children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsx(Button, { variant: "ghost", size: "sm", className: "w-8 p-0", title: tHardcodedUi.raw('componentsThreadToolViewsPresentationToolsFullscreenpresentationviewer.line485JsxAttrTitleExportPresentation'), disabled: isDownloadingPDF || isDownloadingPPTX, children: isDownloadingPDF || isDownloadingPPTX ? (_jsx(KortixLoader, { customSize: 14 })) : (_jsx(Download, { className: "h-3.5 w-3.5" })) }) }), _jsxs(DropdownMenuContent, { align: "end", className: "w-32", children: [_jsxs(DropdownMenuItem, { className: "cursor-pointer", onClick: () => handleDownload(DownloadFormat.PDF), disabled: isDownloadingPDF, children: [_jsx(FileText, { className: "mr-2 h-4 w-4" }), "PDF"] }), _jsxs(DropdownMenuItem, { className: "cursor-pointer", onClick: () => handleDownload(DownloadFormat.PPTX), disabled: isDownloadingPPTX, children: [_jsx(Presentation, { className: "mr-2 h-4 w-4" }), "PPTX"] })] })] }), _jsx(Button, { variant: "ghost", size: "sm", onClick: onClose, className: "h-8 w-8 p-0", title: tHardcodedUi.raw('componentsThreadToolViewsPresentationToolsFullscreenpresentationviewer.line529JsxAttrTitleCloseFullScreen'), children: _jsx(X, { className: "h-3.5 w-3.5" }) })] })] }) }), _jsx("div", { className: "flex min-h-0 flex-1 items-center justify-center bg-zinc-100 p-2 dark:bg-zinc-900", children: isLoading || !currentSlideData ? (_jsxs("div", { className: "text-center", children: [_jsx(KortixLoader, { size: "large", className: "mx-auto mb-4" }), _jsx("p", { className: "text-zinc-700 dark:text-zinc-300", children: retryAttempt > 0
333
324
  ? tI18nComplete('text3df439a7a73b', { value0: retryAttempt + 1 })
334
- : tHardcodedUi.raw('i18nComplete.text1ac9fe8126fa') })] })) : currentSlideData ? (_jsxs("div", { className: "flex h-full w-full flex-col", children: [_jsx("div", { className: "flex-1 overflow-hidden rounded-xl bg-transparent", style: { aspectRatio: '16 / 9' }, children: renderSlide }), _jsxs("div", { className: "mt-3 flex items-center justify-between px-4", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Button, { variant: "ghost", size: "sm", onClick: () => setCurrentSlide(1), disabled: currentSlide <= 1, className: "h-8 w-8 p-0 disabled:opacity-50", children: _jsx(SkipBack, { className: "h-3.5 w-3.5" }) }), _jsx(Button, { variant: "ghost", size: "sm", onClick: goToPreviousSlide, disabled: currentSlide <= 1, className: "h-8 w-8 p-0 disabled:opacity-50", children: _jsx(ChevronLeft, { className: "h-4 w-4" }) })] }), _jsx("div", { className: "flex items-center", children: _jsx("div", { className: "flex gap-2", children: slides.map((slide) => (_jsx("button", { onClick: () => setCurrentSlide(slide.number), className: cn('h-2.5 w-2.5 rounded-full transition-colors duration-200', slide.number === currentSlide
325
+ : tHardcodedUi.raw('i18nComplete.text1ac9fe8126fa') })] })) : currentSlideData ? (_jsxs("div", { className: "flex h-full w-full flex-col", children: [_jsx("div", { className: "flex-1 overflow-hidden rounded-xl bg-transparent", style: { aspectRatio: '16 / 9' }, children: renderSlide }), _jsxs("div", { className: "mt-3 flex items-center justify-between px-4", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Button, { variant: "ghost", size: "sm", onClick: () => setCurrentSlide(1), disabled: currentSlide <= 1, className: "h-8 w-8 p-0 disabled:opacity-50", children: _jsx(SkipBack, { className: "h-3.5 w-3.5" }) }), _jsx(Button, { variant: "ghost", size: "sm", onClick: goToPreviousSlide, disabled: currentSlide <= 1, className: "h-8 w-8 p-0 disabled:opacity-50", children: _jsx(ChevronLeft, { className: "h-4 w-4" }) })] }), _jsx("div", { className: "flex items-center", children: _jsx("div", { className: "flex gap-2", children: slides.map((slide) => (_jsx("button", { "aria-label": `${tHardcodedUi.raw('i18nComplete.text6bb4c1177681')} ${slide.number}`, onClick: () => setCurrentSlide(slide.number), className: cn('h-2.5 w-2.5 rounded-full transition-colors duration-200', slide.number === currentSlide
335
326
  ? 'bg-black dark:bg-white'
336
327
  : 'bg-zinc-300 hover:bg-zinc-400 dark:bg-zinc-600 dark:hover:bg-zinc-500') }, slide.number))) }) }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Button, { variant: "ghost", size: "sm", onClick: goToNextSlide, disabled: currentSlide >= totalSlides, className: "h-8 w-8 p-0 disabled:opacity-50", children: _jsx(ChevronRight, { className: "h-4 w-4" }) }), _jsx(Button, { variant: "ghost", size: "sm", onClick: () => setCurrentSlide(totalSlides), disabled: currentSlide >= totalSlides, className: "h-8 w-8 p-0 disabled:opacity-50", children: _jsx(SkipForward, { className: "h-3.5 w-3.5" }) })] })] })] })) : (_jsx("div", { className: "text-center", children: _jsx("p", { className: "text-zinc-700 dark:text-zinc-300", children: tHardcodedUi.raw('componentsThreadToolViewsPresentationToolsFullscreenpresentationviewer.line621JsxTextNoSlideFound') }) })) })] }));
337
328
  }
@@ -692,7 +692,7 @@ export function ShowCarousel({ items, LocalhostPreview, onIndexChange, fill = fa
692
692
  const currentItem = items[currentIndex];
693
693
  if (!currentItem)
694
694
  return null;
695
- return (_jsxs("div", { className: cn('outline-none', fill && 'flex h-full flex-col'),
695
+ return (_jsxs("div", { role: "group", className: cn('outline-none', fill && 'flex h-full flex-col'),
696
696
  // -1: a click on the content focuses the card, so ←/→ page it next,
697
697
  // without adding a Tab stop. Tab still reaches the chevrons inside.
698
698
  tabIndex: fill || count < 2 ? undefined : -1, onKeyDown: fill || count < 2 ? undefined : (e) => handleArrowKey(e), children: [_jsx("div", { className: cn(fill ? 'min-h-0 flex-1 overflow-hidden' : 'min-h-[420px]'), children: currentItem.status === 'pending' ? (_jsxs("div", { className: cn('flex items-center justify-center gap-3', fill ? 'h-full' : 'min-h-[420px]'), children: [_jsx(Loading, { className: "text-muted-foreground size-4" }), _jsx(TextShimmer, { duration: 1, spread: 2, className: "text-sm", children: tHardcodedUi.raw('componentsSessionToolRenderers.line4935JsxTextPreparingOutput') })] })) : (_jsx(ShowContentRenderer, { type: currentItem.type, title: currentItem.title, description: currentItem.description, path: currentItem.path, url: currentItem.url, content: currentItem.content, language: currentItem.language, aspectRatio: currentItem.aspect_ratio, attachment: currentItem.attachment, LocalhostPreview: LocalhostPreview, toolbarActions: toolbarActions, fill: fill })) }), count > 1 && !hideNav && (_jsxs("div", { className: "border-border flex shrink-0 items-center gap-2 border-t px-2 py-1.5 pr-3.5", children: [_jsxs("div", { className: "flex shrink-0 items-center", children: [_jsx(Button, { type: "button", variant: "ghost", size: "icon", onClick: prev, className: "hit-area-2 hit-area-r-0 transition-transform active:scale-[0.96]", disabled: currentIndex === 0, "aria-label": tI18nComplete.raw('text81b35f1b4332'), children: _jsx(ChevronLeft, { className: "size-4" }) }), _jsx(Button, { type: "button", variant: "ghost", size: "icon", onClick: next, className: "hit-area-2 hit-area-l-0 transition-transform active:scale-[0.96]", disabled: currentIndex >= count - 1, "aria-label": tI18nComplete.raw('text1e47d4f7a1a3'), children: _jsx(ChevronRight, { className: "size-4" }) })] }), _jsx(FadedScrollArea, { ref: stripRef, orientation: "horizontal", fadeColor: "from-secondary", className: "min-w-0 flex-1 overscroll-x-contain", children: _jsx("div", { className: "flex w-max min-w-0 items-center gap-1", children: items.map((item, i) => {