@nextclaw/ui 0.12.2 → 0.12.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/dist/assets/{ChannelsList-uKmkpD25.js → ChannelsList-CobWeI2V.js} +1 -1
- package/dist/assets/ChatPage-ZIdFFVAv.js +43 -0
- package/dist/assets/DocBrowser-D55C0iyl.js +1 -0
- package/dist/assets/{DocBrowser-C7-1sXqo.js → DocBrowser-NSzgVKka.js} +1 -1
- package/dist/assets/{DocBrowserContext-DN5tjUoS.js → DocBrowserContext-DpgVdRgk.js} +1 -1
- package/dist/assets/{LogoBadge-DDS1sU_U.js → LogoBadge-CHS4YNLw.js} +1 -1
- package/dist/assets/{MarketplacePage-DE0QjYVv.js → MarketplacePage-BFYsRss_.js} +1 -1
- package/dist/assets/MarketplacePage-DII-q-Y1.js +1 -0
- package/dist/assets/{McpMarketplacePage-CeLvv1xy.js → McpMarketplacePage-CPqsGJzz.js} +1 -1
- package/dist/assets/{ModelConfig-D1JtGtQv.js → ModelConfig-Bvuo_IpS.js} +1 -1
- package/dist/assets/{ProviderScopedModelInput-SAJH6nkC.js → ProviderScopedModelInput-BfY8rGsf.js} +1 -1
- package/dist/assets/{ProvidersList-1rKi3aQT.js → ProvidersList-3tlaqwSS.js} +1 -1
- package/dist/assets/{RemoteAccessPage-bIAKxDky.js → RemoteAccessPage-yfbrveNQ.js} +1 -1
- package/dist/assets/{RuntimeConfig-BTk9319O.js → RuntimeConfig-CAd5Kta3.js} +1 -1
- package/dist/assets/{SearchConfig-EjeszXbv.js → SearchConfig-DFwgaAa7.js} +1 -1
- package/dist/assets/{SecretsConfig-cnAXvREZ.js → SecretsConfig-CLFSSoTl.js} +1 -1
- package/dist/assets/{SessionsConfig-BIXiDaK2.js → SessionsConfig-vYrvc2Fk.js} +1 -1
- package/dist/assets/{book-open-DvWqOode.js → book-open-C7TAghTk.js} +1 -1
- package/dist/assets/{chat-session-display-D4bYa0b8.js → chat-session-display-5dVFkJyw.js} +1 -1
- package/dist/assets/{chunk-JZWAC4HX-CxfKRD7X.js → chunk-JZWAC4HX-DbL4EmiT.js} +1 -1
- package/dist/assets/{config-BeGwf2Ao.js → config-CMiW0yaK.js} +1 -1
- package/dist/assets/{createLucideIcon-C7MmdIX3.js → createLucideIcon-BRLFtf-8.js} +1 -1
- package/dist/assets/{dist-RWNFhxvR.js → dist-BFc_H-lY.js} +1 -1
- package/dist/assets/{dist-B6VMuIQN.js → dist-DP-JKR4G.js} +1 -1
- package/dist/assets/{external-link-U86Acd1t.js → external-link-BkJkiWbH.js} +1 -1
- package/dist/assets/{hash-D-OVfV3Z.js → hash-CbP6-6R9.js} +1 -1
- package/dist/assets/i18n-C_2dKw6w.js +1 -0
- package/dist/assets/index-ChUXhq0G.css +1 -0
- package/dist/assets/{index-8XNPYwJu.js → index-DAE8Srx-.js} +3 -3
- package/dist/assets/{label-CHJ1ATds.js → label-D8yyejJS.js} +1 -1
- package/dist/assets/loader-circle-B0sKKO29.js +1 -0
- package/dist/assets/{logos-U1_qDA3U.js → logos-N3dbS6-I.js} +1 -1
- package/dist/assets/{page-layout-Z1klaUFW.js → page-layout-DyuvlNrg.js} +1 -1
- package/dist/assets/plus-CYXs3JtZ.js +1 -0
- package/dist/assets/{popover-xWbqMnIN.js → popover-BKKWGUaG.js} +1 -1
- package/dist/assets/{react-3YE87-lE.js → react-8EIEQjMP.js} +1 -1
- package/dist/assets/{refresh-ccw-JQh1lwq-.js → refresh-ccw-BGMdiNGq.js} +1 -1
- package/dist/assets/{save-4VRlzkii.js → save-Dh4GQzzX.js} +1 -1
- package/dist/assets/search-DOsLw-P9.js +1 -0
- package/dist/assets/{security-config-CGazBahs.js → security-config-CM_tQRXQ.js} +1 -1
- package/dist/assets/{select-DF-AUoie.js → select-BtIi5fnh.js} +1 -1
- package/dist/assets/skeleton-GbHLjPC0.js +1 -0
- package/dist/assets/{status-dot-Bq_8Ojvv.js → status-dot-C4O-2jZP.js} +1 -1
- package/dist/assets/{switch-D7JF_RZ-.js → switch-DPegGIa_.js} +1 -1
- package/dist/assets/{tabs-custom-CLksZ2bO.js → tabs-custom-x5GZexrF.js} +1 -1
- package/dist/assets/{trash-2-VV8jvziy.js → trash-2-CU3LYIpQ.js} +1 -1
- package/dist/assets/{useConfirmDialog-D6HxybcM.js → useConfirmDialog-S5WsGOGf.js} +1 -1
- package/dist/assets/{useMutation-DBTWPbTg.js → useMutation-DSinpgEq.js} +1 -1
- package/dist/assets/x-Bnco_K8b.js +1 -0
- package/dist/index.html +18 -18
- package/package.json +5 -5
- package/src/components/agents/AgentsPage.test.tsx +37 -1
- package/src/components/agents/AgentsPage.tsx +10 -3
- package/src/components/chat/ChatConversationPanel.test.tsx +69 -3
- package/src/components/chat/ChatConversationPanel.tsx +24 -3
- package/src/components/chat/ChatSidebar.test.tsx +168 -28
- package/src/components/chat/ChatSidebar.tsx +103 -28
- package/src/components/chat/chat-sidebar-list-mode-switch.tsx +43 -0
- package/src/components/chat/chat-sidebar-project-groups.tsx +152 -0
- package/src/components/chat/managers/chat-session-list.manager.test.ts +34 -3
- package/src/components/chat/managers/chat-session-list.manager.ts +14 -2
- package/src/components/chat/ncp/NcpChatPage.tsx +18 -4
- package/src/components/chat/session-header/chat-session-project-badge.test.tsx +16 -0
- package/src/components/chat/session-header/chat-session-project-badge.tsx +2 -2
- package/src/components/chat/stores/chat-session-list.store.ts +6 -1
- package/src/components/chat/useChatSessionTypeState.ts +9 -1
- package/src/lib/i18n.chat.ts +3 -0
- package/dist/assets/ChatPage-CslhBPfT.js +0 -43
- package/dist/assets/DocBrowser-DQjtSsY3.js +0 -1
- package/dist/assets/MarketplacePage-BZQW70ti.js +0 -1
- package/dist/assets/i18n-hM3v-3YG.js +0 -1
- package/dist/assets/index-CpxuJa9o.css +0 -1
- package/dist/assets/loader-circle-C8cpaL0w.js +0 -1
- package/dist/assets/plus-CrkO1kob.js +0 -1
- package/dist/assets/search-EX-Papzl.js +0 -1
- package/dist/assets/skeleton-B0mmt1vo.js +0 -1
- package/dist/assets/x-B4sxJkGY.js +0 -1
|
@@ -3,6 +3,7 @@ import { useChatInputStore } from '@/components/chat/stores/chat-input.store';
|
|
|
3
3
|
import type { ChatUiManager } from '@/components/chat/managers/chat-ui.manager';
|
|
4
4
|
import type { SetStateAction } from 'react';
|
|
5
5
|
import type { ChatStreamActionsManager } from '@/components/chat/managers/chat-stream-actions.manager';
|
|
6
|
+
import { normalizeSessionProjectRootValue } from '@/lib/session-project/session-project.utils';
|
|
6
7
|
|
|
7
8
|
export class ChatSessionListManager {
|
|
8
9
|
constructor(
|
|
@@ -35,7 +36,16 @@ export class ChatSessionListManager {
|
|
|
35
36
|
useChatSessionListStore.getState().setSnapshot({ selectedSessionKey: value });
|
|
36
37
|
};
|
|
37
38
|
|
|
38
|
-
|
|
39
|
+
setListMode = (next: SetStateAction<'time-first' | 'project-first'>) => {
|
|
40
|
+
const prev = useChatSessionListStore.getState().snapshot.listMode;
|
|
41
|
+
const value = this.resolveUpdateValue(prev, next);
|
|
42
|
+
if (value === prev) {
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
useChatSessionListStore.getState().setSnapshot({ listMode: value });
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
createSession = (sessionType?: string, projectRoot?: string | null) => {
|
|
39
49
|
const { snapshot } = useChatInputStore.getState();
|
|
40
50
|
const { defaultSessionType: configuredDefaultSessionType } = snapshot;
|
|
41
51
|
const defaultSessionType = configuredDefaultSessionType || 'native';
|
|
@@ -43,10 +53,12 @@ export class ChatSessionListManager {
|
|
|
43
53
|
typeof sessionType === 'string' && sessionType.trim().length > 0
|
|
44
54
|
? sessionType.trim()
|
|
45
55
|
: defaultSessionType;
|
|
56
|
+
const normalizedProjectRoot = normalizeSessionProjectRootValue(projectRoot);
|
|
46
57
|
this.streamActionsManager.resetStreamState();
|
|
58
|
+
useChatSessionListStore.getState().setSnapshot({ selectedSessionKey: null });
|
|
47
59
|
useChatInputStore.getState().setSnapshot({
|
|
48
60
|
pendingSessionType: nextSessionType,
|
|
49
|
-
pendingProjectRoot:
|
|
61
|
+
pendingProjectRoot: normalizedProjectRoot,
|
|
50
62
|
pendingProjectRootSessionKey: null
|
|
51
63
|
});
|
|
52
64
|
this.uiManager.goToChatRoot();
|
|
@@ -131,8 +131,13 @@ export function NcpChatPage({ view }: ChatPageProps) {
|
|
|
131
131
|
[routeSessionIdParam],
|
|
132
132
|
);
|
|
133
133
|
const sessionKey = selectedSessionKey ?? draftSessionId;
|
|
134
|
+
const hasDraftProjectRootOverride =
|
|
135
|
+
pendingProjectRoot !== null &&
|
|
136
|
+
pendingProjectRootSessionKey === null &&
|
|
137
|
+
selectedSessionKey === null;
|
|
134
138
|
const hasSessionProjectRootOverride =
|
|
135
|
-
|
|
139
|
+
pendingProjectRoot !== null &&
|
|
140
|
+
(pendingProjectRootSessionKey === sessionKey || hasDraftProjectRootOverride);
|
|
136
141
|
const sessionProjectRootOverride = hasSessionProjectRootOverride
|
|
137
142
|
? pendingProjectRoot
|
|
138
143
|
: undefined;
|
|
@@ -210,7 +215,10 @@ export function NcpChatPage({ view }: ChatPageProps) {
|
|
|
210
215
|
thinkingLevel: payload.thinkingLevel,
|
|
211
216
|
sessionType: payload.sessionType,
|
|
212
217
|
projectRoot:
|
|
213
|
-
payload.sessionKey === pendingProjectRootSessionKey
|
|
218
|
+
payload.sessionKey === pendingProjectRootSessionKey ||
|
|
219
|
+
(pendingProjectRoot !== null &&
|
|
220
|
+
pendingProjectRootSessionKey === null &&
|
|
221
|
+
selectedSessionKey === null)
|
|
214
222
|
? pendingProjectRoot
|
|
215
223
|
: (selectedSession?.projectRoot ?? null),
|
|
216
224
|
requestedSkills: payload.requestedSkills,
|
|
@@ -265,14 +273,20 @@ export function NcpChatPage({ view }: ChatPageProps) {
|
|
|
265
273
|
pendingProjectRoot,
|
|
266
274
|
pendingProjectRootSessionKey,
|
|
267
275
|
presenter,
|
|
276
|
+
selectedSessionKey,
|
|
268
277
|
selectedSession?.projectRoot,
|
|
269
278
|
sessionKey,
|
|
270
279
|
]);
|
|
271
280
|
|
|
272
281
|
useEffect(() => {
|
|
282
|
+
const matchesPendingProjectSession =
|
|
283
|
+
pendingProjectRootSessionKey === null
|
|
284
|
+
? selectedSessionKey !== null
|
|
285
|
+
: pendingProjectRootSessionKey === selectedSession?.key;
|
|
273
286
|
if (
|
|
274
287
|
!selectedSession ||
|
|
275
|
-
|
|
288
|
+
pendingProjectRoot === null ||
|
|
289
|
+
!matchesPendingProjectSession ||
|
|
276
290
|
(selectedSession.projectRoot ?? null) !== pendingProjectRoot
|
|
277
291
|
) {
|
|
278
292
|
return;
|
|
@@ -281,7 +295,7 @@ export function NcpChatPage({ view }: ChatPageProps) {
|
|
|
281
295
|
pendingProjectRoot: null,
|
|
282
296
|
pendingProjectRootSessionKey: null,
|
|
283
297
|
});
|
|
284
|
-
}, [pendingProjectRoot, pendingProjectRootSessionKey, selectedSession]);
|
|
298
|
+
}, [pendingProjectRoot, pendingProjectRootSessionKey, selectedSession, selectedSessionKey]);
|
|
285
299
|
|
|
286
300
|
useChatSessionSync({
|
|
287
301
|
view,
|
|
@@ -40,6 +40,22 @@ describe('ChatSessionProjectBadge', () => {
|
|
|
40
40
|
expect(screen.getByText('/tmp/project-alpha')).toBeTruthy();
|
|
41
41
|
});
|
|
42
42
|
|
|
43
|
+
it('uses the neutral header tag styling instead of a highlighted accent color', () => {
|
|
44
|
+
render(
|
|
45
|
+
<ChatSessionProjectBadge
|
|
46
|
+
sessionKey="session-1"
|
|
47
|
+
projectName="project-alpha"
|
|
48
|
+
projectRoot="/tmp/project-alpha"
|
|
49
|
+
persistToServer
|
|
50
|
+
/>
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
const trigger = screen.getByRole('button', { name: 'Set Project Directory' });
|
|
54
|
+
expect(trigger.className).toContain('border-gray-200');
|
|
55
|
+
expect(trigger.className).toContain('text-gray-600');
|
|
56
|
+
expect(trigger.className).not.toContain('emerald');
|
|
57
|
+
});
|
|
58
|
+
|
|
43
59
|
it('clears the current project from the badge popover', async () => {
|
|
44
60
|
const user = userEvent.setup();
|
|
45
61
|
|
|
@@ -46,7 +46,7 @@ export function ChatSessionProjectBadge({
|
|
|
46
46
|
<button
|
|
47
47
|
type="button"
|
|
48
48
|
title={projectRoot ?? undefined}
|
|
49
|
-
className="min-w-0 max-w-[320px] shrink rounded-full border border-
|
|
49
|
+
className="min-w-0 max-w-[320px] shrink rounded-full border border-gray-200 bg-gray-100/90 px-2 py-0.5 text-[11px] font-medium text-gray-600 transition-colors hover:border-gray-300 hover:bg-gray-100 disabled:cursor-not-allowed disabled:opacity-60"
|
|
50
50
|
aria-label={t('chatSessionSetProject')}
|
|
51
51
|
disabled={isProjectPending}
|
|
52
52
|
>
|
|
@@ -59,7 +59,7 @@ export function ChatSessionProjectBadge({
|
|
|
59
59
|
</PopoverTrigger>
|
|
60
60
|
<PopoverContent align="start" className="w-72 p-2">
|
|
61
61
|
<div className="px-3 pb-2 pt-1">
|
|
62
|
-
<div className="text-[11px] font-medium uppercase tracking-wider text-
|
|
62
|
+
<div className="text-[11px] font-medium uppercase tracking-wider text-gray-500">
|
|
63
63
|
{projectName}
|
|
64
64
|
</div>
|
|
65
65
|
{projectRoot ? (
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import { create } from 'zustand';
|
|
2
|
+
|
|
3
|
+
export type ChatSessionListMode = 'time-first' | 'project-first';
|
|
4
|
+
|
|
2
5
|
export type ChatSessionListSnapshot = {
|
|
3
6
|
selectedSessionKey: string | null;
|
|
4
7
|
selectedAgentId: string;
|
|
5
8
|
query: string;
|
|
9
|
+
listMode: ChatSessionListMode;
|
|
6
10
|
};
|
|
7
11
|
|
|
8
12
|
type ChatSessionListStore = {
|
|
@@ -13,7 +17,8 @@ type ChatSessionListStore = {
|
|
|
13
17
|
const initialSnapshot: ChatSessionListSnapshot = {
|
|
14
18
|
selectedSessionKey: null,
|
|
15
19
|
selectedAgentId: 'main',
|
|
16
|
-
query: ''
|
|
20
|
+
query: '',
|
|
21
|
+
listMode: 'time-first'
|
|
17
22
|
};
|
|
18
23
|
|
|
19
24
|
export const useChatSessionListStore = create<ChatSessionListStore>((set) => ({
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { useEffect, useMemo, useRef } from 'react';
|
|
2
2
|
import type { Dispatch, SetStateAction } from 'react';
|
|
3
|
-
import type { ChatSessionTypeOptionView, SessionEntryView } from '@/api/types';
|
|
3
|
+
import type { AgentProfileView, ChatSessionTypeOptionView, SessionEntryView } from '@/api/types';
|
|
4
4
|
import { t } from '@/lib/i18n';
|
|
5
5
|
|
|
6
6
|
export const DEFAULT_SESSION_TYPE = 'native';
|
|
@@ -39,6 +39,14 @@ export function normalizeSessionType(value: unknown): string {
|
|
|
39
39
|
return normalized || DEFAULT_SESSION_TYPE;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
export function resolveAgentRuntimeSessionType(
|
|
43
|
+
agent: Pick<AgentProfileView, 'runtime' | 'engine'> | null | undefined,
|
|
44
|
+
fallbackSessionType: string = DEFAULT_SESSION_TYPE
|
|
45
|
+
): string {
|
|
46
|
+
const runtime = agent?.runtime?.trim() || agent?.engine?.trim() || fallbackSessionType;
|
|
47
|
+
return normalizeSessionType(runtime);
|
|
48
|
+
}
|
|
49
|
+
|
|
42
50
|
export function resolveSessionTypeLabel(sessionType: string, fallbackLabel?: string): string {
|
|
43
51
|
if (sessionType === 'native') {
|
|
44
52
|
return t('chatSessionTypeNative');
|
package/src/lib/i18n.chat.ts
CHANGED
|
@@ -125,10 +125,13 @@ export const CHAT_LABELS: Record<string, { zh: string; en: string }> = {
|
|
|
125
125
|
chatSidebarScheduledTasks: { zh: '定时任务', en: 'Scheduled Tasks' },
|
|
126
126
|
chatSidebarSkills: { zh: '技能', en: 'Skills' },
|
|
127
127
|
chatSidebarTaskRecords: { zh: '会话记录', en: 'Sessions' },
|
|
128
|
+
chatSidebarViewTime: { zh: '时间', en: 'Time' },
|
|
129
|
+
chatSidebarViewProject: { zh: '项目', en: 'Project' },
|
|
128
130
|
chatSidebarToday: { zh: '今天', en: 'Today' },
|
|
129
131
|
chatSidebarYesterday: { zh: '昨天', en: 'Yesterday' },
|
|
130
132
|
chatSidebarPrevious7Days: { zh: '近 7 天', en: 'Previous 7 Days' },
|
|
131
133
|
chatSidebarOlder: { zh: '更早', en: 'Older' },
|
|
134
|
+
chatSidebarProjectViewEmpty: { zh: '还没有绑定项目的会话', en: 'No project conversations yet' },
|
|
132
135
|
chatWelcomeTitle: { zh: '你好,有什么可以帮你的吗?', en: 'Hello, how can I help you?' },
|
|
133
136
|
chatWelcomeSubtitle: { zh: '开始一个新任务或选择已有对话', en: 'Start a new task or select an existing conversation' },
|
|
134
137
|
chatWelcomeCapability1Title: { zh: '智能对话', en: 'Smart Conversations' },
|