@nextclaw/ui 0.14.1 → 0.14.3

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 (224) hide show
  1. package/CHANGELOG.md +41 -0
  2. package/dist/assets/{api-DPcvCLfa.js → api-BP_8IaxB.js} +7 -7
  3. package/dist/assets/channels-list-page-DEh5Jjqx.js +8 -0
  4. package/dist/assets/chat-page-BRB0N5WW.js +105 -0
  5. package/dist/assets/config-split-page-CRhlZ_pH.js +1 -0
  6. package/dist/assets/{confirm-dialog-CWh5FfK2.js → confirm-dialog-DsivFJ4r.js} +2 -2
  7. package/dist/assets/{desktop-update-config-DsRhBizi.js → desktop-update-config-B0w9p2ep.js} +1 -1
  8. package/dist/assets/{dist-DPrgcEC0.js → dist-CikkhOlq.js} +1 -1
  9. package/dist/assets/{dist-DsE4OsSS.js → dist-PVA_xL1D.js} +1 -1
  10. package/dist/assets/doc-browser-BoNJ7-tE.js +1 -0
  11. package/dist/assets/doc-browser-CdJ_d4ik.js +1 -0
  12. package/dist/assets/doc-browser-context-MTw4EvKd.js +1 -0
  13. package/dist/assets/{ellipsis-B81FStLm.js → ellipsis-y6vDtq4M.js} +1 -1
  14. package/dist/assets/{external-link-C_dmG-WJ.js → external-link-DVJIQf_G.js} +1 -1
  15. package/dist/assets/index-BiE-K8-q.css +1 -0
  16. package/dist/assets/index-D9BAE_L_.js +105 -0
  17. package/dist/assets/mcp-marketplace-page-B1SZNY5m.js +40 -0
  18. package/dist/assets/mcp-marketplace-page-Cq_Tw42T.js +1 -0
  19. package/dist/assets/middleware-CkFT3R4v.js +1 -0
  20. package/dist/assets/model-config-page-DotaTUHb.js +1 -0
  21. package/dist/assets/plus-BbZqquJe.js +1 -0
  22. package/dist/assets/provider-scoped-model-input-DsFRuWJH.js +1 -0
  23. package/dist/assets/providers-config-page-DW4tQSLN.js +1 -0
  24. package/dist/assets/{react-sZz5HSCm.js → react-VNqT5Zp7.js} +1 -1
  25. package/dist/assets/remote-B8TiUfwW.js +1 -0
  26. package/dist/assets/rotate-cw-DjHDTkCv.js +1 -0
  27. package/dist/assets/runtime-config-page-S6ErRHR8.js +1 -0
  28. package/dist/assets/{save-MzjoiHri.js → save-BOJ477H-.js} +1 -1
  29. package/dist/assets/{search-B29dE4GN.js → search-BEti5beA.js} +1 -1
  30. package/dist/assets/{search-config-page-Dl5sZzob.js → search-config-page-DGj5am03.js} +1 -1
  31. package/dist/assets/{secrets-config-page-C_l-IFCK.js → secrets-config-page--IzrIOid.js} +2 -2
  32. package/dist/assets/{select-BKmh05hd.js → select-hoj8dK4K.js} +2 -2
  33. package/dist/assets/{tag-chip-BS_7Ueom.js → tag-chip-T8-h-die.js} +1 -1
  34. package/dist/assets/use-config-CjRV2hwL.js +1 -0
  35. package/dist/assets/x-D9PXs_xP.js +1 -0
  36. package/dist/index.html +70 -19
  37. package/index.html +55 -5
  38. package/package.json +9 -9
  39. package/src/app/components/app-presenter-provider.tsx +11 -2
  40. package/src/app/components/layout/__tests__/app-layout.test.tsx +11 -2
  41. package/src/app/components/layout/__tests__/sidebar.layout.test.tsx +110 -79
  42. package/src/app/components/layout/app-layout.tsx +18 -4
  43. package/src/app/components/layout/header.tsx +3 -3
  44. package/src/app/components/layout/page-layout.tsx +2 -2
  45. package/src/app/components/layout/runtime-status-entry.tsx +7 -7
  46. package/src/app/components/layout/sidebar-items.tsx +194 -71
  47. package/src/app/components/layout/sidebar-rail.styles.ts +15 -0
  48. package/src/app/components/layout/sidebar.tsx +340 -83
  49. package/src/app/managers/viewport-layout.manager.ts +10 -0
  50. package/src/app/stores/viewport-layout.store.ts +39 -3
  51. package/src/app/styles/design-system.css +388 -26
  52. package/src/app/test/vitest-setup.ts +31 -0
  53. package/src/features/agents/components/__tests__/agents-page.test.tsx +62 -39
  54. package/src/features/agents/components/agents-page.tsx +10 -6
  55. package/src/features/chat/components/chat-sidebar-list-mode-switch.tsx +3 -3
  56. package/src/features/chat/components/conversation/__tests__/chat-conversation-header-section.test.tsx +145 -0
  57. package/src/features/chat/components/conversation/__tests__/chat-conversation-header.test.tsx +4 -2
  58. package/src/features/chat/components/conversation/__tests__/chat-conversation-panel.test.tsx +69 -762
  59. package/src/features/chat/components/conversation/__tests__/chat-conversation-workspace-section.test.tsx +132 -0
  60. package/src/features/chat/components/conversation/chat-conversation-content.tsx +22 -15
  61. package/src/features/chat/components/conversation/chat-conversation-header-section.tsx +15 -16
  62. package/src/features/chat/components/conversation/chat-conversation-header.tsx +7 -6
  63. package/src/features/chat/components/conversation/chat-conversation-panel.tsx +19 -19
  64. package/src/features/chat/components/conversation/chat-conversation-skeleton.tsx +13 -13
  65. package/src/features/chat/components/conversation/chat-conversation-workspace-section.tsx +10 -4
  66. package/src/features/chat/components/layout/__tests__/chat-sidebar-read-state.test.tsx +52 -11
  67. package/src/features/chat/components/layout/__tests__/chat-sidebar.test.tsx +18 -16
  68. package/src/features/chat/components/layout/chat-page-shell.tsx +1 -1
  69. package/src/features/chat/components/layout/chat-sidebar-desktop-layout.tsx +247 -0
  70. package/src/features/chat/components/layout/chat-sidebar-toolbar.tsx +93 -20
  71. package/src/features/chat/components/layout/chat-sidebar-utility-menu.tsx +93 -36
  72. package/src/features/chat/components/layout/chat-sidebar.tsx +60 -93
  73. package/src/features/chat/components/providers/chat-presenter.provider.tsx +0 -6
  74. package/src/features/chat/features/conversation/components/__tests__/session-conversation-area.test.tsx +225 -0
  75. package/src/features/chat/features/conversation/components/__tests__/session-conversation-input.streaming.test.tsx +199 -0
  76. package/src/features/chat/features/conversation/components/session-conversation-area.tsx +308 -0
  77. package/src/features/chat/features/conversation/components/session-conversation-input.tsx +439 -0
  78. package/src/features/chat/features/conversation/hooks/use-session-conversation-controller.ts +194 -0
  79. package/src/features/chat/features/conversation/hooks/use-session-conversation-input-attachments.ts +66 -0
  80. package/src/features/chat/features/{input/hooks/use-chat-input-bar-query-state.ts → conversation/hooks/use-session-conversation-input-query.ts} +51 -20
  81. package/src/features/chat/features/conversation/hooks/use-session-conversation-input-state.ts +281 -0
  82. package/src/features/chat/features/conversation/utils/session-conversation-input-toolbar.utils.ts +158 -0
  83. package/src/features/chat/features/input/hooks/__tests__/use-chat-input-surface-state.test.tsx +56 -0
  84. package/src/features/chat/features/input/hooks/use-chat-input-surface-state.ts +117 -0
  85. package/src/features/chat/features/input/input-surface-plugins/__tests__/panel-app-reference-plugin.test.ts +77 -0
  86. package/src/features/chat/features/input/input-surface-plugins/__tests__/slash-command-plugin.test.ts +108 -0
  87. package/src/features/chat/features/input/input-surface-plugins/chat-input-product-plugin-adapters.types.ts +10 -0
  88. package/src/features/chat/features/input/input-surface-plugins/input-surface-search.utils.ts +108 -0
  89. package/src/features/chat/features/input/input-surface-plugins/panel-app-reference-plugin.utils.ts +108 -0
  90. package/src/features/chat/features/input/input-surface-plugins/slash-command-plugin.utils.ts +161 -0
  91. package/src/features/chat/features/input/utils/__tests__/chat-composer-state.utils.test.ts +22 -1
  92. package/src/features/chat/features/input/utils/__tests__/chat-inline-token.utils.test.ts +26 -13
  93. package/src/features/chat/features/input/utils/__tests__/ncp-chat-input-availability.utils.test.ts +7 -28
  94. package/src/features/chat/features/input/utils/chat-composer-state.utils.ts +6 -0
  95. package/src/features/chat/features/input/utils/chat-inline-token.utils.ts +26 -51
  96. package/src/features/chat/features/input/utils/chat-input-bar.utils.ts +2 -0
  97. package/src/features/chat/features/input/utils/ncp-chat-input-availability.utils.ts +5 -6
  98. package/src/features/chat/features/message/components/__tests__/chat-message-list.container.test.tsx +47 -12
  99. package/src/features/chat/features/message/components/chat-inline-panel-app-card.tsx +7 -7
  100. package/src/features/chat/features/message/components/chat-message-list.container.tsx +99 -18
  101. package/src/features/chat/features/message/utils/__tests__/chat-message.utils.test.ts +31 -12
  102. package/src/features/chat/features/message/utils/chat-message-markdown-part.utils.ts +38 -0
  103. package/src/features/chat/features/message/utils/chat-message-part.utils.ts +1 -1
  104. package/src/features/chat/features/session/components/chat-sidebar-project-groups.tsx +7 -7
  105. package/src/features/chat/features/session/components/chat-sidebar-session-list.tsx +6 -6
  106. package/src/features/chat/features/session/components/session-context-icon.tsx +2 -2
  107. package/src/features/chat/features/session/components/session-header/__tests__/chat-session-project-badge.test.tsx +2 -2
  108. package/src/features/chat/features/session/components/session-header/chat-session-header-actions.tsx +1 -1
  109. package/src/features/chat/features/session/components/session-header/chat-session-header-menu-item.tsx +1 -1
  110. package/src/features/chat/features/session/components/session-header/chat-session-metadata-dialog.tsx +1 -1
  111. package/src/features/chat/features/session/components/session-header/chat-session-project-badge.tsx +3 -3
  112. package/src/features/chat/features/session/components/session-run-badge.tsx +1 -1
  113. package/src/features/chat/features/session/hooks/__tests__/use-chat-session-project.test.tsx +3 -30
  114. package/src/features/chat/features/session/hooks/use-chat-session-project.ts +0 -5
  115. package/src/features/chat/features/session/utils/chat-run-metadata.utils.ts +8 -0
  116. package/src/features/chat/features/session-type/components/__tests__/chat-session-type-menu.test.tsx +2 -2
  117. package/src/features/chat/features/session-type/components/__tests__/chat-session-type-option-item.test.tsx +2 -0
  118. package/src/features/chat/features/session-type/components/chat-session-type-menu.tsx +2 -2
  119. package/src/features/chat/features/session-type/components/chat-session-type-option-item.tsx +2 -2
  120. package/src/features/chat/features/session-type/hooks/use-chat-session-type-state.ts +10 -2
  121. package/src/features/chat/features/welcome/components/__tests__/chat-conversation-welcome.test.tsx +49 -31
  122. package/src/features/chat/features/welcome/components/__tests__/chat-welcome.test.tsx +2 -9
  123. package/src/features/chat/features/welcome/components/chat-conversation-welcome.tsx +21 -10
  124. package/src/features/chat/features/welcome/components/chat-welcome-agent-picker.tsx +3 -3
  125. package/src/features/chat/features/welcome/components/chat-welcome-capability-grid.tsx +4 -4
  126. package/src/features/chat/features/welcome/components/chat-welcome-project-picker.tsx +14 -19
  127. package/src/features/chat/features/welcome/components/chat-welcome-session-type-picker.tsx +5 -5
  128. package/src/features/chat/features/welcome/components/chat-welcome.tsx +6 -6
  129. package/src/features/chat/features/welcome/utils/__tests__/chat-welcome-project-options.utils.test.ts +6 -8
  130. package/src/features/chat/features/welcome/utils/chat-welcome-project-options.utils.ts +1 -16
  131. package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-panel-content.test.tsx +54 -0
  132. package/src/features/chat/features/workspace/components/chat-session-workspace-panel-content.tsx +44 -76
  133. package/src/features/chat/features/workspace/components/chat-session-workspace-panel-nav.tsx +5 -1
  134. package/src/features/chat/features/workspace/components/chat-session-workspace-panel.tsx +7 -1
  135. package/src/features/chat/features/workspace/hooks/use-chat-conversation-workspace-state.ts +40 -31
  136. package/src/features/chat/features/workspace/utils/__tests__/chat-workspace-panel-view-model.utils.test.ts +59 -1
  137. package/src/features/chat/features/workspace/utils/chat-thread-workspace-session.utils.ts +109 -0
  138. package/src/features/chat/features/workspace/utils/chat-workspace-panel-view-model.utils.ts +44 -4
  139. package/src/features/chat/index.ts +0 -1
  140. package/src/features/chat/managers/__tests__/chat-session-list.manager.test.ts +51 -99
  141. package/src/features/chat/managers/__tests__/chat-thread.manager.test.ts +135 -21
  142. package/src/features/chat/managers/chat-session-list.manager.ts +12 -43
  143. package/src/features/chat/managers/chat-thread.manager.ts +108 -34
  144. package/src/features/chat/pages/__tests__/ncp-chat-page.test.ts +48 -1
  145. package/src/features/chat/pages/__tests__/ncp-chat-page.test.tsx +72 -0
  146. package/src/features/chat/pages/ncp-chat-page.tsx +0 -122
  147. package/src/features/chat/presenters/chat.presenter.ts +2 -19
  148. package/src/features/chat/stores/__tests__/chat-thread.store.test.ts +31 -0
  149. package/src/features/chat/stores/chat-thread.store.ts +42 -26
  150. package/src/features/panel-apps/components/panel-app-list-item.tsx +8 -8
  151. package/src/features/panel-apps/components/panel-app-toolbar.tsx +4 -4
  152. package/src/features/panel-apps/components/panel-apps-list.tsx +20 -20
  153. package/src/features/panel-apps/hooks/use-panel-apps.ts +2 -1
  154. package/src/features/pwa/managers/__tests__/pwa-shell-theme.manager.test.ts +70 -6
  155. package/src/features/pwa/managers/pwa-shell-theme.manager.ts +10 -5
  156. package/src/features/service-apps/components/service-action-authorization-dialog.tsx +8 -8
  157. package/src/features/service-apps/components/service-apps-panel.tsx +24 -24
  158. package/src/features/settings/components/config/provider-advanced-settings-section.tsx +5 -5
  159. package/src/features/settings/components/config/provider-auth-section.tsx +7 -7
  160. package/src/features/settings/components/config/provider-form.tsx +10 -10
  161. package/src/features/settings/components/config/provider-models-section.tsx +16 -16
  162. package/src/features/settings/components/config/provider-pill-selector.tsx +1 -1
  163. package/src/features/settings/pages/providers-config-page.tsx +17 -17
  164. package/src/platforms/desktop/components/__tests__/desktop-app-shell.test.tsx +50 -10
  165. package/src/platforms/desktop/components/desktop-app-shell.tsx +34 -10
  166. package/src/platforms/desktop/components/desktop-window-chrome.tsx +41 -16
  167. package/src/shared/components/config-split-page.tsx +11 -11
  168. package/src/shared/components/doc-browser/doc-browser-home-page.tsx +2 -2
  169. package/src/shared/components/doc-browser/doc-browser-panel-parts.tsx +4 -4
  170. package/src/shared/components/doc-browser/doc-browser-tab-strip.tsx +4 -4
  171. package/src/shared/components/doc-browser/doc-browser.tsx +3 -3
  172. package/src/shared/components/resizable-right-panel/resizable-right-panel.tsx +1 -1
  173. package/src/shared/components/ui/actions/icon-action-button.tsx +1 -1
  174. package/src/shared/components/ui/button.tsx +4 -4
  175. package/src/shared/components/ui/card.tsx +4 -4
  176. package/src/shared/components/ui/dialog.tsx +5 -5
  177. package/src/shared/components/ui/input.tsx +1 -1
  178. package/src/shared/components/ui/label.tsx +1 -1
  179. package/src/shared/components/ui/popover.tsx +1 -1
  180. package/src/shared/components/ui/select.tsx +3 -3
  181. package/src/shared/components/ui/switch.tsx +3 -3
  182. package/src/shared/components/ui/tab-strip/__tests__/compact-tab-strip.test.tsx +24 -1
  183. package/src/shared/components/ui/tab-strip/compact-tab-strip.tsx +8 -4
  184. package/src/shared/components/ui/tabs.tsx +4 -4
  185. package/src/shared/components/ui/textarea.tsx +1 -1
  186. package/src/shared/lib/i18n/locales/en-US/chat.json +20 -2
  187. package/src/shared/lib/i18n/locales/en-US/core.json +9 -2
  188. package/src/shared/lib/i18n/locales/zh-CN/chat.json +20 -2
  189. package/src/shared/lib/i18n/locales/zh-CN/core.json +9 -2
  190. package/src/shared/lib/theme/index.ts +94 -52
  191. package/src/shared/lib/ui-document-title/__tests__/ui-document-title.test.ts +49 -0
  192. package/src/shared/lib/ui-document-title/index.ts +50 -21
  193. package/dist/assets/channels-list-page-D6jtziu4.js +0 -8
  194. package/dist/assets/chat-page-BBnNJoKG.js +0 -105
  195. package/dist/assets/config-split-page-BCJhqdK9.js +0 -1
  196. package/dist/assets/doc-browser-C8xOF_9F.js +0 -1
  197. package/dist/assets/doc-browser-DgQedeAn.js +0 -1
  198. package/dist/assets/doc-browser-context-B46tQGmO.js +0 -1
  199. package/dist/assets/index-7o1WdUbU.js +0 -103
  200. package/dist/assets/index-DQWmEWzk.css +0 -1
  201. package/dist/assets/mcp-marketplace-page-CWZN7ohK.js +0 -1
  202. package/dist/assets/mcp-marketplace-page-Dzull_4-.js +0 -40
  203. package/dist/assets/model-config-page-Cv0O3BIj.js +0 -1
  204. package/dist/assets/plus-Bnt56oqG.js +0 -1
  205. package/dist/assets/provider-scoped-model-input-Duuh7i3h.js +0 -1
  206. package/dist/assets/providers-config-page-CPDz0Lxc.js +0 -1
  207. package/dist/assets/remote-B0LMs8u7.js +0 -1
  208. package/dist/assets/rotate-cw-BfyG_KEF.js +0 -1
  209. package/dist/assets/runtime-config-page-q0fvv8ME.js +0 -1
  210. package/dist/assets/use-config-DZkBWIdL.js +0 -1
  211. package/dist/assets/x-CW2KO-Hz.js +0 -1
  212. package/src/features/chat/components/conversation/chat-conversation-alerts.tsx +0 -37
  213. package/src/features/chat/features/input/components/__tests__/chat-attachment-upload-limit.test.ts +0 -38
  214. package/src/features/chat/features/input/components/chat-input-bar.container.tsx +0 -496
  215. package/src/features/chat/features/message/utils/chat-message-inline-content.utils.ts +0 -95
  216. package/src/features/chat/managers/__tests__/chat-input.manager.test.ts +0 -448
  217. package/src/features/chat/managers/__tests__/chat-run-snapshot.manager.test.ts +0 -129
  218. package/src/features/chat/managers/__tests__/chat-run.manager.test.ts +0 -236
  219. package/src/features/chat/managers/__tests__/chat-session-preference-sync.manager.test.ts +0 -219
  220. package/src/features/chat/managers/chat-input.manager.ts +0 -430
  221. package/src/features/chat/managers/chat-run.manager.ts +0 -110
  222. package/src/features/chat/managers/chat-session-preference-sync.manager.ts +0 -142
  223. package/src/features/chat/stores/chat-input.store.ts +0 -104
  224. /package/dist/assets/{config-hints-CTqBnCDp.js → config-hints-BkYBc7z0.js} +0 -0
@@ -1,4 +1,5 @@
1
1
  import { useMemo, useState } from "react";
2
+ import { useNavigate } from "react-router-dom";
2
3
  import {
3
4
  useDeleteAgent,
4
5
  useAgents,
@@ -18,6 +19,7 @@ import {
18
19
  usePresenter,
19
20
  useNcpChatSessionTypes,
20
21
  } from "@/features/chat";
22
+ import { useAppPresenter } from "@/app/components/app-presenter-provider";
21
23
  import { AgentAvatar } from "@/shared/components/common/agent-avatar";
22
24
  import { Button } from "@/shared/components/ui/button";
23
25
  import { Card, CardContent } from "@/shared/components/ui/card";
@@ -235,6 +237,8 @@ function AgentListCard(props: {
235
237
 
236
238
  export function AgentsPage() {
237
239
  const presenter = usePresenter();
240
+ const appPresenter = useAppPresenter();
241
+ const navigate = useNavigate();
238
242
  const agentsQuery = useAgents();
239
243
  const configQuery = useConfig();
240
244
  const providersQuery = useProviders();
@@ -309,14 +313,16 @@ export function AgentsPage() {
309
313
  resolveAgentRuntimeSessionType(agent, defaultRuntime),
310
314
  );
311
315
  };
316
+ const requestAgentCreationDraft = () => {
317
+ navigate("/chat");
318
+ appPresenter.chatDraftIntentManager.requestDraft(AGENT_CREATION_PROMPT);
319
+ };
312
320
 
313
321
  return (
314
322
  <PageLayout className="space-y-5">
315
323
  <AgentsHero
316
324
  agentCount={agents.length}
317
- onCreate={() =>
318
- presenter.startAgentCreationDraft(AGENT_CREATION_PROMPT)
319
- }
325
+ onCreate={requestAgentCreationDraft}
320
326
  />
321
327
 
322
328
  <div className="grid gap-4 md:grid-cols-2 xl:grid-cols-3">
@@ -342,9 +348,7 @@ export function AgentsPage() {
342
348
  type="button"
343
349
  variant="primary"
344
350
  className="mt-5 rounded-2xl px-5"
345
- onClick={() =>
346
- presenter.startAgentCreationDraft(AGENT_CREATION_PROMPT)
347
- }
351
+ onClick={requestAgentCreationDraft}
348
352
  >
349
353
  <Plus className="mr-2 h-4 w-4" />
350
354
  {t("agentsCreateButton")}
@@ -10,16 +10,16 @@ export function ChatSidebarListModeSwitch({ isProjectFirstView, onSelectMode }:
10
10
  type="button"
11
11
  aria-pressed={!isProjectFirstView}
12
12
  onClick={() => onSelectMode('time-first')}
13
- className={cn('transition-colors', isProjectFirstView ? 'text-gray-400 hover:text-gray-600' : 'font-medium text-gray-600')}
13
+ className={cn('transition-colors', isProjectFirstView ? 'text-muted-foreground/65 hover:text-muted-foreground' : 'font-medium text-foreground')}
14
14
  >
15
15
  {t('chatSidebarViewTime')}
16
16
  </button>
17
- <span className="text-gray-300">/</span>
17
+ <span className="text-muted-foreground/35">/</span>
18
18
  <button
19
19
  type="button"
20
20
  aria-pressed={isProjectFirstView}
21
21
  onClick={() => onSelectMode('project-first')}
22
- className={cn('transition-colors', isProjectFirstView ? 'font-medium text-gray-600' : 'text-gray-400 hover:text-gray-600')}
22
+ className={cn('transition-colors', isProjectFirstView ? 'font-medium text-foreground' : 'text-muted-foreground/65 hover:text-muted-foreground')}
23
23
  >
24
24
  {t('chatSidebarViewProject')}
25
25
  </button>
@@ -0,0 +1,145 @@
1
+ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
2
+ import { render, screen } from "@testing-library/react";
3
+ import userEvent from "@testing-library/user-event";
4
+ import type { PersistStorage, StorageValue } from "zustand/middleware";
5
+ import { beforeEach, describe, expect, it, vi } from "vitest";
6
+ import { ChatConversationHeaderSection } from "@/features/chat/components/conversation/chat-conversation-header-section";
7
+ import { useChatQueryStore } from "@/features/chat/stores/ncp-chat-query.store";
8
+ import { useChatSessionListStore } from "@/features/chat/stores/chat-session-list.store";
9
+ import { useChatThreadStore } from "@/features/chat/stores/chat-thread.store";
10
+ import type { NcpSessionSummaryView } from "@/shared/lib/api";
11
+
12
+ const mocks = vi.hoisted(() => ({
13
+ deleteSession: vi.fn(),
14
+ openChildSessionPanel: vi.fn(),
15
+ openSessionCronPanel: vi.fn(),
16
+ }));
17
+
18
+ vi.mock("@/features/chat/components/providers/chat-presenter.provider", () => ({
19
+ usePresenter: () => ({
20
+ chatThreadManager: {
21
+ deleteSession: mocks.deleteSession,
22
+ openChildSessionPanel: mocks.openChildSessionPanel,
23
+ openSessionCronPanel: mocks.openSessionCronPanel,
24
+ },
25
+ }),
26
+ }));
27
+
28
+ vi.mock("@/features/cron", () => ({
29
+ useCronJobs: () => ({ data: { jobs: [] } }),
30
+ }));
31
+
32
+ class MemoryPersistStorage implements PersistStorage<unknown> {
33
+ private readonly values = new Map<string, StorageValue<unknown>>();
34
+
35
+ getItem = (name: string) => this.values.get(name) ?? null;
36
+
37
+ setItem = (name: string, value: StorageValue<unknown>) => {
38
+ this.values.set(name, value);
39
+ };
40
+
41
+ removeItem = (name: string) => {
42
+ this.values.delete(name);
43
+ };
44
+ }
45
+
46
+ function createSummary(
47
+ overrides: Partial<NcpSessionSummaryView> & Pick<NcpSessionSummaryView, "sessionId">,
48
+ ): NcpSessionSummaryView {
49
+ return {
50
+ messageCount: 1,
51
+ status: "idle",
52
+ updatedAt: "2026-06-18T00:00:00.000Z",
53
+ ...overrides,
54
+ };
55
+ }
56
+
57
+ function renderHeaderSection() {
58
+ const queryClient = new QueryClient({
59
+ defaultOptions: {
60
+ queries: { retry: false },
61
+ mutations: { retry: false },
62
+ },
63
+ });
64
+ return render(
65
+ <QueryClientProvider client={queryClient}>
66
+ <ChatConversationHeaderSection layoutMode="desktop" />
67
+ </QueryClientProvider>,
68
+ );
69
+ }
70
+
71
+ describe("ChatConversationHeaderSection", () => {
72
+ beforeEach(() => {
73
+ mocks.deleteSession.mockReset();
74
+ mocks.openChildSessionPanel.mockReset();
75
+ mocks.openSessionCronPanel.mockReset();
76
+ useChatSessionListStore.persist.setOptions({
77
+ storage: new MemoryPersistStorage(),
78
+ });
79
+ useChatThreadStore.persist.setOptions({
80
+ storage: new MemoryPersistStorage(),
81
+ });
82
+ useChatSessionListStore.setState({
83
+ snapshot: {
84
+ ...useChatSessionListStore.getState().snapshot,
85
+ selectedAgentId: "main",
86
+ selectedSessionKey: "parent-session-1",
87
+ },
88
+ });
89
+ useChatThreadStore.setState({
90
+ snapshot: {
91
+ ...useChatThreadStore.getState().snapshot,
92
+ sessionKey: "parent-session-1",
93
+ childSessionTabs: [],
94
+ workspaceFileTabs: [],
95
+ workspacePanelParentKey: null,
96
+ activeWorkspacePanelKind: null,
97
+ },
98
+ });
99
+ useChatQueryStore.setState({
100
+ snapshot: {
101
+ sessionsQuery: {
102
+ data: {
103
+ sessions: [
104
+ createSummary({
105
+ sessionId: "parent-session-1",
106
+ metadata: {
107
+ label: "Parent Task",
108
+ session_type: "native",
109
+ },
110
+ }),
111
+ createSummary({
112
+ sessionId: "child-session-1",
113
+ agentId: "verifier",
114
+ metadata: {
115
+ label: "Child Task",
116
+ parent_session_id: "parent-session-1",
117
+ session_type: "native",
118
+ },
119
+ }),
120
+ ],
121
+ total: 2,
122
+ },
123
+ } as never,
124
+ sessionTypesQuery: {
125
+ data: {
126
+ defaultType: "native",
127
+ options: [],
128
+ },
129
+ } as never,
130
+ },
131
+ });
132
+ });
133
+
134
+ it("shows the child-session entry from session query state before a tool card opens it", async () => {
135
+ const user = userEvent.setup();
136
+
137
+ renderHeaderSection();
138
+ await user.click(screen.getByRole("button", { name: "View child sessions" }));
139
+
140
+ expect(mocks.openChildSessionPanel).toHaveBeenCalledWith({
141
+ parentSessionKey: "parent-session-1",
142
+ activeChildSessionKey: "child-session-1",
143
+ });
144
+ });
145
+ });
@@ -36,9 +36,10 @@ describe("ChatConversationHeader", () => {
36
36
  it("uses a stable desktop height before and after session materialization", () => {
37
37
  renderHeader();
38
38
 
39
- const header = screen.getByText("New Task").closest(".border-b");
39
+ const header = screen.getByTestId("chat-conversation-header");
40
40
 
41
41
  expect(header?.className).toContain("h-[52px]");
42
+ expect(header?.className).not.toContain("border-b");
42
43
  expect(header?.className).not.toContain("transition-all");
43
44
  });
44
45
 
@@ -58,9 +59,10 @@ describe("ChatConversationHeader", () => {
58
59
  });
59
60
 
60
61
  const moreActions = screen.getByRole("button", { name: "More actions" });
61
- const header = screen.getByText("First message").closest(".border-b");
62
+ const header = screen.getByTestId("chat-conversation-header");
62
63
 
63
64
  expect(header?.className).toContain("h-[52px]");
65
+ expect(header?.className).not.toContain("border-b");
64
66
  expect(moreActions.className).toContain("h-7");
65
67
  expect(moreActions.className).toContain("w-7");
66
68
  });