@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.
Files changed (78) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/dist/assets/{ChannelsList-uKmkpD25.js → ChannelsList-CobWeI2V.js} +1 -1
  3. package/dist/assets/ChatPage-ZIdFFVAv.js +43 -0
  4. package/dist/assets/DocBrowser-D55C0iyl.js +1 -0
  5. package/dist/assets/{DocBrowser-C7-1sXqo.js → DocBrowser-NSzgVKka.js} +1 -1
  6. package/dist/assets/{DocBrowserContext-DN5tjUoS.js → DocBrowserContext-DpgVdRgk.js} +1 -1
  7. package/dist/assets/{LogoBadge-DDS1sU_U.js → LogoBadge-CHS4YNLw.js} +1 -1
  8. package/dist/assets/{MarketplacePage-DE0QjYVv.js → MarketplacePage-BFYsRss_.js} +1 -1
  9. package/dist/assets/MarketplacePage-DII-q-Y1.js +1 -0
  10. package/dist/assets/{McpMarketplacePage-CeLvv1xy.js → McpMarketplacePage-CPqsGJzz.js} +1 -1
  11. package/dist/assets/{ModelConfig-D1JtGtQv.js → ModelConfig-Bvuo_IpS.js} +1 -1
  12. package/dist/assets/{ProviderScopedModelInput-SAJH6nkC.js → ProviderScopedModelInput-BfY8rGsf.js} +1 -1
  13. package/dist/assets/{ProvidersList-1rKi3aQT.js → ProvidersList-3tlaqwSS.js} +1 -1
  14. package/dist/assets/{RemoteAccessPage-bIAKxDky.js → RemoteAccessPage-yfbrveNQ.js} +1 -1
  15. package/dist/assets/{RuntimeConfig-BTk9319O.js → RuntimeConfig-CAd5Kta3.js} +1 -1
  16. package/dist/assets/{SearchConfig-EjeszXbv.js → SearchConfig-DFwgaAa7.js} +1 -1
  17. package/dist/assets/{SecretsConfig-cnAXvREZ.js → SecretsConfig-CLFSSoTl.js} +1 -1
  18. package/dist/assets/{SessionsConfig-BIXiDaK2.js → SessionsConfig-vYrvc2Fk.js} +1 -1
  19. package/dist/assets/{book-open-DvWqOode.js → book-open-C7TAghTk.js} +1 -1
  20. package/dist/assets/{chat-session-display-D4bYa0b8.js → chat-session-display-5dVFkJyw.js} +1 -1
  21. package/dist/assets/{chunk-JZWAC4HX-CxfKRD7X.js → chunk-JZWAC4HX-DbL4EmiT.js} +1 -1
  22. package/dist/assets/{config-BeGwf2Ao.js → config-CMiW0yaK.js} +1 -1
  23. package/dist/assets/{createLucideIcon-C7MmdIX3.js → createLucideIcon-BRLFtf-8.js} +1 -1
  24. package/dist/assets/{dist-RWNFhxvR.js → dist-BFc_H-lY.js} +1 -1
  25. package/dist/assets/{dist-B6VMuIQN.js → dist-DP-JKR4G.js} +1 -1
  26. package/dist/assets/{external-link-U86Acd1t.js → external-link-BkJkiWbH.js} +1 -1
  27. package/dist/assets/{hash-D-OVfV3Z.js → hash-CbP6-6R9.js} +1 -1
  28. package/dist/assets/i18n-C_2dKw6w.js +1 -0
  29. package/dist/assets/index-ChUXhq0G.css +1 -0
  30. package/dist/assets/{index-8XNPYwJu.js → index-DAE8Srx-.js} +3 -3
  31. package/dist/assets/{label-CHJ1ATds.js → label-D8yyejJS.js} +1 -1
  32. package/dist/assets/loader-circle-B0sKKO29.js +1 -0
  33. package/dist/assets/{logos-U1_qDA3U.js → logos-N3dbS6-I.js} +1 -1
  34. package/dist/assets/{page-layout-Z1klaUFW.js → page-layout-DyuvlNrg.js} +1 -1
  35. package/dist/assets/plus-CYXs3JtZ.js +1 -0
  36. package/dist/assets/{popover-xWbqMnIN.js → popover-BKKWGUaG.js} +1 -1
  37. package/dist/assets/{react-3YE87-lE.js → react-8EIEQjMP.js} +1 -1
  38. package/dist/assets/{refresh-ccw-JQh1lwq-.js → refresh-ccw-BGMdiNGq.js} +1 -1
  39. package/dist/assets/{save-4VRlzkii.js → save-Dh4GQzzX.js} +1 -1
  40. package/dist/assets/search-DOsLw-P9.js +1 -0
  41. package/dist/assets/{security-config-CGazBahs.js → security-config-CM_tQRXQ.js} +1 -1
  42. package/dist/assets/{select-DF-AUoie.js → select-BtIi5fnh.js} +1 -1
  43. package/dist/assets/skeleton-GbHLjPC0.js +1 -0
  44. package/dist/assets/{status-dot-Bq_8Ojvv.js → status-dot-C4O-2jZP.js} +1 -1
  45. package/dist/assets/{switch-D7JF_RZ-.js → switch-DPegGIa_.js} +1 -1
  46. package/dist/assets/{tabs-custom-CLksZ2bO.js → tabs-custom-x5GZexrF.js} +1 -1
  47. package/dist/assets/{trash-2-VV8jvziy.js → trash-2-CU3LYIpQ.js} +1 -1
  48. package/dist/assets/{useConfirmDialog-D6HxybcM.js → useConfirmDialog-S5WsGOGf.js} +1 -1
  49. package/dist/assets/{useMutation-DBTWPbTg.js → useMutation-DSinpgEq.js} +1 -1
  50. package/dist/assets/x-Bnco_K8b.js +1 -0
  51. package/dist/index.html +18 -18
  52. package/package.json +5 -5
  53. package/src/components/agents/AgentsPage.test.tsx +37 -1
  54. package/src/components/agents/AgentsPage.tsx +10 -3
  55. package/src/components/chat/ChatConversationPanel.test.tsx +69 -3
  56. package/src/components/chat/ChatConversationPanel.tsx +24 -3
  57. package/src/components/chat/ChatSidebar.test.tsx +168 -28
  58. package/src/components/chat/ChatSidebar.tsx +103 -28
  59. package/src/components/chat/chat-sidebar-list-mode-switch.tsx +43 -0
  60. package/src/components/chat/chat-sidebar-project-groups.tsx +152 -0
  61. package/src/components/chat/managers/chat-session-list.manager.test.ts +34 -3
  62. package/src/components/chat/managers/chat-session-list.manager.ts +14 -2
  63. package/src/components/chat/ncp/NcpChatPage.tsx +18 -4
  64. package/src/components/chat/session-header/chat-session-project-badge.test.tsx +16 -0
  65. package/src/components/chat/session-header/chat-session-project-badge.tsx +2 -2
  66. package/src/components/chat/stores/chat-session-list.store.ts +6 -1
  67. package/src/components/chat/useChatSessionTypeState.ts +9 -1
  68. package/src/lib/i18n.chat.ts +3 -0
  69. package/dist/assets/ChatPage-CslhBPfT.js +0 -43
  70. package/dist/assets/DocBrowser-DQjtSsY3.js +0 -1
  71. package/dist/assets/MarketplacePage-BZQW70ti.js +0 -1
  72. package/dist/assets/i18n-hM3v-3YG.js +0 -1
  73. package/dist/assets/index-CpxuJa9o.css +0 -1
  74. package/dist/assets/loader-circle-C8cpaL0w.js +0 -1
  75. package/dist/assets/plus-CrkO1kob.js +0 -1
  76. package/dist/assets/search-EX-Papzl.js +0 -1
  77. package/dist/assets/skeleton-B0mmt1vo.js +0 -1
  78. 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
- createSession = (sessionType?: string) => {
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: null,
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
- pendingProjectRootSessionKey === sessionKey;
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
- pendingProjectRootSessionKey !== selectedSession.key ||
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-emerald-200 bg-emerald-50 px-2 py-0.5 text-[11px] font-medium text-emerald-700 transition-colors hover:border-emerald-300 hover:bg-emerald-100 disabled:cursor-not-allowed disabled:opacity-60"
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-emerald-700/80">
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');
@@ -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' },