@nextclaw/ui 0.14.1-beta.1 → 0.14.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 +61 -0
- package/dist/assets/{api-dQ6uQSZG.js → api-a14tR_z1.js} +7 -7
- package/dist/assets/channels-list-page-CFGkm4DT.js +8 -0
- package/dist/assets/chat-page-CEdavJXc.js +105 -0
- package/dist/assets/{config-split-page-CeFfbaqc.js → config-split-page-B5b9B0uE.js} +1 -1
- package/dist/assets/{confirm-dialog-C95Y4QPC.js → confirm-dialog-ClH_Ec7n.js} +1 -1
- package/dist/assets/{desktop-update-config-CcK6jiEb.js → desktop-update-config-DPNDnVpk.js} +1 -1
- package/dist/assets/{dist-DTGzeil6.js → dist-BtCS2Ucq.js} +1 -1
- package/dist/assets/{dist-fGogBmPA.js → dist-CLGGLm8b.js} +1 -1
- package/dist/assets/doc-browser-5nMWYKBD.js +1 -0
- package/dist/assets/doc-browser-BJRLhztv.js +1 -0
- package/dist/assets/doc-browser-context-D4JwMMxK.js +1 -0
- package/dist/assets/{ellipsis-D2F4KMiU.js → ellipsis-CtJXjIol.js} +1 -1
- package/dist/assets/{external-link-CcgtBK26.js → external-link-CdJiG13p.js} +1 -1
- package/dist/assets/index-BDN1zzMQ.js +105 -0
- package/dist/assets/index-g3uSZXoc.css +1 -0
- package/dist/assets/mcp-marketplace-page-BU0kIjhR.js +40 -0
- package/dist/assets/mcp-marketplace-page-sMNFSq_T.js +1 -0
- package/dist/assets/middleware-CkFT3R4v.js +1 -0
- package/dist/assets/model-config-page-D6hYXROd.js +1 -0
- package/dist/assets/plus-DPjb0piO.js +1 -0
- package/dist/assets/provider-scoped-model-input-DAX2HgmR.js +1 -0
- package/dist/assets/providers-config-page-BzAeaACA.js +1 -0
- package/dist/assets/{react-CTqdhFMk.js → react-C6cZgP44.js} +1 -1
- package/dist/assets/remote-B0G80uPr.js +1 -0
- package/dist/assets/rotate-cw-DnEB1Rju.js +1 -0
- package/dist/assets/runtime-config-page-C5xKaV3i.js +1 -0
- package/dist/assets/{save-C9fKWfVB.js → save-DKA0x4zk.js} +1 -1
- package/dist/assets/{search-D5FQ5q0X.js → search-BNlcoj5c.js} +1 -1
- package/dist/assets/{search-config-page-AMEJJNIS.js → search-config-page-Cq9uJ-N8.js} +1 -1
- package/dist/assets/{secrets-config-page-CcgJnvBO.js → secrets-config-page-CxSbZLBo.js} +2 -2
- package/dist/assets/{select-Cu5n0E-3.js → select-CvTlDZTQ.js} +1 -1
- package/dist/assets/{tag-chip-C5aOtjxu.js → tag-chip-8ffF2y2C.js} +1 -1
- package/dist/assets/use-config-DmT0o1gv.js +1 -0
- package/dist/assets/x-BiSSpgqB.js +1 -0
- package/dist/index.html +15 -14
- package/package.json +9 -9
- package/src/app/components/app-presenter-provider.tsx +11 -2
- package/src/app/components/layout/__tests__/app-layout.test.tsx +11 -2
- package/src/app/components/layout/__tests__/sidebar.layout.test.tsx +110 -79
- package/src/app/components/layout/app-layout.tsx +18 -4
- package/src/app/components/layout/sidebar-items.tsx +194 -71
- package/src/app/components/layout/sidebar-rail.styles.ts +15 -0
- package/src/app/components/layout/sidebar.tsx +340 -83
- package/src/app/managers/viewport-layout.manager.ts +10 -0
- package/src/app/stores/viewport-layout.store.ts +39 -3
- package/src/features/agents/components/__tests__/agents-page.test.tsx +62 -39
- package/src/features/agents/components/agents-page.tsx +10 -6
- package/src/features/chat/components/conversation/__tests__/chat-conversation-header-section.test.tsx +145 -0
- package/src/features/chat/components/conversation/__tests__/chat-conversation-panel.test.tsx +69 -762
- package/src/features/chat/components/conversation/__tests__/chat-conversation-workspace-section.test.tsx +132 -0
- package/src/features/chat/components/conversation/chat-conversation-content.tsx +22 -15
- package/src/features/chat/components/conversation/chat-conversation-header-section.tsx +14 -15
- package/src/features/chat/components/conversation/chat-conversation-panel.tsx +18 -18
- package/src/features/chat/components/conversation/chat-conversation-workspace-section.tsx +10 -4
- package/src/features/chat/components/layout/__tests__/chat-sidebar-read-state.test.tsx +52 -11
- package/src/features/chat/components/layout/__tests__/chat-sidebar.test.tsx +77 -12
- package/src/features/chat/components/layout/chat-sidebar-desktop-layout.tsx +247 -0
- package/src/features/chat/components/layout/chat-sidebar-toolbar.tsx +182 -21
- package/src/features/chat/components/layout/chat-sidebar-utility-menu.tsx +82 -25
- package/src/features/chat/components/layout/chat-sidebar.tsx +79 -93
- package/src/features/chat/components/providers/chat-presenter.provider.tsx +0 -6
- package/src/features/chat/features/conversation/components/session-conversation-area.tsx +289 -0
- package/src/features/chat/features/conversation/components/session-conversation-input.tsx +427 -0
- package/src/features/chat/features/conversation/hooks/use-session-conversation-controller.ts +204 -0
- package/src/features/chat/features/conversation/hooks/use-session-conversation-input-attachments.ts +66 -0
- package/src/features/chat/features/{input/hooks/use-chat-input-bar-query-state.ts → conversation/hooks/use-session-conversation-input-query.ts} +32 -17
- package/src/features/chat/features/conversation/hooks/use-session-conversation-input-state.ts +281 -0
- package/src/features/chat/features/conversation/utils/session-conversation-input-toolbar.utils.ts +158 -0
- package/src/features/chat/features/input/hooks/__tests__/use-chat-input-surface-state.test.tsx +56 -0
- package/src/features/chat/features/input/hooks/use-chat-input-surface-state.ts +117 -0
- package/src/features/chat/features/input/hooks/use-chat-model-favorites.ts +2 -1
- package/src/features/chat/features/input/input-surface-plugins/__tests__/panel-app-reference-plugin.test.ts +77 -0
- package/src/features/chat/features/input/input-surface-plugins/__tests__/slash-command-plugin.test.ts +108 -0
- package/src/features/chat/features/input/input-surface-plugins/chat-input-product-plugin-adapters.types.ts +10 -0
- package/src/features/chat/features/input/input-surface-plugins/input-surface-search.utils.ts +108 -0
- package/src/features/chat/features/input/input-surface-plugins/panel-app-reference-plugin.utils.ts +108 -0
- package/src/features/chat/features/input/input-surface-plugins/slash-command-plugin.utils.ts +161 -0
- package/src/features/chat/features/input/utils/__tests__/chat-composer-state.utils.test.ts +22 -1
- package/src/features/chat/features/input/utils/__tests__/chat-inline-token.utils.test.ts +26 -13
- package/src/features/chat/features/input/utils/__tests__/ncp-chat-input-availability.utils.test.ts +7 -28
- package/src/features/chat/features/input/utils/chat-composer-state.utils.ts +6 -0
- package/src/features/chat/features/input/utils/chat-inline-token.utils.ts +26 -51
- package/src/features/chat/features/input/utils/chat-input-bar.utils.ts +2 -0
- package/src/features/chat/features/input/utils/ncp-chat-input-availability.utils.ts +5 -6
- package/src/features/chat/features/message/components/__tests__/chat-message-list.container.test.tsx +47 -12
- package/src/features/chat/features/message/components/chat-message-list.container.tsx +93 -12
- package/src/features/chat/features/message/utils/__tests__/chat-message.utils.test.ts +31 -12
- package/src/features/chat/features/message/utils/chat-message-markdown-part.utils.ts +38 -0
- package/src/features/chat/features/message/utils/chat-message-part.utils.ts +1 -1
- package/src/features/chat/features/session/components/chat-sidebar-project-groups.tsx +5 -4
- package/src/features/chat/features/session/components/chat-sidebar-session-list.tsx +2 -2
- package/src/features/chat/features/session/hooks/__tests__/use-chat-session-project.test.tsx +3 -30
- package/src/features/chat/features/session/hooks/use-chat-session-project.ts +0 -5
- package/src/features/chat/features/session/utils/chat-run-metadata.utils.ts +8 -0
- package/src/features/chat/features/session-type/components/__tests__/{chat-sidebar-create-menu.test.tsx → chat-session-type-menu.test.tsx} +5 -5
- package/src/features/chat/features/session-type/components/__tests__/chat-session-type-option-item.test.tsx +29 -1
- package/src/features/chat/features/session-type/components/{chat-sidebar-create-menu.tsx → chat-session-type-menu.tsx} +13 -9
- package/src/features/chat/features/session-type/components/chat-session-type-option-item.tsx +17 -5
- package/src/features/chat/features/session-type/hooks/__tests__/use-chat-new-session-type-preference.test.tsx +152 -0
- package/src/features/chat/features/session-type/hooks/use-chat-new-session-type-preference.ts +159 -0
- package/src/features/chat/features/welcome/components/__tests__/chat-conversation-welcome.test.tsx +49 -31
- package/src/features/chat/features/welcome/components/__tests__/chat-welcome.test.tsx +2 -2
- package/src/features/chat/features/welcome/components/chat-conversation-welcome.tsx +21 -10
- package/src/features/chat/features/welcome/components/chat-welcome-session-type-picker.tsx +2 -2
- package/src/features/chat/features/welcome/components/chat-welcome.tsx +2 -2
- package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-panel-content.test.tsx +54 -0
- package/src/features/chat/features/workspace/components/chat-session-workspace-panel-content.tsx +44 -76
- package/src/features/chat/features/workspace/components/chat-session-workspace-panel-nav.tsx +5 -1
- package/src/features/chat/features/workspace/components/chat-session-workspace-panel.tsx +7 -1
- package/src/features/chat/features/workspace/hooks/use-chat-conversation-workspace-state.ts +40 -31
- package/src/features/chat/features/workspace/utils/__tests__/chat-workspace-panel-view-model.utils.test.ts +59 -1
- package/src/features/chat/features/workspace/utils/chat-thread-workspace-session.utils.ts +109 -0
- package/src/features/chat/features/workspace/utils/chat-workspace-panel-view-model.utils.ts +44 -4
- package/src/features/chat/index.ts +0 -1
- package/src/features/chat/managers/__tests__/chat-session-list.manager.test.ts +51 -99
- package/src/features/chat/managers/__tests__/chat-thread.manager.test.ts +135 -21
- package/src/features/chat/managers/chat-session-list.manager.ts +12 -43
- package/src/features/chat/managers/chat-thread.manager.ts +108 -34
- package/src/features/chat/pages/__tests__/ncp-chat-page.test.ts +48 -1
- package/src/features/chat/pages/__tests__/ncp-chat-page.test.tsx +72 -0
- package/src/features/chat/pages/ncp-chat-page.tsx +0 -122
- package/src/features/chat/presenters/chat.presenter.ts +2 -19
- package/src/features/chat/stores/__tests__/chat-thread.store.test.ts +31 -0
- package/src/features/chat/stores/chat-thread.store.ts +42 -26
- package/src/features/marketplace/components/__tests__/marketplace-page.test.tsx +24 -0
- package/src/features/marketplace/components/curated-shelves/marketplace-shelf-card.tsx +8 -3
- package/src/features/marketplace/components/marketplace-item-list-view.tsx +2 -2
- package/src/features/marketplace/components/marketplace-list-card.tsx +124 -98
- package/src/features/marketplace/components/marketplace-page-parts.tsx +11 -6
- package/src/features/panel-apps/hooks/use-panel-apps.ts +2 -1
- package/src/platforms/desktop/components/__tests__/desktop-app-shell.test.tsx +50 -10
- package/src/platforms/desktop/components/desktop-app-shell.tsx +34 -10
- package/src/platforms/desktop/components/desktop-window-chrome.tsx +41 -16
- package/src/shared/components/common/__tests__/agent-avatar.test.tsx +3 -1
- package/src/shared/components/common/agent-avatar.tsx +5 -2
- package/src/shared/components/ui/tab-strip/__tests__/compact-tab-strip.test.tsx +24 -1
- package/src/shared/components/ui/tab-strip/compact-tab-strip.tsx +8 -4
- package/src/shared/lib/api/index.ts +1 -0
- package/src/shared/lib/api/preferences/preference-keys.config.ts +9 -0
- package/src/shared/lib/i18n/locales/en-US/chat.json +20 -2
- package/src/shared/lib/i18n/locales/en-US/core.json +2 -0
- package/src/shared/lib/i18n/locales/en-US/marketplace.json +2 -0
- package/src/shared/lib/i18n/locales/zh-CN/chat.json +20 -2
- package/src/shared/lib/i18n/locales/zh-CN/core.json +2 -0
- package/src/shared/lib/i18n/locales/zh-CN/marketplace.json +2 -0
- package/src/shared/lib/ui-document-title/__tests__/ui-document-title.test.ts +49 -0
- package/src/shared/lib/ui-document-title/index.ts +50 -21
- package/dist/assets/channels-list-page-DfpjB8XB.js +0 -8
- package/dist/assets/chat-page-D3QaEqjs.js +0 -105
- package/dist/assets/doc-browser-CuBTcBEZ.js +0 -1
- package/dist/assets/doc-browser-DVHhEb96.js +0 -1
- package/dist/assets/doc-browser-context-BfMXwnrz.js +0 -1
- package/dist/assets/index-ByJCbQqr.css +0 -1
- package/dist/assets/index-DjXqiloY.js +0 -103
- package/dist/assets/mcp-marketplace-page-98-V__3u.js +0 -1
- package/dist/assets/mcp-marketplace-page-BNq_PNmO.js +0 -40
- package/dist/assets/model-config-page-aAUkZkSX.js +0 -1
- package/dist/assets/plus-1Rxl5FlV.js +0 -1
- package/dist/assets/provider-scoped-model-input-we4_Z4gP.js +0 -1
- package/dist/assets/providers-config-page-CtMkPSyu.js +0 -1
- package/dist/assets/remote-fQ7N_r8u.js +0 -1
- package/dist/assets/rotate-cw-CzfIeAJj.js +0 -1
- package/dist/assets/runtime-config-page-TD1UrTbG.js +0 -1
- package/dist/assets/use-config-D8TESeo6.js +0 -1
- package/dist/assets/x-1qETdQ70.js +0 -1
- package/src/features/chat/components/conversation/chat-conversation-alerts.tsx +0 -37
- package/src/features/chat/features/input/components/__tests__/chat-attachment-upload-limit.test.ts +0 -38
- package/src/features/chat/features/input/components/chat-input-bar.container.tsx +0 -496
- package/src/features/chat/features/message/utils/chat-message-inline-content.utils.ts +0 -95
- package/src/features/chat/managers/__tests__/chat-input.manager.test.ts +0 -448
- package/src/features/chat/managers/__tests__/chat-run-snapshot.manager.test.ts +0 -129
- package/src/features/chat/managers/__tests__/chat-run.manager.test.ts +0 -236
- package/src/features/chat/managers/__tests__/chat-session-preference-sync.manager.test.ts +0 -219
- package/src/features/chat/managers/chat-input.manager.ts +0 -430
- package/src/features/chat/managers/chat-run.manager.ts +0 -110
- package/src/features/chat/managers/chat-session-preference-sync.manager.ts +0 -142
- package/src/features/chat/stores/chat-input.store.ts +0 -104
- /package/dist/assets/{config-hints-CTqBnCDp.js → config-hints-BkYBc7z0.js} +0 -0
package/src/features/chat/features/welcome/components/__tests__/chat-conversation-welcome.test.tsx
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
|
+
import type { SetStateAction } from "react";
|
|
2
3
|
import { render, screen } from "@testing-library/react";
|
|
3
4
|
import userEvent from "@testing-library/user-event";
|
|
4
5
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
5
6
|
import { ChatConversationWelcome } from "@/features/chat/features/welcome/components/chat-conversation-welcome";
|
|
6
|
-
import { useChatInputStore } from "@/features/chat/stores/chat-input.store";
|
|
7
7
|
import { useChatQueryStore } from "@/features/chat/stores/ncp-chat-query.store";
|
|
8
8
|
import { useChatSessionListStore } from "@/features/chat/stores/chat-session-list.store";
|
|
9
9
|
import { useChatThreadStore } from "@/features/chat/stores/chat-thread.store";
|
|
@@ -11,14 +11,24 @@ import type { ChatQuerySnapshot } from "@/features/chat/stores/ncp-chat-query.st
|
|
|
11
11
|
|
|
12
12
|
const mocks = vi.hoisted(() => ({
|
|
13
13
|
setSelectedAgentId: vi.fn(),
|
|
14
|
-
applyPromptSuggestion: vi.fn(),
|
|
15
|
-
setPendingProjectRoot: vi.fn(),
|
|
16
|
-
setPendingSessionType: vi.fn(),
|
|
17
14
|
agents: [
|
|
18
15
|
{ id: "main", displayName: "Main", runtime: "native" },
|
|
19
16
|
{ id: "engineer", displayName: "Engineer", runtime: "codex" },
|
|
20
17
|
],
|
|
21
18
|
}));
|
|
19
|
+
const persistStorage = new Map<string, unknown>();
|
|
20
|
+
|
|
21
|
+
function createPersistStorage() {
|
|
22
|
+
return {
|
|
23
|
+
getItem: (name: string) => persistStorage.get(name) ?? null,
|
|
24
|
+
setItem: (name: string, value: unknown) => {
|
|
25
|
+
persistStorage.set(name, value);
|
|
26
|
+
},
|
|
27
|
+
removeItem: (name: string) => {
|
|
28
|
+
persistStorage.delete(name);
|
|
29
|
+
},
|
|
30
|
+
};
|
|
31
|
+
}
|
|
22
32
|
|
|
23
33
|
vi.mock("@/features/chat/features/welcome/components/chat-welcome", () => ({
|
|
24
34
|
ChatWelcome: ({
|
|
@@ -60,11 +70,6 @@ vi.mock("@/features/chat/components/providers/chat-presenter.provider", () => ({
|
|
|
60
70
|
chatSessionListManager: {
|
|
61
71
|
setSelectedAgentId: mocks.setSelectedAgentId,
|
|
62
72
|
},
|
|
63
|
-
chatInputManager: {
|
|
64
|
-
applyPromptSuggestion: mocks.applyPromptSuggestion,
|
|
65
|
-
setPendingProjectRoot: mocks.setPendingProjectRoot,
|
|
66
|
-
setPendingSessionType: mocks.setPendingSessionType,
|
|
67
|
-
},
|
|
68
73
|
}),
|
|
69
74
|
}));
|
|
70
75
|
|
|
@@ -88,19 +93,10 @@ function createFetchedQuery<TData>(data: TData) {
|
|
|
88
93
|
}
|
|
89
94
|
|
|
90
95
|
function resetWelcomeTestState() {
|
|
96
|
+
persistStorage.clear();
|
|
97
|
+
useChatSessionListStore.persist.setOptions({ storage: createPersistStorage() as never });
|
|
98
|
+
useChatThreadStore.persist.setOptions({ storage: createPersistStorage() as never });
|
|
91
99
|
mocks.setSelectedAgentId.mockReset();
|
|
92
|
-
mocks.applyPromptSuggestion.mockReset();
|
|
93
|
-
mocks.setPendingProjectRoot.mockReset();
|
|
94
|
-
mocks.setPendingSessionType.mockReset();
|
|
95
|
-
useChatInputStore.setState({
|
|
96
|
-
snapshot: {
|
|
97
|
-
...useChatInputStore.getState().snapshot,
|
|
98
|
-
defaultSessionType: "native",
|
|
99
|
-
pendingSessionType: "native",
|
|
100
|
-
selectedSessionType: undefined,
|
|
101
|
-
pendingProjectRoot: null,
|
|
102
|
-
},
|
|
103
|
-
});
|
|
104
100
|
useChatSessionListStore.setState({
|
|
105
101
|
snapshot: {
|
|
106
102
|
...useChatSessionListStore.getState().snapshot,
|
|
@@ -138,56 +134,78 @@ function resetWelcomeTestState() {
|
|
|
138
134
|
});
|
|
139
135
|
}
|
|
140
136
|
|
|
137
|
+
function renderWelcome(overrides: Partial<{
|
|
138
|
+
onSelectPrompt: (prompt: string) => void;
|
|
139
|
+
onSelectProjectRoot: (projectRoot: string | null) => void;
|
|
140
|
+
onSelectSessionType: (sessionType: SetStateAction<string>) => void;
|
|
141
|
+
}> = {}) {
|
|
142
|
+
return render(
|
|
143
|
+
<ChatConversationWelcome
|
|
144
|
+
inputSlot={<div data-testid="input-slot" />}
|
|
145
|
+
pendingProjectRoot={null}
|
|
146
|
+
pendingSessionType="native"
|
|
147
|
+
selectedSessionTypeValue={null}
|
|
148
|
+
onSelectPrompt={overrides.onSelectPrompt ?? vi.fn()}
|
|
149
|
+
onSelectProjectRoot={overrides.onSelectProjectRoot ?? vi.fn()}
|
|
150
|
+
onSelectSessionType={overrides.onSelectSessionType ?? vi.fn()}
|
|
151
|
+
/>,
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
|
|
141
155
|
describe("ChatConversationWelcome", () => {
|
|
142
156
|
beforeEach(resetWelcomeTestState);
|
|
143
157
|
|
|
144
|
-
it("
|
|
158
|
+
it("emits the selected welcome project through the local input callback", async () => {
|
|
145
159
|
const user = userEvent.setup();
|
|
160
|
+
const onSelectProjectRoot = vi.fn();
|
|
146
161
|
|
|
147
|
-
|
|
162
|
+
renderWelcome({ onSelectProjectRoot });
|
|
148
163
|
|
|
149
164
|
await user.click(
|
|
150
165
|
screen.getByRole("button", { name: "select draft project" }),
|
|
151
166
|
);
|
|
152
167
|
|
|
153
|
-
expect(
|
|
168
|
+
expect(onSelectProjectRoot).toHaveBeenCalledWith("/tmp/project-alpha");
|
|
154
169
|
});
|
|
155
170
|
|
|
156
|
-
it("
|
|
171
|
+
it("emits a selected prompt suggestion through the local input callback", async () => {
|
|
157
172
|
const user = userEvent.setup();
|
|
173
|
+
const onSelectPrompt = vi.fn();
|
|
158
174
|
|
|
159
|
-
|
|
175
|
+
renderWelcome({ onSelectPrompt });
|
|
160
176
|
|
|
161
177
|
await user.click(
|
|
162
178
|
screen.getByRole("button", { name: "pick prompt" }),
|
|
163
179
|
);
|
|
164
180
|
|
|
165
|
-
expect(
|
|
181
|
+
expect(onSelectPrompt).toHaveBeenCalledWith("example prompt");
|
|
166
182
|
});
|
|
167
183
|
|
|
168
184
|
|
|
169
185
|
it("syncs the pending session type when switching the draft agent", async () => {
|
|
170
186
|
const user = userEvent.setup();
|
|
187
|
+
const onSelectSessionType = vi.fn();
|
|
171
188
|
|
|
172
|
-
|
|
189
|
+
renderWelcome({ onSelectSessionType });
|
|
173
190
|
|
|
174
191
|
await user.click(
|
|
175
192
|
screen.getByRole("button", { name: "switch draft agent" }),
|
|
176
193
|
);
|
|
177
194
|
|
|
178
195
|
expect(mocks.setSelectedAgentId).toHaveBeenCalledWith("engineer");
|
|
179
|
-
expect(
|
|
196
|
+
expect(onSelectSessionType).toHaveBeenCalledWith("codex");
|
|
180
197
|
});
|
|
181
198
|
|
|
182
199
|
it("stores an explicit welcome session type selection", async () => {
|
|
183
200
|
const user = userEvent.setup();
|
|
201
|
+
const onSelectSessionType = vi.fn();
|
|
184
202
|
|
|
185
|
-
|
|
203
|
+
renderWelcome({ onSelectSessionType });
|
|
186
204
|
|
|
187
205
|
await user.click(
|
|
188
206
|
screen.getByRole("button", { name: "switch session type" }),
|
|
189
207
|
);
|
|
190
208
|
|
|
191
|
-
expect(
|
|
209
|
+
expect(onSelectSessionType).toHaveBeenCalledWith("codex");
|
|
192
210
|
});
|
|
193
211
|
});
|
|
@@ -10,8 +10,8 @@ vi.mock(
|
|
|
10
10
|
);
|
|
11
11
|
|
|
12
12
|
const sessionTypeOptions = [
|
|
13
|
-
{ value: 'native', label: 'Native', ready: true },
|
|
14
|
-
{ value: 'codex', label: 'Codex', ready: true },
|
|
13
|
+
{ value: 'native', label: 'Native', icon: null, ready: true },
|
|
14
|
+
{ value: 'codex', label: 'Codex', icon: null, ready: true },
|
|
15
15
|
];
|
|
16
16
|
|
|
17
17
|
function renderWelcome(
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { ReactNode } from "react";
|
|
2
|
+
import type { SetStateAction } from "react";
|
|
2
3
|
import { usePresenter } from "@/features/chat/components/providers/chat-presenter.provider";
|
|
3
4
|
import {
|
|
4
5
|
buildSessionTypeOptions,
|
|
@@ -11,7 +12,6 @@ import {
|
|
|
11
12
|
resolveChatWelcomeSelectedSessionType,
|
|
12
13
|
} from "@/features/chat/features/welcome/utils/chat-welcome-selection.utils";
|
|
13
14
|
import { buildChatWelcomeProjectOptions } from "@/features/chat/features/welcome/utils/chat-welcome-project-options.utils";
|
|
14
|
-
import { useChatInputStore } from "@/features/chat/stores/chat-input.store";
|
|
15
15
|
import { useChatQueryStore } from "@/features/chat/stores/ncp-chat-query.store";
|
|
16
16
|
import { useChatSessionListStore } from "@/features/chat/stores/chat-session-list.store";
|
|
17
17
|
import { useChatThreadStore } from "@/features/chat/stores/chat-thread.store";
|
|
@@ -23,13 +23,24 @@ const EMPTY_NCP_SESSION_SUMMARIES: NcpSessionSummaryView[] = [];
|
|
|
23
23
|
|
|
24
24
|
type ChatConversationWelcomeProps = {
|
|
25
25
|
inputSlot: ReactNode;
|
|
26
|
+
pendingProjectRoot: string | null;
|
|
27
|
+
pendingSessionType: string;
|
|
28
|
+
selectedSessionTypeValue: string | null;
|
|
29
|
+
onSelectProjectRoot: (projectRoot: string | null) => void;
|
|
30
|
+
onSelectPrompt: (prompt: string) => void;
|
|
31
|
+
onSelectSessionType: (sessionType: SetStateAction<string>) => void;
|
|
26
32
|
};
|
|
27
33
|
|
|
28
34
|
export function ChatConversationWelcome({
|
|
29
35
|
inputSlot,
|
|
36
|
+
pendingProjectRoot,
|
|
37
|
+
pendingSessionType,
|
|
38
|
+
selectedSessionTypeValue,
|
|
39
|
+
onSelectProjectRoot,
|
|
40
|
+
onSelectPrompt,
|
|
41
|
+
onSelectSessionType,
|
|
30
42
|
}: ChatConversationWelcomeProps) {
|
|
31
43
|
const presenter = usePresenter();
|
|
32
|
-
const inputSnapshot = useChatInputStore((state) => state.snapshot);
|
|
33
44
|
const selectedAgentId = useChatSessionListStore(
|
|
34
45
|
(state) => state.snapshot.selectedAgentId,
|
|
35
46
|
);
|
|
@@ -53,18 +64,18 @@ export function ChatConversationWelcome({
|
|
|
53
64
|
config?.agents.defaults.workspace,
|
|
54
65
|
);
|
|
55
66
|
const selectedProjectRoot = normalizeSessionProjectRootValue(
|
|
56
|
-
|
|
67
|
+
pendingProjectRoot,
|
|
57
68
|
);
|
|
58
69
|
const sessionTypeOptions = buildSessionTypeOptions(
|
|
59
70
|
sessionTypesData?.options ?? [],
|
|
60
71
|
);
|
|
61
72
|
const defaultSessionType = normalizeSessionType(
|
|
62
|
-
sessionTypesData?.defaultType ??
|
|
73
|
+
sessionTypesData?.defaultType ?? DEFAULT_SESSION_TYPE,
|
|
63
74
|
);
|
|
64
75
|
const selectedSessionType = resolveChatWelcomeSelectedSessionType({
|
|
65
76
|
defaultSessionType,
|
|
66
|
-
pendingSessionType
|
|
67
|
-
selectedSessionType:
|
|
77
|
+
pendingSessionType,
|
|
78
|
+
selectedSessionType: selectedSessionTypeValue,
|
|
68
79
|
sessionTypeOptions,
|
|
69
80
|
});
|
|
70
81
|
const projectOptions = buildChatWelcomeProjectOptions({
|
|
@@ -73,7 +84,7 @@ export function ChatConversationWelcome({
|
|
|
73
84
|
});
|
|
74
85
|
const selectDraftAgent = (agentId: string) => {
|
|
75
86
|
presenter.chatSessionListManager.setSelectedAgentId(agentId);
|
|
76
|
-
|
|
87
|
+
onSelectSessionType(
|
|
77
88
|
resolveChatWelcomeSelectedSessionType({
|
|
78
89
|
agents: availableAgents,
|
|
79
90
|
agentId,
|
|
@@ -96,9 +107,9 @@ export function ChatConversationWelcome({
|
|
|
96
107
|
selectedSessionType={selectedSessionType}
|
|
97
108
|
sessionTypeOptions={sessionTypeOptions}
|
|
98
109
|
onSelectAgent={selectDraftAgent}
|
|
99
|
-
onSelectPrompt={
|
|
100
|
-
onSelectProjectRoot={
|
|
101
|
-
onSelectSessionType={
|
|
110
|
+
onSelectPrompt={onSelectPrompt}
|
|
111
|
+
onSelectProjectRoot={onSelectProjectRoot}
|
|
112
|
+
onSelectSessionType={onSelectSessionType}
|
|
102
113
|
/>
|
|
103
114
|
);
|
|
104
115
|
}
|
|
@@ -2,7 +2,7 @@ import { useState } from 'react';
|
|
|
2
2
|
import { Bot, ChevronDown } from 'lucide-react';
|
|
3
3
|
import { SessionContextIconNode } from '@/features/chat/features/session/components/session-context-icon';
|
|
4
4
|
import { ChatSessionTypeOptionItem } from '@/features/chat/features/session-type/components/chat-session-type-option-item';
|
|
5
|
-
import type {
|
|
5
|
+
import type { ChatSessionTypeOption } from '@/features/chat/features/session-type/utils/chat-session-type.utils';
|
|
6
6
|
import {
|
|
7
7
|
Popover,
|
|
8
8
|
PopoverContent,
|
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
} from '@/shared/components/ui/popover';
|
|
12
12
|
import { t } from '@/shared/lib/i18n';
|
|
13
13
|
|
|
14
|
-
type SessionTypeOption =
|
|
14
|
+
type SessionTypeOption = ChatSessionTypeOption;
|
|
15
15
|
|
|
16
16
|
type ChatWelcomeSessionTypePickerProps = {
|
|
17
17
|
options: readonly SessionTypeOption[];
|
|
@@ -7,11 +7,11 @@ import { ChatWelcomeCapabilityGrid } from '@/features/chat/features/welcome/comp
|
|
|
7
7
|
import { ChatWelcomeProjectPicker } from '@/features/chat/features/welcome/components/chat-welcome-project-picker';
|
|
8
8
|
import { ChatWelcomeSessionTypePicker } from '@/features/chat/features/welcome/components/chat-welcome-session-type-picker';
|
|
9
9
|
import type { ChatWelcomeProjectOption } from '@/features/chat/features/welcome/utils/chat-welcome-project-options.utils';
|
|
10
|
-
import type {
|
|
10
|
+
import type { ChatSessionTypeOption } from '@/features/chat/features/session-type/utils/chat-session-type.utils';
|
|
11
11
|
import type { AgentProfileView } from '@/shared/lib/api';
|
|
12
12
|
import { t } from '@/shared/lib/i18n';
|
|
13
13
|
|
|
14
|
-
type SessionTypeOption =
|
|
14
|
+
type SessionTypeOption = ChatSessionTypeOption;
|
|
15
15
|
|
|
16
16
|
type ChatWelcomeProps = {
|
|
17
17
|
agents: AgentProfileView[];
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { render, screen } from "@testing-library/react";
|
|
2
|
+
import { expect, it, vi } from "vitest";
|
|
3
|
+
import { ChatSessionWorkspacePanelContent } from "@/features/chat/features/workspace/components/chat-session-workspace-panel-content";
|
|
4
|
+
import type { ResolvedChildSessionTab } from "@/features/chat/features/ncp/hooks/use-ncp-child-session-tabs-view";
|
|
5
|
+
|
|
6
|
+
vi.mock("@/features/chat/components/providers/chat-presenter.provider", () => ({
|
|
7
|
+
usePresenter: () => ({
|
|
8
|
+
chatThreadManager: {
|
|
9
|
+
materializeSideChatDraft: vi.fn(),
|
|
10
|
+
openFilePreview: vi.fn(),
|
|
11
|
+
},
|
|
12
|
+
}),
|
|
13
|
+
}));
|
|
14
|
+
|
|
15
|
+
vi.mock("@/features/chat/features/conversation/components/session-conversation-area", () => ({
|
|
16
|
+
SessionConversationArea: () => <div data-testid="session-conversation-area" />,
|
|
17
|
+
}));
|
|
18
|
+
|
|
19
|
+
function createChildTab(): ResolvedChildSessionTab {
|
|
20
|
+
return {
|
|
21
|
+
sessionKey: "child-1",
|
|
22
|
+
parentSessionKey: "parent-1",
|
|
23
|
+
title: "Child title",
|
|
24
|
+
agentId: "agent-1",
|
|
25
|
+
updatedAt: null,
|
|
26
|
+
lastMessageAt: null,
|
|
27
|
+
readAt: null,
|
|
28
|
+
runStatus: undefined,
|
|
29
|
+
sessionTypeLabel: "原生",
|
|
30
|
+
preferredModel: "minimax/MiniMax-M3",
|
|
31
|
+
projectName: "nextbot",
|
|
32
|
+
projectRoot: "/Users/peiwang/Projects/nextbot",
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
it("shows compact child session metadata without repeating the tab title", () => {
|
|
37
|
+
render(
|
|
38
|
+
<ChatSessionWorkspacePanelContent
|
|
39
|
+
activeSelection={{
|
|
40
|
+
kind: "child-session",
|
|
41
|
+
tab: createChildTab(),
|
|
42
|
+
}}
|
|
43
|
+
sessionCronJobs={[]}
|
|
44
|
+
sessionProjectRoot={null}
|
|
45
|
+
sessionWorkingDir={null}
|
|
46
|
+
/>,
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
expect(screen.queryByText("Child title")).toBeNull();
|
|
50
|
+
expect(screen.getByText("原生")).toBeTruthy();
|
|
51
|
+
expect(screen.getByText("minimax/MiniMax-M3")).toBeTruthy();
|
|
52
|
+
expect(screen.getByText("nextbot")).toBeTruthy();
|
|
53
|
+
expect(screen.getByTitle("/Users/peiwang/Projects/nextbot")).toBeTruthy();
|
|
54
|
+
});
|
package/src/features/chat/features/workspace/components/chat-session-workspace-panel-content.tsx
CHANGED
|
@@ -1,15 +1,11 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { useStickyBottomScroll } from "@nextclaw/agent-chat-ui";
|
|
3
|
-
import { FolderGit2, Loader2 } from "lucide-react";
|
|
1
|
+
import { MessageSquarePlus } from "lucide-react";
|
|
4
2
|
import type { CronJobView } from "@/shared/lib/api";
|
|
5
|
-
import { ChatMessageListContainer } from "@/features/chat/features/message/components/chat-message-list.container";
|
|
6
3
|
import { usePresenter } from "@/features/chat/components/providers/chat-presenter.provider";
|
|
4
|
+
import { SessionConversationArea } from "@/features/chat/features/conversation/components/session-conversation-area";
|
|
7
5
|
import { ChatSessionWorkspaceFilePreview } from "@/features/chat/features/workspace/components/chat-session-workspace-file-preview";
|
|
8
6
|
import { SessionCronJobContent } from "@/features/chat/features/workspace/components/session-cron-job-content";
|
|
9
7
|
import type { ResolvedChildSessionTab } from "@/features/chat/features/ncp/hooks/use-ncp-child-session-tabs-view";
|
|
10
|
-
import { useNcpSessionConversation } from "@/features/chat/features/ncp/hooks/use-ncp-session-conversation";
|
|
11
8
|
import type { WorkspaceSelection } from "@/features/chat/features/workspace/utils/chat-workspace-panel-view-model.utils";
|
|
12
|
-
import { AgentIdentityAvatar } from "@/shared/components/common/agent-identity";
|
|
13
9
|
import { t } from "@/shared/lib/i18n";
|
|
14
10
|
|
|
15
11
|
type ChatSessionWorkspacePanelContentProps = {
|
|
@@ -19,53 +15,9 @@ type ChatSessionWorkspacePanelContentProps = {
|
|
|
19
15
|
sessionWorkingDir: string | null;
|
|
20
16
|
};
|
|
21
17
|
|
|
22
|
-
function ChildSessionContent({ sessionKey }: { sessionKey: string }) {
|
|
23
|
-
const agent = useNcpSessionConversation(sessionKey);
|
|
24
|
-
const messages = agent.visibleMessages;
|
|
25
|
-
const scrollRef = useRef<HTMLDivElement>(null);
|
|
26
|
-
const { onScroll } = useStickyBottomScroll({
|
|
27
|
-
scrollRef,
|
|
28
|
-
resetKey: sessionKey,
|
|
29
|
-
isLoading: agent.isHydrating,
|
|
30
|
-
hasContent: messages.length > 0,
|
|
31
|
-
contentVersion: messages[messages.length - 1] ?? null,
|
|
32
|
-
stickyThresholdPx: 20,
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
return (
|
|
36
|
-
<div
|
|
37
|
-
ref={scrollRef}
|
|
38
|
-
onScroll={onScroll}
|
|
39
|
-
className="h-full overflow-y-auto custom-scrollbar"
|
|
40
|
-
>
|
|
41
|
-
{agent.isHydrating ? (
|
|
42
|
-
<div className="flex h-full items-center justify-center text-sm text-gray-500">
|
|
43
|
-
<Loader2 className="mr-2 h-4 w-4 animate-spin" />
|
|
44
|
-
{t("chatChildSessionLoading")}
|
|
45
|
-
</div>
|
|
46
|
-
) : agent.hydrateError ? (
|
|
47
|
-
<div className="px-4 py-5 text-sm text-rose-600">
|
|
48
|
-
{agent.hydrateError.message}
|
|
49
|
-
</div>
|
|
50
|
-
) : messages.length === 0 && !agent.isRunning ? (
|
|
51
|
-
<div className="px-4 py-5 text-sm text-gray-500">
|
|
52
|
-
{t("chatChildSessionEmpty")}
|
|
53
|
-
</div>
|
|
54
|
-
) : (
|
|
55
|
-
<div className="px-4 py-5">
|
|
56
|
-
<ChatMessageListContainer
|
|
57
|
-
messages={messages}
|
|
58
|
-
isSending={agent.isRunning}
|
|
59
|
-
/>
|
|
60
|
-
</div>
|
|
61
|
-
)}
|
|
62
|
-
</div>
|
|
63
|
-
);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
18
|
function ChildSessionMetaChip({ value }: { value: string }) {
|
|
67
19
|
return (
|
|
68
|
-
<span className="inline-flex max-w-full items-center rounded border border-gray-200 bg-gray-50 px-
|
|
20
|
+
<span className="inline-flex max-w-full shrink-0 items-center rounded border border-gray-200 bg-gray-50 px-1.5 py-0.5 text-[10px] font-medium text-gray-600">
|
|
69
21
|
<span className="truncate">{value}</span>
|
|
70
22
|
</span>
|
|
71
23
|
);
|
|
@@ -83,41 +35,32 @@ function ChildSessionMetaStrip({ tab }: { tab: ResolvedChildSessionTab }) {
|
|
|
83
35
|
}
|
|
84
36
|
|
|
85
37
|
return (
|
|
86
|
-
<div className="
|
|
87
|
-
{metaItems.
|
|
88
|
-
<
|
|
89
|
-
|
|
90
|
-
<ChildSessionMetaChip key={item} value={item} />
|
|
91
|
-
))}
|
|
92
|
-
</div>
|
|
93
|
-
) : null}
|
|
38
|
+
<div className="flex min-h-9 min-w-0 items-center gap-1.5 border-b border-gray-200/70 px-3 py-1.5 text-[11px] text-gray-500">
|
|
39
|
+
{metaItems.map((item) => (
|
|
40
|
+
<ChildSessionMetaChip key={item} value={item} />
|
|
41
|
+
))}
|
|
94
42
|
{tab.projectRoot ? (
|
|
95
|
-
<
|
|
43
|
+
<span
|
|
96
44
|
title={tab.projectRoot}
|
|
97
|
-
className="truncate rounded border border-gray-200 bg-gray-50 px-
|
|
45
|
+
className="min-w-0 flex-1 truncate rounded border border-gray-200 bg-gray-50 px-1.5 py-0.5 font-mono text-[10px] text-gray-500"
|
|
98
46
|
>
|
|
99
47
|
{tab.projectRoot}
|
|
100
|
-
</
|
|
48
|
+
</span>
|
|
101
49
|
) : null}
|
|
102
50
|
</div>
|
|
103
51
|
);
|
|
104
52
|
}
|
|
105
53
|
|
|
106
|
-
function
|
|
54
|
+
function WorkspaceSideChatDraftHeader() {
|
|
107
55
|
return (
|
|
108
56
|
<div className="border-b border-gray-200/70 px-4 py-3">
|
|
109
57
|
<div className="flex min-w-0 items-center gap-2 text-sm font-semibold text-gray-900">
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
agentId={tab.agentId}
|
|
113
|
-
className="h-4 w-4 shrink-0"
|
|
114
|
-
/>
|
|
115
|
-
) : (
|
|
116
|
-
<FolderGit2 className="h-4 w-4 shrink-0 text-gray-400" />
|
|
117
|
-
)}
|
|
118
|
-
<span className="truncate">{tab.title}</span>
|
|
58
|
+
<MessageSquarePlus className="h-4 w-4 shrink-0 text-primary" />
|
|
59
|
+
<span className="truncate">{t("chatWorkspaceSideChatDraftTitle")}</span>
|
|
119
60
|
</div>
|
|
120
|
-
<
|
|
61
|
+
<p className="mt-1 text-xs leading-5 text-gray-500">
|
|
62
|
+
{t("chatWorkspaceSideChatDraftSubtitle")}
|
|
63
|
+
</p>
|
|
121
64
|
</div>
|
|
122
65
|
);
|
|
123
66
|
}
|
|
@@ -130,12 +73,37 @@ export function ChatSessionWorkspacePanelContent({
|
|
|
130
73
|
}: ChatSessionWorkspacePanelContentProps) {
|
|
131
74
|
const presenter = usePresenter();
|
|
132
75
|
|
|
76
|
+
if (activeSelection.kind === "side-chat-draft") {
|
|
77
|
+
return (
|
|
78
|
+
<>
|
|
79
|
+
<WorkspaceSideChatDraftHeader />
|
|
80
|
+
<div className="flex min-h-0 flex-1 flex-col">
|
|
81
|
+
<SessionConversationArea
|
|
82
|
+
materializationContext={{
|
|
83
|
+
kind: "child",
|
|
84
|
+
parentSessionKey: activeSelection.draft.parentSessionKey,
|
|
85
|
+
inheritContext: true,
|
|
86
|
+
}}
|
|
87
|
+
sessionKey={null}
|
|
88
|
+
showWelcomeForDraft={false}
|
|
89
|
+
onSessionMaterialized={(sessionKey) =>
|
|
90
|
+
presenter.chatThreadManager.materializeSideChatDraft({
|
|
91
|
+
draftKey: activeSelection.draft.draftKey,
|
|
92
|
+
sessionKey,
|
|
93
|
+
})
|
|
94
|
+
}
|
|
95
|
+
/>
|
|
96
|
+
</div>
|
|
97
|
+
</>
|
|
98
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
133
101
|
if (activeSelection.kind === "child-session") {
|
|
134
102
|
return (
|
|
135
103
|
<>
|
|
136
|
-
<
|
|
137
|
-
<div className="flex
|
|
138
|
-
<
|
|
104
|
+
<ChildSessionMetaStrip tab={activeSelection.tab} />
|
|
105
|
+
<div className="flex min-h-0 flex-1 flex-col">
|
|
106
|
+
<SessionConversationArea sessionKey={activeSelection.tab.sessionKey} />
|
|
139
107
|
</div>
|
|
140
108
|
</>
|
|
141
109
|
);
|
package/src/features/chat/features/workspace/components/chat-session-workspace-panel-nav.tsx
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { AlarmClock, ArrowLeft, ArrowRight, FileCode2, MessageSquareText, X } from "lucide-react";
|
|
1
|
+
import { AlarmClock, ArrowLeft, ArrowRight, FileCode2, MessageSquarePlus, MessageSquareText, X } from "lucide-react";
|
|
2
2
|
import type { WorkspaceTabViewModel } from "@/features/chat/features/workspace/utils/chat-workspace-panel-view-model.utils";
|
|
3
3
|
import { AgentIdentityAvatar } from "@/shared/components/common/agent-identity";
|
|
4
4
|
import {
|
|
@@ -17,6 +17,10 @@ function WorkspaceTabIcon({ agentId, kind }: Pick<WorkspaceTabViewModel, "agentI
|
|
|
17
17
|
return <FileCode2 className="h-3.5 w-3.5 shrink-0 text-gray-400" />;
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
+
if (kind === "side-chat-draft") {
|
|
21
|
+
return <MessageSquarePlus className="h-3.5 w-3.5 shrink-0 text-primary" />;
|
|
22
|
+
}
|
|
23
|
+
|
|
20
24
|
if (agentId) {
|
|
21
25
|
return (
|
|
22
26
|
<AgentIdentityAvatar agentId={agentId} className="h-3.5 w-3.5 shrink-0" />
|
|
@@ -4,6 +4,7 @@ import { useNcpChildSessionTabsView } from "@/features/chat/features/ncp/hooks/u
|
|
|
4
4
|
import { useChatSessionListStore } from "@/features/chat/stores/chat-session-list.store";
|
|
5
5
|
import type {
|
|
6
6
|
ChatChildSessionTab,
|
|
7
|
+
ChatWorkspaceSideChatDraft,
|
|
7
8
|
ChatWorkspaceNavigationEntry,
|
|
8
9
|
ChatWorkspaceFileTab,
|
|
9
10
|
} from "@/features/chat/stores/chat-thread.store";
|
|
@@ -26,11 +27,12 @@ type ChatSessionWorkspacePanelProps = {
|
|
|
26
27
|
sessionKey: string | null;
|
|
27
28
|
childSessionTabs: readonly ChatChildSessionTab[];
|
|
28
29
|
activeChildSessionKey: string | null;
|
|
30
|
+
activeSideChatDraft: ChatWorkspaceSideChatDraft | null;
|
|
29
31
|
workspaceFileTabs: readonly ChatWorkspaceFileTab[];
|
|
30
32
|
activeWorkspaceFileKey: string | null;
|
|
31
33
|
workspaceNavigationHistory?: readonly ChatWorkspaceNavigationEntry[];
|
|
32
34
|
workspaceNavigationHistoryIndex?: number;
|
|
33
|
-
activePanelKind?: "child-session" | "file" | "cron" | null;
|
|
35
|
+
activePanelKind?: "child-session" | "side-chat-draft" | "file" | "cron" | null;
|
|
34
36
|
sessionCronJobs?: readonly CronJobView[];
|
|
35
37
|
sessionProjectRoot: string | null;
|
|
36
38
|
sessionWorkingDir: string | null;
|
|
@@ -41,6 +43,7 @@ export function ChatSessionWorkspacePanel({
|
|
|
41
43
|
sessionKey,
|
|
42
44
|
childSessionTabs,
|
|
43
45
|
activeChildSessionKey,
|
|
46
|
+
activeSideChatDraft,
|
|
44
47
|
workspaceFileTabs,
|
|
45
48
|
activeWorkspaceFileKey,
|
|
46
49
|
workspaceNavigationHistory = [],
|
|
@@ -58,6 +61,7 @@ export function ChatSessionWorkspacePanel({
|
|
|
58
61
|
);
|
|
59
62
|
const activeSelection = resolveWorkspaceSelection({
|
|
60
63
|
activeChildSessionKey,
|
|
64
|
+
activeSideChatDraft,
|
|
61
65
|
activeWorkspaceFileKey,
|
|
62
66
|
activePanelKind,
|
|
63
67
|
childSessionTabs: resolvedChildTabs,
|
|
@@ -77,6 +81,7 @@ export function ChatSessionWorkspacePanel({
|
|
|
77
81
|
() =>
|
|
78
82
|
buildWorkspaceTabsViewModel({
|
|
79
83
|
resolvedChildTabs,
|
|
84
|
+
activeSideChatDraft,
|
|
80
85
|
workspaceFileTabs,
|
|
81
86
|
sessionCronJobCount: sessionCronJobs.length,
|
|
82
87
|
activeSelection,
|
|
@@ -91,6 +96,7 @@ export function ChatSessionWorkspacePanel({
|
|
|
91
96
|
}),
|
|
92
97
|
[
|
|
93
98
|
activeSelection,
|
|
99
|
+
activeSideChatDraft,
|
|
94
100
|
optimisticReadAtBySessionKey,
|
|
95
101
|
presenter.chatThreadManager,
|
|
96
102
|
resolvedChildTabs,
|