@kortix/ui 0.14.8 → 0.14.9

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 (528) hide show
  1. package/README.md +2 -2
  2. package/dist/_vendor/kortix-shared.js +63 -3
  3. package/dist/_vendor/shared/app-config.d.ts +175 -0
  4. package/dist/_vendor/shared/channel-message.d.ts +34 -5
  5. package/dist/_vendor/shared/index.d.ts +1 -0
  6. package/dist/_vendor/shared/space-slug.d.ts +37 -0
  7. package/dist/access/access/access-detail-shell.js +1 -1
  8. package/dist/access/access/principal-picker.d.ts +11 -0
  9. package/dist/access/access/principal-picker.js +3 -2
  10. package/dist/apps/app-preview-pool.d.ts +7 -2
  11. package/dist/apps/app-preview-pool.js +11 -5
  12. package/dist/apps/app-shared.d.ts +22 -15
  13. package/dist/apps/app-shared.js +37 -19
  14. package/dist/apps/index.d.ts +2 -2
  15. package/dist/apps/index.js +2 -2
  16. package/dist/artifacts/artifact-frame.d.ts +16 -0
  17. package/dist/artifacts/artifact-frame.js +51 -0
  18. package/dist/artifacts/artifact-session.d.ts +18 -0
  19. package/dist/artifacts/artifact-session.js +101 -0
  20. package/dist/artifacts/frame-policy.d.ts +30 -0
  21. package/dist/artifacts/frame-policy.js +61 -0
  22. package/dist/artifacts/index.d.ts +3 -0
  23. package/dist/artifacts/index.js +5 -0
  24. package/dist/browser/sandbox-browser-chrome.d.ts +4 -1
  25. package/dist/browser/sandbox-browser-chrome.js +2 -2
  26. package/dist/customize/agents/agent-grant-pages.d.ts +5 -1
  27. package/dist/customize/agents/agent-grant-pages.js +30 -4
  28. package/dist/customize/agents/agent-page.js +3 -1
  29. package/dist/customize/agents/agent-policy-sets.d.ts +43 -0
  30. package/dist/customize/agents/agent-policy-sets.js +72 -0
  31. package/dist/customize/agents/agent-triggers-section.js +2 -1
  32. package/dist/customize/connectors/add-mcp/add-mcp-server-dialog.d.ts +6 -1
  33. package/dist/customize/connectors/add-mcp/add-mcp-server-dialog.js +10 -4
  34. package/dist/customize/connectors/agent-access.d.ts +35 -0
  35. package/dist/customize/connectors/agent-access.js +77 -0
  36. package/dist/customize/connectors/catalog/browse-sections.d.ts +2 -29
  37. package/dist/customize/connectors/catalog/browse-sections.js +7 -74
  38. package/dist/customize/connectors/catalog/catalog-entry.d.ts +18 -37
  39. package/dist/customize/connectors/catalog/catalog-entry.js +28 -40
  40. package/dist/customize/connectors/catalog/connector-browse.d.ts +3 -32
  41. package/dist/customize/connectors/catalog/connector-browse.js +19 -50
  42. package/dist/customize/connectors/catalog/use-catalog.d.ts +20 -59
  43. package/dist/customize/connectors/catalog/use-catalog.js +48 -175
  44. package/dist/customize/connectors/connector-identity.d.ts +9 -11
  45. package/dist/customize/connectors/connector-identity.js +13 -42
  46. package/dist/customize/connectors/connector-moves-banner.d.ts +2 -1
  47. package/dist/customize/connectors/connector-moves-banner.js +4 -6
  48. package/dist/customize/connectors/connector-routes.d.ts +21 -9
  49. package/dist/customize/connectors/connector-routes.js +29 -20
  50. package/dist/customize/connectors/connectors-page.js +53 -82
  51. package/dist/customize/connectors/detail/app-page.js +226 -98
  52. package/dist/customize/connectors/detail/computer-app-page.d.ts +16 -0
  53. package/dist/customize/connectors/detail/computer-app-page.js +39 -0
  54. package/dist/customize/connectors/detail/connector-accounts.js +3 -1
  55. package/dist/customize/connectors/detail/connector-advanced-tools.d.ts +4 -1
  56. package/dist/customize/connectors/detail/connector-advanced-tools.js +2 -2
  57. package/dist/customize/connectors/detail/connector-agents.d.ts +14 -0
  58. package/dist/customize/connectors/detail/connector-agents.js +69 -0
  59. package/dist/customize/connectors/detail/connector-detail-tabs.js +2 -1
  60. package/dist/customize/connectors/detail/connector-move-row.d.ts +8 -5
  61. package/dist/customize/connectors/detail/connector-move-row.js +23 -14
  62. package/dist/customize/connectors/detail/connector-page.d.ts +4 -1
  63. package/dist/customize/connectors/detail/connector-page.js +14 -10
  64. package/dist/customize/connectors/detail/connector-policy-sets.d.ts +28 -0
  65. package/dist/customize/connectors/detail/connector-policy-sets.js +203 -0
  66. package/dist/customize/connectors/detail/connector-settings.d.ts +4 -1
  67. package/dist/customize/connectors/detail/connector-settings.js +7 -3
  68. package/dist/customize/connectors/detail/connector-status.d.ts +19 -6
  69. package/dist/customize/connectors/detail/connector-status.js +34 -10
  70. package/dist/customize/connectors/detail/connector-tabs.d.ts +4 -1
  71. package/dist/customize/connectors/detail/connector-tabs.js +8 -2
  72. package/dist/customize/connectors/detail/connector-tools.d.ts +3 -3
  73. package/dist/customize/connectors/detail/connector-tools.js +105 -48
  74. package/dist/customize/connectors/detail/email-inboxes.d.ts +43 -0
  75. package/dist/customize/connectors/detail/email-inboxes.js +184 -0
  76. package/dist/customize/connectors/detail/provider-info.d.ts +1 -1
  77. package/dist/customize/connectors/detail/provider-info.js +2 -2
  78. package/dist/customize/connectors/detail/status-badge.d.ts +1 -1
  79. package/dist/customize/connectors/detail/status-badge.js +4 -5
  80. package/dist/customize/connectors/detail/use-connector-detail.d.ts +6 -0
  81. package/dist/customize/connectors/detail/use-connector-detail.js +14 -4
  82. package/dist/customize/connectors/install/install-dialog.d.ts +23 -0
  83. package/dist/customize/connectors/install/install-dialog.js +40 -0
  84. package/dist/customize/connectors/install/install.d.ts +13 -2
  85. package/dist/customize/connectors/install/install.js +9 -4
  86. package/dist/customize/connectors/install/use-install.d.ts +19 -2
  87. package/dist/customize/connectors/install/use-install.js +65 -37
  88. package/dist/customize/connectors/install/way-kind.d.ts +5 -0
  89. package/dist/customize/connectors/install/way-kind.js +16 -0
  90. package/dist/customize/connectors/provider-label.d.ts +2 -1
  91. package/dist/customize/connectors/provider-label.js +13 -3
  92. package/dist/customize/connectors/tools/pattern-rule-draft.d.ts +4 -0
  93. package/dist/customize/connectors/tools/pattern-rule-draft.js +12 -3
  94. package/dist/customize/connectors/tools/policy-sets.d.ts +27 -0
  95. package/dist/customize/connectors/tools/policy-sets.js +41 -0
  96. package/dist/customize/connectors/tools/tool-groups.d.ts +32 -9
  97. package/dist/customize/connectors/tools/tool-groups.js +78 -16
  98. package/dist/customize/connectors/tools/tool-policy-control.d.ts +11 -10
  99. package/dist/customize/connectors/tools/tool-policy-control.js +15 -16
  100. package/dist/customize/connectors/tools/tool-policy-labels.d.ts +6 -5
  101. package/dist/customize/connectors/tools/tool-policy-labels.js +17 -16
  102. package/dist/customize/connectors/tools/tool-policy.d.ts +50 -4
  103. package/dist/customize/connectors/tools/tool-policy.js +74 -8
  104. package/dist/customize/connectors/use-agent-access.d.ts +85 -0
  105. package/dist/customize/connectors/use-agent-access.js +72 -0
  106. package/dist/customize/migrate-to-v2/index.d.ts +1 -2
  107. package/dist/customize/migrate-to-v2/index.js +1 -2
  108. package/dist/customize/migrate-to-v2/migration-prompt.d.ts +12 -25
  109. package/dist/customize/migrate-to-v2/migration-prompt.js +34 -236
  110. package/dist/customize/migrate-to-v2/upgrade-defs.d.ts +1 -1
  111. package/dist/customize/migrate-to-v2/upgrade-defs.js +7 -6
  112. package/dist/customize/migrate-to-v2/upgrade-view.js +7 -7
  113. package/dist/customize/migrate-to-v2/use-run-upgrade.d.ts +3 -3
  114. package/dist/customize/providers/provider-accordion.js +17 -2
  115. package/dist/customize/sections/component/channel-access-panel.d.ts +16 -0
  116. package/dist/customize/sections/component/channel-access-panel.js +146 -0
  117. package/dist/customize/sections/component/channel-connect-hero.d.ts +3 -2
  118. package/dist/customize/sections/component/channel-connect-hero.js +3 -2
  119. package/dist/customize/sections/component/channel-hero-frame.d.ts +31 -0
  120. package/dist/customize/sections/component/channel-hero-frame.js +40 -0
  121. package/dist/customize/sections/component/channel-mocks.d.ts +6 -0
  122. package/dist/customize/sections/component/channel-mocks.js +46 -0
  123. package/dist/customize/sections/component/channel-row.d.ts +13 -3
  124. package/dist/customize/sections/component/channel-row.js +10 -4
  125. package/dist/customize/sections/component/email-connect-form.d.ts +27 -0
  126. package/dist/customize/sections/component/email-connect-form.js +183 -0
  127. package/dist/customize/sections/component/slack-connect-card.d.ts +7 -0
  128. package/dist/customize/sections/component/slack-connect-card.js +2 -3
  129. package/dist/customize/sections/component/teams-connect-card.d.ts +7 -0
  130. package/dist/customize/sections/component/teams-connect-card.js +2 -3
  131. package/dist/customize/sections/component/telegram-channel-row.js +16 -25
  132. package/dist/customize/sections/connectors-view.d.ts +1 -15
  133. package/dist/customize/sections/connectors-view.js +81 -314
  134. package/dist/customize/sections/view/agent-editor-catalog.js +5 -0
  135. package/dist/customize/sections/view/channels-view.d.ts +5 -1
  136. package/dist/customize/sections/view/channels-view.js +61 -75
  137. package/dist/customize/sections/view/gateway/gateway-overview.js +10 -2
  138. package/dist/customize/settings/tabs/experimental-tab.js +35 -16
  139. package/dist/customize/shared/catalog/catalog-empty-state.d.ts +1 -12
  140. package/dist/customize/shared/catalog/catalog-empty-state.js +3 -3
  141. package/dist/customize/shared/channels-switch-dialog.d.ts +18 -0
  142. package/dist/customize/shared/channels-switch-dialog.js +30 -0
  143. package/dist/customize/shared/feature-gate-screen.js +27 -9
  144. package/dist/customize/shared/use-customize-prefetch.d.ts +2 -3
  145. package/dist/customize/shared/use-customize-prefetch.js +9 -27
  146. package/dist/customize/triggers/schedule/post-to-field.d.ts +18 -0
  147. package/dist/customize/triggers/schedule/post-to-field.js +49 -0
  148. package/dist/customize/triggers/schedule/schedule-copy.d.ts +10 -6
  149. package/dist/customize/triggers/schedule/schedule-copy.js +42 -11
  150. package/dist/customize/triggers/schedule/schedule-detail-sheet.js +2 -1
  151. package/dist/customize/triggers/schedule/trigger-composer-logic.d.ts +22 -0
  152. package/dist/customize/triggers/schedule/trigger-composer-logic.js +25 -0
  153. package/dist/customize/triggers/schedule/trigger-composer.d.ts +5 -0
  154. package/dist/customize/triggers/schedule/trigger-composer.js +23 -14
  155. package/dist/customize/triggers/schedule/trigger-edit-logic.js +3 -0
  156. package/dist/customize/triggers/schedule/trigger-filter.js +1 -1
  157. package/dist/customize/triggers/schedule/trigger-runs-logic.d.ts +2 -2
  158. package/dist/customize/triggers/schedule/trigger-runs-panel.js +1 -0
  159. package/dist/customize/triggers/schedule/trigger-toast.js +2 -1
  160. package/dist/customize/triggers/schedule-view.js +5 -2
  161. package/dist/files/index.d.ts +1 -0
  162. package/dist/files/index.js +1 -0
  163. package/dist/files/project/change-request-recovery.d.ts +1 -26
  164. package/dist/files/project/change-request-recovery.js +1 -59
  165. package/dist/files/project/components/change-request-detail-dialog.js +13 -3
  166. package/dist/files/project/components/drive-explorer.js +15 -15
  167. package/dist/files/project/components/drive-toolbar.d.ts +16 -2
  168. package/dist/files/project/components/drive-toolbar.js +14 -5
  169. package/dist/files/project/hooks/use-change-request-recovery.js +3 -19
  170. package/dist/files/project/hooks/use-change-requests.d.ts +1 -0
  171. package/dist/files/project/hooks/use-change-requests.js +11 -2
  172. package/dist/files/renderers/image-frame.d.ts +46 -0
  173. package/dist/files/renderers/image-frame.js +59 -0
  174. package/dist/files/renderers/image-renderer.d.ts +11 -1
  175. package/dist/files/renderers/image-renderer.js +13 -3
  176. package/dist/files/renderers/pdf/pdf-clipboard.d.ts +2 -0
  177. package/dist/files/renderers/pdf/pdf-clipboard.js +21 -0
  178. package/dist/files/renderers/pdf/pdf-viewer.js +4 -2
  179. package/dist/files/renderers/show-content-renderer.d.ts +9 -1
  180. package/dist/files/renderers/show-content-renderer.js +56 -14
  181. package/dist/files/runtime/file-source.js +2 -0
  182. package/dist/files/runtime/hooks/use-binary-blob.d.ts +10 -1
  183. package/dist/files/runtime/hooks/use-binary-blob.js +10 -4
  184. package/dist/files/runtime/hooks/use-shared-image.d.ts +41 -0
  185. package/dist/files/runtime/hooks/use-shared-image.js +177 -0
  186. package/dist/files/viewer/file-content-renderer.d.ts +22 -1
  187. package/dist/files/viewer/file-content-renderer.js +50 -7
  188. package/dist/files/viewer/file-header.d.ts +7 -3
  189. package/dist/files/viewer/file-header.js +20 -11
  190. package/dist/files/viewer/file-preview-modal.d.ts +1 -1
  191. package/dist/files/viewer/file-preview-modal.js +10 -22
  192. package/dist/files/viewer/file-source.d.ts +13 -0
  193. package/dist/files/viewer/use-file-content-state.d.ts +2 -0
  194. package/dist/files/viewer/use-file-content-state.js +28 -10
  195. package/dist/files/viewer/viewer-actions.d.ts +3 -1
  196. package/dist/files/viewer/viewer-actions.js +2 -2
  197. package/dist/hooks/use-media-query.d.ts +1 -0
  198. package/dist/hooks/use-mobile.d.ts +5 -0
  199. package/dist/hooks/use-mobile.js +8 -0
  200. package/dist/i18n/en.d.ts +873 -85
  201. package/dist/i18n/en.js +888 -100
  202. package/dist/i18n/ui-catalog/localize-ui-catalog.js +4 -0
  203. package/dist/i18n/ui-catalog/remaining-ui-translation-keys.generated.js +15 -3
  204. package/dist/index.d.ts +2 -2
  205. package/dist/index.js +2 -2
  206. package/dist/internal/account-hub/account-settings-sidebar.js +1 -1
  207. package/dist/internal/account-hub/hub-sheet.d.ts +9 -1
  208. package/dist/internal/account-hub/hub-sheet.js +21 -5
  209. package/dist/internal/account-hub/sections.d.ts +1 -1
  210. package/dist/internal/account-hub/sections.js +2 -1
  211. package/dist/internal/auth/auth-card-shell.js +3 -3
  212. package/dist/internal/components/agent-mark.js +5 -2
  213. package/dist/internal/connector-logo/connector-logo-source.d.ts +63 -0
  214. package/dist/internal/connector-logo/connector-logo-source.js +48 -0
  215. package/dist/internal/connector-logo/connector-logo.d.ts +39 -0
  216. package/dist/internal/connector-logo/connector-logo.js +56 -0
  217. package/dist/internal/connector-logo/connector-mark-files.d.ts +11 -0
  218. package/dist/internal/connector-logo/connector-mark-files.js +35 -0
  219. package/dist/internal/files/file-read-retry.d.ts +13 -0
  220. package/dist/internal/files/file-read-retry.js +23 -3
  221. package/dist/internal/files/session-drive-files.d.ts +5 -1
  222. package/dist/internal/files/session-drive-files.js +7 -2
  223. package/dist/internal/hooks/channels/use-channels-installations.d.ts +32 -5
  224. package/dist/internal/hooks/channels/use-channels-installations.js +55 -7
  225. package/dist/internal/hooks/channels/use-email-inboxes.d.ts +19 -0
  226. package/dist/internal/hooks/channels/use-email-inboxes.js +48 -0
  227. package/dist/internal/hooks/connectors/use-add-account.js +1 -1
  228. package/dist/internal/hooks/index.d.ts +1 -1
  229. package/dist/internal/hooks/index.js +1 -1
  230. package/dist/internal/hooks/projects/use-new-project-session.d.ts +9 -0
  231. package/dist/internal/hooks/projects/use-new-project-session.js +28 -12
  232. package/dist/internal/hooks/use-auto-scroll.d.ts +8 -1
  233. package/dist/internal/hooks/use-auto-scroll.js +4 -4
  234. package/dist/internal/icons/telegram.d.ts +5 -0
  235. package/dist/internal/icons/telegram.js +6 -1
  236. package/dist/internal/layout/nav-hover-card.d.ts +35 -0
  237. package/dist/internal/layout/nav-hover-card.js +84 -0
  238. package/dist/internal/layout/project-nav-row.d.ts +3 -1
  239. package/dist/internal/layout/project-nav-row.js +3 -2
  240. package/dist/internal/layout/project-page-header.d.ts +4 -2
  241. package/dist/internal/layout/project-page-header.js +4 -3
  242. package/dist/internal/layout/project-settings-nav.js +59 -2
  243. package/dist/internal/lib/browser-error-noise.d.ts +1 -1
  244. package/dist/internal/lib/browser-error-noise.js +1 -1
  245. package/dist/internal/lib/browser-noise/rules/injected-scripts.d.ts +7 -0
  246. package/dist/internal/lib/browser-noise/rules/injected-scripts.js +15 -0
  247. package/dist/internal/lib/manifest-version.d.ts +1 -1
  248. package/dist/internal/lib/manifest-version.js +2 -2
  249. package/dist/internal/lib/memory-href.d.ts +16 -0
  250. package/dist/internal/lib/memory-href.js +46 -0
  251. package/dist/internal/lib/use-project-feature-flags.js +9 -9
  252. package/dist/internal/lib/utils/heic-convert.d.ts +1 -1
  253. package/dist/internal/lib/utils/heic-convert.js +3 -4
  254. package/dist/internal/lib/web-notifications.d.ts +20 -0
  255. package/dist/internal/lib/web-notifications.js +48 -4
  256. package/dist/internal/notifications/notification-bell.d.ts +4 -1
  257. package/dist/internal/notifications/notification-bell.js +2 -2
  258. package/dist/internal/selection/selection-bar.d.ts +2 -1
  259. package/dist/internal/selection/selection-bar.js +1 -1
  260. package/dist/internal/stores/file-preview-store.d.ts +29 -2
  261. package/dist/internal/stores/file-preview-store.js +19 -1
  262. package/dist/internal/stores/kortix-computer-store.js +3 -0
  263. package/dist/internal/stores/sidebar-nav-store.d.ts +1 -1
  264. package/dist/internal/stores/sidebar-nav-store.js +3 -1
  265. package/dist/lib/routes.d.ts +13 -1
  266. package/dist/lib/routes.js +13 -0
  267. package/dist/markdown/index.d.ts +2 -1
  268. package/dist/markdown/index.js +2 -1
  269. package/dist/markdown/setup-links/approval-decision.d.ts +1 -0
  270. package/dist/markdown/setup-links/approval-decision.js +6 -2
  271. package/dist/markdown/setup-links/connector-handshake.d.ts +3 -1
  272. package/dist/markdown/setup-links/connector-handshake.js +12 -10
  273. package/dist/markdown/setup-links/secret-intake-form.d.ts +0 -10
  274. package/dist/markdown/setup-links/secret-intake-form.js +1 -1
  275. package/dist/markdown/setup-links/show-connect-hero.d.ts +28 -0
  276. package/dist/markdown/setup-links/show-connect-hero.js +91 -0
  277. package/dist/markdown/unified-markdown.js +5 -5
  278. package/dist/primitives/badge.d.ts +1 -1
  279. package/dist/primitives/badge.js +2 -0
  280. package/dist/primitives/disclosure.js +14 -2
  281. package/dist/primitives/empty-art.d.ts +12 -0
  282. package/dist/primitives/empty-art.js +11 -0
  283. package/dist/primitives/mermaid-renderer.d.ts +2 -0
  284. package/dist/primitives/mermaid-renderer.js +21 -15
  285. package/dist/primitives/resizable.js +6 -1
  286. package/dist/primitives/resize-seam.d.ts +11 -0
  287. package/dist/primitives/resize-seam.js +12 -0
  288. package/dist/primitives/sidebar-panel.js +4 -7
  289. package/dist/primitives/tabs.d.ts +14 -1
  290. package/dist/primitives/tabs.js +1 -1
  291. package/dist/providers/ui-provider.d.ts +9 -0
  292. package/dist/session/composer/ComposerAboveCard.d.ts +1 -1
  293. package/dist/session/composer/ComposerAboveCard.js +2 -2
  294. package/dist/session/composer/ComposerCard.d.ts +1 -1
  295. package/dist/session/composer/ComposerCard.js +3 -3
  296. package/dist/session/composer/agent-selector.d.ts +13 -1
  297. package/dist/session/composer/agent-selector.js +25 -5
  298. package/dist/session/composer/composer-agent-access.d.ts +15 -0
  299. package/dist/session/composer/composer-agent-access.js +27 -0
  300. package/dist/session/composer/composer-chat-input.d.ts +8 -2
  301. package/dist/session/composer/composer-chat-input.js +8 -6
  302. package/dist/session/composer/composer-logic.d.ts +16 -0
  303. package/dist/session/composer/composer-logic.js +12 -0
  304. package/dist/session/composer/composer-underbar.d.ts +3 -1
  305. package/dist/session/composer/composer-underbar.js +4 -3
  306. package/dist/session/composer/composer.d.ts +15 -1
  307. package/dist/session/composer/composer.js +19 -1
  308. package/dist/session/composer/draft/composer-draft.d.ts +6 -2
  309. package/dist/session/composer/draft/composer-draft.js +5 -1
  310. package/dist/session/composer/reasoning-effort-selector.js +1 -1
  311. package/dist/session/models/chatgpt-connection-button.d.ts +11 -0
  312. package/dist/session/models/chatgpt-connection-button.js +54 -0
  313. package/dist/session/models/model-selector.js +5 -2
  314. package/dist/session/models/use-model-connection-gate.d.ts +5 -5
  315. package/dist/session/models/use-model-connection-gate.js +5 -5
  316. package/dist/session/outcomes/jump-to-outcome.d.ts +10 -0
  317. package/dist/session/outcomes/jump-to-outcome.js +11 -0
  318. package/dist/session/outcomes/session-outcomes-bridge.d.ts +14 -0
  319. package/dist/session/outcomes/session-outcomes-bridge.js +12 -0
  320. package/dist/session/outcomes/session-outcomes-provider.d.ts +3 -1
  321. package/dist/session/outcomes/session-outcomes-provider.js +33 -3
  322. package/dist/session/panel/easy/app-preview.d.ts +10 -0
  323. package/dist/session/panel/easy/app-preview.js +31 -12
  324. package/dist/session/panel/easy/change-requests-card.d.ts +7 -0
  325. package/dist/session/panel/easy/change-requests-card.js +17 -0
  326. package/dist/session/panel/easy/easy-panel-logic.js +7 -1
  327. package/dist/session/panel/easy/easy-panel.js +5 -2
  328. package/dist/session/panel/easy/file-preview.js +1 -1
  329. package/dist/session/panel/easy/outputs-card.d.ts +2 -1
  330. package/dist/session/panel/easy/outputs-card.js +3 -2
  331. package/dist/session/panel/mobile-tool-drawer.js +7 -1
  332. package/dist/session/panel/session-audit-panel.js +9 -2
  333. package/dist/session/panel/session-detail-panel.js +9 -3
  334. package/dist/session/panel/session-files-explorer.d.ts +9 -0
  335. package/dist/session/panel/session-files-explorer.js +12 -3
  336. package/dist/session/panel/session-panel-provider.d.ts +15 -1
  337. package/dist/session/panel/session-panel-provider.js +32 -7
  338. package/dist/session/panel/shared/derive-panels.d.ts +8 -1
  339. package/dist/session/panel/shared/derive-panels.js +12 -2
  340. package/dist/session/panel/shared/output-priority.js +2 -0
  341. package/dist/session/participants/session-participants.d.ts +5 -1
  342. package/dist/session/participants/session-participants.js +9 -2
  343. package/dist/session/prompts/approval-request.d.ts +5 -0
  344. package/dist/session/prompts/approval-request.js +7 -1
  345. package/dist/session/prompts/session-approval-review.d.ts +9 -0
  346. package/dist/session/prompts/session-approval-review.js +18 -0
  347. package/dist/session/status/session-error-banner.js +2 -49
  348. package/dist/session/status/session-starting-loader.d.ts +14 -2
  349. package/dist/session/status/session-starting-loader.js +16 -4
  350. package/dist/session/thread/after-first-prompt.d.ts +7 -0
  351. package/dist/session/thread/after-first-prompt.js +8 -0
  352. package/dist/session/thread/detect-command.d.ts +12 -0
  353. package/dist/session/thread/detect-command.js +20 -0
  354. package/dist/session/thread/session-chat.d.ts +3 -1
  355. package/dist/session/thread/session-chat.js +377 -252
  356. package/dist/session/thread/session-thread.d.ts +3 -1
  357. package/dist/session/thread/session-thread.js +9 -2
  358. package/dist/session/thread/thread-boot-rows.d.ts +36 -0
  359. package/dist/session/thread/thread-boot-rows.js +89 -0
  360. package/dist/session/thread/transcript-rows.d.ts +31 -0
  361. package/dist/session/thread/transcript-rows.js +3 -0
  362. package/dist/session/thread/transcript.d.ts +0 -9
  363. package/dist/session/thread/transcript.js +104 -19
  364. package/dist/session/tool/shared/infrastructure-contexts.d.ts +28 -0
  365. package/dist/session/tool/shared/infrastructure-contexts.js +31 -3
  366. package/dist/session/tool/tool-part-renderer.d.ts +5 -4
  367. package/dist/session/tool/tool-part-renderer.js +8 -3
  368. package/dist/session/tool/tools/bash-tool.js +7 -6
  369. package/dist/session/tool/tools/channel-send-card.d.ts +1 -2
  370. package/dist/session/tool/tools/channel-send.d.ts +2 -1
  371. package/dist/session/tool/tools/codemode-tool.js +1 -1
  372. package/dist/session/tool/tools/connector-tools.js +1 -1
  373. package/dist/session/tool/tools/image-gen-tool.d.ts +1 -1
  374. package/dist/session/tool/tools/image-gen-tool.js +240 -53
  375. package/dist/session/tool/tools/show-tool.js +19 -8
  376. package/dist/session/turn/channel-brand.d.ts +8 -3
  377. package/dist/session/turn/channel-brand.js +20 -4
  378. package/dist/session/turn/message-author.d.ts +8 -0
  379. package/dist/session/turn/message-author.js +24 -0
  380. package/dist/session/turn/message-row.d.ts +52 -0
  381. package/dist/session/turn/message-row.js +44 -0
  382. package/dist/session/turn/plan-anchor.d.ts +1 -1
  383. package/dist/session/turn/plan-anchor.js +1 -1
  384. package/dist/session/turn/user-message.d.ts +7 -1
  385. package/dist/session/turn/user-message.js +21 -7
  386. package/dist/styles.css +1 -1
  387. package/dist/workspace/home/access-requests-bell.d.ts +9 -2
  388. package/dist/workspace/home/access-requests-bell.js +20 -6
  389. package/dist/workspace/home/first-chat.d.ts +8 -21
  390. package/dist/workspace/home/first-chat.js +22 -72
  391. package/dist/workspace/index.d.ts +6 -0
  392. package/dist/workspace/index.js +6 -0
  393. package/dist/workspace/layout/project-home.d.ts +14 -2
  394. package/dist/workspace/layout/project-home.js +60 -21
  395. package/dist/workspace/layout/use-project-home-send.d.ts +9 -1
  396. package/dist/workspace/layout/use-project-home-send.js +82 -3
  397. package/dist/workspace/memory/body-doc.d.ts +17 -0
  398. package/dist/workspace/memory/body-doc.js +208 -0
  399. package/dist/workspace/memory/body-extensions.d.ts +38 -0
  400. package/dist/workspace/memory/body-extensions.js +103 -0
  401. package/dist/workspace/memory/company-memory-page.d.ts +8 -0
  402. package/dist/workspace/memory/company-memory-page.js +16 -0
  403. package/dist/workspace/memory/memory-all.d.ts +20 -0
  404. package/dist/workspace/memory/memory-all.js +27 -0
  405. package/dist/workspace/memory/memory-body.d.ts +19 -0
  406. package/dist/workspace/memory/memory-body.js +139 -0
  407. package/dist/workspace/memory/memory-empty.d.ts +13 -0
  408. package/dist/workspace/memory/memory-empty.js +28 -0
  409. package/dist/workspace/memory/memory-history.d.ts +27 -0
  410. package/dist/workspace/memory/memory-history.js +108 -0
  411. package/dist/workspace/memory/memory-labels.d.ts +16 -0
  412. package/dist/workspace/memory/memory-labels.js +47 -0
  413. package/dist/workspace/memory/memory-page-list.d.ts +34 -0
  414. package/dist/workspace/memory/memory-page-list.js +156 -0
  415. package/dist/workspace/memory/memory-reader.d.ts +58 -0
  416. package/dist/workspace/memory/memory-reader.js +123 -0
  417. package/dist/workspace/memory/memory-view.d.ts +21 -0
  418. package/dist/workspace/memory/memory-view.js +124 -0
  419. package/dist/workspace/memory/remember-popover.d.ts +19 -0
  420. package/dist/workspace/memory/remember-popover.js +61 -0
  421. package/dist/workspace/memory/remember-this.d.ts +12 -0
  422. package/dist/workspace/memory/remember-this.js +89 -0
  423. package/dist/workspace/memory/source-mark.d.ts +18 -0
  424. package/dist/workspace/memory/source-mark.js +79 -0
  425. package/dist/workspace/memory/used-memory-chip.d.ts +14 -0
  426. package/dist/workspace/memory/used-memory-chip.js +61 -0
  427. package/dist/workspace/new/advanced-fields.d.ts +2 -1
  428. package/dist/workspace/new/advanced-fields.js +2 -2
  429. package/dist/workspace/new/source-param.d.ts +1 -1
  430. package/dist/workspace/new/source-param.js +3 -1
  431. package/dist/workspace/new/use-create-workspace.d.ts +8 -10
  432. package/dist/workspace/new/use-create-workspace.js +3 -3
  433. package/dist/workspace/projects/onboarding/app-logo.d.ts +7 -2
  434. package/dist/workspace/projects/onboarding/app-logo.js +6 -13
  435. package/dist/workspace/projects/policies-panel.js +5 -3
  436. package/dist/workspace/review/review-actions.d.ts +4 -2
  437. package/dist/workspace/review/review-actions.js +8 -2
  438. package/dist/workspace/review/review-center.js +11 -7
  439. package/dist/workspace/review/review-detail.d.ts +10 -0
  440. package/dist/workspace/review/review-detail.js +101 -13
  441. package/dist/workspace/saved-session-skeleton.d.ts +2 -2
  442. package/dist/workspace/saved-session-skeleton.js +3 -3
  443. package/dist/workspace/session-workspace.js +15 -13
  444. package/dist/workspace/sessions/project-sessions-view.js +3 -2
  445. package/dist/workspace/sessions/sessions-toolbar.d.ts +3 -1
  446. package/dist/workspace/sessions/sessions-toolbar.js +2 -2
  447. package/dist/workspace/sidebar/footer/project-apps-nav.d.ts +5 -0
  448. package/dist/workspace/sidebar/footer/project-apps-nav.js +41 -2
  449. package/dist/workspace/sidebar/footer/project-artifacts-nav.d.ts +6 -0
  450. package/dist/workspace/sidebar/footer/project-artifacts-nav.js +22 -0
  451. package/dist/workspace/sidebar/footer/project-manifest-upgrade-alert.js +13 -13
  452. package/dist/workspace/sidebar/footer/project-memory-nav.d.ts +7 -0
  453. package/dist/workspace/sidebar/footer/project-memory-nav.js +19 -0
  454. package/dist/workspace/sidebar/nav-row-meta.js +14 -2
  455. package/dist/workspace/sidebar/project-nav-items.js +3 -0
  456. package/dist/workspace/sidebar/project-session-list.js +68 -56
  457. package/dist/workspace/sidebar/project-sidebar.js +9 -2
  458. package/dist/workspace/sidebar/project-spaces-nav.d.ts +8 -0
  459. package/dist/workspace/sidebar/project-spaces-nav.js +69 -0
  460. package/dist/workspace/sidebar/session-group-order.d.ts +9 -0
  461. package/dist/workspace/sidebar/session-group-order.js +25 -0
  462. package/dist/workspace/sidebar/session-group-sections.d.ts +62 -0
  463. package/dist/workspace/sidebar/session-group-sections.js +267 -0
  464. package/dist/workspace/sidebar/session-list-chrome.d.ts +28 -0
  465. package/dist/workspace/sidebar/session-list-chrome.js +50 -0
  466. package/dist/workspace/spaces/channel-glyph.d.ts +5 -0
  467. package/dist/workspace/spaces/channel-glyph.js +6 -0
  468. package/dist/workspace/spaces/channel-setup.d.ts +16 -0
  469. package/dist/workspace/spaces/channel-setup.js +105 -0
  470. package/dist/workspace/spaces/channels-onboarding.d.ts +13 -0
  471. package/dist/workspace/spaces/channels-onboarding.js +37 -0
  472. package/dist/workspace/spaces/create-channel-dialog.d.ts +16 -0
  473. package/dist/workspace/spaces/create-channel-dialog.js +158 -0
  474. package/dist/workspace/spaces/private-channels-not-in.d.ts +9 -0
  475. package/dist/workspace/spaces/private-channels-not-in.js +69 -0
  476. package/dist/workspace/spaces/space-agents.d.ts +10 -0
  477. package/dist/workspace/spaces/space-agents.js +10 -0
  478. package/dist/workspace/spaces/space-details-dialog.d.ts +20 -0
  479. package/dist/workspace/spaces/space-details-dialog.js +176 -0
  480. package/dist/workspace/spaces/space-link-label.d.ts +49 -0
  481. package/dist/workspace/spaces/space-link-label.js +73 -0
  482. package/dist/workspace/spaces/space-links.d.ts +19 -0
  483. package/dist/workspace/spaces/space-links.js +230 -0
  484. package/dist/workspace/spaces/space-members.d.ts +46 -0
  485. package/dist/workspace/spaces/space-members.js +182 -0
  486. package/dist/workspace/spaces/space-roster.d.ts +15 -0
  487. package/dist/workspace/spaces/space-roster.js +44 -0
  488. package/dist/workspace/spaces/space-threads-tab.d.ts +56 -0
  489. package/dist/workspace/spaces/space-threads-tab.js +156 -0
  490. package/dist/workspace/spaces/space-timeline-view.d.ts +254 -0
  491. package/dist/workspace/spaces/space-timeline-view.js +235 -0
  492. package/dist/workspace/spaces/space-timeline.d.ts +106 -0
  493. package/dist/workspace/spaces/space-timeline.js +183 -0
  494. package/dist/workspace/spaces/space-triggers.d.ts +13 -0
  495. package/dist/workspace/spaces/space-triggers.js +78 -0
  496. package/dist/workspace/spaces/space-view.d.ts +37 -0
  497. package/dist/workspace/spaces/space-view.js +436 -0
  498. package/package.json +27 -36
  499. package/skills/kortix-ui/SKILL.md +3 -3
  500. package/skills/kortix-ui/references/custom-dashboard.md +3 -3
  501. package/skills/kortix-ui/references/modules.md +28 -4
  502. package/skills/kortix-ui/references/theming.md +1 -1
  503. package/dist/customize/connectors/catalog/merge-search.d.ts +0 -10
  504. package/dist/customize/connectors/catalog/merge-search.js +0 -26
  505. package/dist/customize/connectors/detail/find-easy-connect-app.d.ts +0 -29
  506. package/dist/customize/connectors/detail/find-easy-connect-app.js +0 -22
  507. package/dist/customize/migrate-to-v2/use-migrate-to-v2.d.ts +0 -9
  508. package/dist/customize/migrate-to-v2/use-migrate-to-v2.js +0 -24
  509. package/dist/customize/sections/connector-connection-header.d.ts +0 -36
  510. package/dist/customize/sections/connector-connection-header.js +0 -33
  511. package/dist/customize/sections/connector-connection-modal.d.ts +0 -34
  512. package/dist/customize/sections/connector-connection-modal.js +0 -72
  513. package/dist/customize/sections/discover-catalogue-card.d.ts +0 -19
  514. package/dist/customize/sections/discover-catalogue-card.js +0 -26
  515. package/dist/customize/sections/discover-catalogue-detail.d.ts +0 -15
  516. package/dist/customize/sections/discover-catalogue-detail.js +0 -24
  517. package/dist/customize/sections/discover-catalogue.d.ts +0 -17
  518. package/dist/customize/sections/discover-catalogue.js +0 -132
  519. package/dist/customize/sections/llm-provider/provider-access-menu.d.ts +0 -10
  520. package/dist/customize/sections/llm-provider/provider-access-menu.js +0 -23
  521. package/dist/files/project/components/drive-empty-art.d.ts +0 -2
  522. package/dist/files/project/components/drive-empty-art.js +0 -5
  523. package/dist/internal/hooks/use-media-query.d.ts +0 -2
  524. package/dist/internal/share/public-share-link-button.d.ts +0 -14
  525. package/dist/internal/share/public-share-link-button.js +0 -17
  526. package/dist/markdown/setup-links/app-credentials-form.d.ts +0 -12
  527. package/dist/markdown/setup-links/app-credentials-form.js +0 -115
  528. /package/dist/{internal/hooks → hooks}/use-media-query.js +0 -0
@@ -0,0 +1,230 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { ApiError } from '@kortix/sdk';
4
+ import { safeHttpUrl } from '../../_vendor/kortix-shared.js';
5
+ import { useAddProjectSpaceLink, usePinProjectSpaceLink, useProjectSpaceLinks, useRemoveProjectSpaceLink, } from '@kortix/sdk/react';
6
+ import { ChatTeardropTextIcon, LinkSimpleIcon, MagnifyingGlassIcon, PlusIcon, PushPinIcon, PushPinSlashIcon, TrashIcon, XIcon, } from '@phosphor-icons/react';
7
+ import { useId, useMemo, useState } from 'react';
8
+ import { useLocale, useTranslations } from '../../i18n/index.js';
9
+ import { Copy } from '../../icons/copy.js';
10
+ import { useCopy } from '../../internal/hooks/use-copy.js';
11
+ import { SolidCheckIcon } from '../../internal/icons/solid-check-icon.js';
12
+ import { relativeTime } from '../../internal/lib/relative-time.js';
13
+ import { Button } from '../../primitives/button.js';
14
+ import { ButtonGroup } from '../../primitives/button-group.js';
15
+ import { ConfirmDialog } from '../../primitives/confirm-dialog.js';
16
+ import { DropdownMenuRadioGroup, DropdownMenuRadioItem, DropdownMenuSeparator } from '../../primitives/dropdown-menu.js';
17
+ import { EmptyArt } from '../../primitives/empty-art.js';
18
+ import { EmptyState } from '../../primitives/empty-state.js';
19
+ import { ErrorState } from '../../primitives/error-state.js';
20
+ import { Field, FieldDescription, FieldGroup, FieldLabel } from '../../primitives/field.js';
21
+ import Hint from '../../primitives/hint.js';
22
+ import { Input } from '../../primitives/input.js';
23
+ import Loading from '../../primitives/loading.js';
24
+ import { Modal, ModalBody, ModalContent, ModalDescription, ModalFooter, ModalHeader, ModalTitle, } from '../../primitives/modal.js';
25
+ import { FaviconAvatar } from '../../primitives/favicon-avatar.js';
26
+ import { errorToast, successToast } from '../../primitives/toast.js';
27
+ import { UserAvatar } from '../../primitives/user-avatar.js';
28
+ import { useUiViewerId } from '../../providers/ui-provider.js';
29
+ import { participantLabel } from '../../session/participants/session-participants.js';
30
+ import { filterLinks, LINK_ADDED, linkFiltersFromParams, linkHost, linkTitle, } from './space-link-label.js';
31
+ import { dayKind } from './space-timeline.js';
32
+ import { Facet, FilterMenu, FilterSearch, FilterTokens } from './space-threads-tab.js';
33
+ /** The API's limits: an http(s) URL of at most 2,048 characters, a title of at most 200. */
34
+ const URL_MAX = 2048;
35
+ const TITLE_MAX = 200;
36
+ /** The URL keys of the search and the filters. */
37
+ const FILTER_PARAMS = ['q', 'pinned', 'by', 'added'];
38
+ /** The radio value of a facet's "Any" row (Radix needs a non-empty value). */
39
+ const ANY = 'any';
40
+ /** "example.com/x" becomes "https://example.com/x"; a value with a scheme is kept as typed. */
41
+ function withScheme(value) {
42
+ return /^[a-z][a-z\d+.-]*:\/\//i.test(value) ? value : `https://${value}`;
43
+ }
44
+ /** An http(s) URL whose host has a dot ("localhost" and "foo" are not links). */
45
+ function isWebUrl(value) {
46
+ try {
47
+ const { protocol, hostname } = new URL(value);
48
+ return (protocol === 'http:' || protocol === 'https:') && hostname.includes('.');
49
+ }
50
+ catch {
51
+ return false;
52
+ }
53
+ }
54
+ const personName = (name) => (name ? participantLabel({ name, email: null }) : '');
55
+ /**
56
+ * A channel's Links tab, laid out like its Threads tab: one toolbar (search,
57
+ * the Filter menu, the active filters, "Add link"), then one list on one left
58
+ * edge. Pinned links come first under "Pinned"; the others follow by the day
59
+ * they were last shared (Today, Yesterday, Earlier). The channel's links all
60
+ * load at once, so search and filters read the loaded list. The URL holds
61
+ * them (`?q=&pinned=1&by=&added=`).
62
+ */
63
+ export function SpaceLinks({ projectId, space, place, onOpenThread, params, setParams, }) {
64
+ const t = useTranslations('spaces.view');
65
+ const tf = useTranslations('spaces.view.threadFilter');
66
+ const viewerId = useUiViewerId();
67
+ const links = useProjectSpaceLinks(projectId, space.space_id);
68
+ const [adding, setAdding] = useState(false);
69
+ const [removing, setRemoving] = useState(null);
70
+ const remove = useRemoveProjectSpaceLink(projectId, space.space_id);
71
+ const pin = usePinProjectSpaceLink(projectId, space.space_id);
72
+ const filters = linkFiltersFromParams(params);
73
+ const setParam = (key, value) => setParams((next) => (value ? next.set(key, value) : next.delete(key)));
74
+ const clearAll = () => setParams((next) => FILTER_PARAMS.forEach((key) => next.delete(key)));
75
+ // Everyone who shared a link here, by name; the viewer is "Me".
76
+ const people = useMemo(() => {
77
+ const byId = new Map();
78
+ for (const link of links.data ?? []) {
79
+ if (link.created_by && link.created_by !== viewerId && !byId.has(link.created_by)) {
80
+ byId.set(link.created_by, personName(link.created_by_name) || t('authorFallback'));
81
+ }
82
+ }
83
+ return [...byId].map(([id, name]) => ({ id, name })).sort((a, b) => a.name.localeCompare(b.name));
84
+ }, [links.data, viewerId, t]);
85
+ const groups = useMemo(() => {
86
+ const now = new Date();
87
+ const shown = filterLinks(links.data ?? [], filters, viewerId, now);
88
+ const pinned = shown
89
+ .filter((link) => link.pinned)
90
+ .sort((a, b) => Date.parse(b.pinned_at ?? b.created_at) - Date.parse(a.pinned_at ?? a.created_at));
91
+ const result = pinned.length ? [{ key: 'pinned', label: t('links.pinnedLabel'), links: pinned }] : [];
92
+ for (const link of shown) {
93
+ if (link.pinned)
94
+ continue;
95
+ const kind = dayKind(new Date(link.last_shared_at), now);
96
+ let group = result.find((g) => g.key === kind);
97
+ if (!group) {
98
+ group = { key: kind, label: kind === 'earlier' ? t('links.earlier') : t(kind), links: [] };
99
+ result.push(group);
100
+ }
101
+ group.links.push(link);
102
+ }
103
+ return result;
104
+ // `filters` is rebuilt each render from the URL; its fields are the inputs.
105
+ // eslint-disable-next-line react-hooks/exhaustive-deps
106
+ }, [links.data, filters.q, filters.pinned, filters.by, filters.added, viewerId, t]);
107
+ const byLabel = (by) => by === 'me' || by === viewerId ? tf('me') : (people.find((p) => p.id === by)?.name ?? t('authorFallback'));
108
+ const addedLabel = (added) => tf(`activityValue.${added}`);
109
+ const tokens = [];
110
+ if (filters.pinned)
111
+ tokens.push({ key: 'pinned', facet: t('links.show'), label: t('links.pinnedLabel') });
112
+ if (filters.by)
113
+ tokens.push({ key: 'by', facet: t('links.sharedBy'), label: byLabel(filters.by) });
114
+ if (filters.added)
115
+ tokens.push({ key: 'added', facet: t('links.added'), label: addedLabel(filters.added) });
116
+ const pick = (key) => (value) => setParam(key, value === ANY ? null : value);
117
+ const setPinned = (link, next) => {
118
+ pin.mutate({ linkId: link.link_id, pinned: next }, {
119
+ onSuccess: (result) =>
120
+ // `null` only from an older server, where unpinning an added link removed it.
121
+ successToast(result === null ? t('links.removed') : next ? t('links.pinnedToast') : t('links.unpinnedToast')),
122
+ onError: (err) => errorToast(err instanceof ApiError && err.code === 'link_limit'
123
+ ? t('links.limit')
124
+ : next
125
+ ? t('links.pinFailed')
126
+ : t('links.unpinFailed')),
127
+ });
128
+ };
129
+ let body;
130
+ if (links.isError && !links.data) {
131
+ body = (_jsx("div", { className: "px-5 py-8", children: _jsx(ErrorState, { size: "sm", title: t('links.loadError'), action: _jsx(Button, { variant: "outline", size: "sm", onClick: () => links.refetch(), children: t('retry') }) }) }));
132
+ }
133
+ else if (!links.data) {
134
+ body = null;
135
+ }
136
+ else if (links.data.length === 0) {
137
+ body = (_jsx(EmptyState, { className: "min-h-full", media: _jsx(EmptyArt, { icon: LinkSimpleIcon }), title: t('empty.links.title'), description: t('empty.links.description', { place }), action: _jsxs(Button, { variant: "outline", size: "sm", className: "gap-1.5", onClick: () => setAdding(true), children: [_jsx(PlusIcon, { className: "size-3.5 shrink-0" }), t('links.add')] }) }));
138
+ }
139
+ else if (groups.length === 0) {
140
+ body = (_jsx(EmptyState, { className: "min-h-full", media: _jsx(EmptyArt, { icon: MagnifyingGlassIcon }), title: t('links.noMatch'), description: tf('noMatchHint'), action: _jsxs(Button, { variant: "outline", size: "sm", className: "gap-1.5", onClick: clearAll, children: [_jsx(XIcon, { className: "size-3.5 shrink-0" }), tf('clearFilters')] }) }));
141
+ }
142
+ else {
143
+ body = (_jsx("div", { className: "py-2", children: groups.map((group, index) => (_jsxs("section", { "aria-labelledby": `links-${group.key}`, children: [_jsx("h3", { id: `links-${group.key}`, className: `text-muted-foreground px-5 pb-1 text-xs font-medium ${index === 0 ? 'pt-1' : 'pt-4'}`, children: group.label }), _jsx("ul", { children: group.links.map((link) => (_jsx(LinkRow, { link: link, busy: pin.isPending, onPin: () => setPinned(link, !link.pinned), onOpenThread: link.session_id && onOpenThread ? () => onOpenThread(link.session_id) : undefined, onRemove: link.can_delete ? () => setRemoving(link) : undefined }, link.link_id))) })] }, group.key))) }));
144
+ }
145
+ return (_jsxs("div", { className: "flex min-h-0 flex-1 flex-col", children: [links.data?.length ? (_jsxs("div", { className: "flex shrink-0 flex-wrap items-center gap-2 px-5 pt-3 pb-1", children: [_jsx(FilterSearch, { value: filters.q, placeholder: t('links.search'), onSearch: (q) => setParam('q', q || null) }), _jsxs(FilterMenu, { children: [_jsx(Facet, { label: t('links.show'), value: filters.pinned ? t('links.pinnedLabel') : t('links.all'), children: _jsxs(DropdownMenuRadioGroup, { value: filters.pinned ? '1' : ANY, onValueChange: pick('pinned'), children: [_jsx(DropdownMenuRadioItem, { value: ANY, children: t('links.all') }), _jsx(DropdownMenuRadioItem, { value: "1", children: t('links.pinnedLabel') })] }) }), _jsx(Facet, { label: t('links.sharedBy'), value: filters.by ? byLabel(filters.by) : tf('anyone'), wide: true, children: _jsxs(DropdownMenuRadioGroup, { value: filters.by ?? ANY, onValueChange: pick('by'), children: [_jsx(DropdownMenuRadioItem, { value: ANY, children: tf('anyone') }), _jsx(DropdownMenuRadioItem, { value: "me", children: tf('me') }), people.length > 0 ? _jsx(DropdownMenuSeparator, {}) : null, people.map((person) => (_jsxs(DropdownMenuRadioItem, { value: person.id, children: [_jsx(UserAvatar, { size: "xs", name: person.name, email: "" }), _jsx("span", { className: "min-w-0 truncate", children: person.name })] }, person.id)))] }) }), _jsx(Facet, { label: t('links.added'), value: filters.added ? addedLabel(filters.added) : tf('anyTime'), children: _jsxs(DropdownMenuRadioGroup, { value: filters.added ?? ANY, onValueChange: pick('added'), children: [_jsx(DropdownMenuRadioItem, { value: ANY, children: tf('anyTime') }), LINK_ADDED.map((added) => (_jsx(DropdownMenuRadioItem, { value: added, children: addedLabel(added) }, added)))] }) })] }), _jsx(FilterTokens, { tokens: tokens, onRemove: (key) => setParam(key, null), onClear: clearAll }), _jsxs(Button, { variant: "outline", size: "sm", className: "ml-auto gap-1.5", onClick: () => setAdding(true), children: [_jsx(PlusIcon, { className: "size-3.5 shrink-0" }), t('links.add')] })] })) : null, _jsx("div", { className: "min-h-0 flex-1 overflow-y-auto", children: body }), _jsx(AddLinkModal, { projectId: projectId, space: space, place: place, open: adding, onOpenChange: setAdding }), _jsx(ConfirmDialog, { open: !!removing, onOpenChange: (open) => !open && setRemoving(null), title: t('links.removeTitle'), description: t('links.removeDescription', { link: removing ? linkTitle(removing) : '', place }), confirmLabel: t('links.remove'), confirmVariant: "destructive", isPending: remove.isPending, onConfirm: () => {
146
+ if (!removing)
147
+ return;
148
+ remove.mutate(removing.link_id, {
149
+ onSuccess: () => {
150
+ setRemoving(null);
151
+ successToast(t('links.removed'));
152
+ },
153
+ onError: () => errorToast(t('links.removeFailed')),
154
+ });
155
+ } })] }));
156
+ }
157
+ /**
158
+ * One link on one line, at the Threads row's height and padding: the site's
159
+ * favicon (the app's favicon service, never the stored `icon_url`), the title, the site muted,
160
+ * and who shared it and when at the right. Hover or focus swaps that for the
161
+ * actions: Pin / Unpin, Copy link, Open thread, Remove. The row opens the link.
162
+ */
163
+ function LinkRow({ link, busy, onPin, onOpenThread, onRemove, }) {
164
+ const t = useTranslations('spaces.view');
165
+ const locale = useLocale();
166
+ const { copy, copied } = useCopy({ successMessage: t('links.linkCopied') });
167
+ const host = linkHost(link.url);
168
+ const site = link.site_name && link.site_name.toLowerCase() !== host.toLowerCase() ? link.site_name : host;
169
+ const name = personName(link.created_by_name);
170
+ const when = relativeTime(link.last_shared_at, locale);
171
+ const pinLabel = link.pinned ? t('links.unpin') : t('links.pin');
172
+ const action = (label, hint, onClick, icon, disabled) => (_jsx(Hint, { label: hint, side: "top", children: _jsx(Button, { variant: "outline", size: "icon-xs", "aria-label": label, disabled: disabled, onClick: onClick, children: icon }) }));
173
+ return (_jsxs("li", { className: "group hover:bg-hover focus-within:bg-hover relative flex items-center gap-3 px-5 py-2", children: [_jsx(FaviconAvatar, { value: link.url, size: "xs", className: "shrink-0" }), _jsxs("div", { className: "flex min-w-0 flex-1 items-baseline gap-2", children: [_jsx("a", {
174
+ // A row another writer stored with a non-http(s) URL is shown, never linked.
175
+ href: safeHttpUrl(link.url) ? link.url : undefined, target: "_blank", rel: "noopener noreferrer", title: link.url, className: "focus-visible:after:ring-ring min-w-0 truncate text-sm font-medium outline-none after:absolute after:inset-0 focus-visible:after:ring-2 focus-visible:after:ring-inset", children: linkTitle(link) }), _jsx("span", { className: "text-muted-foreground max-w-48 shrink-0 truncate text-xs", children: site })] }), _jsx("span", { className: "text-muted-foreground shrink-0 text-xs tabular-nums group-focus-within:invisible group-hover:invisible pointer-coarse:hidden", children: name ? `${name} · ${when}` : when }), _jsxs(ButtonGroup, { className: "absolute inset-y-0 right-5 z-10 my-auto hidden h-fit group-focus-within:flex group-hover:flex pointer-coarse:static pointer-coarse:flex", children: [action(pinLabel, link.pinned ? t('links.unpinHint') : t('links.pinHint'), onPin, link.pinned ? _jsx(PushPinSlashIcon, { className: "size-3.5 shrink-0" }) : _jsx(PushPinIcon, { className: "size-3.5 shrink-0" }), busy), action(t('links.copyLink'), copied ? t('links.linkCopied') : t('links.copyLink'), () => void copy(link.url), copied ? _jsx(SolidCheckIcon, { className: "size-3.5 shrink-0" }) : _jsx(Copy, { className: "size-3.5 shrink-0" })), onOpenThread
176
+ ? action(t('links.openThread'), t('links.openThread'), onOpenThread, _jsx(ChatTeardropTextIcon, { className: "size-3.5 shrink-0" }))
177
+ : null, onRemove
178
+ ? action(t('links.remove'), t('links.remove'), onRemove, _jsx(TrashIcon, { className: "size-3.5 shrink-0" }))
179
+ : null] })] }));
180
+ }
181
+ function AddLinkModal({ projectId, space, place, open, onOpenChange, }) {
182
+ const t = useTranslations('spaces.view');
183
+ const tI18nComplete = useTranslations('hardcodedUi.i18nComplete');
184
+ const id = useId();
185
+ const add = useAddProjectSpaceLink(projectId, space.space_id);
186
+ const [url, setUrl] = useState('');
187
+ const [title, setTitle] = useState('');
188
+ const [error, setError] = useState(null);
189
+ const close = () => {
190
+ if (add.isPending)
191
+ return;
192
+ setUrl('');
193
+ setTitle('');
194
+ setError(null);
195
+ onOpenChange(false);
196
+ };
197
+ const submit = () => {
198
+ if (add.isPending)
199
+ return;
200
+ const trimmed = withScheme(url.trim());
201
+ if (!isWebUrl(trimmed))
202
+ return setError('invalid');
203
+ add.mutate({ url: trimmed, ...(title.trim() ? { title: title.trim() } : {}) }, {
204
+ onSuccess: () => {
205
+ successToast(t('links.added'));
206
+ setUrl('');
207
+ setTitle('');
208
+ setError(null);
209
+ onOpenChange(false);
210
+ },
211
+ onError: (err) => setError(err instanceof ApiError && err.code === 'link_limit' ? 'limit' : 'failed'),
212
+ });
213
+ };
214
+ return (_jsx(Modal, { open: open, onOpenChange: (next) => !next && close(), children: _jsxs(ModalContent, { className: "lg:max-w-md", children: [_jsxs(ModalHeader, { children: [_jsx(ModalTitle, { children: t('links.add') }), _jsx(ModalDescription, { children: t('links.addDescription', { place }) })] }), _jsxs("form", {
215
+ // The URL check below says what is wrong, in the viewer's language.
216
+ noValidate: true, onSubmit: (event) => {
217
+ event.preventDefault();
218
+ submit();
219
+ }, children: [_jsx(ModalBody, { children: _jsxs(FieldGroup, { className: "gap-5", children: [_jsxs(Field, { className: "gap-1.5", children: [_jsx(FieldLabel, { htmlFor: `${id}-url`, children: t('links.urlLabel') }), _jsx(Input, { id: `${id}-url`, type: "url", inputMode: "url", autoComplete: "off", spellCheck: false, autoFocus: true, value: url, maxLength: URL_MAX, placeholder: "https://", "aria-invalid": error === 'invalid' ? true : undefined, "aria-describedby": `${id}-url-hint`, onChange: (event) => {
220
+ setUrl(event.target.value);
221
+ if (error)
222
+ setError(null);
223
+ } }), _jsx(FieldDescription, { id: `${id}-url-hint`, className: "text-destructive", children: _jsx("span", { "aria-live": "polite", children: error === 'invalid'
224
+ ? t('links.invalidUrl')
225
+ : error === 'limit'
226
+ ? t('links.addLimit')
227
+ : error === 'failed'
228
+ ? t('links.addFailed')
229
+ : null }) })] }), _jsxs(Field, { className: "gap-1.5", children: [_jsx(FieldLabel, { htmlFor: `${id}-title`, children: t('links.titleLabel') }), _jsx(Input, { id: `${id}-title`, autoComplete: "off", value: title, maxLength: TITLE_MAX, placeholder: t('links.titlePlaceholder'), onChange: (event) => setTitle(event.target.value) })] })] }) }), _jsxs(ModalFooter, { className: "sm:justify-between", children: [_jsx(Button, { type: "button", variant: "outline-ghost", onClick: close, disabled: add.isPending, children: tI18nComplete.raw('text19766ed6ccb2') }), _jsxs(Button, { type: "submit", disabled: add.isPending, "aria-busy": add.isPending || undefined, children: [add.isPending ? _jsx(Loading, { className: "size-4 shrink-0" }) : null, t('links.add')] })] })] })] }) }));
230
+ }
@@ -0,0 +1,46 @@
1
+ import type { ProjectSpace, ProjectSpaceMember } from '@kortix/sdk';
2
+ /**
3
+ * The project's people, by display name: `#general`'s member list, which is
4
+ * every project member. `notIn`: the people not yet in that channel.
5
+ */
6
+ export declare function useProjectPeople(projectId: string, notIn?: ProjectSpace): {
7
+ available: ProjectSpaceMember[];
8
+ isLoading: boolean;
9
+ };
10
+ /**
11
+ * Invite someone to the project by email: the project's own grant dialog
12
+ * (`AccessDialog`, the one Access → Projects opens), for a viewer who may
13
+ * manage the project's members. `dialog` is rendered by the caller.
14
+ */
15
+ export declare function useInviteToProject(projectId: string): {
16
+ canInvite: boolean;
17
+ invite: () => void;
18
+ dialog: import("react").JSX.Element | null;
19
+ };
20
+ /** A person's face and display name, never an email. */
21
+ export declare function MemberAvatar({ member, size }: {
22
+ member: ProjectSpaceMember;
23
+ size?: 'xs' | 'sm' | 'md';
24
+ }): import("react").JSX.Element;
25
+ /**
26
+ * "Add members": one checklist of the project's people and agents not yet in
27
+ * the channel, in the access picker's rows, People first. People show to
28
+ * whoever may add (`can_add`), agents to whoever may edit the channel
29
+ * (`can_edit`); an empty group is hidden. Each check adds a chip. Arrow keys
30
+ * move the highlight across both groups from the search field; Enter checks
31
+ * the highlighted row. The footer adds the people (one request) and appends
32
+ * the agents in pick order (one PATCH), in parallel: on an empty agent list
33
+ * the first agent picked becomes the default. "Invite by email" in the
34
+ * footer opens the project's invite dialog, for someone not in the project.
35
+ */
36
+ export declare function AddChannelMembersDialog({ projectId, space, open, onOpenChange, }: {
37
+ projectId: string;
38
+ space: ProjectSpace;
39
+ open: boolean;
40
+ onOpenChange: (open: boolean) => void;
41
+ }): import("react").JSX.Element;
42
+ /** "Join channel", in the header of a public channel the viewer is not in. */
43
+ export declare function JoinChannelButton({ projectId, space }: {
44
+ projectId: string;
45
+ space: ProjectSpace;
46
+ }): import("react").JSX.Element;
@@ -0,0 +1,182 @@
1
+ 'use client';
2
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useAddProjectSpaceMembers, useJoinProjectSpace, useProjectSpaceMembers, useProjectAccountId, useProjectName, useProjectSpaces, useUpdateProjectSpace, useVisibleAgents, } from '@kortix/sdk/react';
4
+ import { EnvelopeSimpleIcon, MagnifyingGlassIcon } from '@phosphor-icons/react';
5
+ import { useEffect, useMemo, useRef, useState } from 'react';
6
+ import { AccessDialog } from '../../access/access/access-dialog.js';
7
+ import { PickerRow } from '../../access/access/principal-picker.js';
8
+ import { useTranslations } from '../../i18n/index.js';
9
+ import { Close } from '../../icons/close.js';
10
+ import { AgentMark } from '../../internal/components/agent-mark.js';
11
+ import { PROJECT_ACTIONS } from '../../internal/lib/project-actions.js';
12
+ import { useProjectCan } from '../../internal/lib/use-project-can.js';
13
+ import { Badge } from '../../primitives/badge.js';
14
+ import { Button } from '../../primitives/button.js';
15
+ import { InputGroupSearch, InputGroupSearchClear, InputGroupSearchIcon, InputGroupSearchInput, } from '../../primitives/input-group.js';
16
+ import Loading from '../../primitives/loading.js';
17
+ import { Modal, ModalBody, ModalContent, ModalDescription, ModalFooter, ModalHeader, ModalTitle, } from '../../primitives/modal.js';
18
+ import { errorToast, successToast } from '../../primitives/toast.js';
19
+ import { UserAvatar } from '../../primitives/user-avatar.js';
20
+ import { agentLabel } from './space-timeline.js';
21
+ /**
22
+ * The project's people, by display name: `#general`'s member list, which is
23
+ * every project member. `notIn`: the people not yet in that channel.
24
+ */
25
+ export function useProjectPeople(projectId, notIn) {
26
+ const spaces = useProjectSpaces(projectId);
27
+ const generalId = spaces.data?.find((space) => space.is_default)?.space_id;
28
+ const everyone = useProjectSpaceMembers(projectId, generalId);
29
+ const inChannel = useProjectSpaceMembers(projectId, notIn?.is_default ? null : notIn?.space_id);
30
+ const available = useMemo(() => {
31
+ const taken = new Set((inChannel.data?.members ?? []).map((member) => member.user_id));
32
+ return (everyone.data?.members ?? []).filter((member) => !taken.has(member.user_id));
33
+ }, [everyone.data, inChannel.data]);
34
+ return { available, isLoading: everyone.isLoading || inChannel.isLoading };
35
+ }
36
+ /**
37
+ * Invite someone to the project by email: the project's own grant dialog
38
+ * (`AccessDialog`, the one Access → Projects opens), for a viewer who may
39
+ * manage the project's members. `dialog` is rendered by the caller.
40
+ */
41
+ export function useInviteToProject(projectId) {
42
+ const canInvite = useProjectCan(projectId, PROJECT_ACTIONS.PROJECT_MEMBERS_MANAGE).allowed === true;
43
+ const accountId = useProjectAccountId(canInvite ? projectId : undefined);
44
+ const projectName = useProjectName(canInvite ? projectId : undefined) ?? '';
45
+ const [open, setOpen] = useState(false);
46
+ const dialog = accountId ? (_jsx(AccessDialog, { open: open, onOpenChange: setOpen, accountId: accountId, scope: { kind: 'project', projectId, projectName }, mode: { kind: 'grant' } })) : null;
47
+ return { canInvite: canInvite && !!accountId, invite: () => setOpen(true), dialog };
48
+ }
49
+ /** A person's face and display name, never an email. */
50
+ export function MemberAvatar({ member, size = 'md' }) {
51
+ return _jsx(UserAvatar, { email: "", name: member.name, avatarUrl: member.avatar_url, size: size });
52
+ }
53
+ const candidateKey = (candidate) => `${candidate.kind}:${candidate.id}`;
54
+ /**
55
+ * "Add members": one checklist of the project's people and agents not yet in
56
+ * the channel, in the access picker's rows, People first. People show to
57
+ * whoever may add (`can_add`), agents to whoever may edit the channel
58
+ * (`can_edit`); an empty group is hidden. Each check adds a chip. Arrow keys
59
+ * move the highlight across both groups from the search field; Enter checks
60
+ * the highlighted row. The footer adds the people (one request) and appends
61
+ * the agents in pick order (one PATCH), in parallel: on an empty agent list
62
+ * the first agent picked becomes the default. "Invite by email" in the
63
+ * footer opens the project's invite dialog, for someone not in the project.
64
+ */
65
+ export function AddChannelMembersDialog({ projectId, space, open, onOpenChange, }) {
66
+ const invite = useInviteToProject(projectId);
67
+ return (_jsxs(_Fragment, { children: [_jsx(Modal, { open: open, onOpenChange: onOpenChange, children: _jsx(ModalContent, { className: "lg:max-w-md", children: open ? (_jsx(AddMembersForm, { projectId: projectId, space: space, onDone: () => onOpenChange(false), onInvite: invite.canInvite
68
+ ? () => {
69
+ onOpenChange(false);
70
+ invite.invite();
71
+ }
72
+ : null })) : null }) }), invite.dialog] }));
73
+ }
74
+ function AddMembersForm({ projectId, space, onDone, onInvite, }) {
75
+ const t = useTranslations('spaces.addMembers');
76
+ const canAdd = useProjectSpaceMembers(projectId, space.space_id).data?.can_add === true;
77
+ // Its creator or a project manager; an older API sends no `can_edit`.
78
+ const editable = space.can_edit !== false;
79
+ const outside = space.visibility === 'private' && space.is_member === false;
80
+ const people = useProjectPeople(projectId, canAdd ? space : undefined);
81
+ const agents = useVisibleAgents({ projectId });
82
+ const add = useAddProjectSpaceMembers(projectId, space.space_id);
83
+ const update = useUpdateProjectSpace(projectId);
84
+ const [picked, setPicked] = useState([]);
85
+ const [query, setQuery] = useState('');
86
+ const [highlight, setHighlight] = useState(0);
87
+ const listRef = useRef(null);
88
+ const pending = add.isPending || update.isPending;
89
+ const name = space.slug ?? space.name;
90
+ const current = useMemo(() => space.agents ?? [], [space.agents]);
91
+ const personRows = useMemo(() => canAdd
92
+ ? people.available
93
+ // A manager outside a private channel adds others, never themself (D1).
94
+ .filter((person) => !(outside && person.is_viewer))
95
+ .map((person) => ({ kind: 'person', id: person.user_id, label: person.name, person }))
96
+ : [], [canAdd, outside, people.available]);
97
+ const agentRows = useMemo(() => editable
98
+ ? agents.filter((agent) => !current.includes(agent.name)).map((agent) => ({ kind: 'agent', id: agent.name, label: agentLabel(agent.name) }))
99
+ : [], [editable, agents, current]);
100
+ const needle = query.trim().toLowerCase();
101
+ // A person by display name; an agent by its label or its slug.
102
+ const matches = (row) => !needle || row.label.toLowerCase().includes(needle) || (row.kind === 'agent' && row.id.toLowerCase().includes(needle));
103
+ const shownPeople = personRows.filter(matches);
104
+ const shownAgents = agentRows.filter(matches);
105
+ // One list for the arrow keys: People, then Agents.
106
+ const shown = [...shownPeople, ...shownAgents];
107
+ const pickedKeys = new Set(picked.map(candidateKey));
108
+ const toggle = (row) => setPicked((list) => (list.some((item) => candidateKey(item) === candidateKey(row)) ? list.filter((item) => candidateKey(item) !== candidateKey(row)) : [...list, row]));
109
+ // The highlighted row stays in view as the arrow keys move it.
110
+ useEffect(() => {
111
+ listRef.current?.querySelector(`[data-row="${highlight}"]`)?.scrollIntoView({ block: 'nearest' });
112
+ }, [highlight]);
113
+ const onKeyDown = (event) => {
114
+ if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {
115
+ event.preventDefault();
116
+ const step = event.key === 'ArrowDown' ? 1 : -1;
117
+ setHighlight((index) => (shown.length === 0 ? 0 : (index + step + shown.length) % shown.length));
118
+ }
119
+ else if (event.key === 'Enter') {
120
+ event.preventDefault();
121
+ const row = shown[Math.min(highlight, shown.length - 1)];
122
+ if (row)
123
+ toggle(row);
124
+ }
125
+ };
126
+ /** "1 person", "2 agents", "1 person and 2 agents". */
127
+ const summary = (personCount, agentCount) => {
128
+ const who = personCount > 0 ? t('peopleCount', { count: personCount }) : null;
129
+ const what = agentCount > 0 ? t('agentsCount', { count: agentCount }) : null;
130
+ return who && what ? t('both', { people: who, agents: what }) : (who ?? what ?? '');
131
+ };
132
+ const pickedPeople = picked.filter((row) => row.kind === 'person').map((row) => row.id);
133
+ const pickedAgents = picked.filter((row) => row.kind === 'agent').map((row) => row.id);
134
+ const submit = async () => {
135
+ if (picked.length === 0 || pending)
136
+ return;
137
+ const [peopleResult, agentsResult] = await Promise.allSettled([
138
+ pickedPeople.length > 0 ? add.mutateAsync(pickedPeople) : null,
139
+ pickedAgents.length > 0 ? update.mutateAsync({ spaceId: space.space_id, input: { agents: [...current, ...pickedAgents] } }) : null,
140
+ ]);
141
+ const peopleFailed = peopleResult.status === 'rejected';
142
+ const agentsFailed = agentsResult.status === 'rejected';
143
+ if (!peopleFailed && !agentsFailed) {
144
+ successToast(t('added', { what: summary(pickedPeople.length, pickedAgents.length), name }));
145
+ onDone();
146
+ return;
147
+ }
148
+ // Keep the part that failed selected, so a second click retries only it.
149
+ setPicked((list) => list.filter((row) => (row.kind === 'person' ? peopleFailed : agentsFailed)));
150
+ if (peopleFailed && agentsFailed)
151
+ errorToast(t('failed'));
152
+ else if (peopleFailed)
153
+ errorToast(pickedAgents.length > 0 ? t('peopleFailedAgentsAdded', { what: summary(0, pickedAgents.length), name }) : t('peopleFailed'));
154
+ else
155
+ errorToast(pickedPeople.length > 0 ? t('agentsFailedPeopleAdded', { what: summary(pickedPeople.length, 0), name }) : t('agentsFailed'));
156
+ };
157
+ const loading = canAdd && people.isLoading;
158
+ const empty = loading
159
+ ? null
160
+ : personRows.length + agentRows.length === 0
161
+ ? t('allAdded')
162
+ : shown.length === 0
163
+ ? t('noMatches', { query: query.trim() })
164
+ : null;
165
+ const group = (label, rows, offset) => rows.length === 0 ? null : (_jsxs("div", { role: "group", "aria-label": label, children: [_jsx("h3", { className: "text-muted-foreground px-2 pt-2 pb-1 text-xs font-medium", children: label }), rows.map((row, index) => (_jsx("div", { "data-row": offset + index, children: _jsx(PickerRow, { selection: "multi", selected: pickedKeys.has(candidateKey(row)), highlighted: offset + index === highlight, disabled: pending, onSelect: () => toggle(row),
166
+ // The 28px tile, as in the Members list: a person row and an agent row share one height.
167
+ leading: row.kind === 'person' ? _jsx(MemberAvatar, { member: row.person }) : _jsx(AgentMark, { slug: row.id, size: 21 }), label: row.label }) }, candidateKey(row))))] }));
168
+ return (_jsxs(_Fragment, { children: [_jsxs(ModalHeader, { children: [_jsx(ModalTitle, { children: t('title', { name }) }), _jsx(ModalDescription, { children: t('description') })] }), _jsxs(ModalBody, { className: "space-y-3", children: [picked.length > 0 ? (_jsx("ul", { className: "flex flex-wrap gap-1.5", "aria-label": t('selected'), children: picked.map((row) => (_jsx("li", { children: _jsxs(Badge, { variant: "outline", size: "sm", className: "gap-1.5 py-0.5 pr-0.5 pl-1 font-sans text-xs tracking-normal", children: [row.kind === 'person' ? _jsx(MemberAvatar, { member: row.person, size: "xs" }) : _jsx(AgentMark, { slug: row.id, size: 14, tile: 18 }), row.label, _jsx(Button, { type: "button", variant: "ghost", size: "icon-xs", className: "text-muted-foreground size-5", "aria-label": t('unpick', { member: row.label }), disabled: pending, onClick: () => toggle(row), children: _jsx(Close, { className: "size-3" }) })] }) }, candidateKey(row)))) })) : null, _jsxs("div", { className: "border-border overflow-hidden rounded-md border", children: [_jsxs(InputGroupSearch, { className: "border-b", children: [_jsx(InputGroupSearchIcon, { children: _jsx(MagnifyingGlassIcon, {}) }), _jsx(InputGroupSearchInput, { value: query, onChange: (event) => {
169
+ setQuery(event.target.value);
170
+ setHighlight(0);
171
+ }, onKeyDown: onKeyDown, placeholder: t('search'), "aria-label": t('search'), autoFocus: true }), query ? _jsx(InputGroupSearchClear, { onClick: () => setQuery('') }) : null] }), _jsx("div", { ref: listRef, className: "max-h-72 overflow-y-auto p-1", children: loading ? (_jsx("div", { className: "flex justify-center py-6", children: _jsx(Loading, { className: "size-4 shrink-0" }) })) : empty ? (_jsxs("div", { className: "flex flex-col items-center gap-3 px-3 py-6", children: [_jsx("p", { className: "text-muted-foreground text-center text-xs", children: empty }), onInvite && !needle ? (_jsxs(Button, { type: "button", variant: "outline", size: "sm", className: "gap-1.5", onClick: onInvite, children: [_jsx(EnvelopeSimpleIcon, { "aria-hidden": true, className: "size-3.5 shrink-0" }), t('inviteByEmail')] })) : null] })) : (_jsxs(_Fragment, { children: [group(t('people'), shownPeople, 0), group(t('agents'), shownAgents, shownPeople.length)] })) })] })] }), _jsxs(ModalFooter, { className: "sm:justify-between", children: [onInvite ? (_jsx(Button, { type: "button", variant: "transparent", size: "sm", className: "text-muted-foreground hover:text-foreground h-auto p-0 text-xs font-normal", onClick: onInvite, children: t('inviteByEmail') })) : (_jsx("span", {})), _jsxs("div", { className: "flex w-full flex-col-reverse gap-2 sm:w-auto sm:flex-row", children: [_jsx(Button, { type: "button", variant: "outline-ghost", onClick: onDone, disabled: pending, children: t('cancel') }), _jsxs(Button, { type: "button", onClick: submit, disabled: picked.length === 0 || pending, "aria-busy": pending || undefined, children: [pending ? _jsx(Loading, { className: "size-4 shrink-0" }) : null, picked.length === 0 ? t('confirmEmpty') : t('confirm', { what: summary(pickedPeople.length, pickedAgents.length) })] })] })] })] }));
172
+ }
173
+ /** "Join channel", in the header of a public channel the viewer is not in. */
174
+ export function JoinChannelButton({ projectId, space }) {
175
+ const t = useTranslations('spaces.view');
176
+ const join = useJoinProjectSpace(projectId, space.space_id);
177
+ const name = space.slug ?? space.name;
178
+ return (_jsxs(Button, { size: "sm", variant: "secondary", className: "shrink-0", disabled: join.isPending, "aria-busy": join.isPending || undefined, onClick: () => join.mutate(undefined, {
179
+ onSuccess: () => successToast(t('joined', { name })),
180
+ onError: () => errorToast(t('joinFailed')),
181
+ }), children: [join.isPending ? _jsx(Loading, { className: "size-4 shrink-0" }) : null, t('join')] }));
182
+ }
@@ -0,0 +1,15 @@
1
+ import { type spaceRoster } from './space-timeline.js';
2
+ type Roster = ReturnType<typeof spaceRoster>;
3
+ /**
4
+ * Who is in the channel, in its header: its members' faces, a hairline, its
5
+ * agents' tiles. The same for every viewer (the channel's member list and
6
+ * agent list, not the threads a viewer can load). People and agents never mix, so a glance tells them apart.
7
+ * Hover, or a click, opens the session header's people card
8
+ * (`SessionParticipantStack`): People, then Agents, each a label, a count and
9
+ * plain rows. Its one action, "View all members", opens the Members tab.
10
+ */
11
+ export declare function SpaceRosterButton({ roster, onViewAll }: {
12
+ roster: Roster;
13
+ onViewAll: () => void;
14
+ }): import("react").JSX.Element;
15
+ export {};
@@ -0,0 +1,44 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { useState } from 'react';
4
+ import { useTranslations } from '../../i18n/index.js';
5
+ import { AgentMark } from '../../internal/components/agent-mark.js';
6
+ import { AvatarGroup, AvatarGroupCount } from '../../primitives/avatar.js';
7
+ import { Button } from '../../primitives/button.js';
8
+ import { FadedScrollArea } from '../../primitives/faded-scroll-area.js';
9
+ import { HoverCard, HoverCardContent, HoverCardTrigger } from '../../primitives/hover-card.js';
10
+ import { UserAvatar } from '../../primitives/user-avatar.js';
11
+ import { participantLabel } from '../../session/participants/session-participants.js';
12
+ import { agentLabel } from './space-timeline.js';
13
+ /** Faces before the rest collapse into "+N": two people, three agents. */
14
+ const PEOPLE_SHOWN = 2;
15
+ const AGENTS_SHOWN = 3;
16
+ /**
17
+ * Who is in the channel, in its header: its members' faces, a hairline, its
18
+ * agents' tiles. The same for every viewer (the channel's member list and
19
+ * agent list, not the threads a viewer can load). People and agents never mix, so a glance tells them apart.
20
+ * Hover, or a click, opens the session header's people card
21
+ * (`SessionParticipantStack`): People, then Agents, each a label, a count and
22
+ * plain rows. Its one action, "View all members", opens the Members tab.
23
+ */
24
+ export function SpaceRosterButton({ roster, onViewAll }) {
25
+ const t = useTranslations('spaces.view');
26
+ const [open, setOpen] = useState(false);
27
+ const { people, agents } = roster;
28
+ const morePeople = people.length - PEOPLE_SHOWN;
29
+ const moreAgents = agents.length - AGENTS_SHOWN;
30
+ const label = t('roster', {
31
+ people: t('rosterPeople', { count: people.length }),
32
+ agents: t('rosterAgents', { count: agents.length }),
33
+ });
34
+ return (_jsxs(HoverCard, { open: open, onOpenChange: setOpen, openDelay: 300, closeDelay: 100, children: [_jsx(HoverCardTrigger, { asChild: true, children: _jsxs("button", { type: "button", "aria-label": label, "aria-expanded": open, onClick: () => setOpen((value) => !value), className: "hover:bg-hover focus-visible:ring-ring data-[state=open]:bg-hover flex h-8 shrink-0 cursor-pointer items-center gap-2 rounded-md border px-1.5 outline-none focus-visible:ring-2", children: [people.length > 0 ? (_jsxs(AvatarGroup, { className: "-space-x-1", children: [people.slice(0, PEOPLE_SHOWN).map((person) => (_jsx(UserAvatar, { email: person.email ?? '', name: participantLabel(person), avatarUrl: person.avatarUrl, size: "xs", ring: true }, person.id))), morePeople > 0 ? (_jsxs(AvatarGroupCount, { className: "h-5 w-auto min-w-5 rounded-full px-1 text-xs tabular-nums", children: ["+", morePeople] })) : null] })) : null, people.length > 0 && agents.length > 0 ? _jsx("span", { "aria-hidden": true, className: "bg-border h-4 w-px shrink-0" }) : null, agents.length > 0 ? (_jsxs("span", { className: "flex -space-x-1", children: [agents.slice(0, AGENTS_SHOWN).map((agent) => (
35
+ // 18px tile: the people's `xs` faces and the `+N` chip are `h-5`.
36
+ _jsx(AgentMark, { slug: agent, size: 14, tile: 18, className: "ring-background ring-2" }, agent))), moreAgents > 0 ? (_jsxs("span", { className: "bg-muted text-muted-foreground ring-background flex h-5 min-w-5 items-center justify-center rounded-sm px-1 text-xs font-medium tabular-nums ring-2", children: ["+", moreAgents] })) : null] })) : null] }) }), _jsxs(HoverCardContent, { side: "bottom", align: "end", sideOffset: 6, animated: false, className: "w-72 overflow-hidden p-0", onEscapeKeyDown: () => setOpen(false), children: [_jsxs(FadedScrollArea, { fadeColor: "from-popover", fadeSize: "6", className: "max-h-80 overscroll-contain", children: [people.length > 0 ? (_jsx(RosterGroup, { title: t('rosterTitlePeople'), count: people.length, children: people.map((person) => (_jsxs("li", { className: "text-foreground flex min-h-9 items-center gap-2.5 px-2 py-1 text-sm", children: [_jsx(UserAvatar, { email: person.email ?? '', name: participantLabel(person), avatarUrl: person.avatarUrl, size: "md" }), _jsx("span", { className: "min-w-0 flex-1 truncate", children: participantLabel(person) })] }, person.id))) })) : null, agents.length > 0 ? (_jsx(RosterGroup, { title: t('rosterTitleAgents'), count: agents.length, children: agents.map((agent) => (_jsxs("li", { className: "text-foreground flex min-h-9 items-center gap-2.5 px-2 py-1 text-sm", children: [_jsx(AgentMark, { slug: agent, size: 21 }), _jsxs("span", { className: "flex min-w-0 flex-1 flex-col", children: [_jsx("span", { className: "truncate leading-tight", children: agentLabel(agent) }), _jsx("span", { className: "text-muted-foreground truncate text-xs leading-tight tabular-nums", children: t('agentThreads', { count: roster.agentThreads[agent] ?? 0 }) })] })] }, agent))) })) : null] }), _jsx("div", { className: "border-t p-1", children: _jsx(Button, { variant: "ghost", size: "sm", className: "w-full justify-start font-normal", onClick: () => {
37
+ setOpen(false);
38
+ onViewAll();
39
+ }, children: t('viewAllMembers') }) })] })] }));
40
+ }
41
+ /** "People 6", then the rows: the session card's header line, once per group. */
42
+ function RosterGroup({ title, count, children }) {
43
+ return (_jsxs("section", { children: [_jsxs("div", { className: "text-muted-foreground flex items-center justify-between px-3.5 pt-2.5 pb-1 text-xs", children: [_jsx("span", { children: title }), _jsx("span", { className: "tabular-nums", children: count })] }), _jsx("ul", { className: "p-1 pt-0", children: children })] }));
44
+ }
@@ -0,0 +1,56 @@
1
+ import type { ProjectSpace } from '@kortix/sdk';
2
+ import { type ReactNode } from 'react';
3
+ import { type SpaceThreads } from './space-timeline-view.js';
4
+ /**
5
+ * The Threads tab of a channel or DM: a search over titles and first prompts,
6
+ * one Filter menu (Status, Started by, Agent, Activity), the active filters
7
+ * as removable tokens, and the rows. Search, person, agent and activity run
8
+ * on the server; Status reads the loaded rows, as on the Sessions page. The
9
+ * URL holds every value (`?q=&status=&by=&agent=&active=`).
10
+ */
11
+ export declare function SpaceThreadsTab({ projectId, space, threads, selectedId, onOpenThread, params, setParams, }: {
12
+ projectId: string;
13
+ space: ProjectSpace;
14
+ /** The space's unfiltered threads (the Chat tab's list): the people and agents the menu offers. */
15
+ threads: SpaceThreads;
16
+ selectedId: string | null;
17
+ onOpenThread: (sessionId: string) => void;
18
+ params: {
19
+ get(name: string): string | null;
20
+ };
21
+ setParams: (change: (params: URLSearchParams) => void) => void;
22
+ }): import("react").JSX.Element;
23
+ /**
24
+ * The search field of a channel tab's toolbar (Threads, Links). The text is
25
+ * local while typing; `onSearch` gets the settled query ('' below `minChars`),
26
+ * and Esc clears it. A new `value` (Clear, the back button) replaces the text.
27
+ */
28
+ export declare function FilterSearch({ value, placeholder, minChars, onSearch, }: {
29
+ value: string;
30
+ placeholder: string;
31
+ minChars?: number;
32
+ onSearch: (q: string) => void;
33
+ }): import("react").JSX.Element;
34
+ /** The quiet "Filter" button and its menu; the children are `Facet` rows. */
35
+ export declare function FilterMenu({ children }: {
36
+ children: ReactNode;
37
+ }): import("react").JSX.Element;
38
+ export type FilterToken<K extends string> = {
39
+ key: K;
40
+ facet: string;
41
+ label: string;
42
+ icon?: ReactNode;
43
+ };
44
+ /** The active filters as removable tokens, then Clear. */
45
+ export declare function FilterTokens<K extends string>({ tokens, onRemove, onClear, }: {
46
+ tokens: readonly FilterToken<K>[];
47
+ onRemove: (key: K) => void;
48
+ onClear: () => void;
49
+ }): import("react").JSX.Element | null;
50
+ /** A facet row: its name, its current value muted on the right, its choices in a submenu. */
51
+ export declare function Facet({ label, value, wide, children }: {
52
+ label: string;
53
+ value: string;
54
+ wide?: boolean;
55
+ children: ReactNode;
56
+ }): import("react").JSX.Element;