@nextclaw/ui 0.6.5 → 0.6.7
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 +12 -0
- package/dist/assets/ChannelsList-Dz8AGmaQ.js +1 -0
- package/dist/assets/ChatPage-BXDyt7BL.js +34 -0
- package/dist/assets/DocBrowser-CkKvzF7m.js +1 -0
- package/dist/assets/LogoBadge-C_ygxoGB.js +1 -0
- package/dist/assets/{MarketplacePage-Cxt223yL.js → MarketplacePage-DEvRs-Jc.js} +2 -2
- package/dist/assets/ModelConfig-BGfliN2Z.js +1 -0
- package/dist/assets/ProvidersList-BHLGLSvs.js +1 -0
- package/dist/assets/RuntimeConfig-Clltld_h.js +1 -0
- package/dist/assets/{SecretsConfig-C_3yJm1I.js → SecretsConfig-CaJLf7oJ.js} +2 -2
- package/dist/assets/SessionsConfig-3QF7K9wm.js +2 -0
- package/dist/assets/{card-sDEXo_R4.js → card-DXo3NsaB.js} +1 -1
- package/dist/assets/index-CGo5Vnh0.js +7 -0
- package/dist/assets/index-DcxYzrFm.css +1 -0
- package/dist/assets/input-CzTldMKo.js +1 -0
- package/dist/assets/{label-DhIqXnKx.js → label-De__vsU7.js} +1 -1
- package/dist/assets/{page-layout-CC6kzYFp.js → page-layout-BOgLC2tK.js} +1 -1
- package/dist/assets/session-run-status-DQVCDxTb.js +5 -0
- package/dist/assets/{switch-DFPJEEVz.js → switch-pMrS4heA.js} +1 -1
- package/dist/assets/{tabs-custom-C_1pBckQ.js → tabs-custom-DhOxWfCb.js} +1 -1
- package/dist/assets/{useConfirmDialog-BNkeOTcY.js → useConfirmDialog-CseKBGh5.js} +2 -2
- package/dist/assets/{vendor-Dj2ULvht.js → vendor-D33xZtEC.js} +6 -6
- package/dist/index.html +3 -3
- package/package.json +1 -1
- package/src/api/config.ts +53 -0
- package/src/api/types.ts +48 -0
- package/src/components/chat/ChatPage.tsx +15 -7
- package/src/components/chat/ChatSidebar.tsx +12 -7
- package/src/components/common/BrandHeader.tsx +23 -0
- package/src/components/common/SessionRunBadge.tsx +23 -0
- package/src/components/config/ProviderForm.tsx +193 -29
- package/src/components/config/ProvidersList.tsx +1 -2
- package/src/components/config/SessionsConfig.tsx +22 -2
- package/src/components/layout/Sidebar.tsx +2 -6
- package/src/hooks/useConfig.ts +31 -0
- package/src/index.css +39 -1
- package/src/lib/i18n.ts +17 -0
- package/src/lib/logos.ts +0 -19
- package/src/lib/session-run-status.ts +63 -0
- package/dist/assets/ChannelsList-DiX7ssoj.js +0 -1
- package/dist/assets/ChatPage-CEEbtfae.js +0 -34
- package/dist/assets/DocBrowser-CkDugJv3.js +0 -1
- package/dist/assets/ModelConfig-BRRJU2mk.js +0 -1
- package/dist/assets/ProvidersList-Bl-OMAwu.js +0 -1
- package/dist/assets/RuntimeConfig-C0wurlgT.js +0 -1
- package/dist/assets/SessionsConfig-D13xFf5J.js +0 -2
- package/dist/assets/chat-message-pw9oafI4.js +0 -5
- package/dist/assets/index-6azf0otP.css +0 -1
- package/dist/assets/index-DP9xXu9V.js +0 -2
- package/dist/assets/logos-B9Qiy9wo.js +0 -1
- package/dist/assets/useConfig-q7QqH3JB.js +0 -6
|
@@ -5,7 +5,6 @@ import { ProviderForm } from './ProviderForm';
|
|
|
5
5
|
import { cn } from '@/lib/utils';
|
|
6
6
|
import { Tabs } from '@/components/ui/tabs-custom';
|
|
7
7
|
import { LogoBadge } from '@/components/common/LogoBadge';
|
|
8
|
-
import { getProviderLogo } from '@/lib/logos';
|
|
9
8
|
import { hintForPath } from '@/lib/config-hints';
|
|
10
9
|
import { StatusDot } from '@/components/ui/status-dot';
|
|
11
10
|
import { t } from '@/lib/i18n';
|
|
@@ -156,7 +155,7 @@ export function ProvidersList() {
|
|
|
156
155
|
<div className="flex min-w-0 items-center gap-3">
|
|
157
156
|
<LogoBadge
|
|
158
157
|
name={provider.name}
|
|
159
|
-
src={
|
|
158
|
+
src={provider.logo ? `/logos/${provider.logo}` : null}
|
|
160
159
|
className={cn(
|
|
161
160
|
'h-10 w-10 rounded-lg border',
|
|
162
161
|
isReady ? 'border-primary/30 bg-white' : 'border-gray-200/70 bg-white'
|
|
@@ -1,13 +1,19 @@
|
|
|
1
1
|
import { useEffect, useMemo, useState } from 'react';
|
|
2
2
|
import type { SessionEntryView, SessionMessageView } from '@/api/types';
|
|
3
3
|
import { useConfirmDialog } from '@/hooks/useConfirmDialog';
|
|
4
|
-
import { useDeleteSession, useSessionHistory, useSessions, useUpdateSession } from '@/hooks/useConfig';
|
|
4
|
+
import { useChatRuns, useDeleteSession, useSessionHistory, useSessions, useUpdateSession } from '@/hooks/useConfig';
|
|
5
5
|
import { Button } from '@/components/ui/button';
|
|
6
6
|
import { Input } from '@/components/ui/input';
|
|
7
7
|
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@/components/ui/select';
|
|
8
|
+
import { SessionRunBadge } from '@/components/common/SessionRunBadge';
|
|
8
9
|
import { cn } from '@/lib/utils';
|
|
9
10
|
import { formatDateShort, formatDateTime, t } from '@/lib/i18n';
|
|
10
11
|
import { extractMessageText } from '@/lib/chat-message';
|
|
12
|
+
import {
|
|
13
|
+
buildActiveRunBySessionKey,
|
|
14
|
+
buildSessionRunStatusByKey,
|
|
15
|
+
type SessionRunStatus
|
|
16
|
+
} from '@/lib/session-run-status';
|
|
11
17
|
import { PageLayout, PageHeader } from '@/components/layout/page-layout';
|
|
12
18
|
import { RefreshCw, Search, Clock, Inbox, Hash, Bot, User, MessageCircle, Settings as SettingsIcon } from 'lucide-react';
|
|
13
19
|
|
|
@@ -40,11 +46,12 @@ function displayChannelName(channel: string): string {
|
|
|
40
46
|
type SessionListItemProps = {
|
|
41
47
|
session: SessionEntryView;
|
|
42
48
|
channel: string;
|
|
49
|
+
runStatus?: SessionRunStatus;
|
|
43
50
|
isSelected: boolean;
|
|
44
51
|
onSelect: () => void;
|
|
45
52
|
};
|
|
46
53
|
|
|
47
|
-
function SessionListItem({ session, channel, isSelected, onSelect }: SessionListItemProps) {
|
|
54
|
+
function SessionListItem({ session, channel, runStatus, isSelected, onSelect }: SessionListItemProps) {
|
|
48
55
|
const channelDisplay = displayChannelName(channel);
|
|
49
56
|
const displayName = session.label || session.key.split(':').pop() || session.key;
|
|
50
57
|
|
|
@@ -69,6 +76,9 @@ function SessionListItem({ session, channel, isSelected, onSelect }: SessionList
|
|
|
69
76
|
|
|
70
77
|
<div className={cn("flex items-center text-xs justify-between mt-2 font-medium", isSelected ? "text-brand-600/80" : "text-gray-400")}>
|
|
71
78
|
<div className="flex items-center gap-1.5">
|
|
79
|
+
<span className="inline-flex h-3.5 w-3.5 shrink-0 items-center justify-center">
|
|
80
|
+
{runStatus ? <SessionRunBadge status={runStatus} /> : null}
|
|
81
|
+
</span>
|
|
72
82
|
<Clock className="w-3.5 h-3.5 opacity-70" />
|
|
73
83
|
<span className="truncate max-w-[100px]">{formatDateShort(session.updatedAt)}</span>
|
|
74
84
|
</div>
|
|
@@ -136,6 +146,7 @@ export function SessionsConfig() {
|
|
|
136
146
|
|
|
137
147
|
const sessionsParams = useMemo(() => ({ q: query.trim() || undefined, limit, activeMinutes }), [query, limit, activeMinutes]);
|
|
138
148
|
const sessionsQuery = useSessions(sessionsParams);
|
|
149
|
+
const activeRunsQuery = useChatRuns({ states: ['queued', 'running'], limit: 200 });
|
|
139
150
|
const historyQuery = useSessionHistory(selectedKey, 200);
|
|
140
151
|
|
|
141
152
|
const updateSession = useUpdateSession();
|
|
@@ -143,6 +154,14 @@ export function SessionsConfig() {
|
|
|
143
154
|
const { confirm, ConfirmDialog } = useConfirmDialog();
|
|
144
155
|
|
|
145
156
|
const sessions = useMemo(() => sessionsQuery.data?.sessions ?? [], [sessionsQuery.data?.sessions]);
|
|
157
|
+
const activeRunBySessionKey = useMemo(
|
|
158
|
+
() => buildActiveRunBySessionKey(activeRunsQuery.data?.runs ?? []),
|
|
159
|
+
[activeRunsQuery.data?.runs]
|
|
160
|
+
);
|
|
161
|
+
const sessionRunStatusByKey = useMemo(
|
|
162
|
+
() => buildSessionRunStatusByKey(activeRunBySessionKey),
|
|
163
|
+
[activeRunBySessionKey]
|
|
164
|
+
);
|
|
146
165
|
const selectedSession = useMemo(() => sessions.find(s => s.key === selectedKey), [sessions, selectedKey]);
|
|
147
166
|
|
|
148
167
|
const channels = useMemo(() => {
|
|
@@ -273,6 +292,7 @@ export function SessionsConfig() {
|
|
|
273
292
|
key={session.key}
|
|
274
293
|
session={session}
|
|
275
294
|
channel={resolveChannelFromSessionKey(session.key)}
|
|
295
|
+
runStatus={sessionRunStatusByKey.get(session.key)}
|
|
276
296
|
isSelected={selectedKey === session.key}
|
|
277
297
|
onSelect={() => setSelectedKey(session.key)}
|
|
278
298
|
/>
|
|
@@ -4,6 +4,7 @@ import { THEME_OPTIONS, type UiTheme } from '@/lib/theme';
|
|
|
4
4
|
import { Cpu, GitBranch, History, MessageCircle, MessageSquare, Sparkles, BookOpen, Plug, BrainCircuit, AlarmClock, Languages, Palette, KeyRound, Settings, ArrowLeft } from 'lucide-react';
|
|
5
5
|
import { NavLink } from 'react-router-dom';
|
|
6
6
|
import { useDocBrowser } from '@/components/doc-browser';
|
|
7
|
+
import { BrandHeader } from '@/components/common/BrandHeader';
|
|
7
8
|
import { useI18n } from '@/components/providers/I18nProvider';
|
|
8
9
|
import { useTheme } from '@/components/providers/ThemeProvider';
|
|
9
10
|
import { Select, SelectContent, SelectItem, SelectTrigger } from '@/components/ui/select';
|
|
@@ -114,12 +115,7 @@ export function Sidebar({ mode }: SidebarProps) {
|
|
|
114
115
|
</div>
|
|
115
116
|
) : (
|
|
116
117
|
<div className="px-2 mb-8">
|
|
117
|
-
<
|
|
118
|
-
<div className="h-7 w-7 rounded-lg overflow-hidden flex items-center justify-center">
|
|
119
|
-
<img src="/logo.svg" alt="NextClaw" className="h-full w-full object-contain" />
|
|
120
|
-
</div>
|
|
121
|
-
<span className="text-[15px] font-semibold text-gray-800 tracking-[-0.01em]">NextClaw</span>
|
|
122
|
-
</div>
|
|
118
|
+
<BrandHeader className="flex items-center gap-2.5 cursor-pointer" />
|
|
123
119
|
</div>
|
|
124
120
|
)}
|
|
125
121
|
|
package/src/hooks/useConfig.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
|
|
2
2
|
import {
|
|
3
|
+
fetchAppMeta,
|
|
3
4
|
fetchConfig,
|
|
4
5
|
fetchConfigMeta,
|
|
5
6
|
fetchConfigSchema,
|
|
@@ -8,6 +9,9 @@ import {
|
|
|
8
9
|
deleteProvider,
|
|
9
10
|
updateProvider,
|
|
10
11
|
testProviderConnection,
|
|
12
|
+
startProviderAuth,
|
|
13
|
+
pollProviderAuth,
|
|
14
|
+
importProviderAuthFromCli,
|
|
11
15
|
updateChannel,
|
|
12
16
|
updateRuntime,
|
|
13
17
|
updateSecrets,
|
|
@@ -37,6 +41,14 @@ export function useConfig() {
|
|
|
37
41
|
});
|
|
38
42
|
}
|
|
39
43
|
|
|
44
|
+
export function useAppMeta() {
|
|
45
|
+
return useQuery({
|
|
46
|
+
queryKey: ['app-meta'],
|
|
47
|
+
queryFn: fetchAppMeta,
|
|
48
|
+
staleTime: Infinity
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
40
52
|
export function useConfigMeta() {
|
|
41
53
|
return useQuery({
|
|
42
54
|
queryKey: ['config-meta'],
|
|
@@ -125,6 +137,25 @@ export function useTestProviderConnection() {
|
|
|
125
137
|
});
|
|
126
138
|
}
|
|
127
139
|
|
|
140
|
+
export function useStartProviderAuth() {
|
|
141
|
+
return useMutation({
|
|
142
|
+
mutationFn: ({ provider }: { provider: string }) => startProviderAuth(provider)
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export function usePollProviderAuth() {
|
|
147
|
+
return useMutation({
|
|
148
|
+
mutationFn: ({ provider, data }: { provider: string; data: unknown }) =>
|
|
149
|
+
pollProviderAuth(provider, data as Parameters<typeof pollProviderAuth>[1])
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
export function useImportProviderAuthFromCli() {
|
|
154
|
+
return useMutation({
|
|
155
|
+
mutationFn: ({ provider }: { provider: string }) => importProviderAuthFromCli(provider)
|
|
156
|
+
});
|
|
157
|
+
}
|
|
158
|
+
|
|
128
159
|
export function useUpdateChannel() {
|
|
129
160
|
const queryClient = useQueryClient();
|
|
130
161
|
|
package/src/index.css
CHANGED
|
@@ -263,7 +263,41 @@
|
|
|
263
263
|
.chat-markdown ul,
|
|
264
264
|
.chat-markdown ol {
|
|
265
265
|
margin: 0.35rem 0;
|
|
266
|
-
padding-left: 1.
|
|
266
|
+
padding-left: 1.5rem;
|
|
267
|
+
list-style-position: outside;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
.chat-markdown ul {
|
|
271
|
+
list-style-type: disc;
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
.chat-markdown ol {
|
|
275
|
+
list-style-type: decimal;
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
.chat-markdown ul ul {
|
|
279
|
+
list-style-type: circle;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
.chat-markdown ul ul ul {
|
|
283
|
+
list-style-type: square;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
.chat-markdown ol ol {
|
|
287
|
+
list-style-type: lower-alpha;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
.chat-markdown ol ol ol {
|
|
291
|
+
list-style-type: lower-roman;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
.chat-markdown li {
|
|
295
|
+
display: list-item;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
.chat-markdown li::marker {
|
|
299
|
+
color: rgba(51, 65, 85, 0.9);
|
|
300
|
+
font-weight: 600;
|
|
267
301
|
}
|
|
268
302
|
|
|
269
303
|
.chat-markdown li + li {
|
|
@@ -286,6 +320,10 @@
|
|
|
286
320
|
gap: 0.52rem;
|
|
287
321
|
}
|
|
288
322
|
|
|
323
|
+
.chat-markdown-user li::marker {
|
|
324
|
+
color: rgba(219, 234, 254, 0.95);
|
|
325
|
+
}
|
|
326
|
+
|
|
289
327
|
.chat-markdown .chat-task-checkbox {
|
|
290
328
|
position: relative;
|
|
291
329
|
top: 0.2rem;
|
package/src/lib/i18n.ts
CHANGED
|
@@ -254,6 +254,21 @@ export const LABELS: Record<string, { zh: string; en: string }> = {
|
|
|
254
254
|
providerApiBaseHelpShort: { zh: '一般只需填写域名,系统自动补全路径', en: 'Usually just the domain; path auto-appended' },
|
|
255
255
|
providerExtraHeadersHelpShort: { zh: '可选,用于自定义鉴权等场景', en: 'Optional, for custom auth etc.' },
|
|
256
256
|
providerAdvancedSettings: { zh: '高级设置', en: 'Advanced Settings' },
|
|
257
|
+
providerAuthSectionTitle: { zh: '提供商授权', en: 'Provider Authorization' },
|
|
258
|
+
providerAuthStarting: { zh: '启动中...', en: 'Starting...' },
|
|
259
|
+
providerAuthAuthorizing: { zh: '授权中...', en: 'Authorizing...' },
|
|
260
|
+
providerAuthAuthorizeInBrowser: { zh: '浏览器授权', en: 'Authorize in Browser' },
|
|
261
|
+
providerAuthWaitingBrowser: { zh: '等待浏览器完成授权...', en: 'Waiting for browser authorization...' },
|
|
262
|
+
providerAuthCompleted: { zh: '授权已完成。', en: 'Authorization completed.' },
|
|
263
|
+
providerAuthOpenPrompt: { zh: '请在浏览器完成授权,验证码:', en: 'Open browser and complete authorization (code: ' },
|
|
264
|
+
providerAuthOpenPromptSuffix: { zh: '', en: ')' },
|
|
265
|
+
providerAuthStartFailed: { zh: '启动授权失败', en: 'Failed to start authorization' },
|
|
266
|
+
providerAuthImportFromCli: { zh: '从 Qwen CLI 导入', en: 'Import From Qwen CLI' },
|
|
267
|
+
providerAuthImporting: { zh: '导入中...', en: 'Importing...' },
|
|
268
|
+
providerAuthImportSuccess: { zh: '已从 CLI 导入凭证。', en: 'Imported provider credentials from CLI.' },
|
|
269
|
+
providerAuthImportStatusPrefix: { zh: 'CLI 导入成功。', en: 'Imported credentials from CLI successfully.' },
|
|
270
|
+
providerAuthImportFailed: { zh: '导入凭证失败', en: 'Failed to import credentials' },
|
|
271
|
+
providerAuthSessionLabel: { zh: '会话', en: 'Session' },
|
|
257
272
|
resetToDefault: { zh: '恢复默认', en: 'Reset to Default' },
|
|
258
273
|
leaveBlankToKeepUnchanged: { zh: '留空则保持不变', en: 'Leave blank to keep unchanged' },
|
|
259
274
|
|
|
@@ -467,6 +482,8 @@ export const LABELS: Record<string, { zh: string; en: string }> = {
|
|
|
467
482
|
sessionsApplyingChanges: { zh: '正在应用会话变更...', en: 'Applying session changes...' },
|
|
468
483
|
sessionsUnknownChannel: { zh: '未知渠道', en: 'Unknown channel' },
|
|
469
484
|
sessionsAllChannels: { zh: '全部渠道', en: 'All Channels' },
|
|
485
|
+
sessionsRunStatusRunning: { zh: '运行中', en: 'Running' },
|
|
486
|
+
sessionsRunStatusQueued: { zh: '排队中', en: 'Queued' },
|
|
470
487
|
sessionsMetadata: { zh: '元信息', en: 'Metadata' },
|
|
471
488
|
sessionsNoSelectionTitle: { zh: '未选择会话', en: 'No Session Selected' },
|
|
472
489
|
sessionsNoSelectionDescription: {
|
package/src/lib/logos.ts
CHANGED
|
@@ -1,20 +1,5 @@
|
|
|
1
1
|
type LogoMap = Record<string, string>;
|
|
2
2
|
|
|
3
|
-
const PROVIDER_LOGOS: LogoMap = {
|
|
4
|
-
openrouter: "openrouter.svg",
|
|
5
|
-
aihubmix: "aihubmix.png",
|
|
6
|
-
anthropic: "anthropic.svg",
|
|
7
|
-
openai: "openai.svg",
|
|
8
|
-
gemini: "gemini.svg",
|
|
9
|
-
deepseek: "deepseek.png",
|
|
10
|
-
zhipu: "zhipu.svg",
|
|
11
|
-
dashscope: "dashscope.png",
|
|
12
|
-
moonshot: "moonshot.png",
|
|
13
|
-
minimax: "minimax.svg",
|
|
14
|
-
vllm: "vllm.svg",
|
|
15
|
-
groq: "groq.svg"
|
|
16
|
-
};
|
|
17
|
-
|
|
18
3
|
const CHANNEL_LOGOS: LogoMap = {
|
|
19
4
|
telegram: "telegram.svg",
|
|
20
5
|
slack: "slack.svg",
|
|
@@ -34,10 +19,6 @@ function resolveLogo(map: LogoMap, name: string): string | null {
|
|
|
34
19
|
return file ? `/logos/${file}` : null;
|
|
35
20
|
}
|
|
36
21
|
|
|
37
|
-
export function getProviderLogo(name: string): string | null {
|
|
38
|
-
return resolveLogo(PROVIDER_LOGOS, name);
|
|
39
|
-
}
|
|
40
|
-
|
|
41
22
|
export function getChannelLogo(name: string): string | null {
|
|
42
23
|
return resolveLogo(CHANNEL_LOGOS, name);
|
|
43
24
|
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { ChatRunState, ChatRunView } from '@/api/types';
|
|
2
|
+
|
|
3
|
+
export type SessionRunStatus = Extract<ChatRunState, 'queued' | 'running'>;
|
|
4
|
+
|
|
5
|
+
const RUN_STATUS_PRIORITY: Record<SessionRunStatus, number> = {
|
|
6
|
+
queued: 1,
|
|
7
|
+
running: 2
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
function toSessionRunStatus(state: ChatRunState): SessionRunStatus | null {
|
|
11
|
+
if (state === 'queued' || state === 'running') {
|
|
12
|
+
return state;
|
|
13
|
+
}
|
|
14
|
+
return null;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function toComparableTimestamp(value?: string): number {
|
|
18
|
+
const parsed = Date.parse(value ?? '');
|
|
19
|
+
return Number.isFinite(parsed) ? parsed : 0;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function shouldReplaceRun(current: ChatRunView, next: ChatRunView): boolean {
|
|
23
|
+
const currentStatus = toSessionRunStatus(current.state);
|
|
24
|
+
const nextStatus = toSessionRunStatus(next.state);
|
|
25
|
+
if (!currentStatus || !nextStatus) {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
const currentPriority = RUN_STATUS_PRIORITY[currentStatus];
|
|
29
|
+
const nextPriority = RUN_STATUS_PRIORITY[nextStatus];
|
|
30
|
+
if (nextPriority !== currentPriority) {
|
|
31
|
+
return nextPriority > currentPriority;
|
|
32
|
+
}
|
|
33
|
+
return toComparableTimestamp(next.requestedAt) >= toComparableTimestamp(current.requestedAt);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function buildActiveRunBySessionKey(runs: readonly ChatRunView[]): Map<string, ChatRunView> {
|
|
37
|
+
const map = new Map<string, ChatRunView>();
|
|
38
|
+
for (const run of runs) {
|
|
39
|
+
const key = run.sessionKey?.trim();
|
|
40
|
+
if (!key || !toSessionRunStatus(run.state)) {
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
const current = map.get(key);
|
|
44
|
+
if (!current || shouldReplaceRun(current, run)) {
|
|
45
|
+
map.set(key, run);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return map;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function buildSessionRunStatusByKey(
|
|
52
|
+
activeRunBySessionKey: ReadonlyMap<string, ChatRunView>
|
|
53
|
+
): Map<string, SessionRunStatus> {
|
|
54
|
+
const map = new Map<string, SessionRunStatus>();
|
|
55
|
+
for (const [sessionKey, run] of activeRunBySessionKey.entries()) {
|
|
56
|
+
const status = toSessionRunStatus(run.state);
|
|
57
|
+
if (!status) {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
map.set(sessionKey, status);
|
|
61
|
+
}
|
|
62
|
+
return map;
|
|
63
|
+
}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{r as j,j as a,at as Z,v as ee,aH as T,K as ae,a5 as te,aI as se,aJ as ne,aK as le,q as re,Y as oe,as as ce,n as ie}from"./vendor-Dj2ULvht.js";import{u as q,a as K,b as $,t as me,v as pe,I as D}from"./useConfig-q7QqH3JB.js";import{B as E,P as de,a as be}from"./page-layout-CC6kzYFp.js";import{L as ue}from"./label-DhIqXnKx.js";import{S as xe}from"./switch-DFPJEEVz.js";import{t as e,c as P,h as ye,S as ge,a as he,b as fe,d as we,e as je}from"./index-DP9xXu9V.js";import{C as ve,a as ke,L as H,d as J,S as z,c as Se,b as Ce}from"./logos-B9Qiy9wo.js";import{h as _}from"./config-hints-CApS3K_7.js";import{T as Ne}from"./tabs-custom-C_1pBckQ.js";function Ie({value:t,onChange:p,className:i,placeholder:c=""}){const[r,u]=j.useState(""),d=x=>{x.key==="Enter"&&r.trim()?(x.preventDefault(),p([...t,r.trim()]),u("")):x.key==="Backspace"&&!r&&t.length>0&&p(t.slice(0,-1))},g=x=>{p(t.filter((v,h)=>h!==x))};return a.jsxs("div",{className:P("flex flex-wrap gap-2 p-2 border rounded-md min-h-[42px]",i),children:[t.map((x,v)=>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(v),className:"hover:text-red-300 transition-colors",children:a.jsx(Z,{className:"h-3 w-3"})})]},v)),a.jsx("input",{type:"text",value:r,onChange:x=>u(x.target.value),onKeyDown:d,className:"flex-1 outline-none min-w-[100px] bg-transparent text-sm",placeholder:c||e("enterTag")})]})}function Y(t){var c,r;const p=ye();return((c=t.tutorialUrls)==null?void 0:c[p])||((r=t.tutorialUrls)==null?void 0:r.default)||t.tutorialUrl}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"}],Pe=[{value:"off",label:"off"},{value:"partial",label:"partial"},{value:"block",label:"block"},{value:"progress",label:"progress"}],Fe=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:Pe},{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,p){const i={...t};for(const[c,r]of Object.entries(p)){const u=i[c];if(A(u)&&A(r)){i[c]=V(u,r);continue}i[c]=r}return i}function Te(t,p){const i=t.split("."),c={};let r=c;for(let u=0;u<i.length-1;u+=1){const d=i[u];r[d]={},r=r[d]}return r[i[i.length-1]]=p,c}function De({channelName:t}){var U,O;const{data:p}=q(),{data:i}=K(),{data:c}=$(),r=me(),u=pe(),[d,g]=j.useState({}),[x,v]=j.useState({}),[h,f]=j.useState(null),k=t?p==null?void 0:p.channels[t]:null,w=t?G()[t]??[]:[],o=c==null?void 0:c.uiHints,m=t?`channels.${t}`:null,S=((U=c==null?void 0:c.actions)==null?void 0:U.filter(s=>s.scope===m))??[],C=t&&(((O=_(`channels.${t}`,o))==null?void 0:O.label)??t),I=i==null?void 0:i.channels.find(s=>s.name===t),F=I?Y(I):void 0;j.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)}),v(s)}else g({}),v({})},[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}}r.mutate({channel:t,data:n})},Q=s=>{if(!s||!t)return;const n=s.channels;if(!A(n))return;const l=n[t];A(l)&&g(y=>V(y,l))},W=async s=>{if(!(!t||!m)){f(s.id);try{let n={...d};s.saveBeforeRun&&(n={...n,...s.savePatch??{}},g(n),await r.mutateAsync({channel:t,data:n}));const l=await u.mutateAsync({actionId:s.id,data:{scope:m,draftConfig:Te(m,n)}});Q(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||!I||!k)return a.jsx("div",{className:ve,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:ke,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(H,{name:t,src:J(t),className:P("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(z,{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?_(`channels.${t}.${s.name}`,o):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(ue,{htmlFor:s.name,className:"flex items-center gap-2 text-sm font-medium text-gray-900",children:[Fe(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(xe,{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(Ie,{value:d[s.name]||[],onChange:b=>N(s.name,b)}),s.type==="select"&&a.jsxs(ge,{value:d[s.name]||"",onValueChange:b=>N(s.name,b),children:[a.jsx(he,{className:"rounded-xl",children:a.jsx(fe,{})}),a.jsx(we,{children:(s.options??[]).map(b=>a.jsx(je,{value:b.value,children:b.label},b.value))})]}),s.type==="json"&&a.jsx("textarea",{id:s.name,value:x[s.name]??"{}",onChange:b=>v(X=>({...X,[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:()=>W(s),disabled:r.isPending||!!h,variant:"secondary",children:h===s.id?e("connecting"):s.title},s.id))}),a.jsx(E,{type:"submit",disabled:r.isPending||!!h,children:r.isPending?e("saving"):e("save")})]})]})]})}const Ae={telegram:"channelDescTelegram",slack:"channelDescSlack",email:"channelDescEmail",webhook:"channelDescWebhook",discord:"channelDescDiscord",feishu:"channelDescFeishu"};function qe(){const{data:t}=q(),{data:p}=K(),{data:i}=$(),[c,r]=j.useState("enabled"),[u,d]=j.useState(),[g,x]=j.useState(""),v=i==null?void 0:i.uiHints,h=p==null?void 0:p.channels,f=t==null?void 0:t.channels,k=[{id:"enabled",label:e("channelsTabEnabled"),count:(h??[]).filter(o=>{var m;return(m=f==null?void 0:f[o.name])==null?void 0:m.enabled}).length},{id:"all",label:e("channelsTabAll"),count:(h??[]).length}],w=j.useMemo(()=>{const o=g.trim().toLowerCase();return(h??[]).filter(m=>{var C;const S=((C=f==null?void 0:f[m.name])==null?void 0:C.enabled)||!1;return c==="enabled"?S:!0}).filter(m=>o?(m.displayName||m.name).toLowerCase().includes(o)||m.name.toLowerCase().includes(o):!0)},[c,f,h,g]);return j.useEffect(()=>{if(w.length===0){d(void 0);return}w.some(m=>m.name===u)||d(w[0].name)},[w,u]),!t||!p?a.jsx("div",{className:"p-8 text-gray-400",children:e("channelsLoading")}):a.jsxs(de,{className:"xl:flex xl:h-full xl:min-h-0 xl:flex-col xl:pb-0",children:[a.jsx(be,{title:e("channelsPageTitle"),description:e("channelsPageDescription")}),a.jsxs("div",{className:P(Ce,"xl:min-h-0 xl:flex-1"),children:[a.jsxs("section",{className:Se,children:[a.jsx("div",{className:"border-b border-gray-100 px-4 pt-4",children:a.jsx(Ne,{tabs:k,activeTab:c,onChange:r,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:o=>x(o.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(o=>{const m=t.channels[o.name],S=(m==null?void 0:m.enabled)||!1,C=_(`channels.${o.name}`,v),I=Y(o),F=(C==null?void 0:C.help)||e(Ae[o.name]||"channelDescriptionDefault"),N=u===o.name;return a.jsx("button",{type:"button",onClick:()=>d(o.name),className:P("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(H,{name:o.name,src:J(o.name),className:P("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:o.name[0]})}),a.jsxs("div",{className:"min-w-0",children:[a.jsx("p",{className:"truncate text-sm font-semibold text-gray-900",children:o.displayName||o.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:[I&&a.jsx("a",{href:I,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(z,{status:S?"active":"inactive",label:S?e("statusActive"):e("statusInactive"),className:"min-w-[56px] justify-center"})]})]})},o.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(De,{channelName:u})]})]})}export{qe as ChannelsList};
|