@nextclaw/ui 0.15.3 → 0.15.4
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.
- package/CHANGELOG.md +21 -0
- package/dist/assets/aiden0z-pptx-renderer.es-Bd99vut2.js +94 -0
- package/dist/assets/api-BOXOrpcJ.js +13 -0
- package/dist/assets/app-presenter-provider-CkHLbvZQ.js +106 -0
- package/dist/assets/app-presenter-provider-D3BuuOyZ.css +1 -0
- package/dist/assets/appearance-settings-page-fLIJbx1C.js +1 -0
- package/dist/assets/{book-open-C3mJGwiy.js → book-open-DWUjS6aW.js} +1 -1
- package/dist/assets/channels-list-page-CvCTJraa.js +8 -0
- package/dist/assets/chat-page-B42UUIFR.js +1 -0
- package/dist/assets/chunk-DseTPa7n.js +1 -0
- package/dist/assets/config-split-page-DBgt9S8b.js +1 -0
- package/dist/assets/confirm-dialog-GSXIvoRU.js +5 -0
- package/dist/assets/desktop-update-config-7bmNeWIC.js +1 -0
- package/dist/assets/dist-DC7f4TJH.js +41 -0
- package/dist/assets/doc-browser-CgdoLUT92.js +1 -0
- package/dist/assets/doc-browser-D0monHjG.js +1 -0
- package/dist/assets/doc-browser-context-CGwEOhBy.js +1 -0
- package/dist/assets/docx-preview-eFH9DRsS.js +20 -0
- package/dist/assets/download-DiP9zx-J.js +1 -0
- package/dist/assets/{external-link-CU0kzzIP.js → external-link-C6ZeSPef.js} +1 -1
- package/dist/assets/eye-suvKmtwn.js +1 -0
- package/dist/assets/folder-CMELbQGG.js +1 -0
- package/dist/assets/{form-actions-BvCp_0lS.js → form-actions-CUAzpNe_.js} +1 -1
- package/dist/assets/index-BFeNDQ4R.css +1 -0
- package/dist/assets/index-D_6U-M94.js +2 -0
- package/dist/assets/jszip.min-Das2IAnb.js +2 -0
- package/dist/assets/loader-circle-tYHStefV.js +1 -0
- package/dist/assets/logo-badge-Cu5UGH_4.js +1 -0
- package/dist/assets/mcp-marketplace-page-BUzHDwW6.js +9 -0
- package/dist/assets/mcp-marketplace-page-ohUAdfqJ.js +1 -0
- package/dist/assets/model-config-page-CWP6pyBm.js +1 -0
- package/dist/assets/plus-tywizkeY.js +1 -0
- package/dist/assets/popover-DImguRok.js +1 -0
- package/dist/assets/provider-models-C_yOh6DE.js +1 -0
- package/dist/assets/provider-scoped-model-input-CE7p4SbJ.js +1 -0
- package/dist/assets/providers-config-page-BKPo8SjH.js +1 -0
- package/dist/assets/react-5sjAT_6d.js +8 -0
- package/dist/assets/{refresh-cw-CILd1vAP.js → refresh-cw-CHLBzWWj.js} +1 -1
- package/dist/assets/remote-DXJryUxB.js +1 -0
- package/dist/assets/rotate-cw-BefO5brU.js +1 -0
- package/dist/assets/runtime-config-page-1Axv4QGu.js +1 -0
- package/dist/assets/{save-ByJqcPTP.js → save-BABzyrjB.js} +1 -1
- package/dist/assets/{search-DVIV6pfD.js → search-BTqxG3ZG.js} +1 -1
- package/dist/assets/search-config-page-BkKKmxmS.js +1 -0
- package/dist/assets/secrets-config-page-CWJMyu-k.js +3 -0
- package/dist/assets/security-config-DeQUIXfi.js +1 -0
- package/dist/assets/select-TYZDBNmq.js +1 -0
- package/dist/assets/setting-row-DR23Z_5I.js +1 -0
- package/dist/assets/{settings-2-CH5shGg_.js → settings-2-D8WWcBnw.js} +1 -1
- package/dist/assets/{skeleton-DeX1FKw7.js → skeleton-CloHeg0S.js} +1 -1
- package/dist/assets/tabs-CX-ckWoo.js +1 -0
- package/dist/assets/tag-chip-mCc23Rhb.js +1 -0
- package/dist/assets/trash-2-SAW1Z4Po.js +1 -0
- package/dist/assets/use-config-BucdaK23.js +1 -0
- package/dist/assets/use-confirm-dialog-C95F6sT1.js +1 -0
- package/dist/assets/use-viewport-layout-C6m3Nte7.js +1 -0
- package/dist/assets/x-DtCPHwCu.js +1 -0
- package/dist/assets/xlsx-B6zVt1RK.js +64 -0
- package/dist/index.html +34 -28
- package/package.json +11 -6
- package/src/features/chat/components/__tests__/chat-popover-content.test.tsx +41 -0
- package/src/features/chat/components/chat-popover-content.tsx +26 -0
- package/src/features/chat/components/conversation/__tests__/chat-conversation-content.test.tsx +13 -0
- package/src/features/chat/components/conversation/__tests__/chat-conversation-header-section.test.tsx +21 -11
- package/src/features/chat/components/conversation/__tests__/chat-conversation-header.test.tsx +2 -2
- package/src/features/chat/components/conversation/__tests__/chat-conversation-workspace-section.test.tsx +28 -1
- package/src/features/chat/components/conversation/chat-conversation-content.tsx +5 -4
- package/src/features/chat/components/conversation/chat-conversation-header-section.tsx +9 -18
- package/src/features/chat/components/conversation/chat-conversation-track.tsx +35 -0
- package/src/features/chat/components/conversation/chat-conversation-workspace-section.tsx +1 -0
- package/src/features/chat/components/layout/chat-sidebar-toolbar.tsx +7 -7
- package/src/features/chat/components/layout/chat-sidebar-utility-menu.tsx +3 -14
- package/src/features/chat/features/conversation/components/__tests__/session-conversation-input.streaming.test.tsx +20 -1
- package/src/features/chat/features/conversation/components/session-conversation-input.tsx +69 -54
- package/src/features/chat/features/message/components/chat-message-list.container.tsx +16 -1
- package/src/features/chat/features/message/utils/__tests__/chat-message-file-operation.utils.test.ts +30 -0
- package/src/features/chat/features/session/components/__tests__/chat-sidebar-session-item.test.tsx +37 -0
- package/src/features/chat/features/session/components/chat-sidebar-project-groups.tsx +4 -3
- package/src/features/chat/features/session/components/chat-sidebar-session-item.tsx +3 -8
- package/src/features/chat/features/session/components/session-header/__tests__/chat-session-header-actions.test.tsx +65 -20
- package/src/features/chat/features/session/components/session-header/chat-session-header-actions.tsx +26 -28
- package/src/features/chat/features/session/components/session-header/chat-session-project-badge.tsx +3 -3
- package/src/features/chat/features/session/components/session-header/chat-session-title-switcher.tsx +3 -3
- package/src/features/chat/features/welcome/components/chat-welcome-project-picker.tsx +3 -3
- package/src/features/chat/features/welcome/components/chat-welcome-session-type-picker.tsx +3 -3
- package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-file-preview.test.tsx +403 -106
- package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-panel-content.test.tsx +113 -2
- package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-panel.test.tsx +1 -0
- package/src/features/chat/features/workspace/components/chat-session-workspace-directory-browser.tsx +197 -44
- package/src/features/chat/features/workspace/components/chat-session-workspace-file-breadcrumb-browser.tsx +9 -3
- package/src/features/chat/features/workspace/components/chat-session-workspace-file-breadcrumbs.tsx +7 -5
- package/src/features/chat/features/workspace/components/chat-session-workspace-file-preview.tsx +57 -177
- package/src/features/chat/features/workspace/components/chat-session-workspace-panel-content.tsx +239 -1
- package/src/features/chat/features/workspace/components/chat-session-workspace-panel-nav.tsx +56 -6
- package/src/features/chat/features/workspace/components/chat-session-workspace-panel.tsx +29 -7
- package/src/features/chat/features/workspace/components/file-content-preview/use-workspace-file-buffer.ts +42 -0
- package/src/features/chat/features/workspace/components/file-content-preview/workspace-document-preview-state.tsx +18 -0
- package/src/features/chat/features/workspace/components/file-content-preview/workspace-docx-preview.css +89 -0
- package/src/features/chat/features/workspace/components/file-content-preview/workspace-docx-preview.tsx +87 -0
- package/src/features/chat/features/workspace/components/file-content-preview/workspace-presentation-preview.tsx +82 -0
- package/src/features/chat/features/workspace/components/file-content-preview/workspace-spreadsheet-preview.tsx +180 -0
- package/src/features/chat/features/workspace/components/workspace-file-content-preview.tsx +191 -0
- package/src/features/chat/features/workspace/hooks/use-chat-conversation-workspace-state.ts +1 -4
- package/src/features/chat/features/workspace/utils/__tests__/chat-workspace-panel-view-model.utils.test.ts +53 -10
- package/src/features/chat/features/workspace/utils/chat-thread-workspace-session.utils.ts +68 -2
- package/src/features/chat/features/workspace/utils/chat-workspace-file-tab-persistence.utils.ts +17 -0
- package/src/features/chat/features/workspace/utils/chat-workspace-file-tab.utils.ts +63 -0
- package/src/features/chat/features/workspace/utils/chat-workspace-file-viewer.utils.ts +49 -0
- package/src/features/chat/features/workspace/utils/chat-workspace-panel-layout.utils.ts +13 -0
- package/src/features/chat/features/workspace/utils/chat-workspace-panel-view-model.utils.ts +120 -38
- package/src/features/chat/index.ts +1 -0
- package/src/features/chat/managers/__tests__/chat-thread-workspace.manager.test.ts +76 -0
- package/src/features/chat/managers/__tests__/chat-thread.manager.test.ts +44 -60
- package/src/features/chat/managers/chat-thread.manager.ts +123 -126
- package/src/features/chat/pages/ncp-chat-page.tsx +1 -2
- package/src/features/chat/stores/__tests__/chat-thread.store.test.ts +78 -1
- package/src/features/chat/stores/chat-message-layout.store.test.ts +37 -0
- package/src/features/chat/stores/chat-message-layout.store.ts +41 -0
- package/src/features/chat/stores/chat-thread.store.ts +70 -13
- package/src/features/settings/pages/__tests__/appearance-settings-page.test.tsx +25 -8
- package/src/features/settings/pages/appearance-settings-page.tsx +92 -13
- package/src/index.css +36 -2
- package/src/shared/components/__tests__/file-type-icon.test.tsx +61 -0
- package/src/shared/components/doc-browser/__tests__/doc-browser-context.test.tsx +19 -0
- package/src/shared/components/doc-browser/__tests__/doc-browser.test.tsx +16 -0
- package/src/shared/components/doc-browser/doc-browser-context.tsx +1 -0
- package/src/shared/components/doc-browser/doc-browser.tsx +11 -3
- package/src/shared/components/doc-browser/managers/doc-browser.manager.ts +5 -0
- package/src/shared/components/doc-browser/stores/doc-browser.store.ts +6 -1
- package/src/shared/components/doc-browser/types/doc-browser.types.ts +2 -0
- package/src/shared/components/doc-browser/utils/doc-browser-state.utils.ts +11 -0
- package/src/shared/components/file-type-icon.tsx +272 -0
- package/src/shared/components/resizable-right-panel/__tests__/resizable-right-panel.test.tsx +22 -0
- package/src/shared/components/resizable-right-panel/resizable-right-panel.tsx +17 -2
- package/src/shared/components/ui/tab-strip/__tests__/compact-tab-strip.test.tsx +38 -0
- package/src/shared/components/ui/tab-strip/compact-tab-strip.tsx +82 -2
- package/src/shared/lib/api/__tests__/server-path.utils.test.ts +28 -0
- package/src/shared/lib/api/utils/server-path.utils.ts +19 -20
- package/src/shared/lib/i18n/locales/en-US/chat.json +17 -1
- package/src/shared/lib/i18n/locales/en-US/core.json +6 -0
- package/src/shared/lib/i18n/locales/zh-CN/chat.json +17 -1
- package/src/shared/lib/i18n/locales/zh-CN/core.json +6 -0
- package/dist/assets/api-iNBpppzj.js +0 -13
- package/dist/assets/appearance-settings-page-DMffQFR3.js +0 -1
- package/dist/assets/channels-list-page-CCtp0BRS.js +0 -8
- package/dist/assets/chat-page-H5a0dWvO.js +0 -1
- package/dist/assets/config-split-page-CrOJgB-Y.js +0 -1
- package/dist/assets/confirm-dialog-Chv50USy.js +0 -5
- package/dist/assets/desktop-update-config-KzTuXRf_.js +0 -1
- package/dist/assets/dist-BunzmC4B.js +0 -1
- package/dist/assets/dist-ChmGwvtK.js +0 -1
- package/dist/assets/doc-browser-DNRL4Zvd.js +0 -1
- package/dist/assets/doc-browser-Dg0pmkOg.js +0 -1
- package/dist/assets/doc-browser-context-BHY-0FSD.js +0 -1
- package/dist/assets/es2015-DQZ5JWwK.js +0 -41
- package/dist/assets/i18n-provider-Cu8XyZb_.js +0 -1
- package/dist/assets/index-CzfBdvK1.css +0 -1
- package/dist/assets/index-DGqHne1Q.js +0 -104
- package/dist/assets/loader-circle-CDSFuzmk.js +0 -1
- package/dist/assets/mcp-marketplace-page-BeEQK0DL.js +0 -9
- package/dist/assets/mcp-marketplace-page-D6idOTLp.js +0 -1
- package/dist/assets/model-config-page-bNNo-XyG.js +0 -1
- package/dist/assets/plus-D4DsdLN-.js +0 -1
- package/dist/assets/provider-scoped-model-input-IlgQCsoT.js +0 -1
- package/dist/assets/providers-config-page-wLo6CAJw.js +0 -1
- package/dist/assets/react-BPIsQIlO.js +0 -8
- package/dist/assets/remote-uKEYp7AR.js +0 -1
- package/dist/assets/rotate-cw-wPFPg1kH.js +0 -1
- package/dist/assets/runtime-config-page-DDn1sP4G.js +0 -1
- package/dist/assets/search-config-page-B-Cf4iiB.js +0 -1
- package/dist/assets/secrets-config-page-DPKsY8Iw.js +0 -3
- package/dist/assets/security-config-e9SSBlKr.js +0 -1
- package/dist/assets/select-BdgczSNw.js +0 -1
- package/dist/assets/setting-row-BkTVUTKx.js +0 -1
- package/dist/assets/side-dock-BsBvcJ9i.js +0 -3
- package/dist/assets/switch-Cv8Ekb3x.js +0 -1
- package/dist/assets/tag-chip-RB9uKcoC.js +0 -1
- package/dist/assets/tooltip-oQlEN-l6.js +0 -1
- package/dist/assets/use-config-l3W7y8Qz.js +0 -1
- package/dist/assets/use-confirm-dialog-BAxaVOJI.js +0 -1
- package/dist/assets/x-BBMffEN0.js +0 -1
- /package/dist/assets/{config-hints-C_iP1zl_.js → config-hints-fDrYfl0l.js} +0 -0
- /package/dist/assets/{host-capabilities-9bB_998Z.js → host-capabilities-zZvY9U63.js} +0 -0
- /package/dist/assets/{middleware-BILWbJE4.js → middleware-BLMHv9YF.js} +0 -0
|
@@ -49,6 +49,8 @@ import {
|
|
|
49
49
|
} from '@/features/chat/managers/chat-recent-skills.manager';
|
|
50
50
|
|
|
51
51
|
import { useSessionConversationInputAttachments } from '@/features/chat/features/conversation/hooks/use-session-conversation-input-attachments';
|
|
52
|
+
import { ChatConversationTrack } from '@/features/chat/components/conversation/chat-conversation-track';
|
|
53
|
+
import { useChatMessageLayoutStore } from '@/features/chat/stores/chat-message-layout.store';
|
|
52
54
|
import type { useSessionConversationInputQuery } from '@/features/chat/features/conversation/hooks/use-session-conversation-input-query';
|
|
53
55
|
import type {
|
|
54
56
|
SessionConversationQueuedInput,
|
|
@@ -187,6 +189,7 @@ export const SessionConversationInput = memo(function SessionConversationInput(p
|
|
|
187
189
|
} = props;
|
|
188
190
|
const presenter = usePresenter();
|
|
189
191
|
const { language } = useI18n();
|
|
192
|
+
const messageLayout = useChatMessageLayoutStore((state) => state.layout);
|
|
190
193
|
const { isMobile } = useViewportLayout();
|
|
191
194
|
const inputBarRef = useRef<ChatInputBarHandle | null>(null);
|
|
192
195
|
const fileInputRef = useRef<HTMLInputElement | null>(null);
|
|
@@ -389,62 +392,74 @@ export const SessionConversationInput = memo(function SessionConversationInput(p
|
|
|
389
392
|
selectedSkills: inputSnapshot.selectedSkills,
|
|
390
393
|
});
|
|
391
394
|
|
|
395
|
+
const useReadingTrack = surface === 'default' && messageLayout === 'flat';
|
|
396
|
+
const inputBar = (
|
|
397
|
+
<ChatInputBar
|
|
398
|
+
ref={inputBarRef}
|
|
399
|
+
surface={useReadingTrack ? 'embedded' : surface}
|
|
400
|
+
sendError={inputSnapshot.sendError}
|
|
401
|
+
sendErrorDetailsLabel={t('chatErrorDetails', language)}
|
|
402
|
+
topSlot={controller.queuedInputs.length > 0
|
|
403
|
+
? <SessionQueuedInputRows controller={controller} />
|
|
404
|
+
: null}
|
|
405
|
+
composer={{
|
|
406
|
+
nodes: [...inputSnapshot.nodes],
|
|
407
|
+
placeholder: textareaPlaceholder,
|
|
408
|
+
disabled: inputDisabled,
|
|
409
|
+
onNodesChange: handleNodesChange,
|
|
410
|
+
onFilesAdd: handleFilesAdd,
|
|
411
|
+
inputSurfaceTriggerSpecs: inputSurfaceState.triggerSpecs,
|
|
412
|
+
onInputSurfaceTriggerChange: setInputSurfaceTrigger,
|
|
413
|
+
}}
|
|
414
|
+
inputSurface={inputSurfaceState.panel ?? undefined}
|
|
415
|
+
hint={buildModelStateHint({
|
|
416
|
+
isModelOptionsLoading,
|
|
417
|
+
isModelOptionsEmpty,
|
|
418
|
+
onGoToProviders: presenter.chatUiManager.goToProviders,
|
|
419
|
+
texts: {
|
|
420
|
+
noModelOptionsLabel: t('chatModelNoOptions'),
|
|
421
|
+
configureProviderLabel: t('chatGoConfigureProvider'),
|
|
422
|
+
},
|
|
423
|
+
})}
|
|
424
|
+
toolbar={{
|
|
425
|
+
selects: [],
|
|
426
|
+
trailingSelects: toolbarSelects,
|
|
427
|
+
accessories: [
|
|
428
|
+
{
|
|
429
|
+
key: 'attach',
|
|
430
|
+
label: t('chatInputAttach'),
|
|
431
|
+
icon: 'paperclip' as const,
|
|
432
|
+
iconOnly: true,
|
|
433
|
+
disabled: !attachmentSupported || inputDisabled,
|
|
434
|
+
onClick: () => fileInputRef.current?.click(),
|
|
435
|
+
},
|
|
436
|
+
],
|
|
437
|
+
skillPicker,
|
|
438
|
+
actions: {
|
|
439
|
+
isSending: controller.isSending,
|
|
440
|
+
canStopGeneration: controller.canStopGeneration,
|
|
441
|
+
sendDisabled: controller.sendDisabled,
|
|
442
|
+
stopDisabled: controller.stopDisabled,
|
|
443
|
+
stopHint: t('chatStopUnavailable'),
|
|
444
|
+
sendButtonLabel: controller.isSending ? t('chatQueueSend') : t('chatSend'),
|
|
445
|
+
stopButtonLabel: t('chatStop'),
|
|
446
|
+
contextWindow,
|
|
447
|
+
onSend: controller.send,
|
|
448
|
+
onStop: controller.stop,
|
|
449
|
+
},
|
|
450
|
+
}}
|
|
451
|
+
/>
|
|
452
|
+
);
|
|
453
|
+
|
|
392
454
|
return (
|
|
393
455
|
<>
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
nodes: [...inputSnapshot.nodes],
|
|
402
|
-
placeholder: textareaPlaceholder,
|
|
403
|
-
disabled: inputDisabled,
|
|
404
|
-
onNodesChange: handleNodesChange,
|
|
405
|
-
onFilesAdd: handleFilesAdd,
|
|
406
|
-
inputSurfaceTriggerSpecs: inputSurfaceState.triggerSpecs,
|
|
407
|
-
onInputSurfaceTriggerChange: setInputSurfaceTrigger,
|
|
408
|
-
}}
|
|
409
|
-
inputSurface={inputSurfaceState.panel ?? undefined}
|
|
410
|
-
hint={buildModelStateHint({
|
|
411
|
-
isModelOptionsLoading,
|
|
412
|
-
isModelOptionsEmpty,
|
|
413
|
-
onGoToProviders: presenter.chatUiManager.goToProviders,
|
|
414
|
-
texts: {
|
|
415
|
-
noModelOptionsLabel: t('chatModelNoOptions'),
|
|
416
|
-
configureProviderLabel: t('chatGoConfigureProvider'),
|
|
417
|
-
},
|
|
418
|
-
})}
|
|
419
|
-
toolbar={{
|
|
420
|
-
selects: [],
|
|
421
|
-
trailingSelects: toolbarSelects,
|
|
422
|
-
accessories: [
|
|
423
|
-
{
|
|
424
|
-
key: 'attach',
|
|
425
|
-
label: t('chatInputAttach'),
|
|
426
|
-
icon: 'paperclip' as const,
|
|
427
|
-
iconOnly: true,
|
|
428
|
-
disabled: !attachmentSupported || inputDisabled,
|
|
429
|
-
onClick: () => fileInputRef.current?.click(),
|
|
430
|
-
},
|
|
431
|
-
],
|
|
432
|
-
skillPicker,
|
|
433
|
-
actions: {
|
|
434
|
-
sendError: inputSnapshot.sendError,
|
|
435
|
-
isSending: controller.isSending,
|
|
436
|
-
canStopGeneration: controller.canStopGeneration,
|
|
437
|
-
sendDisabled: controller.sendDisabled,
|
|
438
|
-
stopDisabled: controller.stopDisabled,
|
|
439
|
-
stopHint: t('chatStopUnavailable'),
|
|
440
|
-
sendButtonLabel: controller.isSending ? t('chatQueueSend') : t('chatSend'),
|
|
441
|
-
stopButtonLabel: t('chatStop'),
|
|
442
|
-
contextWindow,
|
|
443
|
-
onSend: controller.send,
|
|
444
|
-
onStop: controller.stop,
|
|
445
|
-
},
|
|
446
|
-
}}
|
|
447
|
-
/>
|
|
456
|
+
{useReadingTrack ? (
|
|
457
|
+
<ChatConversationTrack className="pb-4 pt-2" width="composer">
|
|
458
|
+
{inputBar}
|
|
459
|
+
</ChatConversationTrack>
|
|
460
|
+
) : (
|
|
461
|
+
inputBar
|
|
462
|
+
)}
|
|
448
463
|
<input
|
|
449
464
|
ref={fileInputRef}
|
|
450
465
|
type="file"
|
|
@@ -25,7 +25,11 @@ import {
|
|
|
25
25
|
import { AgentIdentityAvatar } from "@/shared/components/common/agent-identity";
|
|
26
26
|
import { ChatInlinePanelAppCard } from "@/features/chat/features/message/components/chat-inline-panel-app-card";
|
|
27
27
|
import { useChatQueryStore } from "@/features/chat/stores/ncp-chat-query.store";
|
|
28
|
+
import { useChatSessionListStore } from "@/features/chat/stores/chat-session-list.store";
|
|
29
|
+
import { useChatMessageLayoutStore } from "@/features/chat/stores/chat-message-layout.store";
|
|
30
|
+
import { useNcpChatSelectedSession } from "@/features/chat/features/ncp/hooks/use-ncp-chat-derived-state";
|
|
28
31
|
import { useI18n } from "@/app/components/i18n-provider";
|
|
32
|
+
import { buildServerPathContentUrl } from "@/shared/lib/api";
|
|
29
33
|
import { formatDateTime, t } from "@/shared/lib/i18n";
|
|
30
34
|
|
|
31
35
|
type ChatMessageListContainerProps = {
|
|
@@ -58,7 +62,6 @@ function renderChatInlineDisplay(display: ChatInlineDisplayViewModel) {
|
|
|
58
62
|
/>
|
|
59
63
|
);
|
|
60
64
|
}
|
|
61
|
-
|
|
62
65
|
type ContextInheritanceTimelineView = {
|
|
63
66
|
sourceSessionId: string;
|
|
64
67
|
inheritedMessageCount: number;
|
|
@@ -286,6 +289,16 @@ export function ChatMessageListContainer({
|
|
|
286
289
|
}: ChatMessageListContainerProps) {
|
|
287
290
|
const presenter = usePresenter();
|
|
288
291
|
const { language } = useI18n();
|
|
292
|
+
const messageLayout = useChatMessageLayoutStore((state) => state.layout);
|
|
293
|
+
const selectedSessionKey = useChatSessionListStore(
|
|
294
|
+
(state) => state.snapshot.selectedSessionKey,
|
|
295
|
+
);
|
|
296
|
+
const selectedSession = useNcpChatSelectedSession(selectedSessionKey);
|
|
297
|
+
const localFileBasePath = selectedSession?.workingDir ?? selectedSession?.projectRoot ?? null;
|
|
298
|
+
const resolveFileContentUrl = useCallback(
|
|
299
|
+
(action: { path: string }) => buildServerPathContentUrl(action.path, localFileBasePath),
|
|
300
|
+
[localFileBasePath],
|
|
301
|
+
);
|
|
289
302
|
const texts = useMemo(
|
|
290
303
|
() => buildChatMessageAdapterTexts(language),
|
|
291
304
|
[language],
|
|
@@ -396,6 +409,7 @@ export function ChatMessageListContainer({
|
|
|
396
409
|
) : (
|
|
397
410
|
<ChatMessageList
|
|
398
411
|
key={item.key}
|
|
412
|
+
layout={messageLayout}
|
|
399
413
|
messages={item.messages}
|
|
400
414
|
isSending={index === timelineItems.length - 1 ? isSending : false}
|
|
401
415
|
hasAssistantDraft={hasAssistantDraft}
|
|
@@ -404,6 +418,7 @@ export function ChatMessageListContainer({
|
|
|
404
418
|
onFileOpen={presenter.chatThreadManager.openFilePreview}
|
|
405
419
|
onAttachmentOpen={handleAttachmentOpen}
|
|
406
420
|
onInlineTokenClick={handleInlineTokenClick}
|
|
421
|
+
resolveFileContentUrl={resolveFileContentUrl}
|
|
407
422
|
renderInlineDisplay={renderChatInlineDisplay}
|
|
408
423
|
renderToolAgent={(agentId) => (
|
|
409
424
|
<AgentIdentityAvatar
|
package/src/features/chat/features/message/utils/__tests__/chat-message-file-operation.utils.test.ts
CHANGED
|
@@ -63,6 +63,36 @@ it("builds edit-file previews from structured args before the tool finishes", ()
|
|
|
63
63
|
expect(editLines[1]).not.toHaveProperty("newLineNumber");
|
|
64
64
|
});
|
|
65
65
|
|
|
66
|
+
it("keeps incomplete edit-file arguments available before preview fields arrive", () => {
|
|
67
|
+
const partialArgs = '{"path":"src/app.ts","oldText":';
|
|
68
|
+
const adapted = adapt([
|
|
69
|
+
{
|
|
70
|
+
id: "assistant-partial-edit-input",
|
|
71
|
+
role: "assistant",
|
|
72
|
+
parts: [
|
|
73
|
+
{
|
|
74
|
+
type: "tool-invocation",
|
|
75
|
+
toolInvocation: {
|
|
76
|
+
status: ToolInvocationStatus.PARTIAL_CALL,
|
|
77
|
+
toolCallId: "edit-partial-1",
|
|
78
|
+
toolName: "edit_file",
|
|
79
|
+
args: partialArgs,
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
],
|
|
83
|
+
},
|
|
84
|
+
] as unknown as ChatMessageSource[]);
|
|
85
|
+
|
|
86
|
+
expect(adapted[0]?.parts[0]).toMatchObject({
|
|
87
|
+
type: "tool-card",
|
|
88
|
+
card: {
|
|
89
|
+
toolName: "edit_file",
|
|
90
|
+
input: partialArgs,
|
|
91
|
+
statusTone: "running",
|
|
92
|
+
},
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
66
96
|
it("uses structured edit-file result line numbers after the tool finishes", () => {
|
|
67
97
|
const adapted = adapt([
|
|
68
98
|
{
|
package/src/features/chat/features/session/components/__tests__/chat-sidebar-session-item.test.tsx
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { render, screen } from '@testing-library/react';
|
|
2
|
+
import { expect, it, vi } from 'vitest';
|
|
3
|
+
import { ChatSidebarSessionItem } from '@/features/chat/features/session/components/chat-sidebar-session-item';
|
|
4
|
+
|
|
5
|
+
it('shows session actions only on hover or when an action owns focus', () => {
|
|
6
|
+
render(
|
|
7
|
+
<ChatSidebarSessionItem
|
|
8
|
+
sessionKey="session:current"
|
|
9
|
+
active
|
|
10
|
+
showUnreadDot={false}
|
|
11
|
+
context={{ icon: null, label: null }}
|
|
12
|
+
isPinned={false}
|
|
13
|
+
title="Current Task"
|
|
14
|
+
previewText="Preview"
|
|
15
|
+
trailingText="Now"
|
|
16
|
+
isEditing={false}
|
|
17
|
+
draftLabel="Current Task"
|
|
18
|
+
isSaving={false}
|
|
19
|
+
onSelect={vi.fn()}
|
|
20
|
+
onStartEditing={vi.fn()}
|
|
21
|
+
onDraftLabelChange={vi.fn()}
|
|
22
|
+
onSave={vi.fn()}
|
|
23
|
+
onCancel={vi.fn()}
|
|
24
|
+
onTogglePinned={vi.fn()}
|
|
25
|
+
/>,
|
|
26
|
+
);
|
|
27
|
+
|
|
28
|
+
screen.getByText('Current Task').closest('button')?.focus();
|
|
29
|
+
const actions = screen.getByLabelText('Pin session').parentElement;
|
|
30
|
+
|
|
31
|
+
expect(actions?.className).toContain('opacity-0');
|
|
32
|
+
expect(actions?.className).toContain('group-hover/session:opacity-100');
|
|
33
|
+
expect(actions?.className).toContain('focus-within:opacity-100');
|
|
34
|
+
expect(actions?.className).not.toContain(
|
|
35
|
+
'group-focus-within/session:opacity-100',
|
|
36
|
+
);
|
|
37
|
+
});
|
|
@@ -2,7 +2,8 @@ import { useMemo, useState, type ReactNode } from 'react';
|
|
|
2
2
|
import { ChevronDown, ChevronRight, Folder, Pin, Plus } from 'lucide-react';
|
|
3
3
|
import { usePresenter } from '@/features/chat/components/providers/chat-presenter.provider';
|
|
4
4
|
import { ChatSessionTypeMenu } from "@/features/chat/features/session-type/components/chat-session-type-menu";
|
|
5
|
-
import { Popover,
|
|
5
|
+
import { Popover, PopoverTrigger } from '@/shared/components/ui/popover';
|
|
6
|
+
import { ChatPopoverContent } from '@/features/chat/components/chat-popover-content';
|
|
6
7
|
import { IconActionButton } from '@/shared/components/ui/actions/icon-action-button';
|
|
7
8
|
import type { ChatSessionTypeOption } from "@/features/chat/features/session-type/utils/chat-session-type.utils";
|
|
8
9
|
import type { NcpSessionListItemView } from '@/features/chat/features/ncp/hooks/use-ncp-session-list-view';
|
|
@@ -107,7 +108,7 @@ export function ChatSidebarProjectGroups(props: ChatSidebarProjectGroupsProps) {
|
|
|
107
108
|
label={actionLabel}
|
|
108
109
|
/>
|
|
109
110
|
</PopoverTrigger>
|
|
110
|
-
<
|
|
111
|
+
<ChatPopoverContent
|
|
111
112
|
align="end"
|
|
112
113
|
className="w-56 rounded-2xl border border-border bg-popover p-1.5 text-popover-foreground shadow-[0_24px_60px_-28px_rgba(15,23,42,0.38)]"
|
|
113
114
|
>
|
|
@@ -122,7 +123,7 @@ export function ChatSidebarProjectGroups(props: ChatSidebarProjectGroupsProps) {
|
|
|
122
123
|
setOpenProjectRoot(null);
|
|
123
124
|
}}
|
|
124
125
|
/>
|
|
125
|
-
</
|
|
126
|
+
</ChatPopoverContent>
|
|
126
127
|
</Popover>
|
|
127
128
|
) : (
|
|
128
129
|
<IconActionButton
|
|
@@ -169,12 +169,7 @@ function ChatSidebarSessionDisplayView({
|
|
|
169
169
|
event.stopPropagation();
|
|
170
170
|
onOpenChildSessions();
|
|
171
171
|
}}
|
|
172
|
-
className=
|
|
173
|
-
'absolute right-12 top-0 inline-flex h-6 items-center gap-1 rounded-md px-1.5 text-[10px] font-medium text-muted-foreground transition-colors hover:bg-black/10 hover:text-foreground',
|
|
174
|
-
active
|
|
175
|
-
? 'opacity-100'
|
|
176
|
-
: 'opacity-0 group-hover/session:opacity-100 group-focus-within/session:opacity-100'
|
|
177
|
-
)}
|
|
172
|
+
className="pointer-events-none absolute right-12 top-0 inline-flex h-6 items-center gap-1 rounded-md px-1.5 text-[10px] font-medium text-muted-foreground opacity-0 transition-colors hover:bg-black/10 hover:text-foreground group-hover/session:pointer-events-auto group-hover/session:opacity-100 focus-visible:pointer-events-auto focus-visible:opacity-100"
|
|
178
173
|
aria-label={t('chatSessionOpenChildSessions')}
|
|
179
174
|
title={t('chatSessionOpenChildSessions')}
|
|
180
175
|
>
|
|
@@ -183,11 +178,11 @@ function ChatSidebarSessionDisplayView({
|
|
|
183
178
|
</button>
|
|
184
179
|
) : null}
|
|
185
180
|
{runStatus ? (
|
|
186
|
-
<span className="absolute right-0 top-0 inline-flex h-6 w-6 items-center justify-center transition-opacity group-hover/session:opacity-0
|
|
181
|
+
<span className="absolute right-0 top-0 inline-flex h-6 w-6 items-center justify-center transition-opacity group-hover/session:opacity-0">
|
|
187
182
|
<SessionRunBadge status={runStatus} />
|
|
188
183
|
</span>
|
|
189
184
|
) : null}
|
|
190
|
-
<div className="absolute right-0 top-0 flex h-6 items-center gap-0.5 opacity-0 transition-opacity group-hover/session:opacity-100
|
|
185
|
+
<div className="pointer-events-none absolute right-0 top-0 flex h-6 items-center gap-0.5 opacity-0 transition-opacity group-hover/session:pointer-events-auto group-hover/session:opacity-100 focus-within:pointer-events-auto focus-within:opacity-100">
|
|
191
186
|
<IconActionButton
|
|
192
187
|
size="sm"
|
|
193
188
|
tone="strong"
|
|
@@ -6,8 +6,7 @@ import { ChatSessionHeaderActions } from '@/features/chat/features/session/compo
|
|
|
6
6
|
const mocks = vi.hoisted(() => ({
|
|
7
7
|
updateSessionProject: vi.fn(),
|
|
8
8
|
onDeleteSession: vi.fn(),
|
|
9
|
-
|
|
10
|
-
onOpenSessionCronJobs: vi.fn(),
|
|
9
|
+
onToggleWorkspace: vi.fn(),
|
|
11
10
|
}));
|
|
12
11
|
|
|
13
12
|
vi.mock('@/features/chat/features/session/hooks/use-chat-session-project', () => ({
|
|
@@ -22,8 +21,7 @@ describe('ChatSessionHeaderActions', () => {
|
|
|
22
21
|
beforeEach(() => {
|
|
23
22
|
mocks.updateSessionProject.mockReset();
|
|
24
23
|
mocks.onDeleteSession.mockReset();
|
|
25
|
-
mocks.
|
|
26
|
-
mocks.onOpenSessionCronJobs.mockReset();
|
|
24
|
+
mocks.onToggleWorkspace.mockReset();
|
|
27
25
|
});
|
|
28
26
|
|
|
29
27
|
it('keeps only the set-project action in the more-actions menu when a project is already attached', async () => {
|
|
@@ -35,8 +33,8 @@ describe('ChatSessionHeaderActions', () => {
|
|
|
35
33
|
canDeleteSession
|
|
36
34
|
isDeletePending={false}
|
|
37
35
|
projectRoot="/tmp/project-alpha"
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
isWorkspaceOpen={false}
|
|
37
|
+
onToggleWorkspace={mocks.onToggleWorkspace}
|
|
40
38
|
onDeleteSession={mocks.onDeleteSession}
|
|
41
39
|
/>
|
|
42
40
|
);
|
|
@@ -58,8 +56,8 @@ describe('ChatSessionHeaderActions', () => {
|
|
|
58
56
|
canDeleteSession={false}
|
|
59
57
|
isDeletePending={false}
|
|
60
58
|
projectRoot={null}
|
|
61
|
-
|
|
62
|
-
|
|
59
|
+
isWorkspaceOpen={false}
|
|
60
|
+
onToggleWorkspace={mocks.onToggleWorkspace}
|
|
63
61
|
onDeleteSession={mocks.onDeleteSession}
|
|
64
62
|
/>
|
|
65
63
|
);
|
|
@@ -84,6 +82,8 @@ describe('ChatSessionHeaderActions', () => {
|
|
|
84
82
|
codex_thread_id: 'thread-123',
|
|
85
83
|
runtime: 'codex',
|
|
86
84
|
}}
|
|
85
|
+
isWorkspaceOpen={false}
|
|
86
|
+
onToggleWorkspace={mocks.onToggleWorkspace}
|
|
87
87
|
onDeleteSession={mocks.onDeleteSession}
|
|
88
88
|
/>
|
|
89
89
|
);
|
|
@@ -98,7 +98,7 @@ describe('ChatSessionHeaderActions', () => {
|
|
|
98
98
|
expect(screen.getByText(/thread-123/)).toBeTruthy();
|
|
99
99
|
});
|
|
100
100
|
|
|
101
|
-
it('
|
|
101
|
+
it('opens the session workspace from one stable header action', async () => {
|
|
102
102
|
const user = userEvent.setup();
|
|
103
103
|
|
|
104
104
|
render(
|
|
@@ -107,28 +107,28 @@ describe('ChatSessionHeaderActions', () => {
|
|
|
107
107
|
canDeleteSession
|
|
108
108
|
isDeletePending={false}
|
|
109
109
|
projectRoot={null}
|
|
110
|
-
|
|
111
|
-
|
|
110
|
+
isWorkspaceOpen={false}
|
|
111
|
+
onToggleWorkspace={mocks.onToggleWorkspace}
|
|
112
112
|
onDeleteSession={mocks.onDeleteSession}
|
|
113
113
|
/>
|
|
114
114
|
);
|
|
115
115
|
|
|
116
|
-
await user.click(screen.getByRole('button', { name: '
|
|
116
|
+
await user.click(screen.getByRole('button', { name: 'Open session workspace' }));
|
|
117
117
|
|
|
118
|
-
expect(mocks.
|
|
118
|
+
expect(mocks.onToggleWorkspace).toHaveBeenCalledTimes(1);
|
|
119
|
+
expect(screen.queryByRole('button', { name: 'View child sessions' })).toBeNull();
|
|
120
|
+
expect(screen.queryByRole('button', { name: 'View session cron jobs' })).toBeNull();
|
|
119
121
|
});
|
|
120
122
|
|
|
121
|
-
it('uses
|
|
123
|
+
it('uses the shared compact action density for workspace and menu buttons', () => {
|
|
122
124
|
render(
|
|
123
125
|
<ChatSessionHeaderActions
|
|
124
126
|
sessionKey="session-actions"
|
|
125
127
|
canDeleteSession
|
|
126
128
|
isDeletePending={false}
|
|
127
129
|
projectRoot={null}
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
onOpenChildSessions={mocks.onOpenChildSessions}
|
|
131
|
-
onOpenSessionCronJobs={mocks.onOpenSessionCronJobs}
|
|
130
|
+
isWorkspaceOpen={false}
|
|
131
|
+
onToggleWorkspace={mocks.onToggleWorkspace}
|
|
132
132
|
onDeleteSession={mocks.onDeleteSession}
|
|
133
133
|
/>
|
|
134
134
|
);
|
|
@@ -136,7 +136,52 @@ describe('ChatSessionHeaderActions', () => {
|
|
|
136
136
|
const actionGroup = screen.getByRole('button', { name: 'More actions' }).parentElement;
|
|
137
137
|
|
|
138
138
|
expect(actionGroup?.className).toContain('gap-1.5');
|
|
139
|
-
expect(screen.getByRole('button', { name: '
|
|
140
|
-
expect(screen.getByRole('button', { name: '
|
|
139
|
+
expect(screen.getByRole('button', { name: 'Open session workspace' }).className).toContain('h-7');
|
|
140
|
+
expect(screen.getByRole('button', { name: 'Open session workspace' }).className).toContain('w-7');
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
it('places the workspace toggle at the far right of the visible header actions', () => {
|
|
144
|
+
render(
|
|
145
|
+
<ChatSessionHeaderActions
|
|
146
|
+
sessionKey="session-actions"
|
|
147
|
+
canDeleteSession
|
|
148
|
+
isDeletePending={false}
|
|
149
|
+
projectRoot={null}
|
|
150
|
+
isWorkspaceOpen={false}
|
|
151
|
+
onToggleWorkspace={mocks.onToggleWorkspace}
|
|
152
|
+
onDeleteSession={mocks.onDeleteSession}
|
|
153
|
+
/>
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
const menuButton = screen.getByRole('button', { name: 'More actions' });
|
|
157
|
+
const workspaceButton = screen.getByRole('button', { name: 'Open session workspace' });
|
|
158
|
+
|
|
159
|
+
expect(menuButton.compareDocumentPosition(workspaceButton)).toBe(
|
|
160
|
+
Node.DOCUMENT_POSITION_FOLLOWING,
|
|
161
|
+
);
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it('changes to a pressed close action while the workspace is open', async () => {
|
|
165
|
+
const user = userEvent.setup();
|
|
166
|
+
|
|
167
|
+
render(
|
|
168
|
+
<ChatSessionHeaderActions
|
|
169
|
+
sessionKey="session-actions"
|
|
170
|
+
canDeleteSession
|
|
171
|
+
isDeletePending={false}
|
|
172
|
+
projectRoot={null}
|
|
173
|
+
isWorkspaceOpen
|
|
174
|
+
onToggleWorkspace={mocks.onToggleWorkspace}
|
|
175
|
+
onDeleteSession={mocks.onDeleteSession}
|
|
176
|
+
/>
|
|
177
|
+
);
|
|
178
|
+
|
|
179
|
+
const closeButton = screen.getByRole('button', {
|
|
180
|
+
name: 'Close session workspace',
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
expect(closeButton.getAttribute('aria-pressed')).toBe('true');
|
|
184
|
+
await user.click(closeButton);
|
|
185
|
+
expect(mocks.onToggleWorkspace).toHaveBeenCalledTimes(1);
|
|
141
186
|
});
|
|
142
187
|
});
|
package/src/features/chat/features/session/components/session-header/chat-session-header-actions.tsx
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { useState } from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { Braces, FolderOpen, MoreVertical, PanelRightClose, PanelRightOpen, Trash2 } from 'lucide-react';
|
|
3
3
|
import { IconActionButton } from '@/shared/components/ui/actions/icon-action-button';
|
|
4
|
-
import { Popover,
|
|
4
|
+
import { Popover, PopoverTrigger } from '@/shared/components/ui/popover';
|
|
5
|
+
import { ChatPopoverContent } from '@/features/chat/components/chat-popover-content';
|
|
5
6
|
import { useChatSessionProject } from '@/features/chat/features/session/hooks/use-chat-session-project';
|
|
6
7
|
import { ChatSessionHeaderMenuItem } from './chat-session-header-menu-item';
|
|
7
8
|
import { ChatSessionMetadataDialog } from './chat-session-metadata-dialog';
|
|
@@ -16,10 +17,8 @@ type ChatSessionHeaderActionsProps = {
|
|
|
16
17
|
isDeletePending: boolean;
|
|
17
18
|
projectRoot?: string | null;
|
|
18
19
|
metadata?: Record<string, unknown> | null;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
onOpenChildSessions?: () => void;
|
|
22
|
-
onOpenSessionCronJobs?: () => void;
|
|
20
|
+
isWorkspaceOpen: boolean;
|
|
21
|
+
onToggleWorkspace: () => void;
|
|
23
22
|
onDeleteSession: () => void;
|
|
24
23
|
};
|
|
25
24
|
|
|
@@ -29,10 +28,8 @@ export function ChatSessionHeaderActions({
|
|
|
29
28
|
isDeletePending,
|
|
30
29
|
projectRoot,
|
|
31
30
|
metadata,
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
onOpenChildSessions,
|
|
35
|
-
onOpenSessionCronJobs,
|
|
31
|
+
isWorkspaceOpen,
|
|
32
|
+
onToggleWorkspace,
|
|
36
33
|
onDeleteSession,
|
|
37
34
|
}: ChatSessionHeaderActionsProps) {
|
|
38
35
|
const updateSessionProject = useChatSessionProject();
|
|
@@ -60,22 +57,6 @@ export function ChatSessionHeaderActions({
|
|
|
60
57
|
|
|
61
58
|
return (
|
|
62
59
|
<div className={SESSION_HEADER_ACTION_GROUP_CLASS}>
|
|
63
|
-
{childSessionCount > 0 && onOpenChildSessions ? (
|
|
64
|
-
<IconActionButton
|
|
65
|
-
icon={<GitBranch className="h-4 w-4" />}
|
|
66
|
-
label={t('chatSessionOpenChildSessions')}
|
|
67
|
-
onClick={onOpenChildSessions}
|
|
68
|
-
disabled={isBusy}
|
|
69
|
-
/>
|
|
70
|
-
) : null}
|
|
71
|
-
{sessionCronJobCount > 0 && onOpenSessionCronJobs ? (
|
|
72
|
-
<IconActionButton
|
|
73
|
-
icon={<AlarmClock className="h-4 w-4" />}
|
|
74
|
-
label={t('chatSessionOpenCronJobs')}
|
|
75
|
-
onClick={onOpenSessionCronJobs}
|
|
76
|
-
disabled={isBusy}
|
|
77
|
-
/>
|
|
78
|
-
) : null}
|
|
79
60
|
<Popover open={isMenuOpen} onOpenChange={setIsMenuOpen}>
|
|
80
61
|
<PopoverTrigger asChild>
|
|
81
62
|
<IconActionButton
|
|
@@ -85,7 +66,7 @@ export function ChatSessionHeaderActions({
|
|
|
85
66
|
disabled={isBusy}
|
|
86
67
|
/>
|
|
87
68
|
</PopoverTrigger>
|
|
88
|
-
<
|
|
69
|
+
<ChatPopoverContent align="end" className="w-56 p-2">
|
|
89
70
|
<div className="space-y-1">
|
|
90
71
|
<ChatSessionHeaderMenuItem
|
|
91
72
|
icon={FolderOpen}
|
|
@@ -116,8 +97,25 @@ export function ChatSessionHeaderActions({
|
|
|
116
97
|
destructive
|
|
117
98
|
/>
|
|
118
99
|
</div>
|
|
119
|
-
</
|
|
100
|
+
</ChatPopoverContent>
|
|
120
101
|
</Popover>
|
|
102
|
+
<IconActionButton
|
|
103
|
+
icon={
|
|
104
|
+
isWorkspaceOpen ? (
|
|
105
|
+
<PanelRightClose className="h-4 w-4" />
|
|
106
|
+
) : (
|
|
107
|
+
<PanelRightOpen className="h-4 w-4" />
|
|
108
|
+
)
|
|
109
|
+
}
|
|
110
|
+
label={t(
|
|
111
|
+
isWorkspaceOpen
|
|
112
|
+
? 'chatSessionCloseWorkspace'
|
|
113
|
+
: 'chatSessionOpenWorkspace',
|
|
114
|
+
)}
|
|
115
|
+
aria-pressed={isWorkspaceOpen}
|
|
116
|
+
onClick={onToggleWorkspace}
|
|
117
|
+
disabled={isBusy}
|
|
118
|
+
/>
|
|
121
119
|
|
|
122
120
|
<ChatSessionProjectDialog
|
|
123
121
|
open={isDialogOpen}
|
package/src/features/chat/features/session/components/session-header/chat-session-project-badge.tsx
CHANGED
|
@@ -5,10 +5,10 @@ import { ChatSessionHeaderMenuItem } from './chat-session-header-menu-item';
|
|
|
5
5
|
import { ChatSessionProjectDialog } from './chat-session-project-dialog';
|
|
6
6
|
import {
|
|
7
7
|
Popover,
|
|
8
|
-
PopoverContent,
|
|
9
8
|
PopoverTrigger,
|
|
10
9
|
createPopoverAvailableHeightLimit,
|
|
11
10
|
} from '@/shared/components/ui/popover';
|
|
11
|
+
import { ChatPopoverContent } from '@/features/chat/components/chat-popover-content';
|
|
12
12
|
import { t } from '@/shared/lib/i18n';
|
|
13
13
|
|
|
14
14
|
type ChatSessionProjectBadgeProps = {
|
|
@@ -66,7 +66,7 @@ export function ChatSessionProjectBadge({
|
|
|
66
66
|
</span>
|
|
67
67
|
</button>
|
|
68
68
|
</PopoverTrigger>
|
|
69
|
-
<
|
|
69
|
+
<ChatPopoverContent
|
|
70
70
|
align="start"
|
|
71
71
|
className="w-72 p-2"
|
|
72
72
|
style={SESSION_PROJECT_MENU_STYLE}
|
|
@@ -100,7 +100,7 @@ export function ChatSessionProjectBadge({
|
|
|
100
100
|
disabled={isProjectPending}
|
|
101
101
|
/>
|
|
102
102
|
</div>
|
|
103
|
-
</
|
|
103
|
+
</ChatPopoverContent>
|
|
104
104
|
</Popover>
|
|
105
105
|
|
|
106
106
|
<ChatSessionProjectDialog
|
package/src/features/chat/features/session/components/session-header/chat-session-title-switcher.tsx
CHANGED
|
@@ -32,9 +32,9 @@ import { useChatQueryStore } from "@/features/chat/stores/ncp-chat-query.store";
|
|
|
32
32
|
import { useViewportLayoutStore } from "@/app/stores/viewport-layout.store";
|
|
33
33
|
import {
|
|
34
34
|
Popover,
|
|
35
|
-
PopoverContent,
|
|
36
35
|
PopoverTrigger,
|
|
37
36
|
} from "@/shared/components/ui/popover";
|
|
37
|
+
import { ChatPopoverContent } from "@/features/chat/components/chat-popover-content";
|
|
38
38
|
import { Input } from "@/shared/components/ui/input";
|
|
39
39
|
import { t } from "@/shared/lib/i18n";
|
|
40
40
|
import { cn } from "@/shared/lib/utils";
|
|
@@ -217,7 +217,7 @@ function ChatSessionTitleSwitcherPopover({
|
|
|
217
217
|
/>
|
|
218
218
|
</button>
|
|
219
219
|
</PopoverTrigger>
|
|
220
|
-
<
|
|
220
|
+
<ChatPopoverContent
|
|
221
221
|
align="start"
|
|
222
222
|
className="w-[22rem] max-w-[calc(100vw-2rem)] p-0"
|
|
223
223
|
>
|
|
@@ -263,7 +263,7 @@ function ChatSessionTitleSwitcherPopover({
|
|
|
263
263
|
/>
|
|
264
264
|
)}
|
|
265
265
|
</div>
|
|
266
|
-
</
|
|
266
|
+
</ChatPopoverContent>
|
|
267
267
|
</Popover>
|
|
268
268
|
);
|
|
269
269
|
}
|
|
@@ -3,10 +3,10 @@ import { ChevronDown, FolderOpen } from 'lucide-react';
|
|
|
3
3
|
import type { ChatWelcomeProjectOption } from '@/features/chat/features/welcome/utils/chat-welcome-project-options.utils';
|
|
4
4
|
import {
|
|
5
5
|
Popover,
|
|
6
|
-
PopoverContent,
|
|
7
6
|
PopoverTrigger,
|
|
8
7
|
createPopoverAvailableHeightLimit,
|
|
9
8
|
} from '@/shared/components/ui/popover';
|
|
9
|
+
import { ChatPopoverContent } from '@/features/chat/components/chat-popover-content';
|
|
10
10
|
import { t } from '@/shared/lib/i18n';
|
|
11
11
|
import { getSessionProjectName } from '@/shared/lib/session-project';
|
|
12
12
|
|
|
@@ -64,7 +64,7 @@ export function ChatWelcomeProjectPicker({
|
|
|
64
64
|
<ChevronDown className="h-3.5 w-3.5 shrink-0 text-muted-foreground/70" />
|
|
65
65
|
</button>
|
|
66
66
|
</PopoverTrigger>
|
|
67
|
-
<
|
|
67
|
+
<ChatPopoverContent
|
|
68
68
|
align="start"
|
|
69
69
|
className="flex w-[min(20rem,calc(100vw-1rem))] flex-col overflow-hidden rounded-2xl border border-border bg-popover p-0 text-popover-foreground shadow-[0_24px_60px_-28px_rgba(15,23,42,0.38)]"
|
|
70
70
|
style={{ maxHeight: PROJECT_PICKER_MAX_HEIGHT }}
|
|
@@ -121,7 +121,7 @@ export function ChatWelcomeProjectPicker({
|
|
|
121
121
|
<span>{t('chatWelcomeProjectOpenFolder')}</span>
|
|
122
122
|
</button>
|
|
123
123
|
</div>
|
|
124
|
-
</
|
|
124
|
+
</ChatPopoverContent>
|
|
125
125
|
</Popover>
|
|
126
126
|
);
|
|
127
127
|
}
|