@nextclaw/ui 0.7.0 → 0.9.0
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 +30 -0
- package/dist/assets/ChannelsList-C7F_As4r.js +1 -0
- package/dist/assets/ChatPage-Oo7-OUsx.js +37 -0
- package/dist/assets/{DocBrowser-B9ws5JL7.js → DocBrowser-Dsd8Dlq8.js} +1 -1
- package/dist/assets/{LogoBadge-DvGAzkZ3.js → LogoBadge-2ChEc_oz.js} +1 -1
- package/dist/assets/MarketplacePage-BXck6-X3.js +49 -0
- package/dist/assets/{ModelConfig-BL_HsOsm.js → ModelConfig-CgHRSD0b.js} +1 -1
- package/dist/assets/ProvidersList-PPfZucvS.js +1 -0
- package/dist/assets/RuntimeConfig-ClLEKNTN.js +1 -0
- package/dist/assets/{SearchConfig-BhaI0fUf.js → SearchConfig-CuXVCbrf.js} +1 -1
- package/dist/assets/{SecretsConfig-CFoimOh9.js → SecretsConfig-udJz6Ake.js} +2 -2
- package/dist/assets/SessionsConfig-C1XnFfiC.js +2 -0
- package/dist/assets/{session-run-status-TkIuGbVw.js → chat-message-BETwXLD4.js} +3 -3
- package/dist/assets/{index-uMsNsQX6.js → index-COJdlL0e.js} +1 -1
- package/dist/assets/index-CsvP4CER.js +8 -0
- package/dist/assets/index-D-bXl7qL.css +1 -0
- package/dist/assets/{label-D8ly4a2P.js → label-BGL-ztxh.js} +1 -1
- package/dist/assets/{page-layout-BSYfvwbp.js → page-layout-aw88k7tG.js} +1 -1
- package/dist/assets/popover-DyEvzhmV.js +1 -0
- package/dist/assets/security-config-BuPAQn82.js +1 -0
- package/dist/assets/skeleton-drzO_tdU.js +1 -0
- package/dist/assets/{switch-Ce_g9lpN.js → switch-BK8jIzto.js} +1 -1
- package/dist/assets/{tabs-custom-Cf5azvT5.js → tabs-custom-Da3cEOji.js} +1 -1
- package/dist/assets/{useConfirmDialog-A8Ek8Wu7.js → useConfirmDialog-z0CE92iS.js} +2 -2
- package/dist/assets/{vendor-B7ozqnFC.js → vendor-CkJHmX1g.js} +65 -70
- package/dist/index.html +3 -3
- package/package.json +5 -2
- package/src/api/config.ts +9 -0
- package/src/api/ncp-session.ts +50 -0
- package/src/api/types.ts +20 -0
- package/src/components/chat/ChatConversationPanel.test.tsx +65 -0
- package/src/components/chat/ChatConversationPanel.tsx +21 -12
- package/src/components/chat/ChatPage.tsx +10 -324
- package/src/components/chat/ChatSidebar.test.tsx +203 -0
- package/src/components/chat/ChatSidebar.tsx +97 -7
- package/src/components/chat/adapters/chat-message.adapter.test.ts +132 -81
- package/src/components/chat/adapters/chat-message.adapter.ts +27 -9
- package/src/components/chat/chat-chain.test.ts +22 -0
- package/src/components/chat/chat-chain.ts +23 -0
- package/src/components/chat/chat-page-data.ts +30 -1
- package/src/components/chat/chat-page-runtime.test.ts +181 -0
- package/src/components/chat/chat-page-runtime.ts +101 -15
- package/src/components/chat/chat-page-shell.tsx +103 -0
- package/src/components/chat/chat-session-preference-sync.test.ts +62 -0
- package/src/components/chat/chat-session-preference-sync.ts +75 -0
- package/src/components/chat/containers/chat-input-bar.container.tsx +0 -22
- package/src/components/chat/containers/chat-message-list.container.tsx +34 -26
- package/src/components/chat/legacy/LegacyChatPage.tsx +252 -0
- package/src/components/chat/managers/chat-input.manager.ts +5 -0
- package/src/components/chat/managers/chat-session-list.manager.test.ts +39 -0
- package/src/components/chat/managers/chat-session-list.manager.ts +9 -3
- package/src/components/chat/ncp/NcpChatPage.tsx +381 -0
- package/src/components/chat/ncp/ncp-chat-input.manager.ts +179 -0
- package/src/components/chat/ncp/ncp-chat-page-data.ts +166 -0
- package/src/components/chat/ncp/ncp-chat-thread.manager.ts +89 -0
- package/src/components/chat/ncp/ncp-chat.presenter.ts +33 -0
- package/src/components/chat/ncp/ncp-session-adapter.test.ts +75 -0
- package/src/components/chat/ncp/ncp-session-adapter.ts +214 -0
- package/src/components/chat/presenter/chat-presenter-context.tsx +43 -4
- package/src/components/chat/stores/chat-thread.store.ts +2 -0
- package/src/components/chat/useChatSessionTypeState.test.tsx +58 -0
- package/src/components/chat/useChatSessionTypeState.ts +25 -8
- package/src/hooks/use-ncp-chat-session-types.ts +11 -0
- package/src/hooks/useConfig.ts +41 -1
- package/src/hooks/useMarketplace.ts +7 -4
- package/src/hooks/useWebSocket.ts +23 -2
- package/src/lib/i18n.ts +1 -1
- package/tailwind.config.js +8 -3
- package/tsconfig.json +4 -1
- package/dist/assets/ChannelsList-DF2U-LY1.js +0 -1
- package/dist/assets/ChatPage-BX39y0U5.js +0 -36
- package/dist/assets/MarketplacePage-DG5mHWJ8.js +0 -49
- package/dist/assets/ProvidersList-CH5z00YT.js +0 -1
- package/dist/assets/RuntimeConfig-BplBgkwo.js +0 -1
- package/dist/assets/SessionsConfig-BHTAYn9T.js +0 -2
- package/dist/assets/index-BLeJkJ0o.css +0 -1
- package/dist/assets/index-DK4TS5ev.js +0 -8
- package/dist/assets/index-X5J6Mm--.js +0 -1
- package/dist/assets/security-config-DlKEYHNN.js +0 -1
- package/dist/assets/skeleton-CWbsNx2h.js +0 -1
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { renderHook } from '@testing-library/react';
|
|
2
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
3
|
+
import { resolveSessionTypeLabel, useChatSessionTypeState } from '@/components/chat/useChatSessionTypeState';
|
|
4
|
+
|
|
5
|
+
vi.mock('@/lib/i18n', () => ({
|
|
6
|
+
t: (key: string) => key
|
|
7
|
+
}));
|
|
8
|
+
|
|
9
|
+
describe('useChatSessionTypeState', () => {
|
|
10
|
+
it('formats non-native runtime labels generically when no explicit label is provided', () => {
|
|
11
|
+
expect(resolveSessionTypeLabel('workspace-agent')).toBe('Workspace Agent');
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('preserves an explicitly selected draft session type instead of resetting to the default', () => {
|
|
15
|
+
const setPendingSessionType = vi.fn();
|
|
16
|
+
|
|
17
|
+
const { result } = renderHook(() =>
|
|
18
|
+
useChatSessionTypeState({
|
|
19
|
+
selectedSession: null,
|
|
20
|
+
selectedSessionKey: null,
|
|
21
|
+
pendingSessionType: 'codex-sdk',
|
|
22
|
+
setPendingSessionType,
|
|
23
|
+
sessionTypesData: {
|
|
24
|
+
defaultType: 'native',
|
|
25
|
+
options: [
|
|
26
|
+
{ value: 'native', label: 'Native' },
|
|
27
|
+
{ value: 'codex-sdk', label: 'Codex' }
|
|
28
|
+
]
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
expect(result.current.selectedSessionType).toBe('codex-sdk');
|
|
34
|
+
expect(setPendingSessionType).not.toHaveBeenCalled();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('hydrates the draft session type from the runtime default when no explicit type exists', () => {
|
|
38
|
+
const setPendingSessionType = vi.fn();
|
|
39
|
+
|
|
40
|
+
renderHook(() =>
|
|
41
|
+
useChatSessionTypeState({
|
|
42
|
+
selectedSession: null,
|
|
43
|
+
selectedSessionKey: null,
|
|
44
|
+
pendingSessionType: '',
|
|
45
|
+
setPendingSessionType,
|
|
46
|
+
sessionTypesData: {
|
|
47
|
+
defaultType: 'codex-sdk',
|
|
48
|
+
options: [
|
|
49
|
+
{ value: 'native', label: 'Native' },
|
|
50
|
+
{ value: 'codex-sdk', label: 'Codex' }
|
|
51
|
+
]
|
|
52
|
+
}
|
|
53
|
+
})
|
|
54
|
+
);
|
|
55
|
+
|
|
56
|
+
expect(setPendingSessionType).toHaveBeenCalledWith('codex-sdk');
|
|
57
|
+
});
|
|
58
|
+
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { useEffect, useMemo } from 'react';
|
|
1
|
+
import { useEffect, useMemo, useRef } from 'react';
|
|
2
2
|
import type { Dispatch, SetStateAction } from 'react';
|
|
3
3
|
import type { SessionEntryView } from '@/api/types';
|
|
4
4
|
import { t } from '@/lib/i18n';
|
|
@@ -33,13 +33,16 @@ export function resolveSessionTypeLabel(sessionType: string, fallbackLabel?: str
|
|
|
33
33
|
if (sessionType === 'native') {
|
|
34
34
|
return t('chatSessionTypeNative');
|
|
35
35
|
}
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
const normalizedFallback = fallbackLabel?.trim();
|
|
37
|
+
if (normalizedFallback) {
|
|
38
|
+
return normalizedFallback;
|
|
38
39
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
40
|
+
return sessionType
|
|
41
|
+
.trim()
|
|
42
|
+
.split(/[-_]+/g)
|
|
43
|
+
.filter(Boolean)
|
|
44
|
+
.map((part) => part.charAt(0).toUpperCase() + part.slice(1))
|
|
45
|
+
.join(' ') || sessionType;
|
|
43
46
|
}
|
|
44
47
|
|
|
45
48
|
function buildSessionTypeOptions(
|
|
@@ -113,6 +116,7 @@ export function useChatSessionTypeState(params: UseChatSessionTypeStateParams):
|
|
|
113
116
|
() => normalizeSessionType(sessionTypesData?.defaultType ?? DEFAULT_SESSION_TYPE),
|
|
114
117
|
[sessionTypesData?.defaultType]
|
|
115
118
|
);
|
|
119
|
+
const lastAutoPendingSessionTypeRef = useRef<string | null>(null);
|
|
116
120
|
const selectedSessionType = useMemo(
|
|
117
121
|
() => normalizeSessionType(selectedSession?.sessionType ?? pendingSessionType ?? defaultSessionType),
|
|
118
122
|
[defaultSessionType, pendingSessionType, selectedSession?.sessionType]
|
|
@@ -122,8 +126,21 @@ export function useChatSessionTypeState(params: UseChatSessionTypeStateParams):
|
|
|
122
126
|
if (selectedSessionKey) {
|
|
123
127
|
return;
|
|
124
128
|
}
|
|
129
|
+
const rawPending = typeof pendingSessionType === 'string' ? pendingSessionType.trim() : '';
|
|
130
|
+
const normalizedPending = normalizeSessionType(pendingSessionType);
|
|
131
|
+
const shouldFollowDefault =
|
|
132
|
+
rawPending.length === 0 ||
|
|
133
|
+
lastAutoPendingSessionTypeRef.current === normalizedPending ||
|
|
134
|
+
(lastAutoPendingSessionTypeRef.current === null && normalizedPending === DEFAULT_SESSION_TYPE);
|
|
135
|
+
if (!shouldFollowDefault) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
lastAutoPendingSessionTypeRef.current = defaultSessionType;
|
|
139
|
+
if (normalizedPending === defaultSessionType) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
125
142
|
setPendingSessionType(defaultSessionType);
|
|
126
|
-
}, [defaultSessionType, selectedSessionKey, setPendingSessionType]);
|
|
143
|
+
}, [defaultSessionType, pendingSessionType, selectedSessionKey, setPendingSessionType]);
|
|
127
144
|
|
|
128
145
|
const canEditSessionType = !selectedSessionKey || Boolean(selectedSession?.sessionTypeMutable);
|
|
129
146
|
const availableSessionTypeSet = useMemo(
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { useQuery } from '@tanstack/react-query';
|
|
2
|
+
import { fetchNcpChatSessionTypes } from '@/api/config';
|
|
3
|
+
|
|
4
|
+
export function useNcpChatSessionTypes() {
|
|
5
|
+
return useQuery({
|
|
6
|
+
queryKey: ['ncp-session-types'],
|
|
7
|
+
queryFn: fetchNcpChatSessionTypes,
|
|
8
|
+
staleTime: 10_000,
|
|
9
|
+
retry: false
|
|
10
|
+
});
|
|
11
|
+
}
|
package/src/hooks/useConfig.ts
CHANGED
|
@@ -31,6 +31,7 @@ import {
|
|
|
31
31
|
setCronJobEnabled,
|
|
32
32
|
runCronJob
|
|
33
33
|
} from '@/api/config';
|
|
34
|
+
import { deleteNcpSession, fetchNcpSessionMessages, fetchNcpSessions } from '@/api/ncp-session';
|
|
34
35
|
import { toast } from 'sonner';
|
|
35
36
|
import { t } from '@/lib/i18n';
|
|
36
37
|
|
|
@@ -252,6 +253,29 @@ export function useSessionHistory(key: string | null, limit = 200) {
|
|
|
252
253
|
});
|
|
253
254
|
}
|
|
254
255
|
|
|
256
|
+
export function useNcpSessions(params?: { limit?: number }) {
|
|
257
|
+
return useQuery({
|
|
258
|
+
queryKey: ['ncp-sessions', params?.limit ?? null],
|
|
259
|
+
queryFn: () => fetchNcpSessions(params),
|
|
260
|
+
staleTime: 5_000,
|
|
261
|
+
retry: false,
|
|
262
|
+
refetchInterval: (query) => {
|
|
263
|
+
const hasRunningSession = Boolean(query.state.data?.sessions.some((session) => session.status === 'running'));
|
|
264
|
+
return hasRunningSession ? 800 : false;
|
|
265
|
+
}
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export function useNcpSessionMessages(sessionId: string | null, limit = 200) {
|
|
270
|
+
return useQuery({
|
|
271
|
+
queryKey: ['ncp-session-messages', sessionId, limit],
|
|
272
|
+
queryFn: () => fetchNcpSessionMessages(sessionId as string, limit),
|
|
273
|
+
enabled: Boolean(sessionId),
|
|
274
|
+
staleTime: 5_000,
|
|
275
|
+
retry: false
|
|
276
|
+
});
|
|
277
|
+
}
|
|
278
|
+
|
|
255
279
|
export function useUpdateSession() {
|
|
256
280
|
const queryClient = useQueryClient();
|
|
257
281
|
|
|
@@ -285,6 +309,22 @@ export function useDeleteSession() {
|
|
|
285
309
|
});
|
|
286
310
|
}
|
|
287
311
|
|
|
312
|
+
export function useDeleteNcpSession() {
|
|
313
|
+
const queryClient = useQueryClient();
|
|
314
|
+
|
|
315
|
+
return useMutation({
|
|
316
|
+
mutationFn: ({ sessionId }: { sessionId: string }) => deleteNcpSession(sessionId),
|
|
317
|
+
onSuccess: () => {
|
|
318
|
+
queryClient.invalidateQueries({ queryKey: ['ncp-sessions'] });
|
|
319
|
+
queryClient.invalidateQueries({ queryKey: ['ncp-session-messages'] });
|
|
320
|
+
toast.success(t('configSavedApplied'));
|
|
321
|
+
},
|
|
322
|
+
onError: (error: Error) => {
|
|
323
|
+
toast.error(t('configSaveFailed') + ': ' + error.message);
|
|
324
|
+
}
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
|
|
288
328
|
export function useSendChatTurn() {
|
|
289
329
|
return useMutation({
|
|
290
330
|
mutationFn: ({ data }: { data: Parameters<typeof sendChatTurn>[0] }) =>
|
|
@@ -348,7 +388,7 @@ export function useChatRuns(params?: {
|
|
|
348
388
|
if (params?.isLocallyRunning) {
|
|
349
389
|
return 800;
|
|
350
390
|
}
|
|
351
|
-
const data = query.state
|
|
391
|
+
const { data } = query.state;
|
|
352
392
|
const hasActiveRuns = Array.isArray(data?.runs) && data.runs.length > 0;
|
|
353
393
|
return hasActiveRuns ? 800 : false;
|
|
354
394
|
},
|
|
@@ -61,8 +61,10 @@ export function useInstallMarketplaceItem() {
|
|
|
61
61
|
mutationFn: (request: MarketplaceInstallRequest) => installMarketplaceItem(request),
|
|
62
62
|
onSuccess: (result) => {
|
|
63
63
|
queryClient.invalidateQueries({ queryKey: ['marketplace-installed', result.type] });
|
|
64
|
-
queryClient.
|
|
65
|
-
|
|
64
|
+
queryClient.invalidateQueries({ queryKey: ['marketplace-items'] });
|
|
65
|
+
if (result.type === 'plugin') {
|
|
66
|
+
queryClient.invalidateQueries({ queryKey: ['ncp-session-types'] });
|
|
67
|
+
}
|
|
66
68
|
const fallback = result.type === 'plugin'
|
|
67
69
|
? t('marketplaceInstallSuccessPlugin')
|
|
68
70
|
: t('marketplaceInstallSuccessSkill');
|
|
@@ -82,8 +84,9 @@ export function useManageMarketplaceItem() {
|
|
|
82
84
|
onSuccess: (result) => {
|
|
83
85
|
queryClient.invalidateQueries({ queryKey: ['marketplace-installed', result.type] });
|
|
84
86
|
queryClient.invalidateQueries({ queryKey: ['marketplace-items'] });
|
|
85
|
-
|
|
86
|
-
|
|
87
|
+
if (result.type === 'plugin') {
|
|
88
|
+
queryClient.invalidateQueries({ queryKey: ['ncp-session-types'] });
|
|
89
|
+
}
|
|
87
90
|
const fallback = result.action === 'enable'
|
|
88
91
|
? t('marketplaceEnableSuccess')
|
|
89
92
|
: result.action === 'disable'
|
|
@@ -73,11 +73,25 @@ export function useWebSocket(queryClient?: QueryClient) {
|
|
|
73
73
|
return;
|
|
74
74
|
}
|
|
75
75
|
queryClient.invalidateQueries({ queryKey: ['sessions'] });
|
|
76
|
+
queryClient.invalidateQueries({ queryKey: ['ncp-sessions'] });
|
|
76
77
|
if (sessionKey && sessionKey.trim().length > 0) {
|
|
77
78
|
queryClient.invalidateQueries({ queryKey: ['session-history', sessionKey.trim()] });
|
|
79
|
+
queryClient.invalidateQueries({ queryKey: ['ncp-session-messages', sessionKey.trim()] });
|
|
78
80
|
return;
|
|
79
81
|
}
|
|
80
82
|
queryClient.invalidateQueries({ queryKey: ['session-history'] });
|
|
83
|
+
queryClient.invalidateQueries({ queryKey: ['ncp-session-messages'] });
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
const shouldInvalidateConfigQuery = (configPath: string) => {
|
|
87
|
+
const normalized = configPath.trim().toLowerCase();
|
|
88
|
+
if (!normalized) {
|
|
89
|
+
return true;
|
|
90
|
+
}
|
|
91
|
+
if (normalized.startsWith('plugins') || normalized.startsWith('skills')) {
|
|
92
|
+
return false;
|
|
93
|
+
}
|
|
94
|
+
return true;
|
|
81
95
|
};
|
|
82
96
|
|
|
83
97
|
setConnectionStatus('connecting');
|
|
@@ -98,13 +112,20 @@ export function useWebSocket(queryClient?: QueryClient) {
|
|
|
98
112
|
});
|
|
99
113
|
|
|
100
114
|
client.on('config.updated', (event) => {
|
|
115
|
+
const payload = event.payload as { path?: unknown } | undefined;
|
|
116
|
+
const configPath = typeof payload?.path === 'string' ? payload.path : '';
|
|
101
117
|
// Trigger refetch of config
|
|
102
|
-
if (queryClient) {
|
|
118
|
+
if (queryClient && shouldInvalidateConfigQuery(configPath)) {
|
|
103
119
|
queryClient.invalidateQueries({ queryKey: ['config'] });
|
|
104
120
|
}
|
|
105
|
-
if (
|
|
121
|
+
if (configPath.startsWith('session')) {
|
|
106
122
|
invalidateSessionQueries();
|
|
107
123
|
}
|
|
124
|
+
if (configPath.startsWith('plugins')) {
|
|
125
|
+
queryClient?.invalidateQueries({ queryKey: ['ncp-session-types'] });
|
|
126
|
+
queryClient?.invalidateQueries({ queryKey: ['marketplace-installed', 'plugin'] });
|
|
127
|
+
queryClient?.invalidateQueries({ queryKey: ['marketplace-items'] });
|
|
128
|
+
}
|
|
108
129
|
});
|
|
109
130
|
|
|
110
131
|
client.on('run.updated', (event) => {
|
package/src/lib/i18n.ts
CHANGED
|
@@ -670,7 +670,7 @@ export const LABELS: Record<string, { zh: string; en: string }> = {
|
|
|
670
670
|
chatToolWorkflowDetails: { zh: '展开查看参数和结果', en: 'Expand to view params and results' },
|
|
671
671
|
chatToolOutput: { zh: '查看输出', en: 'View Output' },
|
|
672
672
|
chatToolNoOutput: { zh: '无输出(执行完成)', en: 'No output (completed)' },
|
|
673
|
-
chatReasoning: { zh: '
|
|
673
|
+
chatReasoning: { zh: '推理过程', en: 'Reasoning' },
|
|
674
674
|
chatUnknownPart: { zh: '未知消息片段', en: 'Unknown message part' },
|
|
675
675
|
chatCodeCopy: { zh: '复制代码', en: 'Copy' },
|
|
676
676
|
chatCodeCopied: { zh: '已复制', en: 'Copied' },
|
package/tailwind.config.js
CHANGED
|
@@ -1,7 +1,13 @@
|
|
|
1
|
+
import tailwindcssAnimate from 'tailwindcss-animate';
|
|
2
|
+
|
|
1
3
|
/** @type {import('tailwindcss').Config} */
|
|
2
4
|
export default {
|
|
3
5
|
darkMode: ['class'],
|
|
4
|
-
content: [
|
|
6
|
+
content: [
|
|
7
|
+
'./index.html',
|
|
8
|
+
'./src/**/*.{js,ts,jsx,tsx}',
|
|
9
|
+
'../nextclaw-agent-chat-ui/src/**/*.{js,ts,jsx,tsx}',
|
|
10
|
+
],
|
|
5
11
|
theme: {
|
|
6
12
|
extend: {
|
|
7
13
|
colors: {
|
|
@@ -146,6 +152,5 @@ export default {
|
|
|
146
152
|
},
|
|
147
153
|
},
|
|
148
154
|
},
|
|
149
|
-
|
|
150
|
-
plugins: [require('tailwindcss-animate')],
|
|
155
|
+
plugins: [tailwindcssAnimate],
|
|
151
156
|
};
|
package/tsconfig.json
CHANGED
|
@@ -13,7 +13,10 @@
|
|
|
13
13
|
"paths": {
|
|
14
14
|
"@/*": ["./src/*"],
|
|
15
15
|
"@nextclaw/agent-chat": ["../nextclaw-agent-chat/src/index.ts"],
|
|
16
|
-
"@nextclaw/agent-chat-ui": ["../nextclaw-agent-chat-ui/src/index.ts"]
|
|
16
|
+
"@nextclaw/agent-chat-ui": ["../nextclaw-agent-chat-ui/src/index.ts"],
|
|
17
|
+
"@nextclaw/ncp": ["../ncp-packages/nextclaw-ncp/src/index.ts"],
|
|
18
|
+
"@nextclaw/ncp-http-agent-client": ["../ncp-packages/nextclaw-ncp-http-agent-client/src/index.ts"],
|
|
19
|
+
"@nextclaw/ncp-react": ["../ncp-packages/nextclaw-ncp-react/src/index.ts"]
|
|
17
20
|
}
|
|
18
21
|
},
|
|
19
22
|
"include": ["src"]
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{r as v,j as a,a5 as Z,F as ee,e as T,K as ae,ai as te,aS as se,aT as ne,aU as le,z as re,s as oe,a9 as ce,v as ie}from"./vendor-B7ozqnFC.js";import{t as e,c as I,U as me,u as q,a as $,b as H,W as pe,X as de,I as D,S as be,e as ue,f as xe,g as ye,h as ge,B as E}from"./index-DK4TS5ev.js";import{L as he}from"./label-D8ly4a2P.js";import{S as fe}from"./switch-Ce_g9lpN.js";import{L as K,S as J}from"./LogoBadge-DvGAzkZ3.js";import{h as U}from"./config-hints-CApS3K_7.js";import{c as we,b as ve,a as je,C as ke}from"./config-layout-BHnOoweL.js";import{T as Se}from"./tabs-custom-Cf5azvT5.js";import{P as Ce,a as Ne}from"./page-layout-BSYfvwbp.js";function Pe({value:t,onChange:m,className:i,placeholder:r=""}){const[o,u]=v.useState(""),d=x=>{x.key==="Enter"&&o.trim()?(x.preventDefault(),m([...t,o.trim()]),u("")):x.key==="Backspace"&&!o&&t.length>0&&m(t.slice(0,-1))},g=x=>{m(t.filter((j,h)=>h!==x))};return a.jsxs("div",{className:I("flex flex-wrap gap-2 p-2 border rounded-md min-h-[42px]",i),children:[t.map((x,j)=>a.jsxs("span",{className:"inline-flex items-center gap-1 px-2 py-1 bg-primary text-primary-foreground rounded text-sm",children:[x,a.jsx("button",{type:"button",onClick:()=>g(j),className:"hover:text-red-300 transition-colors",children:a.jsx(Z,{className:"h-3 w-3"})})]},j)),a.jsx("input",{type:"text",value:o,onChange:x=>u(x.target.value),onKeyDown:d,className:"flex-1 outline-none min-w-[100px] bg-transparent text-sm",placeholder:r||e("enterTag")})]})}function z(t){var r,o;const m=me();return((r=t.tutorialUrls)==null?void 0:r[m])||((o=t.tutorialUrls)==null?void 0:o.default)||t.tutorialUrl}const Ie={telegram:"telegram.svg",slack:"slack.svg",discord:"discord.svg",whatsapp:"whatsapp.svg",qq:"qq.svg",feishu:"feishu.svg",dingtalk:"dingtalk.svg",wecom:"wecom.svg",mochat:"mochat.svg",email:"email.svg"};function Fe(t,m){const i=m.toLowerCase(),r=t[i];return r?`/logos/${r}`:null}function Y(t){return Fe(Ie,t)}const B=[{value:"pairing",label:"pairing"},{value:"allowlist",label:"allowlist"},{value:"open",label:"open"},{value:"disabled",label:"disabled"}],R=[{value:"open",label:"open"},{value:"allowlist",label:"allowlist"},{value:"disabled",label:"disabled"}],Te=[{value:"off",label:"off"},{value:"partial",label:"partial"},{value:"block",label:"block"},{value:"progress",label:"progress"}],De=t=>t.includes("token")||t.includes("secret")||t.includes("password")?a.jsx(ae,{className:"h-3.5 w-3.5 text-gray-500"}):t.includes("url")||t.includes("host")?a.jsx(te,{className:"h-3.5 w-3.5 text-gray-500"}):t.includes("email")||t.includes("mail")?a.jsx(se,{className:"h-3.5 w-3.5 text-gray-500"}):t.includes("id")||t.includes("from")?a.jsx(ne,{className:"h-3.5 w-3.5 text-gray-500"}):t==="enabled"||t==="consentGranted"?a.jsx(le,{className:"h-3.5 w-3.5 text-gray-500"}):a.jsx(re,{className:"h-3.5 w-3.5 text-gray-500"});function G(){return{telegram:[{name:"enabled",type:"boolean",label:e("enabled")},{name:"token",type:"password",label:e("botToken")},{name:"allowFrom",type:"tags",label:e("allowFrom")},{name:"proxy",type:"text",label:e("proxy")},{name:"accountId",type:"text",label:e("accountId")},{name:"dmPolicy",type:"select",label:e("dmPolicy"),options:B},{name:"groupPolicy",type:"select",label:e("groupPolicy"),options:R},{name:"groupAllowFrom",type:"tags",label:e("groupAllowFrom")},{name:"requireMention",type:"boolean",label:e("requireMention")},{name:"mentionPatterns",type:"tags",label:e("mentionPatterns")},{name:"groups",type:"json",label:e("groupRulesJson")}],discord:[{name:"enabled",type:"boolean",label:e("enabled")},{name:"token",type:"password",label:e("botToken")},{name:"allowBots",type:"boolean",label:e("allowBotMessages")},{name:"allowFrom",type:"tags",label:e("allowFrom")},{name:"gatewayUrl",type:"text",label:e("gatewayUrl")},{name:"intents",type:"number",label:e("intents")},{name:"proxy",type:"text",label:e("proxy")},{name:"mediaMaxMb",type:"number",label:e("attachmentMaxSizeMb")},{name:"streaming",type:"select",label:e("streamingMode"),options:Te},{name:"draftChunk",type:"json",label:e("draftChunkingJson")},{name:"textChunkLimit",type:"number",label:e("textChunkLimit")},{name:"accountId",type:"text",label:e("accountId")},{name:"dmPolicy",type:"select",label:e("dmPolicy"),options:B},{name:"groupPolicy",type:"select",label:e("groupPolicy"),options:R},{name:"groupAllowFrom",type:"tags",label:e("groupAllowFrom")},{name:"requireMention",type:"boolean",label:e("requireMention")},{name:"mentionPatterns",type:"tags",label:e("mentionPatterns")},{name:"groups",type:"json",label:e("groupRulesJson")}],whatsapp:[{name:"enabled",type:"boolean",label:e("enabled")},{name:"bridgeUrl",type:"text",label:e("bridgeUrl")},{name:"allowFrom",type:"tags",label:e("allowFrom")}],feishu:[{name:"enabled",type:"boolean",label:e("enabled")},{name:"appId",type:"text",label:e("appId")},{name:"appSecret",type:"password",label:e("appSecret")},{name:"encryptKey",type:"password",label:e("encryptKey")},{name:"verificationToken",type:"password",label:e("verificationToken")},{name:"allowFrom",type:"tags",label:e("allowFrom")}],dingtalk:[{name:"enabled",type:"boolean",label:e("enabled")},{name:"clientId",type:"text",label:e("clientId")},{name:"clientSecret",type:"password",label:e("clientSecret")},{name:"allowFrom",type:"tags",label:e("allowFrom")}],wecom:[{name:"enabled",type:"boolean",label:e("enabled")},{name:"corpId",type:"text",label:e("corpId")},{name:"agentId",type:"text",label:e("agentId")},{name:"secret",type:"password",label:e("secret")},{name:"token",type:"password",label:e("token")},{name:"callbackPort",type:"number",label:e("callbackPort")},{name:"callbackPath",type:"text",label:e("callbackPath")},{name:"allowFrom",type:"tags",label:e("allowFrom")}],slack:[{name:"enabled",type:"boolean",label:e("enabled")},{name:"mode",type:"text",label:e("mode")},{name:"webhookPath",type:"text",label:e("webhookPath")},{name:"allowBots",type:"boolean",label:e("allowBotMessages")},{name:"botToken",type:"password",label:e("botToken")},{name:"appToken",type:"password",label:e("appToken")}],email:[{name:"enabled",type:"boolean",label:e("enabled")},{name:"consentGranted",type:"boolean",label:e("consentGranted")},{name:"imapHost",type:"text",label:e("imapHost")},{name:"imapPort",type:"number",label:e("imapPort")},{name:"imapUsername",type:"text",label:e("imapUsername")},{name:"imapPassword",type:"password",label:e("imapPassword")},{name:"fromAddress",type:"email",label:e("fromAddress")}],mochat:[{name:"enabled",type:"boolean",label:e("enabled")},{name:"baseUrl",type:"text",label:e("baseUrl")},{name:"clawToken",type:"password",label:e("clawToken")},{name:"agentUserId",type:"text",label:e("agentUserId")},{name:"allowFrom",type:"tags",label:e("allowFrom")}],qq:[{name:"enabled",type:"boolean",label:e("enabled")},{name:"appId",type:"text",label:e("appId")},{name:"secret",type:"password",label:e("appSecret")},{name:"markdownSupport",type:"boolean",label:e("markdownSupport")},{name:"allowFrom",type:"tags",label:e("allowFrom")}]}}function A(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}function V(t,m){const i={...t};for(const[r,o]of Object.entries(m)){const u=i[r];if(A(u)&&A(o)){i[r]=V(u,o);continue}i[r]=o}return i}function Ae(t,m){const i=t.split("."),r={};let o=r;for(let u=0;u<i.length-1;u+=1){const d=i[u];o[d]={},o=o[d]}return o[i[i.length-1]]=m,r}function Le({channelName:t}){var _,O;const{data:m}=q(),{data:i}=$(),{data:r}=H(),o=pe(),u=de(),[d,g]=v.useState({}),[x,j]=v.useState({}),[h,f]=v.useState(null),k=t?m==null?void 0:m.channels[t]:null,w=t?G()[t]??[]:[],c=r==null?void 0:r.uiHints,p=t?`channels.${t}`:null,S=((_=r==null?void 0:r.actions)==null?void 0:_.filter(s=>s.scope===p))??[],C=t&&(((O=U(`channels.${t}`,c))==null?void 0:O.label)??t),P=i==null?void 0:i.channels.find(s=>s.name===t),F=P?z(P):void 0;v.useEffect(()=>{if(k){g({...k});const s={};(t?G()[t]??[]:[]).filter(l=>l.type==="json").forEach(l=>{const y=k[l.name];s[l.name]=JSON.stringify(y??{},null,2)}),j(s)}else g({}),j({})},[k,t]);const N=(s,n)=>{g(l=>({...l,[s]:n}))},L=s=>{if(s.preventDefault(),!t)return;const n={...d};for(const l of w){if(l.type!=="password")continue;const y=n[l.name];(typeof y!="string"||y.length===0)&&delete n[l.name]}for(const l of w){if(l.type!=="json")continue;const y=x[l.name]??"";try{n[l.name]=y.trim()?JSON.parse(y):{}}catch{T.error(`${e("invalidJson")}: ${l.name}`);return}}o.mutate({channel:t,data:n})},W=s=>{if(!s||!t)return;const n=s.channels;if(!A(n))return;const l=n[t];A(l)&&g(y=>V(y,l))},X=async s=>{if(!(!t||!p)){f(s.id);try{let n={...d};s.saveBeforeRun&&(n={...n,...s.savePatch??{}},g(n),await o.mutateAsync({channel:t,data:n}));const l=await u.mutateAsync({actionId:s.id,data:{scope:p,draftConfig:Ae(p,n)}});W(l.patch),l.ok?T.success(l.message||e("success")):T.error(l.message||e("error"))}catch(n){const l=n instanceof Error?n.message:String(n);T.error(`${e("error")}: ${l}`)}finally{f(null)}}};if(!t||!P||!k)return a.jsx("div",{className:we,children:a.jsxs("div",{children:[a.jsx("h3",{className:"text-base font-semibold text-gray-900",children:e("channelsSelectTitle")}),a.jsx("p",{className:"mt-2 text-sm text-gray-500",children:e("channelsSelectDescription")})]})});const M=!!k.enabled;return a.jsxs("div",{className:ve,children:[a.jsx("div",{className:"border-b border-gray-100 px-6 py-5",children:a.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3",children:[a.jsxs("div",{className:"min-w-0",children:[a.jsxs("div",{className:"flex items-center gap-3",children:[a.jsx(K,{name:t,src:Y(t),className:I("h-9 w-9 rounded-lg border",M?"border-primary/30 bg-white":"border-gray-200/70 bg-white"),imgClassName:"h-5 w-5 object-contain",fallback:a.jsx("span",{className:"text-sm font-semibold uppercase text-gray-500",children:t[0]})}),a.jsx("h3",{className:"truncate text-lg font-semibold text-gray-900 capitalize",children:C})]}),a.jsx("p",{className:"mt-2 text-sm text-gray-500",children:e("channelsFormDescription")}),F&&a.jsxs("a",{href:F,className:"mt-2 inline-flex items-center gap-1.5 text-xs text-primary transition-colors hover:text-primary-hover",children:[a.jsx(ee,{className:"h-3.5 w-3.5"}),e("channelsGuideTitle")]})]}),a.jsx(J,{status:M?"active":"inactive",label:M?e("statusActive"):e("statusInactive")})]})}),a.jsxs("form",{onSubmit:L,className:"flex min-h-0 flex-1 flex-col",children:[a.jsx("div",{className:"min-h-0 flex-1 space-y-6 overflow-y-auto overscroll-contain px-6 py-5",children:w.map(s=>{const n=t?U(`channels.${t}.${s.name}`,c):void 0,l=(n==null?void 0:n.label)??s.label,y=n==null?void 0:n.placeholder;return a.jsxs("div",{className:"space-y-2.5",children:[a.jsxs(he,{htmlFor:s.name,className:"flex items-center gap-2 text-sm font-medium text-gray-900",children:[De(s.name),l]}),s.type==="boolean"&&a.jsxs("div",{className:"flex items-center justify-between rounded-xl bg-gray-50 p-3",children:[a.jsx("span",{className:"text-sm text-gray-500",children:d[s.name]?e("enabled"):e("disabled")}),a.jsx(fe,{id:s.name,checked:d[s.name]||!1,onCheckedChange:b=>N(s.name,b),className:"data-[state=checked]:bg-emerald-500"})]}),(s.type==="text"||s.type==="email")&&a.jsx(D,{id:s.name,type:s.type,value:d[s.name]||"",onChange:b=>N(s.name,b.target.value),placeholder:y,className:"rounded-xl"}),s.type==="password"&&a.jsx(D,{id:s.name,type:"password",value:d[s.name]||"",onChange:b=>N(s.name,b.target.value),placeholder:y??e("leaveBlankToKeepUnchanged"),className:"rounded-xl"}),s.type==="number"&&a.jsx(D,{id:s.name,type:"number",value:d[s.name]||0,onChange:b=>N(s.name,parseInt(b.target.value,10)||0),placeholder:y,className:"rounded-xl"}),s.type==="tags"&&a.jsx(Pe,{value:d[s.name]||[],onChange:b=>N(s.name,b)}),s.type==="select"&&a.jsxs(be,{value:d[s.name]||"",onValueChange:b=>N(s.name,b),children:[a.jsx(ue,{className:"rounded-xl",children:a.jsx(xe,{})}),a.jsx(ye,{children:(s.options??[]).map(b=>a.jsx(ge,{value:b.value,children:b.label},b.value))})]}),s.type==="json"&&a.jsx("textarea",{id:s.name,value:x[s.name]??"{}",onChange:b=>j(Q=>({...Q,[s.name]:b.target.value})),className:"min-h-[120px] w-full resize-none rounded-lg border border-gray-200 bg-white px-3 py-2 text-xs font-mono"})]},s.name)})}),a.jsxs("div",{className:"flex flex-wrap items-center justify-between gap-3 border-t border-gray-100 px-6 py-4",children:[a.jsx("div",{className:"flex flex-wrap items-center gap-2",children:S.filter(s=>s.trigger==="manual").map(s=>a.jsx(E,{type:"button",onClick:()=>X(s),disabled:o.isPending||!!h,variant:"secondary",children:h===s.id?e("connecting"):s.title},s.id))}),a.jsx(E,{type:"submit",disabled:o.isPending||!!h,children:o.isPending?e("saving"):e("save")})]})]})]})}const Me={telegram:"channelDescTelegram",slack:"channelDescSlack",email:"channelDescEmail",webhook:"channelDescWebhook",discord:"channelDescDiscord",feishu:"channelDescFeishu"};function He(){const{data:t}=q(),{data:m}=$(),{data:i}=H(),[r,o]=v.useState("enabled"),[u,d]=v.useState(),[g,x]=v.useState(""),j=i==null?void 0:i.uiHints,h=m==null?void 0:m.channels,f=t==null?void 0:t.channels,k=[{id:"enabled",label:e("channelsTabEnabled"),count:(h??[]).filter(c=>{var p;return(p=f==null?void 0:f[c.name])==null?void 0:p.enabled}).length},{id:"all",label:e("channelsTabAll"),count:(h??[]).length}],w=v.useMemo(()=>{const c=g.trim().toLowerCase();return(h??[]).filter(p=>{var C;const S=((C=f==null?void 0:f[p.name])==null?void 0:C.enabled)||!1;return r==="enabled"?S:!0}).filter(p=>c?(p.displayName||p.name).toLowerCase().includes(c)||p.name.toLowerCase().includes(c):!0)},[r,f,h,g]);return v.useEffect(()=>{if(w.length===0){d(void 0);return}w.some(p=>p.name===u)||d(w[0].name)},[w,u]),!t||!m?a.jsx("div",{className:"p-8 text-gray-400",children:e("channelsLoading")}):a.jsxs(Ce,{className:"xl:flex xl:h-full xl:min-h-0 xl:flex-col xl:pb-0",children:[a.jsx(Ne,{title:e("channelsPageTitle"),description:e("channelsPageDescription")}),a.jsxs("div",{className:I(ke,"xl:min-h-0 xl:flex-1"),children:[a.jsxs("section",{className:je,children:[a.jsx("div",{className:"border-b border-gray-100 px-4 pt-4",children:a.jsx(Se,{tabs:k,activeTab:r,onChange:o,className:"mb-0"})}),a.jsx("div",{className:"border-b border-gray-100 px-4 py-3",children:a.jsxs("div",{className:"relative",children:[a.jsx(oe,{className:"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-gray-400"}),a.jsx(D,{value:g,onChange:c=>x(c.target.value),placeholder:e("channelsFilterPlaceholder"),className:"h-10 rounded-xl pl-9"})]})}),a.jsxs("div",{className:"min-h-0 flex-1 space-y-2 overflow-y-auto overscroll-contain p-3",children:[w.map(c=>{const p=t.channels[c.name],S=(p==null?void 0:p.enabled)||!1,C=U(`channels.${c.name}`,j),P=z(c),F=(C==null?void 0:C.help)||e(Me[c.name]||"channelDescriptionDefault"),N=u===c.name;return a.jsx("button",{type:"button",onClick:()=>d(c.name),className:I("w-full rounded-xl border p-2.5 text-left transition-all",N?"border-primary/30 bg-primary-50/40 shadow-sm":"border-gray-200/70 bg-white hover:border-gray-300 hover:bg-gray-50/70"),children:a.jsxs("div",{className:"flex items-start justify-between gap-3",children:[a.jsxs("div",{className:"flex min-w-0 items-center gap-3",children:[a.jsx(K,{name:c.name,src:Y(c.name),className:I("h-10 w-10 rounded-lg border",S?"border-primary/30 bg-white":"border-gray-200/70 bg-white"),imgClassName:"h-5 w-5 object-contain",fallback:a.jsx("span",{className:"text-sm font-semibold uppercase text-gray-500",children:c.name[0]})}),a.jsxs("div",{className:"min-w-0",children:[a.jsx("p",{className:"truncate text-sm font-semibold text-gray-900",children:c.displayName||c.name}),a.jsx("p",{className:"line-clamp-1 text-[11px] text-gray-500",children:F})]})]}),a.jsxs("div",{className:"flex items-center gap-2",children:[P&&a.jsx("a",{href:P,onClick:L=>L.stopPropagation(),className:"inline-flex h-7 w-7 items-center justify-center rounded-md text-gray-300 transition-colors hover:bg-gray-100/70 hover:text-gray-500",title:e("channelsGuideTitle"),children:a.jsx(ce,{className:"h-3.5 w-3.5"})}),a.jsx(J,{status:S?"active":"inactive",label:S?e("statusActive"):e("statusInactive"),className:"min-w-[56px] justify-center"})]})]})},c.name)}),w.length===0&&a.jsxs("div",{className:"flex h-full min-h-[220px] flex-col items-center justify-center rounded-xl border border-dashed border-gray-200 bg-gray-50/70 py-10 text-center",children:[a.jsx("div",{className:"mb-3 flex h-10 w-10 items-center justify-center rounded-lg bg-white",children:a.jsx(ie,{className:"h-5 w-5 text-gray-300"})}),a.jsx("p",{className:"text-sm font-medium text-gray-700",children:e("channelsNoMatch")})]})]})]}),a.jsx(Le,{channelName:u})]})]})}export{He as ChannelsList};
|