@nextclaw/ui 0.15.1 → 0.15.2
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 +31 -0
- package/dist/assets/{api-b1R9VdeH.js → api-B7Qigvtm.js} +2 -2
- package/dist/assets/{appearance-settings-page-D2O9pch9.js → appearance-settings-page-CuE0Iiqj.js} +1 -1
- package/dist/assets/{book-open-B77lQ2Tg.js → book-open-Ba2f7YiG.js} +1 -1
- package/dist/assets/channels-list-page-CTsM6TcP.js +8 -0
- package/dist/assets/{chat-page-CZ7WxPir.js → chat-page-C_5dcuE3.js} +1 -1
- package/dist/assets/config-split-page-Fbb4PtTf.js +1 -0
- package/dist/assets/{confirm-dialog-C-NXSioX.js → confirm-dialog-D2EG3nqE.js} +1 -1
- package/dist/assets/{desktop-update-config-usHpXugP.js → desktop-update-config-BGR3HUi1.js} +1 -1
- package/dist/assets/{dist-jdGmbb6w.js → dist-7JTjycxE.js} +1 -1
- package/dist/assets/{dist-YtoqU-AT.js → dist-wXLhk4hl.js} +1 -1
- package/dist/assets/doc-browser-bHyXnxlj.js +1 -0
- package/dist/assets/doc-browser-context-CYAGm5d5.js +1 -0
- package/dist/assets/doc-browser-gTrQ3jCF.js +1 -0
- package/dist/assets/{es2015-bNpL2LKy.js → es2015-j1SRCIX5.js} +1 -1
- package/dist/assets/{external-link-BM6fk8q-.js → external-link-DxuPaDoK.js} +1 -1
- package/dist/assets/form-actions-BztL7P_T.js +1 -0
- package/dist/assets/{i18n-provider-CntWolRA.js → i18n-provider-B4oMxOFx.js} +1 -1
- package/dist/assets/index-CvrvblgX.css +1 -0
- package/dist/assets/index-Obd4JYU2.js +104 -0
- package/dist/assets/loader-circle-CdzgK4eH.js +1 -0
- package/dist/assets/{mcp-marketplace-page-CLmUstLN.js → mcp-marketplace-page-Bt7CuOoq.js} +2 -2
- package/dist/assets/mcp-marketplace-page-Ck3t78_n.js +1 -0
- package/dist/assets/model-config-page-DeKk9gvE.js +1 -0
- package/dist/assets/plus-Bx7wQbhG.js +1 -0
- package/dist/assets/{provider-scoped-model-input-Cm_a4GHf.js → provider-scoped-model-input-DsH2LF1q.js} +1 -1
- package/dist/assets/providers-config-page-BFnGp68F.js +1 -0
- package/dist/assets/{react-BN8uzPnp.js → react-UirzUuST.js} +1 -1
- package/dist/assets/{refresh-cw-BpVcFPmJ.js → refresh-cw-eT8BF-8B.js} +1 -1
- package/dist/assets/remote-CDkHZtA8.js +1 -0
- package/dist/assets/rotate-cw-1JqxHTuw.js +1 -0
- package/dist/assets/runtime-config-page-BelAqiNG.js +1 -0
- package/dist/assets/{save-BpFW5fpk.js → save-Cb2g0BOi.js} +1 -1
- package/dist/assets/{search-D0uO7enf.js → search-BcHjwdsb.js} +1 -1
- package/dist/assets/search-config-page-zPm6--Ig.js +1 -0
- package/dist/assets/secrets-config-page-Cxyp-KuQ.js +3 -0
- package/dist/assets/security-config-B_gCq9fn.js +1 -0
- package/dist/assets/{select-Bh-CrA4p.js → select-CdSEOwVM.js} +1 -1
- package/dist/assets/{setting-row-BJfCHRcb.js → setting-row-CTAtGexr.js} +1 -1
- package/dist/assets/{settings-2-Blzi1vr6.js → settings-2-2DWauOjY.js} +1 -1
- package/dist/assets/{side-dock-ZdaSrQVB.js → side-dock-DPvakJ0a.js} +2 -2
- package/dist/assets/{skeleton-BLlEzebZ.js → skeleton-P5oM14E1.js} +1 -1
- package/dist/assets/{switch-CFLJFNSd.js → switch-BU_UEULb.js} +1 -1
- package/dist/assets/{tag-chip-CzGihiQx.js → tag-chip-D-WsKoT1.js} +1 -1
- package/dist/assets/{tooltip-CdcrBjrC.js → tooltip-CjkOaHW7.js} +1 -1
- package/dist/assets/{use-config-CVPgsBmU.js → use-config--hx5oxQn.js} +1 -1
- package/dist/assets/{use-confirm-dialog-CSeBk9SF.js → use-confirm-dialog-CD9a_SK1.js} +1 -1
- package/dist/assets/x-DT5x45JU.js +1 -0
- package/dist/index.html +38 -30
- package/index.html +12 -4
- package/package.json +9 -9
- package/src/app/components/layout/__tests__/sidebar.layout.test.tsx +29 -1
- package/src/app/components/layout/sidebar-items.tsx +43 -4
- package/src/app/components/layout/sidebar.tsx +83 -61
- package/src/app/configs/app-navigation.config.ts +49 -0
- package/src/app/styles/design-system.css +82 -0
- package/src/features/channels/components/config/channel-form.tsx +14 -11
- package/src/features/chat/components/conversation/__tests__/chat-conversation-header-section.test.tsx +40 -0
- package/src/features/chat/components/conversation/chat-conversation-header-section.tsx +3 -1
- package/src/features/chat/components/conversation/chat-conversation-panel.tsx +1 -1
- package/src/features/chat/components/layout/__tests__/chat-sidebar-toolbar.test.tsx +48 -0
- package/src/features/chat/components/layout/__tests__/chat-sidebar-utility-menu.test.tsx +55 -0
- package/src/features/chat/components/layout/chat-sidebar-desktop-layout.tsx +0 -3
- package/src/features/chat/components/layout/chat-sidebar-toolbar.tsx +3 -4
- package/src/features/chat/components/layout/chat-sidebar-utility-menu.tsx +29 -30
- package/src/features/chat/components/layout/chat-sidebar.tsx +21 -7
- package/src/features/chat/features/conversation/components/session-conversation-input.tsx +2 -1
- package/src/features/chat/features/message/components/__tests__/chat-inline-panel-app-card.test.tsx +22 -1
- package/src/features/chat/features/message/components/chat-inline-panel-app-card.tsx +10 -5
- package/src/features/chat/features/message/utils/chat-inline-panel-app-card.utils.ts +0 -11
- package/src/features/chat/features/session/components/__tests__/chat-sidebar-project-groups.test.tsx +116 -0
- package/src/features/chat/features/session/components/chat-sidebar-project-groups.tsx +108 -46
- package/src/features/chat/features/session/components/chat-sidebar-session-entry.tsx +6 -0
- package/src/features/chat/features/session/components/chat-sidebar-session-item.tsx +48 -24
- package/src/features/chat/features/session/components/chat-sidebar-session-list.tsx +0 -3
- package/src/features/chat/features/session/components/session-header/chat-session-header-actions.tsx +0 -4
- package/src/features/chat/features/session/utils/chat-sidebar-session-groups.utils.ts +25 -3
- package/src/features/chat/features/welcome/components/chat-welcome-capability-grid.tsx +9 -4
- package/src/features/chat/features/welcome/components/chat-welcome.tsx +0 -5
- package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-file-preview.test.tsx +159 -56
- package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-panel-content.test.tsx +1 -0
- package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-panel.test.tsx +144 -0
- package/src/features/chat/features/workspace/components/chat-session-workspace-directory-browser.tsx +99 -0
- package/src/features/chat/features/workspace/components/chat-session-workspace-file-breadcrumbs.tsx +3 -1
- package/src/features/chat/features/workspace/components/chat-session-workspace-file-preview.tsx +66 -7
- package/src/features/chat/features/workspace/components/chat-session-workspace-panel-content.tsx +3 -0
- package/src/features/chat/features/workspace/components/chat-session-workspace-panel-nav.tsx +44 -1
- package/src/features/chat/features/workspace/components/chat-session-workspace-panel.tsx +45 -3
- package/src/features/chat/managers/__tests__/chat-session-list.manager.test.ts +33 -2
- package/src/features/chat/managers/chat-session-list.manager.ts +32 -0
- package/src/features/chat/stores/chat-session-list.store.ts +28 -5
- package/src/features/marketplace/components/mcp/mcp-marketplace-page.tsx +5 -12
- package/src/features/panel-apps/components/panel-app-list-item.tsx +6 -6
- package/src/features/panel-apps/index.ts +1 -0
- package/src/features/panel-apps/utils/panel-app-doc-browser.utils.tsx +2 -10
- package/src/features/panel-apps/utils/panel-app-iframe.utils.ts +6 -0
- package/src/features/pwa/managers/__tests__/pwa-shell-theme.manager.test.ts +11 -3
- package/src/features/pwa/managers/pwa-shell-theme.manager.ts +3 -1
- package/src/features/service-apps/components/service-apps-panel.tsx +145 -35
- package/src/features/settings/components/config/provider-auth-section.tsx +1 -1
- package/src/features/settings/components/config/provider-form.tsx +11 -8
- package/src/features/settings/components/config/provider-models-section.tsx +7 -7
- package/src/features/settings/components/config/provider-pill-selector.tsx +1 -1
- package/src/features/settings/components/config/secrets-config-form.tsx +5 -4
- package/src/features/settings/pages/model-config-page.tsx +26 -25
- package/src/features/settings/pages/providers-config-page.tsx +10 -13
- package/src/features/settings/pages/search-config-page.tsx +8 -5
- package/src/features/system-status/components/config/runtime-config-editor.tsx +5 -4
- package/src/index.css +18 -0
- package/src/shared/components/config-split-page.tsx +6 -6
- package/src/shared/components/doc-browser/__tests__/doc-browser-url.utils.test.ts +73 -0
- package/src/shared/components/doc-browser/__tests__/doc-browser.test.tsx +48 -0
- package/src/shared/components/doc-browser/doc-browser-context.tsx +4 -0
- package/src/shared/components/doc-browser/doc-browser-panel-parts.tsx +5 -1
- package/src/shared/components/doc-browser/doc-browser-renderer.types.ts +2 -1
- package/src/shared/components/doc-browser/doc-browser-tab-strip.tsx +10 -10
- package/src/shared/components/doc-browser/doc-browser.tsx +6 -4
- package/src/shared/components/doc-browser/utils/doc-browser-url.utils.ts +62 -4
- package/src/shared/components/resizable-right-panel/__tests__/resizable-right-panel.test.tsx +18 -0
- package/src/shared/components/resizable-right-panel/resizable-right-panel.tsx +28 -3
- package/src/shared/components/ui/actions/__tests__/icon-action-button.test.tsx +36 -0
- package/src/shared/components/ui/actions/form-actions.tsx +25 -0
- package/src/shared/components/ui/actions/icon-action-button.tsx +25 -2
- package/src/shared/components/ui/card.tsx +12 -4
- package/src/shared/components/ui/tab-strip/compact-tab-strip.tsx +2 -1
- package/src/shared/hooks/use-server-path-browse.ts +26 -4
- package/src/shared/hooks/use-server-path-read.ts +11 -1
- package/src/shared/lib/api/utils/server-path.utils.ts +1 -0
- package/src/shared/lib/i18n/locales/en-US/chat.json +16 -0
- package/src/shared/lib/i18n/locales/en-US/core.json +3 -0
- package/src/shared/lib/i18n/locales/en-US/doc-browser.json +5 -0
- package/src/shared/lib/i18n/locales/zh-CN/chat.json +16 -0
- package/src/shared/lib/i18n/locales/zh-CN/core.json +3 -0
- package/src/shared/lib/i18n/locales/zh-CN/doc-browser.json +5 -0
- package/src/shared/lib/session-project/workspace-file-breadcrumb.utils.ts +9 -5
- package/src/shared/lib/theme/index.test.ts +21 -0
- package/src/shared/lib/theme/index.ts +6 -4
- package/src/vite-env.d.ts +2 -0
- package/dist/assets/channels-list-page-DcsIQc6A.js +0 -8
- package/dist/assets/config-split-page-BWQ6_Raq.js +0 -1
- package/dist/assets/doc-browser-B_Tf9n70.js +0 -1
- package/dist/assets/doc-browser-BdZPFOVa.js +0 -1
- package/dist/assets/doc-browser-context-DwokemUn.js +0 -1
- package/dist/assets/index-BIcEw90u.js +0 -104
- package/dist/assets/index-BiNSTKTU.css +0 -1
- package/dist/assets/loader-circle-MBgNSVIH.js +0 -1
- package/dist/assets/mcp-marketplace-page-rZkmWPMy.js +0 -1
- package/dist/assets/model-config-page-Di0ySJD2.js +0 -1
- package/dist/assets/plus-vDqW5Kxp.js +0 -1
- package/dist/assets/providers-config-page-BAf2W0MV.js +0 -1
- package/dist/assets/remote-CLQ0IBM8.js +0 -1
- package/dist/assets/rotate-cw-CvNBv7_w.js +0 -1
- package/dist/assets/runtime-config-page-CflvvoDc.js +0 -1
- package/dist/assets/search-config-page-D0klFUXd.js +0 -1
- package/dist/assets/secrets-config-page-dVZ631Wp.js +0 -3
- package/dist/assets/security-config-C5gnlkuj.js +0 -1
- package/dist/assets/x-BF2KQ--V.js +0 -1
- /package/dist/assets/{config-hints-fGnUjDe9.js → config-hints-C_iP1zl_.js} +0 -0
|
@@ -2,13 +2,17 @@ import { useEffect, useId, useMemo, useRef } from 'react';
|
|
|
2
2
|
import type { ChatPanelAppCardViewModel } from '@nextclaw/agent-chat-ui';
|
|
3
3
|
import { AppWindow, Maximize2 } from 'lucide-react';
|
|
4
4
|
import { getPresenter } from '@/app/presenters/app.presenter';
|
|
5
|
-
import {
|
|
5
|
+
import {
|
|
6
|
+
PANEL_APP_IFRAME_SANDBOX,
|
|
7
|
+
findPanelAppEntryByDisplayId,
|
|
8
|
+
focusPanelAppIframe,
|
|
9
|
+
usePanelApps,
|
|
10
|
+
} from '@/features/panel-apps';
|
|
6
11
|
import { createPanelAppRightPanelResourceTarget } from '@/features/right-panel-resources';
|
|
7
12
|
import {
|
|
8
13
|
createInlinePanelAppCardUrl,
|
|
9
14
|
createFallbackPanelAppContentPath,
|
|
10
15
|
createInlinePanelAppTab,
|
|
11
|
-
PANEL_APP_INLINE_IFRAME_SANDBOX,
|
|
12
16
|
} from '@/features/chat/features/message/utils/chat-inline-panel-app-card.utils';
|
|
13
17
|
import { useDocBrowser } from '@/shared/components/doc-browser';
|
|
14
18
|
import { IconActionButton } from '@/shared/components/ui/actions/icon-action-button';
|
|
@@ -98,7 +102,7 @@ export function ChatInlinePanelAppCard({
|
|
|
98
102
|
</div>
|
|
99
103
|
{showExpandAction ? (
|
|
100
104
|
<IconActionButton
|
|
101
|
-
|
|
105
|
+
size="md"
|
|
102
106
|
icon={<Maximize2 className="h-3.5 w-3.5" />}
|
|
103
107
|
label={t('chatPanelCardExpand')}
|
|
104
108
|
onClick={openExpanded}
|
|
@@ -113,8 +117,9 @@ export function ChatInlinePanelAppCard({
|
|
|
113
117
|
key={iframeInstanceId}
|
|
114
118
|
src={cardUrl}
|
|
115
119
|
title={title}
|
|
116
|
-
sandbox={
|
|
117
|
-
|
|
120
|
+
sandbox={PANEL_APP_IFRAME_SANDBOX}
|
|
121
|
+
tabIndex={0}
|
|
122
|
+
onPointerOver={() => focusPanelAppIframe(iframeRef.current)}
|
|
118
123
|
className="h-full w-full border-0 bg-card"
|
|
119
124
|
/>
|
|
120
125
|
</div>
|
|
@@ -4,17 +4,6 @@ import {
|
|
|
4
4
|
} from '@/features/right-panel-resources';
|
|
5
5
|
import type { DocBrowserTab } from '@/shared/components/doc-browser/doc-browser-context';
|
|
6
6
|
|
|
7
|
-
export const PANEL_APP_INLINE_IFRAME_SANDBOX = [
|
|
8
|
-
'allow-scripts',
|
|
9
|
-
'allow-forms',
|
|
10
|
-
'allow-modals',
|
|
11
|
-
'allow-popups',
|
|
12
|
-
'allow-popups-to-escape-sandbox',
|
|
13
|
-
'allow-downloads',
|
|
14
|
-
'allow-pointer-lock',
|
|
15
|
-
'allow-presentation',
|
|
16
|
-
].join(' ');
|
|
17
|
-
|
|
18
7
|
const PANEL_APP_INLINE_CARD_SEARCH_PARAMS = {
|
|
19
8
|
nextclawDisplayMode: 'card',
|
|
20
9
|
nextclawPlacement: 'inline',
|
package/src/features/chat/features/session/components/__tests__/chat-sidebar-project-groups.test.tsx
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { fireEvent, render, screen } from "@testing-library/react";
|
|
2
|
+
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
3
|
+
import { ChatSidebarProjectGroups } from "@/features/chat/features/session/components/chat-sidebar-project-groups";
|
|
4
|
+
import { useChatSessionListStore } from "@/features/chat/stores/chat-session-list.store";
|
|
5
|
+
|
|
6
|
+
const mocks = vi.hoisted(() => ({
|
|
7
|
+
createSession: vi.fn(),
|
|
8
|
+
toggleProjectCollapsed: vi.fn(),
|
|
9
|
+
toggleProjectPinned: vi.fn(),
|
|
10
|
+
}));
|
|
11
|
+
|
|
12
|
+
vi.mock("@/features/chat/components/providers/chat-presenter.provider", () => ({
|
|
13
|
+
usePresenter: () => ({
|
|
14
|
+
chatSessionListManager: mocks,
|
|
15
|
+
}),
|
|
16
|
+
}));
|
|
17
|
+
|
|
18
|
+
const projectGroup = {
|
|
19
|
+
projectRoot: "/tmp/analysis-project",
|
|
20
|
+
projectName: "analysis-project",
|
|
21
|
+
items: [
|
|
22
|
+
{
|
|
23
|
+
session: {
|
|
24
|
+
key: "session:analysis",
|
|
25
|
+
createdAt: "2026-07-12T00:00:00.000Z",
|
|
26
|
+
updatedAt: "2026-07-12T00:00:00.000Z",
|
|
27
|
+
sessionType: "native",
|
|
28
|
+
sessionTypeMutable: false,
|
|
29
|
+
messageCount: 1,
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
latestUpdatedAt: 1,
|
|
34
|
+
isPinned: false,
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
function renderProjectGroups(isPinned = false) {
|
|
38
|
+
return render(
|
|
39
|
+
<ChatSidebarProjectGroups
|
|
40
|
+
groups={[{ ...projectGroup, isPinned }]}
|
|
41
|
+
defaultSessionType="native"
|
|
42
|
+
sessionTypeOptions={[
|
|
43
|
+
{ value: "native", label: "Native", icon: null, ready: true },
|
|
44
|
+
]}
|
|
45
|
+
renderSessionItem={() => <div>Project session</div>}
|
|
46
|
+
/>,
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
describe("ChatSidebarProjectGroups", () => {
|
|
51
|
+
beforeEach(() => {
|
|
52
|
+
mocks.createSession.mockReset();
|
|
53
|
+
mocks.toggleProjectCollapsed.mockReset();
|
|
54
|
+
mocks.toggleProjectPinned.mockReset();
|
|
55
|
+
useChatSessionListStore.setState({
|
|
56
|
+
snapshot: {
|
|
57
|
+
...useChatSessionListStore.getState().snapshot,
|
|
58
|
+
collapsedProjectRoots: [],
|
|
59
|
+
selectedSessionKey: "session:current",
|
|
60
|
+
},
|
|
61
|
+
});
|
|
62
|
+
mocks.toggleProjectCollapsed.mockImplementation((projectRoot: string) => {
|
|
63
|
+
useChatSessionListStore.getState().setSnapshot({
|
|
64
|
+
collapsedProjectRoots: [projectRoot],
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
it("keeps the project header as the full-width folder row and collapses its sessions", () => {
|
|
70
|
+
renderProjectGroups();
|
|
71
|
+
|
|
72
|
+
const header = screen.getByLabelText("Collapse project");
|
|
73
|
+
expect(header.parentElement?.className).toContain("h-10");
|
|
74
|
+
expect(header.parentElement?.className).toContain("hover:bg-gray-200/60");
|
|
75
|
+
expect(header.parentElement?.className).not.toContain("focus-within:bg");
|
|
76
|
+
expect(screen.getByText("analysis-project").nextElementSibling?.tagName).toBe("svg");
|
|
77
|
+
|
|
78
|
+
fireEvent.click(header);
|
|
79
|
+
|
|
80
|
+
expect(mocks.toggleProjectCollapsed).toHaveBeenCalledWith(
|
|
81
|
+
"/tmp/analysis-project",
|
|
82
|
+
);
|
|
83
|
+
expect(useChatSessionListStore.getState().snapshot.selectedSessionKey).toBe(
|
|
84
|
+
"session:current",
|
|
85
|
+
);
|
|
86
|
+
expect(screen.queryByText("Project session")).toBeNull();
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it("keeps project creation and pinning in one trailing action cluster", () => {
|
|
90
|
+
renderProjectGroups();
|
|
91
|
+
|
|
92
|
+
fireEvent.click(screen.getByLabelText("Pin project"));
|
|
93
|
+
|
|
94
|
+
expect(mocks.toggleProjectPinned).toHaveBeenCalledWith(
|
|
95
|
+
"/tmp/analysis-project",
|
|
96
|
+
);
|
|
97
|
+
expect(screen.getByLabelText("New Task · analysis-project")).not.toBeNull();
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it("uses the same pin control to show and clear the project pin state", () => {
|
|
101
|
+
renderProjectGroups(true);
|
|
102
|
+
|
|
103
|
+
const unpinButton = screen.getByLabelText("Unpin project");
|
|
104
|
+
const pinIcon = unpinButton.querySelector("svg");
|
|
105
|
+
|
|
106
|
+
expect(pinIcon?.getAttribute("class")).toContain("fill-current");
|
|
107
|
+
expect(pinIcon?.getAttribute("class")).toContain("text-foreground");
|
|
108
|
+
expect(document.querySelectorAll("svg.fill-current")).toHaveLength(1);
|
|
109
|
+
|
|
110
|
+
fireEvent.click(unpinButton);
|
|
111
|
+
|
|
112
|
+
expect(mocks.toggleProjectPinned).toHaveBeenCalledWith(
|
|
113
|
+
"/tmp/analysis-project",
|
|
114
|
+
);
|
|
115
|
+
});
|
|
116
|
+
});
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { useMemo, useState, type ReactNode } from 'react';
|
|
2
|
-
import { Plus } from 'lucide-react';
|
|
2
|
+
import { ChevronDown, ChevronRight, Folder, Pin, Plus } from 'lucide-react';
|
|
3
|
+
import { usePresenter } from '@/features/chat/components/providers/chat-presenter.provider';
|
|
3
4
|
import { ChatSessionTypeMenu } from "@/features/chat/features/session-type/components/chat-session-type-menu";
|
|
4
5
|
import { Popover, PopoverContent, PopoverTrigger } from '@/shared/components/ui/popover';
|
|
5
6
|
import { IconActionButton } from '@/shared/components/ui/actions/icon-action-button';
|
|
6
7
|
import type { ChatSessionTypeOption } from "@/features/chat/features/session-type/utils/chat-session-type.utils";
|
|
7
8
|
import type { NcpSessionListItemView } from '@/features/chat/features/ncp/hooks/use-ncp-session-list-view';
|
|
8
9
|
import type { ChatSidebarProjectGroup } from '@/features/chat/features/session/utils/chat-sidebar-session-groups.utils';
|
|
10
|
+
import { useChatSessionListStore } from '@/features/chat/stores/chat-session-list.store';
|
|
9
11
|
import { t } from '@/shared/lib/i18n';
|
|
10
12
|
|
|
11
13
|
export type { ChatSidebarProjectGroup };
|
|
@@ -17,7 +19,6 @@ type ChatSidebarProjectGroupsProps = {
|
|
|
17
19
|
defaultSessionType: string;
|
|
18
20
|
sessionTypeOptions: SessionTypeOption[];
|
|
19
21
|
renderSessionItem: (item: NcpSessionListItemView) => ReactNode;
|
|
20
|
-
onCreateSession: (sessionType: string, projectRoot: string) => void;
|
|
21
22
|
};
|
|
22
23
|
|
|
23
24
|
function resolveProjectGroupDefaultSessionType(
|
|
@@ -31,7 +32,11 @@ function resolveProjectGroupDefaultSessionType(
|
|
|
31
32
|
}
|
|
32
33
|
|
|
33
34
|
export function ChatSidebarProjectGroups(props: ChatSidebarProjectGroupsProps) {
|
|
34
|
-
const { groups, defaultSessionType, sessionTypeOptions, renderSessionItem
|
|
35
|
+
const { groups, defaultSessionType, sessionTypeOptions, renderSessionItem } = props;
|
|
36
|
+
const presenter = usePresenter();
|
|
37
|
+
const collapsedProjectRoots = useChatSessionListStore(
|
|
38
|
+
(state) => state.snapshot.collapsedProjectRoots,
|
|
39
|
+
);
|
|
35
40
|
const [openProjectRoot, setOpenProjectRoot] = useState<string | null>(null);
|
|
36
41
|
const preferredSessionType = useMemo(
|
|
37
42
|
() => resolveProjectGroupDefaultSessionType(defaultSessionType, sessionTypeOptions),
|
|
@@ -43,62 +48,119 @@ export function ChatSidebarProjectGroups(props: ChatSidebarProjectGroupsProps) {
|
|
|
43
48
|
<div className="space-y-3">
|
|
44
49
|
{groups.map((group) => {
|
|
45
50
|
const actionLabel = `${t('chatSidebarNewTask')} · ${group.projectName}`;
|
|
51
|
+
const isCollapsed = collapsedProjectRoots.includes(group.projectRoot);
|
|
52
|
+
const pinLabel = t(
|
|
53
|
+
group.isPinned ? 'chatSidebarUnpinProject' : 'chatSidebarPinProject',
|
|
54
|
+
);
|
|
46
55
|
|
|
47
56
|
return (
|
|
48
57
|
<div key={group.projectRoot}>
|
|
49
|
-
<div className="
|
|
50
|
-
<
|
|
51
|
-
|
|
52
|
-
|
|
58
|
+
<div className="group/project relative h-10 rounded-lg px-2 text-muted-foreground transition-colors hover:bg-gray-200/60 hover:text-gray-900">
|
|
59
|
+
<button
|
|
60
|
+
type="button"
|
|
61
|
+
aria-expanded={!isCollapsed}
|
|
62
|
+
aria-label={t(
|
|
63
|
+
isCollapsed
|
|
64
|
+
? 'chatSidebarExpandProject'
|
|
65
|
+
: 'chatSidebarCollapseProject',
|
|
66
|
+
)}
|
|
67
|
+
className="flex h-full w-full min-w-0 items-center gap-1.5 pr-14 text-left focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-primary/40"
|
|
68
|
+
onClick={() =>
|
|
69
|
+
presenter.chatSessionListManager.toggleProjectCollapsed(
|
|
70
|
+
group.projectRoot,
|
|
71
|
+
)
|
|
72
|
+
}
|
|
73
|
+
>
|
|
74
|
+
<Folder className="h-3.5 w-3.5 shrink-0" aria-hidden="true" />
|
|
75
|
+
<span
|
|
76
|
+
className="truncate text-[11px] font-medium uppercase tracking-wider"
|
|
53
77
|
title={group.projectRoot}
|
|
54
78
|
>
|
|
55
79
|
{group.projectName}
|
|
56
|
-
</
|
|
80
|
+
</span>
|
|
81
|
+
{isCollapsed ? (
|
|
82
|
+
<ChevronRight
|
|
83
|
+
className="h-3.5 w-3.5 shrink-0"
|
|
84
|
+
aria-hidden="true"
|
|
85
|
+
/>
|
|
86
|
+
) : (
|
|
87
|
+
<ChevronDown
|
|
88
|
+
className="h-3.5 w-3.5 shrink-0"
|
|
89
|
+
aria-hidden="true"
|
|
90
|
+
/>
|
|
91
|
+
)}
|
|
57
92
|
<span className="shrink-0 text-[10px] text-muted-foreground/70">
|
|
58
93
|
{group.items.length}
|
|
59
94
|
</span>
|
|
60
|
-
</
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
<PopoverTrigger asChild>
|
|
69
|
-
<IconActionButton
|
|
70
|
-
icon={<Plus className="h-3.5 w-3.5" />}
|
|
71
|
-
label={actionLabel}
|
|
72
|
-
tooltip={false}
|
|
73
|
-
className="h-7 w-7 shrink-0 rounded-lg text-muted-foreground hover:bg-gray-200/60 hover:text-gray-900"
|
|
74
|
-
/>
|
|
75
|
-
</PopoverTrigger>
|
|
76
|
-
<PopoverContent
|
|
77
|
-
align="end"
|
|
78
|
-
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)]"
|
|
95
|
+
</button>
|
|
96
|
+
<div className="pointer-events-none absolute right-2 top-1/2 flex -translate-y-1/2 items-center opacity-0 transition-opacity group-hover/project:pointer-events-auto group-hover/project:opacity-100 focus-within:pointer-events-auto focus-within:opacity-100">
|
|
97
|
+
{supportsSessionTypeChoice ? (
|
|
98
|
+
<Popover
|
|
99
|
+
open={openProjectRoot === group.projectRoot}
|
|
100
|
+
onOpenChange={(nextOpen) => {
|
|
101
|
+
setOpenProjectRoot(nextOpen ? group.projectRoot : null);
|
|
102
|
+
}}
|
|
79
103
|
>
|
|
80
|
-
<
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
104
|
+
<PopoverTrigger asChild>
|
|
105
|
+
<IconActionButton
|
|
106
|
+
icon={<Plus className="h-3.5 w-3.5" />}
|
|
107
|
+
label={actionLabel}
|
|
108
|
+
/>
|
|
109
|
+
</PopoverTrigger>
|
|
110
|
+
<PopoverContent
|
|
111
|
+
align="end"
|
|
112
|
+
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
|
+
<ChatSessionTypeMenu
|
|
115
|
+
options={sessionTypeOptions}
|
|
116
|
+
selectedSessionType={preferredSessionType}
|
|
117
|
+
onSelect={(sessionType) => {
|
|
118
|
+
presenter.chatSessionListManager.createSession(
|
|
119
|
+
sessionType,
|
|
120
|
+
group.projectRoot,
|
|
121
|
+
);
|
|
122
|
+
setOpenProjectRoot(null);
|
|
123
|
+
}}
|
|
124
|
+
/>
|
|
125
|
+
</PopoverContent>
|
|
126
|
+
</Popover>
|
|
127
|
+
) : (
|
|
128
|
+
<IconActionButton
|
|
129
|
+
icon={<Plus className="h-3.5 w-3.5" />}
|
|
130
|
+
label={actionLabel}
|
|
131
|
+
onClick={() =>
|
|
132
|
+
presenter.chatSessionListManager.createSession(
|
|
133
|
+
preferredSessionType,
|
|
134
|
+
group.projectRoot,
|
|
135
|
+
)
|
|
136
|
+
}
|
|
137
|
+
/>
|
|
138
|
+
)}
|
|
91
139
|
<IconActionButton
|
|
92
|
-
icon={
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
140
|
+
icon={
|
|
141
|
+
<Pin
|
|
142
|
+
className={
|
|
143
|
+
group.isPinned
|
|
144
|
+
? 'h-3.5 w-3.5 fill-current text-foreground'
|
|
145
|
+
: 'h-3.5 w-3.5'
|
|
146
|
+
}
|
|
147
|
+
/>
|
|
148
|
+
}
|
|
149
|
+
label={pinLabel}
|
|
150
|
+
tooltipSide="right"
|
|
151
|
+
onClick={() =>
|
|
152
|
+
presenter.chatSessionListManager.toggleProjectPinned(
|
|
153
|
+
group.projectRoot,
|
|
154
|
+
)
|
|
155
|
+
}
|
|
96
156
|
/>
|
|
97
|
-
|
|
98
|
-
</div>
|
|
99
|
-
<div className="space-y-0.5 pl-2">
|
|
100
|
-
{group.items.map(renderSessionItem)}
|
|
157
|
+
</div>
|
|
101
158
|
</div>
|
|
159
|
+
{isCollapsed ? null : (
|
|
160
|
+
<div className="mt-0.5 space-y-0.5 pl-2">
|
|
161
|
+
{group.items.map(renderSessionItem)}
|
|
162
|
+
</div>
|
|
163
|
+
)}
|
|
102
164
|
</div>
|
|
103
165
|
);
|
|
104
166
|
})}
|
|
@@ -22,6 +22,7 @@ export function ChatSidebarSessionEntry(props: {
|
|
|
22
22
|
draftLabel: string;
|
|
23
23
|
savingSessionKey: string | null;
|
|
24
24
|
sessionTypeOptions: ChatSessionTypeOption[];
|
|
25
|
+
isPinned: boolean;
|
|
25
26
|
sessionTitle: (session: SessionEntryView) => string;
|
|
26
27
|
onSelectSession: (sessionKey: string) => void;
|
|
27
28
|
onOpenChildSessions: (
|
|
@@ -32,6 +33,7 @@ export function ChatSidebarSessionEntry(props: {
|
|
|
32
33
|
onDraftLabelChange: (value: string) => void;
|
|
33
34
|
onSaveSessionLabel: (session: SessionEntryView) => void;
|
|
34
35
|
onCancelEditingSessionLabel: () => void;
|
|
36
|
+
onTogglePinned: () => void;
|
|
35
37
|
}) {
|
|
36
38
|
const {
|
|
37
39
|
item,
|
|
@@ -43,6 +45,7 @@ export function ChatSidebarSessionEntry(props: {
|
|
|
43
45
|
draftLabel,
|
|
44
46
|
savingSessionKey,
|
|
45
47
|
sessionTypeOptions,
|
|
48
|
+
isPinned,
|
|
46
49
|
sessionTitle,
|
|
47
50
|
onSelectSession,
|
|
48
51
|
onOpenChildSessions,
|
|
@@ -50,6 +53,7 @@ export function ChatSidebarSessionEntry(props: {
|
|
|
50
53
|
onDraftLabelChange,
|
|
51
54
|
onSaveSessionLabel,
|
|
52
55
|
onCancelEditingSessionLabel,
|
|
56
|
+
onTogglePinned,
|
|
53
57
|
} = props;
|
|
54
58
|
const { session, runStatus } = item;
|
|
55
59
|
const active = selectedSessionKey === session.key;
|
|
@@ -80,6 +84,7 @@ export function ChatSidebarSessionEntry(props: {
|
|
|
80
84
|
})}
|
|
81
85
|
runStatus={runStatus}
|
|
82
86
|
context={resolveSessionContextView(session, sessionTypeOptions)}
|
|
87
|
+
isPinned={isPinned}
|
|
83
88
|
title={sessionTitle(session)}
|
|
84
89
|
previewText={previewText}
|
|
85
90
|
trailingText={formatSessionListTime(
|
|
@@ -104,6 +109,7 @@ export function ChatSidebarSessionEntry(props: {
|
|
|
104
109
|
onDraftLabelChange={onDraftLabelChange}
|
|
105
110
|
onSave={() => onSaveSessionLabel(session)}
|
|
106
111
|
onCancel={onCancelEditingSessionLabel}
|
|
112
|
+
onTogglePinned={onTogglePinned}
|
|
107
113
|
/>
|
|
108
114
|
);
|
|
109
115
|
}
|
|
@@ -7,7 +7,7 @@ import { type SessionContextView } from '@/features/chat/features/session/utils/
|
|
|
7
7
|
import type { SessionRunStatus } from '@/features/chat/types/session-run-status.types';
|
|
8
8
|
import { cn } from '@/shared/lib/utils';
|
|
9
9
|
import { t } from '@/shared/lib/i18n';
|
|
10
|
-
import { Check, GitBranch, Pencil, X } from 'lucide-react';
|
|
10
|
+
import { Check, GitBranch, Pencil, Pin, X } from 'lucide-react';
|
|
11
11
|
|
|
12
12
|
type ChatSidebarSessionItemProps = {
|
|
13
13
|
sessionKey: string;
|
|
@@ -15,6 +15,7 @@ type ChatSidebarSessionItemProps = {
|
|
|
15
15
|
showUnreadDot: boolean;
|
|
16
16
|
runStatus?: SessionRunStatus;
|
|
17
17
|
context: SessionContextView;
|
|
18
|
+
isPinned: boolean;
|
|
18
19
|
title: string;
|
|
19
20
|
previewText: string;
|
|
20
21
|
trailingText: string;
|
|
@@ -31,6 +32,7 @@ type ChatSidebarSessionItemProps = {
|
|
|
31
32
|
onDraftLabelChange: (value: string) => void;
|
|
32
33
|
onSave: () => void | Promise<void>;
|
|
33
34
|
onCancel: () => void;
|
|
35
|
+
onTogglePinned: () => void;
|
|
34
36
|
};
|
|
35
37
|
|
|
36
38
|
type ChatSidebarSessionEditingViewProps = Pick<
|
|
@@ -72,7 +74,6 @@ function ChatSidebarSessionEditingView({
|
|
|
72
74
|
icon={<Check className="h-3.5 w-3.5" />}
|
|
73
75
|
label={t('save')}
|
|
74
76
|
tooltip={false}
|
|
75
|
-
className="h-7 w-7 rounded-lg text-gray-500 hover:bg-white hover:text-gray-900"
|
|
76
77
|
onClick={() => void onSave()}
|
|
77
78
|
disabled={isSaving}
|
|
78
79
|
/>
|
|
@@ -80,7 +81,6 @@ function ChatSidebarSessionEditingView({
|
|
|
80
81
|
icon={<X className="h-3.5 w-3.5" />}
|
|
81
82
|
label={t('cancel')}
|
|
82
83
|
tooltip={false}
|
|
83
|
-
className="h-7 w-7 rounded-lg text-gray-500 hover:bg-white hover:text-gray-900"
|
|
84
84
|
onClick={onCancel}
|
|
85
85
|
disabled={isSaving}
|
|
86
86
|
/>
|
|
@@ -100,6 +100,7 @@ function ChatSidebarSessionDisplayView({
|
|
|
100
100
|
showUnreadDot,
|
|
101
101
|
runStatus,
|
|
102
102
|
context,
|
|
103
|
+
isPinned,
|
|
103
104
|
title,
|
|
104
105
|
previewText,
|
|
105
106
|
trailingText,
|
|
@@ -109,14 +110,15 @@ function ChatSidebarSessionDisplayView({
|
|
|
109
110
|
childSessionCount = 0,
|
|
110
111
|
onSelect,
|
|
111
112
|
onOpenChildSessions,
|
|
112
|
-
onStartEditing
|
|
113
|
+
onStartEditing,
|
|
114
|
+
onTogglePinned
|
|
113
115
|
}: ChatSidebarSessionDisplayViewProps) {
|
|
114
|
-
const trailingControlsClassName = childSessionCount > 0 && onOpenChildSessions ? 'pr-
|
|
116
|
+
const trailingControlsClassName = childSessionCount > 0 && onOpenChildSessions ? 'pr-20' : 'pr-12';
|
|
115
117
|
|
|
116
118
|
return (
|
|
117
119
|
<div className="group/session relative">
|
|
118
120
|
<button type="button" onClick={onSelect} className="w-full text-left">
|
|
119
|
-
<div className={cn('flex min-w-0 items-
|
|
121
|
+
<div className={cn('flex min-h-6 min-w-0 items-center', trailingControlsClassName)}>
|
|
120
122
|
<span className="flex min-w-0 items-center gap-1.5">
|
|
121
123
|
{agentId?.trim() && agentId.trim().toLowerCase() !== 'main' ? (
|
|
122
124
|
<AgentAvatar
|
|
@@ -126,7 +128,7 @@ function ChatSidebarSessionDisplayView({
|
|
|
126
128
|
className="h-5 w-5 shrink-0"
|
|
127
129
|
/>
|
|
128
130
|
) : null}
|
|
129
|
-
<span className="truncate font-medium">{title}</span>
|
|
131
|
+
<span className="truncate leading-6 font-medium">{title}</span>
|
|
130
132
|
{context.label ? (
|
|
131
133
|
<span
|
|
132
134
|
className={cn(
|
|
@@ -140,7 +142,7 @@ function ChatSidebarSessionDisplayView({
|
|
|
140
142
|
</span>
|
|
141
143
|
) : null}
|
|
142
144
|
{context.icon ? (
|
|
143
|
-
<span className="inline-flex h-
|
|
145
|
+
<span className="inline-flex h-5 w-5 shrink-0 items-center justify-center">
|
|
144
146
|
<SessionContextIconNode icon={context.icon} className={active ? 'text-gray-700' : 'text-gray-500'} />
|
|
145
147
|
</span>
|
|
146
148
|
) : null}
|
|
@@ -168,7 +170,7 @@ function ChatSidebarSessionDisplayView({
|
|
|
168
170
|
onOpenChildSessions();
|
|
169
171
|
}}
|
|
170
172
|
className={cn(
|
|
171
|
-
'absolute right-
|
|
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',
|
|
172
174
|
active
|
|
173
175
|
? 'opacity-100'
|
|
174
176
|
: 'opacity-0 group-hover/session:opacity-100 group-focus-within/session:opacity-100'
|
|
@@ -181,23 +183,41 @@ function ChatSidebarSessionDisplayView({
|
|
|
181
183
|
</button>
|
|
182
184
|
) : null}
|
|
183
185
|
{runStatus ? (
|
|
184
|
-
<span className="absolute right-0 top-0 inline-flex h-
|
|
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 group-focus-within/session:opacity-0">
|
|
185
187
|
<SessionRunBadge status={runStatus} />
|
|
186
188
|
</span>
|
|
187
189
|
) : null}
|
|
188
|
-
<
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
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 group-focus-within/session:opacity-100">
|
|
191
|
+
<IconActionButton
|
|
192
|
+
size="sm"
|
|
193
|
+
tone="strong"
|
|
194
|
+
icon={
|
|
195
|
+
<Pin
|
|
196
|
+
className={cn(
|
|
197
|
+
'h-3.5 w-3.5',
|
|
198
|
+
isPinned && 'fill-current text-foreground',
|
|
199
|
+
)}
|
|
200
|
+
/>
|
|
201
|
+
}
|
|
202
|
+
label={t(isPinned ? 'chatSidebarUnpinSession' : 'chatSidebarPinSession')}
|
|
203
|
+
tooltipSide="right"
|
|
204
|
+
onClick={(event) => {
|
|
205
|
+
event.stopPropagation();
|
|
206
|
+
onTogglePinned();
|
|
207
|
+
}}
|
|
208
|
+
/>
|
|
209
|
+
<IconActionButton
|
|
210
|
+
size="sm"
|
|
211
|
+
tone="strong"
|
|
212
|
+
icon={<Pencil className="h-3.5 w-3.5" />}
|
|
213
|
+
label={t('edit')}
|
|
214
|
+
tooltipSide="right"
|
|
215
|
+
onClick={(event) => {
|
|
216
|
+
event.stopPropagation();
|
|
217
|
+
onStartEditing();
|
|
218
|
+
}}
|
|
219
|
+
/>
|
|
220
|
+
</div>
|
|
201
221
|
</div>
|
|
202
222
|
);
|
|
203
223
|
}
|
|
@@ -208,6 +228,7 @@ export function ChatSidebarSessionItem({
|
|
|
208
228
|
showUnreadDot,
|
|
209
229
|
runStatus,
|
|
210
230
|
context,
|
|
231
|
+
isPinned,
|
|
211
232
|
title,
|
|
212
233
|
previewText,
|
|
213
234
|
trailingText,
|
|
@@ -223,7 +244,8 @@ export function ChatSidebarSessionItem({
|
|
|
223
244
|
onStartEditing,
|
|
224
245
|
onDraftLabelChange,
|
|
225
246
|
onSave,
|
|
226
|
-
onCancel
|
|
247
|
+
onCancel,
|
|
248
|
+
onTogglePinned
|
|
227
249
|
}: ChatSidebarSessionItemProps) {
|
|
228
250
|
return (
|
|
229
251
|
<div
|
|
@@ -249,6 +271,7 @@ export function ChatSidebarSessionItem({
|
|
|
249
271
|
showUnreadDot={showUnreadDot}
|
|
250
272
|
runStatus={runStatus}
|
|
251
273
|
context={context}
|
|
274
|
+
isPinned={isPinned}
|
|
252
275
|
title={title}
|
|
253
276
|
previewText={previewText}
|
|
254
277
|
trailingText={trailingText}
|
|
@@ -259,6 +282,7 @@ export function ChatSidebarSessionItem({
|
|
|
259
282
|
childSessionCount={childSessionCount}
|
|
260
283
|
onOpenChildSessions={onOpenChildSessions}
|
|
261
284
|
onStartEditing={onStartEditing}
|
|
285
|
+
onTogglePinned={onTogglePinned}
|
|
262
286
|
/>
|
|
263
287
|
)}
|
|
264
288
|
</div>
|
|
@@ -19,7 +19,6 @@ type ChatSidebarSessionListProps = {
|
|
|
19
19
|
defaultSessionType: string;
|
|
20
20
|
sessionTypeOptions: SessionTypeOption[];
|
|
21
21
|
renderSessionItem: (item: NcpSessionListItemView) => ReactNode;
|
|
22
|
-
onCreateSession: (sessionType: string, projectRoot?: string | null) => void;
|
|
23
22
|
};
|
|
24
23
|
|
|
25
24
|
function ChatSidebarEmptyState({ label }: { label: string }) {
|
|
@@ -36,7 +35,6 @@ export function ChatSidebarSessionList({
|
|
|
36
35
|
groups,
|
|
37
36
|
isLoading,
|
|
38
37
|
isProjectFirstView,
|
|
39
|
-
onCreateSession,
|
|
40
38
|
projectGroups,
|
|
41
39
|
renderSessionItem,
|
|
42
40
|
sessionTypeOptions,
|
|
@@ -54,7 +52,6 @@ export function ChatSidebarSessionList({
|
|
|
54
52
|
defaultSessionType={defaultSessionType}
|
|
55
53
|
sessionTypeOptions={sessionTypeOptions}
|
|
56
54
|
renderSessionItem={renderSessionItem}
|
|
57
|
-
onCreateSession={onCreateSession}
|
|
58
55
|
/>
|
|
59
56
|
);
|
|
60
57
|
}
|
package/src/features/chat/features/session/components/session-header/chat-session-header-actions.tsx
CHANGED
|
@@ -9,7 +9,6 @@ import { ChatSessionProjectDialog } from './chat-session-project-dialog';
|
|
|
9
9
|
import { t } from '@/shared/lib/i18n';
|
|
10
10
|
|
|
11
11
|
const SESSION_HEADER_ACTION_GROUP_CLASS = 'flex shrink-0 items-center gap-1.5';
|
|
12
|
-
const SESSION_HEADER_ACTION_BUTTON_CLASS = 'h-7 w-7 shrink-0 rounded-lg text-muted-foreground/70 hover:bg-accent hover:text-accent-foreground';
|
|
13
12
|
|
|
14
13
|
type ChatSessionHeaderActionsProps = {
|
|
15
14
|
sessionKey: string;
|
|
@@ -65,7 +64,6 @@ export function ChatSessionHeaderActions({
|
|
|
65
64
|
<IconActionButton
|
|
66
65
|
icon={<GitBranch className="h-4 w-4" />}
|
|
67
66
|
label={t('chatSessionOpenChildSessions')}
|
|
68
|
-
className={SESSION_HEADER_ACTION_BUTTON_CLASS}
|
|
69
67
|
onClick={onOpenChildSessions}
|
|
70
68
|
disabled={isBusy}
|
|
71
69
|
/>
|
|
@@ -74,7 +72,6 @@ export function ChatSessionHeaderActions({
|
|
|
74
72
|
<IconActionButton
|
|
75
73
|
icon={<AlarmClock className="h-4 w-4" />}
|
|
76
74
|
label={t('chatSessionOpenCronJobs')}
|
|
77
|
-
className={SESSION_HEADER_ACTION_BUTTON_CLASS}
|
|
78
75
|
onClick={onOpenSessionCronJobs}
|
|
79
76
|
disabled={isBusy}
|
|
80
77
|
/>
|
|
@@ -85,7 +82,6 @@ export function ChatSessionHeaderActions({
|
|
|
85
82
|
icon={<MoreVertical className="h-4 w-4" />}
|
|
86
83
|
label={t('chatSessionMoreActions')}
|
|
87
84
|
tooltip={false}
|
|
88
|
-
className={SESSION_HEADER_ACTION_BUTTON_CLASS}
|
|
89
85
|
disabled={isBusy}
|
|
90
86
|
/>
|
|
91
87
|
</PopoverTrigger>
|