@nextclaw/ui 0.15.24 → 0.15.25
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/{api-BxPNDp30.js → api-FK7tikI1.js} +3 -3
- package/dist/assets/appearance-settings-page-BYbvl2wj.js +1 -0
- package/dist/assets/{channels-list-page-DRaNWAxC.js → channels-list-page-CocdcIko.js} +2 -2
- package/dist/assets/chat-page-C5E-LLVd.js +1 -0
- package/dist/assets/{config-split-page-BVWVDbvG.js → config-split-page-CA_a0AJ5.js} +1 -1
- package/dist/assets/{confirm-dialog-mA2iVzxh.js → confirm-dialog-CxZfenjK.js} +1 -1
- package/dist/assets/{desktop-update-config-DyQb1LXr.js → desktop-update-config-BEKC8Ly9.js} +1 -1
- package/dist/assets/{dist-B4Pf5X3Q.js → dist-BH7W5yCi.js} +1 -1
- package/dist/assets/{dist-DHEWkGWX.js → dist-CaYdVVeO.js} +1 -1
- package/dist/assets/doc-browser-Cl2ldE3f.js +1 -0
- package/dist/assets/doc-browser-DXCSd63E.js +1 -0
- package/dist/assets/{doc-browser-context-CuGI6PQc.js → doc-browser-context-FDPs3gJf.js} +1 -1
- package/dist/assets/{form-actions-BOfIyG3O.js → form-actions-0c0aw_bl.js} +1 -1
- package/dist/assets/i18n-provider-DkITJNz8.js +1 -0
- package/dist/assets/index-CQ2LcI2p.css +1 -0
- package/dist/assets/index-CrdfvBVg.js +107 -0
- package/dist/assets/loader-circle-DHtUxCIA.js +1 -0
- package/dist/assets/{mcp-marketplace-page-ofDqbOIF.js → mcp-marketplace-page-Bc_jI5iH.js} +2 -2
- package/dist/assets/mcp-marketplace-page-CzCieD9r.js +1 -0
- package/dist/assets/{model-config-page-D73Tu3jW.js → model-config-page-C4jw-pcj.js} +1 -1
- package/dist/assets/{navigation-link-CAFOcXNg.js → navigation-link-CVy0_kVl.js} +1 -1
- package/dist/assets/plus-CG1RwZQq.js +1 -0
- package/dist/assets/{provider-scoped-model-input-BaJJJYMX.js → provider-scoped-model-input-CmH4BFvc.js} +1 -1
- package/dist/assets/{providers-config-page-BL6IRVBm.js → providers-config-page-CJQjwzaw.js} +1 -1
- package/dist/assets/{react-BC_orpAj.js → react-DjFBVA0n.js} +1 -1
- package/dist/assets/{refresh-cw-CWDp_JnN.js → refresh-cw-j2bl79Ea.js} +1 -1
- package/dist/assets/remote-BIlpD3yL.js +1 -0
- package/dist/assets/rotate-cw-bKG8zH8M.js +1 -0
- package/dist/assets/runtime-config-page-B_x2Glz5.js +1 -0
- package/dist/assets/{save-Cnr71JON.js → save-BKNrtK81.js} +1 -1
- package/dist/assets/{search-CCX11X2m.js → search-CkOm65W_.js} +1 -1
- package/dist/assets/{search-config-page-BB6d5gT7.js → search-config-page-BaIijtmO.js} +1 -1
- package/dist/assets/{secrets-config-page-DYsDeT9K.js → secrets-config-page-CJjtdFAl.js} +2 -2
- package/dist/assets/security-config-DB8apj09.js +1 -0
- package/dist/assets/{select-DvwBu99K.js → select-Ea7ffKCE.js} +1 -1
- package/dist/assets/{settings-2-Dmv6zMne.js → settings-2-CtyN3m_V.js} +1 -1
- package/dist/assets/skeleton-Bt6zxcAB.js +1 -0
- package/dist/assets/{tag-chip-gMPvx7n_.js → tag-chip-C9l4xsKp.js} +1 -1
- package/dist/assets/x-CowtCu9Z.js +1 -0
- package/dist/index.html +20 -20
- package/package.json +8 -8
- package/src/features/chat/features/conversation/components/__tests__/session-conversation-area.test.tsx +30 -1
- package/src/features/chat/features/conversation/components/session-conversation-area.tsx +1 -1
- package/src/features/chat/features/ncp/hooks/__tests__/use-hydrated-ncp-agent.test.tsx +40 -3
- package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-file-preview.selection.test.tsx +66 -0
- package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-file-preview.test.tsx +13 -1
- package/src/features/chat/features/workspace/components/__tests__/chat-session-workspace-panel-content.test.tsx +573 -90
- package/src/features/chat/features/workspace/components/chat-session-workspace-directory-browser.tsx +389 -288
- package/src/features/chat/features/workspace/components/chat-session-workspace-file-breadcrumbs.tsx +54 -35
- package/src/features/chat/features/workspace/components/chat-session-workspace-file-preview.tsx +79 -148
- package/src/features/chat/features/workspace/components/chat-session-workspace-panel-content.tsx +149 -94
- package/src/features/chat/features/workspace/components/project-files/__tests__/workspace-directory-entry-menu.test.tsx +50 -0
- package/src/features/chat/features/workspace/components/project-files/workspace-directory-entry-menu.tsx +209 -0
- package/src/features/chat/features/workspace/components/project-files/workspace-directory-tree.tsx +411 -0
- package/src/features/chat/features/workspace/components/project-files/workspace-new-folder-tree-item.tsx +112 -0
- package/src/features/chat/features/workspace/components/project-files/workspace-project-files-toolbar.tsx +64 -0
- package/src/features/chat/features/workspace/hooks/use-workspace-explorer-layout.ts +88 -0
- package/src/features/chat/features/workspace/hooks/use-workspace-file-actions.ts +335 -0
- package/src/features/chat/features/workspace/utils/chat-workspace-file-path-mutation.utils.ts +58 -0
- package/src/features/chat/features/workspace/utils/chat-workspace-file-tab.utils.ts +23 -22
- package/src/features/chat/features/workspace/utils/chat-workspace-panel-layout.utils.ts +13 -4
- package/src/features/chat/managers/__tests__/chat-composer-intent.manager.test.ts +86 -60
- package/src/features/chat/managers/__tests__/chat-thread.manager.test.ts +103 -99
- package/src/features/chat/managers/chat-composer-intent.manager.ts +37 -33
- package/src/features/chat/managers/chat-thread.manager.ts +132 -128
- package/src/features/chat/stores/__tests__/chat-thread.store.test.ts +20 -40
- package/src/features/chat/stores/chat-thread.store.ts +47 -74
- package/src/shared/components/resizable-right-panel/__tests__/resizable-right-panel.test.tsx +35 -38
- package/src/shared/components/resizable-right-panel/resizable-right-panel.tsx +25 -19
- package/src/shared/components/ui/context-menu/__tests__/context-menu.test.tsx +60 -34
- package/src/shared/components/ui/context-menu/context-menu.tsx +95 -68
- package/src/shared/lib/api/managers/client.manager.ts +31 -17
- package/src/shared/lib/api/server-path/server-path.types.ts +66 -0
- package/src/shared/lib/api/types.ts +145 -116
- package/src/shared/lib/api/utils/server-path.utils.ts +35 -11
- package/src/shared/lib/i18n/locales/en-US/chat.json +42 -0
- package/src/shared/lib/i18n/locales/zh-CN/chat.json +42 -0
- package/dist/assets/appearance-settings-page-DpVJjvkB.js +0 -1
- package/dist/assets/chat-page-BuFDmG5_.js +0 -1
- package/dist/assets/doc-browser-CtO_HtRy.js +0 -1
- package/dist/assets/doc-browser-eMUagyBV.js +0 -1
- package/dist/assets/index-BjBdWHV1.js +0 -107
- package/dist/assets/index-DmpmjAGQ.css +0 -1
- package/dist/assets/loader-circle-Df8wF2Pr.js +0 -1
- package/dist/assets/mcp-marketplace-page-DI49IKxp.js +0 -1
- package/dist/assets/plus-DVU5RLCS.js +0 -1
- package/dist/assets/remote-T24O58lH.js +0 -1
- package/dist/assets/rotate-cw-BqhwSV5p.js +0 -1
- package/dist/assets/runtime-config-page-CXUx017t.js +0 -1
- package/dist/assets/security-config-CVPgqL7G.js +0 -1
- package/dist/assets/skeleton-C5tWata3.js +0 -1
- package/dist/assets/use-confirm-dialog-D_3-QpZU.js +0 -1
- package/dist/assets/x-BEWSqeux.js +0 -1
|
@@ -1,8 +1,5 @@
|
|
|
1
1
|
import { appQueryClient } from '@/app-query-client';
|
|
2
|
-
import {
|
|
3
|
-
deleteNcpSession as deleteNcpSessionApi,
|
|
4
|
-
deleteNcpSessionSummaryInQueryClient,
|
|
5
|
-
} from '@/shared/lib/api';
|
|
2
|
+
import { deleteNcpSession as deleteNcpSessionApi, deleteNcpSessionSummaryInQueryClient } from '@/shared/lib/api';
|
|
6
3
|
import type {
|
|
7
4
|
ChatFileOpenActionViewModel,
|
|
8
5
|
ChatUiShowContentRequest,
|
|
@@ -20,7 +17,10 @@ import type {
|
|
|
20
17
|
ChatWorkspaceFileTab,
|
|
21
18
|
} from '@/features/chat/stores/chat-thread.store';
|
|
22
19
|
import { useChatThreadStore } from '@/features/chat/stores/chat-thread.store';
|
|
23
|
-
import {
|
|
20
|
+
import {
|
|
21
|
+
normalizeChatWorkspaceExplorerWidth,
|
|
22
|
+
normalizeChatWorkspacePanelWidth,
|
|
23
|
+
} from '@/features/chat/features/workspace/utils/chat-workspace-panel-layout.utils';
|
|
24
24
|
import { t } from '@/shared/lib/i18n';
|
|
25
25
|
import {
|
|
26
26
|
areWorkspaceNavigationEntriesEqual,
|
|
@@ -31,10 +31,7 @@ import {
|
|
|
31
31
|
materializeSideChatDraftSnapshot,
|
|
32
32
|
upsertChildSessionTab,
|
|
33
33
|
} from '@/features/chat/features/workspace/utils/chat-thread-workspace-session.utils';
|
|
34
|
-
import {
|
|
35
|
-
pushNavigationHistoryEntry,
|
|
36
|
-
stepNavigationHistory,
|
|
37
|
-
} from '@/shared/lib/navigation-history';
|
|
34
|
+
import { pushNavigationHistoryEntry, stepNavigationHistory } from '@/shared/lib/navigation-history';
|
|
38
35
|
import {
|
|
39
36
|
resolveAlternateWorkspaceFileViewer,
|
|
40
37
|
type ChatWorkspaceFileViewer,
|
|
@@ -43,6 +40,10 @@ import {
|
|
|
43
40
|
createWorkspaceFileTab,
|
|
44
41
|
upsertWorkspaceFileTab,
|
|
45
42
|
} from '@/features/chat/features/workspace/utils/chat-workspace-file-tab.utils';
|
|
43
|
+
import {
|
|
44
|
+
createRemovedWorkspacePathSnapshot,
|
|
45
|
+
createRenamedWorkspacePathPatch,
|
|
46
|
+
} from '@/features/chat/features/workspace/utils/chat-workspace-file-path-mutation.utils';
|
|
46
47
|
|
|
47
48
|
type WorkspaceChildReadState = Parameters<ChatSessionListManager['markVisibleWorkspaceChildRead']>[0];
|
|
48
49
|
export type ChatVisibleWorkspaceSelection =
|
|
@@ -61,7 +62,9 @@ export class ChatThreadManager {
|
|
|
61
62
|
|
|
62
63
|
private hasSnapshotChanges = (patch: Partial<ChatThreadSnapshot>): boolean => {
|
|
63
64
|
const current = useChatThreadStore.getState().snapshot;
|
|
64
|
-
for (const [key, value] of Object.entries(patch) as Array<
|
|
65
|
+
for (const [key, value] of Object.entries(patch) as Array<
|
|
66
|
+
[keyof ChatThreadSnapshot, ChatThreadSnapshot[keyof ChatThreadSnapshot]]
|
|
67
|
+
>) {
|
|
65
68
|
if (!Object.is(current[key], value)) {
|
|
66
69
|
return true;
|
|
67
70
|
}
|
|
@@ -112,27 +115,23 @@ export class ChatThreadManager {
|
|
|
112
115
|
return useChatSessionListStore.getState().snapshot.selectedSessionKey ?? null;
|
|
113
116
|
};
|
|
114
117
|
|
|
115
|
-
private activateWorkspaceFileTab = (
|
|
116
|
-
nextTab: ChatWorkspaceFileTab,
|
|
117
|
-
adjacentToKey?: string,
|
|
118
|
-
) => {
|
|
118
|
+
private activateWorkspaceFileTab = (nextTab: ChatWorkspaceFileTab, adjacentToKey?: string) => {
|
|
119
119
|
const { parentSessionKey } = nextTab;
|
|
120
120
|
const { workspaceFileTabs } = useChatThreadStore.getState().snapshot;
|
|
121
|
-
this.setWorkspaceSelection(
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
workspaceFileTabs,
|
|
126
|
-
nextTab,
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
});
|
|
121
|
+
this.setWorkspaceSelection(
|
|
122
|
+
{
|
|
123
|
+
workspacePanelParentKey: parentSessionKey,
|
|
124
|
+
activeWorkspacePanelKind: 'file',
|
|
125
|
+
workspaceFileTabs: upsertWorkspaceFileTab(workspaceFileTabs, nextTab, adjacentToKey),
|
|
126
|
+
activeWorkspaceFileKey: nextTab.key,
|
|
127
|
+
activeChildSessionKey: null,
|
|
128
|
+
activeSideChatDraft: null,
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
kind: 'file',
|
|
132
|
+
key: nextTab.key,
|
|
133
|
+
},
|
|
134
|
+
);
|
|
136
135
|
this.ensureWorkspaceParentRoute(parentSessionKey);
|
|
137
136
|
this.onWorkspacePanelOpened?.();
|
|
138
137
|
};
|
|
@@ -149,10 +148,7 @@ export class ChatThreadManager {
|
|
|
149
148
|
}
|
|
150
149
|
};
|
|
151
150
|
|
|
152
|
-
private setWorkspaceSelection = (
|
|
153
|
-
patch: Partial<ChatThreadSnapshot>,
|
|
154
|
-
entry: ChatWorkspaceNavigationEntry,
|
|
155
|
-
) => {
|
|
151
|
+
private setWorkspaceSelection = (patch: Partial<ChatThreadSnapshot>, entry: ChatWorkspaceNavigationEntry) => {
|
|
156
152
|
const { snapshot } = useChatThreadStore.getState();
|
|
157
153
|
const history = pushNavigationHistoryEntry(
|
|
158
154
|
{
|
|
@@ -163,8 +159,7 @@ export class ChatThreadManager {
|
|
|
163
159
|
areWorkspaceNavigationEntriesEqual,
|
|
164
160
|
);
|
|
165
161
|
const closedWorkspaceTabEntries =
|
|
166
|
-
patch.workspacePanelParentKey &&
|
|
167
|
-
patch.workspacePanelParentKey !== snapshot.workspacePanelParentKey
|
|
162
|
+
patch.workspacePanelParentKey && patch.workspacePanelParentKey !== snapshot.workspacePanelParentKey
|
|
168
163
|
? []
|
|
169
164
|
: snapshot.closedWorkspaceTabEntries.filter(
|
|
170
165
|
(candidate) => !areWorkspaceNavigationEntriesEqual(candidate, entry),
|
|
@@ -185,13 +180,16 @@ export class ChatThreadManager {
|
|
|
185
180
|
if (!parentSessionKey && kind !== 'project-files') {
|
|
186
181
|
return;
|
|
187
182
|
}
|
|
188
|
-
this.setWorkspaceSelection(
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
183
|
+
this.setWorkspaceSelection(
|
|
184
|
+
{
|
|
185
|
+
workspacePanelParentKey: parentSessionKey,
|
|
186
|
+
activeWorkspacePanelKind: kind,
|
|
187
|
+
activeChildSessionKey: null,
|
|
188
|
+
activeSideChatDraft: null,
|
|
189
|
+
activeWorkspaceFileKey: null,
|
|
190
|
+
},
|
|
191
|
+
{ kind },
|
|
192
|
+
);
|
|
195
193
|
this.ensureWorkspaceParentRoute(parentSessionKey);
|
|
196
194
|
this.onWorkspacePanelOpened?.();
|
|
197
195
|
};
|
|
@@ -203,10 +201,7 @@ export class ChatThreadManager {
|
|
|
203
201
|
toggleWorkspacePanel = (sessionKey: string | null) => {
|
|
204
202
|
const normalizedSessionKey = sessionKey?.trim() || null;
|
|
205
203
|
const { snapshot } = useChatThreadStore.getState();
|
|
206
|
-
if (
|
|
207
|
-
snapshot.workspacePanelParentKey === normalizedSessionKey &&
|
|
208
|
-
snapshot.activeWorkspacePanelKind
|
|
209
|
-
) {
|
|
204
|
+
if (snapshot.workspacePanelParentKey === normalizedSessionKey && snapshot.activeWorkspacePanelKind) {
|
|
210
205
|
this.closeWorkspacePanel();
|
|
211
206
|
return;
|
|
212
207
|
}
|
|
@@ -223,6 +218,22 @@ export class ChatThreadManager {
|
|
|
223
218
|
});
|
|
224
219
|
};
|
|
225
220
|
|
|
221
|
+
setWorkspaceExplorerWidth = (width: number) => {
|
|
222
|
+
this.syncSnapshot({
|
|
223
|
+
workspaceExplorerWidth: normalizeChatWorkspaceExplorerWidth(width),
|
|
224
|
+
});
|
|
225
|
+
};
|
|
226
|
+
|
|
227
|
+
renameWorkspacePath = (params: { previousPath: string; path: string; label: string }) => {
|
|
228
|
+
const patch = createRenamedWorkspacePathPatch(useChatThreadStore.getState().snapshot, params);
|
|
229
|
+
if (patch) this.syncSnapshot(patch);
|
|
230
|
+
};
|
|
231
|
+
|
|
232
|
+
removeWorkspacePath = (path: string) => {
|
|
233
|
+
const snapshot = createRemovedWorkspacePathSnapshot(useChatThreadStore.getState().snapshot, path);
|
|
234
|
+
if (snapshot) useChatThreadStore.getState().setSnapshot(snapshot);
|
|
235
|
+
};
|
|
236
|
+
|
|
226
237
|
openChildSessions = (sessionKey: string) => {
|
|
227
238
|
this.openWorkspacePage(sessionKey, 'child-sessions');
|
|
228
239
|
};
|
|
@@ -236,10 +247,7 @@ export class ChatThreadManager {
|
|
|
236
247
|
if (!sessionKey || !this.uiManager.isAtChatRoot()) {
|
|
237
248
|
return;
|
|
238
249
|
}
|
|
239
|
-
const patch = materializeDraftWorkspaceSnapshot(
|
|
240
|
-
useChatThreadStore.getState().snapshot,
|
|
241
|
-
sessionKey,
|
|
242
|
-
);
|
|
250
|
+
const patch = materializeDraftWorkspaceSnapshot(useChatThreadStore.getState().snapshot, sessionKey);
|
|
243
251
|
if (!patch) {
|
|
244
252
|
return;
|
|
245
253
|
}
|
|
@@ -271,15 +279,12 @@ export class ChatThreadManager {
|
|
|
271
279
|
activeWorkspaceFileKey: null,
|
|
272
280
|
};
|
|
273
281
|
if (activeChildSessionKey && childSessionTab) {
|
|
274
|
-
patch.childSessionTabs = upsertChildSessionTab(
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
agentId: childSessionTab.agentId?.trim() || null,
|
|
281
|
-
},
|
|
282
|
-
);
|
|
282
|
+
patch.childSessionTabs = upsertChildSessionTab(useChatThreadStore.getState().snapshot.childSessionTabs, {
|
|
283
|
+
sessionKey: activeChildSessionKey,
|
|
284
|
+
parentSessionKey,
|
|
285
|
+
label: childSessionTab.label?.trim() || null,
|
|
286
|
+
agentId: childSessionTab.agentId?.trim() || null,
|
|
287
|
+
});
|
|
283
288
|
}
|
|
284
289
|
if (activeChildSessionKey) {
|
|
285
290
|
this.setWorkspaceSelection(patch, {
|
|
@@ -294,22 +299,24 @@ export class ChatThreadManager {
|
|
|
294
299
|
};
|
|
295
300
|
|
|
296
301
|
openSideChatDraft = (parentSessionKey?: string | null) => {
|
|
297
|
-
const resolvedParentSessionKey =
|
|
298
|
-
parentSessionKey?.trim() || this.resolveWorkspaceParentSessionKey()?.trim();
|
|
302
|
+
const resolvedParentSessionKey = parentSessionKey?.trim() || this.resolveWorkspaceParentSessionKey()?.trim();
|
|
299
303
|
if (!resolvedParentSessionKey) {
|
|
300
304
|
return;
|
|
301
305
|
}
|
|
302
306
|
const activeSideChatDraft = createSideChatDraft(resolvedParentSessionKey);
|
|
303
|
-
this.setWorkspaceSelection(
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
307
|
+
this.setWorkspaceSelection(
|
|
308
|
+
{
|
|
309
|
+
workspacePanelParentKey: resolvedParentSessionKey,
|
|
310
|
+
activeWorkspacePanelKind: 'side-chat-draft',
|
|
311
|
+
activeChildSessionKey: null,
|
|
312
|
+
activeSideChatDraft,
|
|
313
|
+
activeWorkspaceFileKey: null,
|
|
314
|
+
},
|
|
315
|
+
{
|
|
316
|
+
kind: 'side-chat-draft',
|
|
317
|
+
key: activeSideChatDraft.draftKey,
|
|
318
|
+
},
|
|
319
|
+
);
|
|
313
320
|
this.ensureWorkspaceParentRoute(resolvedParentSessionKey);
|
|
314
321
|
this.onWorkspacePanelOpened?.();
|
|
315
322
|
};
|
|
@@ -340,34 +347,32 @@ export class ChatThreadManager {
|
|
|
340
347
|
this.activateWorkspaceFileTab(nextTab);
|
|
341
348
|
};
|
|
342
349
|
|
|
343
|
-
openWorkspaceFileViewer = (
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
const sourceTab = useChatThreadStore.getState().snapshot.workspaceFileTabs
|
|
348
|
-
.find((tab) => tab.key === fileKey.trim());
|
|
350
|
+
openWorkspaceFileViewer = (fileKey: string, viewer?: ChatWorkspaceFileViewer) => {
|
|
351
|
+
const sourceTab = useChatThreadStore
|
|
352
|
+
.getState()
|
|
353
|
+
.snapshot.workspaceFileTabs.find((tab) => tab.key === fileKey.trim());
|
|
349
354
|
if (!sourceTab || sourceTab.viewMode !== 'preview') {
|
|
350
355
|
return;
|
|
351
356
|
}
|
|
352
|
-
const nextViewer = viewer ?? resolveAlternateWorkspaceFileViewer(
|
|
353
|
-
sourceTab.path,
|
|
354
|
-
sourceTab.previewViewer,
|
|
355
|
-
);
|
|
357
|
+
const nextViewer = viewer ?? resolveAlternateWorkspaceFileViewer(sourceTab.path, sourceTab.previewViewer);
|
|
356
358
|
if (!nextViewer) {
|
|
357
359
|
return;
|
|
358
360
|
}
|
|
359
|
-
const nextTab = createWorkspaceFileTab(
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
361
|
+
const nextTab = createWorkspaceFileTab(
|
|
362
|
+
{
|
|
363
|
+
path: sourceTab.path,
|
|
364
|
+
label: sourceTab.label ?? undefined,
|
|
365
|
+
viewMode: 'preview',
|
|
366
|
+
previewViewer: nextViewer,
|
|
367
|
+
line: sourceTab.line ?? undefined,
|
|
368
|
+
column: sourceTab.column ?? undefined,
|
|
369
|
+
params: sourceTab.params ?? undefined,
|
|
370
|
+
rawText: sourceTab.rawText ?? undefined,
|
|
371
|
+
contentUrl: sourceTab.contentUrl ?? undefined,
|
|
372
|
+
mimeType: sourceTab.mimeType ?? undefined,
|
|
373
|
+
},
|
|
374
|
+
sourceTab.parentSessionKey,
|
|
375
|
+
);
|
|
371
376
|
if (nextTab) {
|
|
372
377
|
this.activateWorkspaceFileTab(nextTab, sourceTab.key);
|
|
373
378
|
}
|
|
@@ -383,9 +388,7 @@ export class ChatThreadManager {
|
|
|
383
388
|
}
|
|
384
389
|
if (action.sessionKind === 'child' && !this.uiManager.isCompactViewport()) {
|
|
385
390
|
const parentSessionKey =
|
|
386
|
-
action.parentSessionId?.trim() ||
|
|
387
|
-
useChatSessionListStore.getState().snapshot.selectedSessionKey ||
|
|
388
|
-
null;
|
|
391
|
+
action.parentSessionId?.trim() || useChatSessionListStore.getState().snapshot.selectedSessionKey || null;
|
|
389
392
|
if (parentSessionKey) {
|
|
390
393
|
this.openChildSessionPanel({
|
|
391
394
|
parentSessionKey,
|
|
@@ -457,15 +460,18 @@ export class ChatThreadManager {
|
|
|
457
460
|
if (!normalizedSessionKey) {
|
|
458
461
|
return;
|
|
459
462
|
}
|
|
460
|
-
this.setWorkspaceSelection(
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
463
|
+
this.setWorkspaceSelection(
|
|
464
|
+
{
|
|
465
|
+
activeChildSessionKey: normalizedSessionKey,
|
|
466
|
+
activeWorkspaceFileKey: null,
|
|
467
|
+
activeWorkspacePanelKind: 'child-session',
|
|
468
|
+
activeSideChatDraft: null,
|
|
469
|
+
},
|
|
470
|
+
{
|
|
471
|
+
kind: 'child-session',
|
|
472
|
+
key: normalizedSessionKey,
|
|
473
|
+
},
|
|
474
|
+
);
|
|
469
475
|
};
|
|
470
476
|
|
|
471
477
|
selectWorkspaceFile = (fileKey: string) => {
|
|
@@ -477,15 +483,18 @@ export class ChatThreadManager {
|
|
|
477
483
|
if (!workspaceFileTabs.some((tab) => tab.key === normalizedFileKey)) {
|
|
478
484
|
return;
|
|
479
485
|
}
|
|
480
|
-
this.setWorkspaceSelection(
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
486
|
+
this.setWorkspaceSelection(
|
|
487
|
+
{
|
|
488
|
+
activeWorkspaceFileKey: normalizedFileKey,
|
|
489
|
+
activeChildSessionKey: null,
|
|
490
|
+
activeWorkspacePanelKind: 'file',
|
|
491
|
+
activeSideChatDraft: null,
|
|
492
|
+
},
|
|
493
|
+
{
|
|
494
|
+
kind: 'file',
|
|
495
|
+
key: normalizedFileKey,
|
|
496
|
+
},
|
|
497
|
+
);
|
|
489
498
|
};
|
|
490
499
|
|
|
491
500
|
closeWorkspaceTab = (entry: ChatWorkspaceNavigationEntry) => {
|
|
@@ -545,19 +554,12 @@ export class ChatThreadManager {
|
|
|
545
554
|
};
|
|
546
555
|
|
|
547
556
|
goToParentSession = () => {
|
|
548
|
-
const {
|
|
549
|
-
|
|
550
|
-
activeSideChatDraft,
|
|
551
|
-
childSessionTabs,
|
|
552
|
-
activeChildSessionKey,
|
|
553
|
-
} = useChatThreadStore.getState().snapshot;
|
|
557
|
+
const { parentSessionKey, activeSideChatDraft, childSessionTabs, activeChildSessionKey } =
|
|
558
|
+
useChatThreadStore.getState().snapshot;
|
|
554
559
|
const activeChildParentSessionKey =
|
|
555
|
-
childSessionTabs.find((tab) => tab.sessionKey === activeChildSessionKey)
|
|
556
|
-
?.parentSessionKey ?? null;
|
|
560
|
+
childSessionTabs.find((tab) => tab.sessionKey === activeChildSessionKey)?.parentSessionKey ?? null;
|
|
557
561
|
const resolvedParentSessionKey =
|
|
558
|
-
parentSessionKey ??
|
|
559
|
-
activeSideChatDraft?.parentSessionKey ??
|
|
560
|
-
activeChildParentSessionKey;
|
|
562
|
+
parentSessionKey ?? activeSideChatDraft?.parentSessionKey ?? activeChildParentSessionKey;
|
|
561
563
|
if (!resolvedParentSessionKey) {
|
|
562
564
|
return;
|
|
563
565
|
}
|
|
@@ -567,7 +569,7 @@ export class ChatThreadManager {
|
|
|
567
569
|
|
|
568
570
|
deleteSession = async () => {
|
|
569
571
|
const {
|
|
570
|
-
snapshot: { selectedSessionKey }
|
|
572
|
+
snapshot: { selectedSessionKey },
|
|
571
573
|
} = useChatSessionListStore.getState();
|
|
572
574
|
if (!selectedSessionKey) {
|
|
573
575
|
return;
|
|
@@ -575,7 +577,7 @@ export class ChatThreadManager {
|
|
|
575
577
|
const confirmed = await this.uiManager.confirm({
|
|
576
578
|
title: t('chatDeleteSessionConfirm'),
|
|
577
579
|
variant: 'destructive',
|
|
578
|
-
confirmLabel: t('delete')
|
|
580
|
+
confirmLabel: t('delete'),
|
|
579
581
|
});
|
|
580
582
|
if (!confirmed) {
|
|
581
583
|
return;
|
|
@@ -584,7 +586,9 @@ export class ChatThreadManager {
|
|
|
584
586
|
try {
|
|
585
587
|
await deleteNcpSessionApi(selectedSessionKey);
|
|
586
588
|
deleteNcpSessionSummaryInQueryClient(appQueryClient, selectedSessionKey);
|
|
587
|
-
appQueryClient.removeQueries({
|
|
589
|
+
appQueryClient.removeQueries({
|
|
590
|
+
queryKey: ['ncp-session-messages', selectedSessionKey],
|
|
591
|
+
});
|
|
588
592
|
this.clearDeletedSessionState();
|
|
589
593
|
this.uiManager.goToChatRoot({ replace: true });
|
|
590
594
|
} finally {
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { beforeEach, describe, expect, it } from 'vitest';
|
|
2
|
+
import { useChatThreadStore } from '@/features/chat/stores/chat-thread.store';
|
|
2
3
|
import {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
CHAT_WORKSPACE_EXPLORER_DEFAULT_WIDTH,
|
|
5
|
+
CHAT_WORKSPACE_PANEL_DEFAULT_WIDTH,
|
|
6
|
+
} from '@/features/chat/features/workspace/utils/chat-workspace-panel-layout.utils';
|
|
6
7
|
|
|
7
8
|
const chatThreadWorkspaceStorageKey = 'nextclaw.chat.workspace-panel.state';
|
|
8
9
|
|
|
@@ -10,7 +11,7 @@ function createLocalStoragePersistStorage() {
|
|
|
10
11
|
return {
|
|
11
12
|
getItem: (name: string) => JSON.parse(window.localStorage.getItem(name) ?? 'null'),
|
|
12
13
|
setItem: (name: string, value: unknown) => window.localStorage.setItem(name, JSON.stringify(value)),
|
|
13
|
-
removeItem: (name: string) => window.localStorage.removeItem(name)
|
|
14
|
+
removeItem: (name: string) => window.localStorage.removeItem(name),
|
|
14
15
|
};
|
|
15
16
|
}
|
|
16
17
|
|
|
@@ -31,6 +32,7 @@ function resetChatThreadStore() {
|
|
|
31
32
|
closedWorkspaceTabEntries: [],
|
|
32
33
|
workspaceNavigationHistory: [],
|
|
33
34
|
workspaceNavigationHistoryIndex: 0,
|
|
35
|
+
workspaceExplorerWidth: CHAT_WORKSPACE_EXPLORER_DEFAULT_WIDTH,
|
|
34
36
|
workspacePanelWidth: CHAT_WORKSPACE_PANEL_DEFAULT_WIDTH,
|
|
35
37
|
},
|
|
36
38
|
});
|
|
@@ -66,10 +68,7 @@ describe('chat thread workspace panel persistence', () => {
|
|
|
66
68
|
},
|
|
67
69
|
],
|
|
68
70
|
activeWorkspaceFileKey: 'session-1::preview::README.md',
|
|
69
|
-
closedWorkspaceTabEntries: [
|
|
70
|
-
{ kind: 'project-files' },
|
|
71
|
-
{ kind: 'child-session', key: 'child-session-2' },
|
|
72
|
-
],
|
|
71
|
+
closedWorkspaceTabEntries: [{ kind: 'project-files' }, { kind: 'child-session', key: 'child-session-2' }],
|
|
73
72
|
workspaceNavigationHistory: [
|
|
74
73
|
{ kind: 'child-session', key: 'child-session-1' },
|
|
75
74
|
{ kind: 'file', key: 'session-1::preview::README.md' },
|
|
@@ -77,18 +76,13 @@ describe('chat thread workspace panel persistence', () => {
|
|
|
77
76
|
workspaceNavigationHistoryIndex: 1,
|
|
78
77
|
});
|
|
79
78
|
|
|
80
|
-
const persisted = JSON.parse(
|
|
81
|
-
window.localStorage.getItem(chatThreadWorkspaceStorageKey) ?? '{}',
|
|
82
|
-
);
|
|
79
|
+
const persisted = JSON.parse(window.localStorage.getItem(chatThreadWorkspaceStorageKey) ?? '{}');
|
|
83
80
|
|
|
84
81
|
expect(persisted.state.snapshot).toMatchObject({
|
|
85
82
|
workspacePanelParentKey: 'session-1',
|
|
86
83
|
activeWorkspacePanelKind: 'file',
|
|
87
84
|
activeWorkspaceFileKey: 'session-1::preview::README.md',
|
|
88
|
-
closedWorkspaceTabEntries: [
|
|
89
|
-
{ kind: 'project-files' },
|
|
90
|
-
{ kind: 'child-session', key: 'child-session-2' },
|
|
91
|
-
],
|
|
85
|
+
closedWorkspaceTabEntries: [{ kind: 'project-files' }, { kind: 'child-session', key: 'child-session-2' }],
|
|
92
86
|
workspaceNavigationHistory: [
|
|
93
87
|
{ kind: 'child-session', key: 'child-session-1' },
|
|
94
88
|
{ kind: 'file', key: 'session-1::preview::README.md' },
|
|
@@ -120,16 +114,12 @@ describe('chat thread workspace panel persistence', () => {
|
|
|
120
114
|
workspaceNavigationHistoryIndex: 1,
|
|
121
115
|
});
|
|
122
116
|
|
|
123
|
-
const persisted = JSON.parse(
|
|
124
|
-
window.localStorage.getItem(chatThreadWorkspaceStorageKey) ?? '{}',
|
|
125
|
-
);
|
|
117
|
+
const persisted = JSON.parse(window.localStorage.getItem(chatThreadWorkspaceStorageKey) ?? '{}');
|
|
126
118
|
|
|
127
119
|
expect(persisted.state.snapshot).toMatchObject({
|
|
128
120
|
workspacePanelParentKey: 'session-1',
|
|
129
121
|
activeWorkspacePanelKind: null,
|
|
130
|
-
workspaceNavigationHistory: [
|
|
131
|
-
{ kind: 'child-session', key: 'child-session-1' },
|
|
132
|
-
],
|
|
122
|
+
workspaceNavigationHistory: [{ kind: 'child-session', key: 'child-session-1' }],
|
|
133
123
|
workspaceNavigationHistoryIndex: 0,
|
|
134
124
|
});
|
|
135
125
|
expect(persisted.state.snapshot.activeSideChatDraft).toBeUndefined();
|
|
@@ -139,12 +129,9 @@ describe('chat thread workspace panel persistence', () => {
|
|
|
139
129
|
useChatThreadStore.getState().setSnapshot({
|
|
140
130
|
workspacePanelParentKey: 'session-1',
|
|
141
131
|
activeWorkspacePanelKind: 'project-files',
|
|
142
|
-
workspaceNavigationHistory: [
|
|
143
|
-
{ kind: 'overview' },
|
|
144
|
-
{ kind: 'child-sessions' },
|
|
145
|
-
{ kind: 'project-files' },
|
|
146
|
-
],
|
|
132
|
+
workspaceNavigationHistory: [{ kind: 'overview' }, { kind: 'child-sessions' }, { kind: 'project-files' }],
|
|
147
133
|
workspaceNavigationHistoryIndex: 2,
|
|
134
|
+
workspaceExplorerWidth: 318,
|
|
148
135
|
workspacePanelWidth: 620,
|
|
149
136
|
});
|
|
150
137
|
|
|
@@ -158,12 +145,9 @@ describe('chat thread workspace panel persistence', () => {
|
|
|
158
145
|
expect(useChatThreadStore.getState().snapshot).toMatchObject({
|
|
159
146
|
workspacePanelParentKey: 'session-1',
|
|
160
147
|
activeWorkspacePanelKind: 'project-files',
|
|
161
|
-
workspaceNavigationHistory: [
|
|
162
|
-
{ kind: 'overview' },
|
|
163
|
-
{ kind: 'child-sessions' },
|
|
164
|
-
{ kind: 'project-files' },
|
|
165
|
-
],
|
|
148
|
+
workspaceNavigationHistory: [{ kind: 'overview' }, { kind: 'child-sessions' }, { kind: 'project-files' }],
|
|
166
149
|
workspaceNavigationHistoryIndex: 2,
|
|
150
|
+
workspaceExplorerWidth: 318,
|
|
167
151
|
workspacePanelWidth: 620,
|
|
168
152
|
});
|
|
169
153
|
});
|
|
@@ -182,9 +166,7 @@ describe('chat thread workspace panel persistence', () => {
|
|
|
182
166
|
activeWorkspacePanelKind: 'file',
|
|
183
167
|
workspaceFileTabs,
|
|
184
168
|
activeWorkspaceFileKey,
|
|
185
|
-
workspaceNavigationHistory: [
|
|
186
|
-
{ kind: 'file', key: activeWorkspaceFileKey },
|
|
187
|
-
],
|
|
169
|
+
workspaceNavigationHistory: [{ kind: 'file', key: activeWorkspaceFileKey }],
|
|
188
170
|
workspaceNavigationHistoryIndex: 0,
|
|
189
171
|
});
|
|
190
172
|
|
|
@@ -202,9 +184,7 @@ describe('chat thread workspace panel persistence', () => {
|
|
|
202
184
|
});
|
|
203
185
|
expect(useChatThreadStore.getState().snapshot.workspaceFileTabs).toHaveLength(8);
|
|
204
186
|
expect(
|
|
205
|
-
useChatThreadStore.getState().snapshot.workspaceFileTabs.some(
|
|
206
|
-
(tab) => tab.key === activeWorkspaceFileKey,
|
|
207
|
-
),
|
|
187
|
+
useChatThreadStore.getState().snapshot.workspaceFileTabs.some((tab) => tab.key === activeWorkspaceFileKey),
|
|
208
188
|
).toBe(true);
|
|
209
189
|
});
|
|
210
190
|
|
|
@@ -223,6 +203,7 @@ describe('chat thread workspace panel persistence', () => {
|
|
|
223
203
|
{ kind: 'file', key: 'session-1::preview::README.md' },
|
|
224
204
|
],
|
|
225
205
|
workspaceNavigationHistoryIndex: 1,
|
|
206
|
+
workspaceExplorerWidth: 999,
|
|
226
207
|
workspaceFileTabs: [
|
|
227
208
|
{
|
|
228
209
|
key: 'session-1::preview::README.md',
|
|
@@ -252,10 +233,9 @@ describe('chat thread workspace panel persistence', () => {
|
|
|
252
233
|
workspacePanelParentKey: 'session-1',
|
|
253
234
|
activeWorkspacePanelKind: 'file',
|
|
254
235
|
activeWorkspaceFileKey: 'session-1::preview::README.md',
|
|
236
|
+
workspaceExplorerWidth: 400,
|
|
255
237
|
activeChildSessionKey: 'child-session-1',
|
|
256
|
-
workspaceNavigationHistory: [
|
|
257
|
-
{ kind: 'file', key: 'session-1::preview::README.md' },
|
|
258
|
-
],
|
|
238
|
+
workspaceNavigationHistory: [{ kind: 'file', key: 'session-1::preview::README.md' }],
|
|
259
239
|
workspaceNavigationHistoryIndex: 0,
|
|
260
240
|
workspaceFileTabs: [
|
|
261
241
|
{
|