@nextclaw/ui 0.12.24 → 0.12.26
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 +136 -29
- package/dist/assets/api-DGD9_Bg4.js +15 -0
- package/dist/assets/app-manager-provider-oYdeYPSv.js +1 -0
- package/dist/assets/{book-open-DDlN5MvX.js → book-open-BcnAiKde.js} +1 -1
- package/dist/assets/channels-list-page-HgLgrEg4.js +8 -0
- package/dist/assets/chat-page-DAKMFDrS.js +1 -0
- package/dist/assets/config-split-page-CcrEUtwu.js +1 -0
- package/dist/assets/cpu-DPPwMzoC.js +3 -0
- package/dist/assets/{createLucideIcon-BLMK3QUd.js → createLucideIcon-DzY6wN61.js} +1 -1
- package/dist/assets/desktop-DVUbOWbR.js +3 -0
- package/dist/assets/desktop-update-config-CP8dFYXK.js +1 -0
- package/dist/assets/{dialog-C3D7Be0p.js → dialog-BKo0RItd.js} +1 -1
- package/dist/assets/{dist-CPlbUgwU.js → dist-CFiwgaLs.js} +1 -1
- package/dist/assets/doc-browser-CAhfnm0D.js +1 -0
- package/dist/assets/{doc-browser-context-BJuMaI3o.js → doc-browser-context-FukQHvyo.js} +1 -1
- package/dist/assets/doc-browser-p9DDNPWB.js +1 -0
- package/dist/assets/doc-browser-rZIQIjuw.js +1 -0
- package/dist/assets/download-CMM8po31.js +1 -0
- package/dist/assets/{es2015-xqN1slyW.js → es2015-BhznEEyJ.js} +1 -1
- package/dist/assets/{external-link-DwfSfTLB.js → external-link-CpEvG65F.js} +1 -1
- package/dist/assets/i18n-D1144VAA.js +1 -0
- package/dist/assets/index-Cuwst6cc.js +100 -0
- package/dist/assets/index-dlcqieQ0.css +1 -0
- package/dist/assets/{key-round-CJ5gDAAG.js → key-round-DUq47t0P.js} +1 -1
- package/dist/assets/marketplace-page-BeFbwxR-.js +105 -0
- package/dist/assets/marketplace-page-CR4xq-TM.js +1 -0
- package/dist/assets/mcp-marketplace-page-DlRrSCj3.js +1 -0
- package/dist/assets/mcp-marketplace-page-DwnaLNTx.js +40 -0
- package/dist/assets/model-config-L2l6YAlQ.js +1 -0
- package/dist/assets/{notice-card-BFDbKQDA.js → notice-card-Dr6xCwva.js} +1 -1
- package/dist/assets/play-AqrNslHI.js +1 -0
- package/dist/assets/plus-B-YHtTNC.js +1 -0
- package/dist/assets/{popover-B86Dbfhf.js → popover-BDFNiLlg.js} +1 -1
- package/dist/assets/provider-scoped-model-input-BMTp4BEH.js +1 -0
- package/dist/assets/providers-list-DYAEunOp.js +1 -0
- package/dist/assets/refresh-cw-CrbD8EkT.js +1 -0
- package/dist/assets/remote-Dr3jcfWP.js +1 -0
- package/dist/assets/{rotate-cw-BZ2JObNs.js → rotate-cw-BN9yjccP.js} +1 -1
- package/dist/assets/runtime-config-page-BdeU8PEK.js +1 -0
- package/dist/assets/{save-euRxl8pI.js → save-CO_4qf6b.js} +1 -1
- package/dist/assets/{search-CLd7m0M7.js → search-CRtQwr-h.js} +1 -1
- package/dist/assets/search-config-CQUhd5RU.js +1 -0
- package/dist/assets/secrets-config-D-NWlW9q.js +3 -0
- package/dist/assets/{select-CJ0wbo3D.js → select-BUTwE_lC.js} +1 -1
- package/dist/assets/{setting-row-D1Yygqp7.js → setting-row-BavcnXw1.js} +1 -1
- package/dist/assets/settings-MWL2SMyk.js +1 -0
- package/dist/assets/{sparkles-DVfeSVJQ.js → sparkles-BmgOD4nY.js} +1 -1
- package/dist/assets/{status-dot-ChvPCib9.js → status-dot-l3kPFdq_.js} +1 -1
- package/dist/assets/{tabs-custom-Hia_ong0.js → tabs-custom-D48zdZoc.js} +1 -1
- package/dist/assets/{tag-chip-FrkmkT8r.js → tag-chip-Dm2Lqnpu.js} +1 -1
- package/dist/assets/use-config-Cyv5IuSt.js +1 -0
- package/dist/assets/use-infinite-scroll-loader-CFVdPpNv.js +1 -0
- package/dist/assets/x-BeyYA_h6.js +1 -0
- package/dist/index.html +29 -40
- package/package.json +9 -9
- package/src/app/components/layout/sidebar.layout.test.tsx +2 -4
- package/src/app/components/theme-provider.tsx +1 -0
- package/src/app/configs/app-navigation.config.ts +0 -6
- package/src/app/index.tsx +4 -7
- package/src/features/agents/components/agents-page.test.tsx +25 -15
- package/src/features/agents/components/agents-page.tsx +133 -172
- package/src/features/channels/components/config/channel-form.test.tsx +1 -0
- package/src/features/channels/components/config/channel-form.tsx +4 -3
- package/src/features/channels/components/config/weixin-channel-auth-section.test.tsx +38 -1
- package/src/features/channels/components/config/weixin-channel-auth-section.tsx +137 -40
- package/src/features/channels/index.ts +1 -1
- package/src/features/channels/utils/channel-form-fields.utils.test.ts +26 -0
- package/src/features/channels/utils/channel-form-fields.utils.ts +32 -18
- package/src/features/chat/components/chat-session-workspace-panel-nav.tsx +23 -4
- package/src/features/chat/components/chat-session-workspace-panel.tsx +53 -35
- package/src/features/chat/components/chat-sidebar-session-item.tsx +16 -12
- package/src/features/chat/components/conversation/chat-conversation-header.test.tsx +74 -0
- package/src/features/chat/components/conversation/chat-conversation-header.tsx +8 -2
- package/src/features/chat/components/conversation/chat-conversation-panel.test.tsx +262 -114
- package/src/features/chat/components/conversation/chat-conversation-panel.tsx +210 -174
- package/src/features/chat/components/conversation/chat-input-bar.container.tsx +11 -1
- package/src/features/chat/components/conversation/session-header/chat-session-header-actions.test.tsx +24 -0
- package/src/features/chat/components/conversation/session-header/chat-session-header-actions.tsx +27 -6
- package/src/features/chat/components/layout/chat-sidebar-utility-menu.tsx +174 -0
- package/src/features/chat/components/layout/chat-sidebar.test.tsx +45 -8
- package/src/features/chat/components/layout/chat-sidebar.tsx +29 -46
- package/src/features/chat/components/providers/chat-presenter.provider.tsx +4 -0
- package/src/features/chat/components/workspace/session-cron-job-content.tsx +103 -0
- package/src/features/chat/hooks/use-ncp-agent-runtime.test.tsx +153 -80
- package/src/features/chat/hooks/use-ncp-chat-page-data.test.tsx +70 -0
- package/src/features/chat/hooks/use-ncp-chat-page-data.ts +1 -1
- package/src/features/chat/hooks/use-ncp-child-session-tabs-view.ts +2 -8
- package/src/features/chat/hooks/use-ncp-session-list-view.ts +1 -2
- package/src/features/chat/managers/chat-session-list.manager.test.ts +7 -9
- package/src/features/chat/managers/chat-session-list.manager.ts +5 -10
- package/src/features/chat/managers/ncp-chat-input.manager.test.ts +20 -2
- package/src/features/chat/managers/ncp-chat-input.manager.ts +18 -0
- package/src/features/chat/managers/ncp-chat-presenter.manager.ts +7 -0
- package/src/features/chat/managers/ncp-chat-thread.manager.test.ts +52 -1
- package/src/features/chat/managers/ncp-chat-thread.manager.ts +21 -0
- package/src/features/chat/pages/ncp-chat-page.tsx +9 -5
- package/src/features/chat/stores/chat-input.store.ts +3 -1
- package/src/features/chat/stores/chat-session-list.store.ts +0 -2
- package/src/features/chat/stores/chat-thread.store.ts +4 -0
- package/src/features/chat/utils/chat-session-display.utils.test.ts +83 -1
- package/src/features/chat/utils/chat-session-display.utils.ts +73 -0
- package/src/features/chat/utils/ncp-chat-input-availability.utils.test.ts +1 -0
- package/src/features/chat/utils/ncp-session-adapter.utils.test.ts +22 -0
- package/src/features/chat/utils/ncp-session-adapter.utils.ts +32 -0
- package/src/features/marketplace/components/curated-shelves/marketplace-curated-scene-route.test.tsx +235 -0
- package/src/features/marketplace/components/curated-shelves/marketplace-curated-shelves.config.ts +162 -0
- package/src/features/marketplace/components/curated-shelves/marketplace-curated-shelves.tsx +355 -0
- package/src/features/marketplace/components/curated-shelves/marketplace-shelf-card.tsx +118 -0
- package/src/features/marketplace/components/detail-doc/marketplace-detail-doc-renderer.ts +201 -0
- package/src/features/marketplace/components/detail-doc/marketplace-detail-doc.test.ts +40 -0
- package/src/features/marketplace/components/marketplace-catalog-grid.tsx +114 -0
- package/src/features/marketplace/components/marketplace-detail-doc.ts +73 -24
- package/src/features/marketplace/components/marketplace-item-icon.tsx +45 -0
- package/src/features/marketplace/components/marketplace-list-card.tsx +177 -93
- package/src/features/marketplace/components/marketplace-page-detail.test.tsx +9 -2
- package/src/features/marketplace/components/marketplace-page-parts.tsx +1 -1
- package/src/features/marketplace/components/marketplace-page.test.tsx +25 -6
- package/src/features/marketplace/components/marketplace-page.tsx +154 -132
- package/src/features/marketplace/hooks/use-marketplace-curated-scene-route.ts +97 -0
- package/src/features/marketplace/hooks/use-marketplace.ts +59 -3
- package/src/features/system-status/components/config/runtime-agent-list-card.tsx +4 -8
- package/src/features/system-status/components/config/runtime-binding-list-card.tsx +5 -7
- package/src/features/system-status/components/config/runtime-config-editor.tsx +1 -19
- package/src/features/system-status/components/config/runtime-entry-list-card.tsx +10 -11
- package/src/features/system-status/components/config/runtime-settings-card.tsx +15 -23
- package/src/features/system-status/components/runtime-control-card.test.tsx +8 -6
- package/src/features/system-status/components/runtime-control-card.tsx +7 -6
- package/src/features/system-status/pages/runtime-config-page.test.tsx +19 -9
- package/src/features/system-status/pages/runtime-config-page.tsx +2 -3
- package/src/features/system-status/utils/runtime-config-agent.utils.ts +4 -4
- package/src/features/system-status/utils/system-status.utils.ts +31 -6
- package/src/index.css +8 -0
- package/src/platforms/desktop/components/desktop-app-shell.test.tsx +68 -0
- package/src/platforms/desktop/components/desktop-app-shell.tsx +46 -18
- package/src/platforms/desktop/components/desktop-window-chrome.tsx +30 -0
- package/src/platforms/desktop/index.ts +6 -0
- package/src/platforms/desktop/types/desktop-update.types.ts +3 -0
- package/src/platforms/desktop/utils/desktop-host.utils.ts +56 -0
- package/src/shared/components/common/brand-header.tsx +36 -16
- package/src/shared/components/config/provider-form-support.ts +2 -22
- package/src/shared/components/cron-config.tsx +12 -58
- package/src/shared/components/doc-browser/doc-browser.tsx +4 -4
- package/src/shared/components/ui/select.tsx +19 -7
- package/src/shared/lib/api/channel-auth.types.ts +1 -0
- package/src/shared/lib/api/ncp-session.types.ts +9 -0
- package/src/shared/lib/api/types.ts +12 -1
- package/src/shared/lib/api/utils/marketplace.utils.ts +7 -1
- package/src/shared/lib/cron/cron-job-view.utils.ts +59 -0
- package/src/shared/lib/cron/index.ts +1 -0
- package/src/shared/lib/i18n/{channel-auth.ts → channel-auth.constants.ts} +31 -0
- package/src/shared/lib/i18n/chat-labels.utils.ts +3 -2
- package/src/shared/lib/i18n/index.ts +20 -59
- package/src/shared/lib/i18n/{runtime-control.ts → runtime-control-labels.utils.ts} +30 -1
- package/src/shared/lib/provider-models/index.test.ts +39 -0
- package/src/shared/lib/provider-models/index.ts +1 -3
- package/src/shared/lib/ui-document-title/index.ts +0 -1
- package/tsconfig.json +1 -0
- package/vite.config.ts +1 -1
- package/vitest.config.ts +1 -1
- package/dist/assets/api-D2xRKmZd.js +0 -15
- package/dist/assets/app-manager-provider-CNaZboG4.js +0 -1
- package/dist/assets/app-navigation.config-Ihhrrt--.js +0 -1
- package/dist/assets/channels-list-page-p26lgxLk.js +0 -8
- package/dist/assets/chat-Dkh2qtuz.js +0 -61
- package/dist/assets/chat-page-DoTmE2wx.js +0 -1
- package/dist/assets/chunk-JZWAC4HX-Kydj4yEz.js +0 -3
- package/dist/assets/config-split-page-DIOCjj2Q.js +0 -1
- package/dist/assets/desktop-update-config-DlpzDfKM.js +0 -1
- package/dist/assets/doc-browser-C8FM5fC0.js +0 -1
- package/dist/assets/doc-browser-RJUOL_GO.js +0 -1
- package/dist/assets/doc-browser-p82AdNO-.js +0 -1
- package/dist/assets/folder-CeJKPx5P.js +0 -1
- package/dist/assets/hash-BqxRTZW5.js +0 -1
- package/dist/assets/i18n-DnTGDIRw.js +0 -1
- package/dist/assets/index-D8MKmXtO.css +0 -1
- package/dist/assets/index-pBvbJ5Mt.js +0 -2
- package/dist/assets/loader-circle-fd-vQKtW.js +0 -1
- package/dist/assets/logo-badge-KAe-7d8c.js +0 -1
- package/dist/assets/logos-C4sYP1Vl.js +0 -1
- package/dist/assets/marketplace-page-Cql0kDi-.js +0 -1
- package/dist/assets/marketplace-page-m4P5g_Ht.js +0 -49
- package/dist/assets/mcp-marketplace-page-9WVKl1m1.js +0 -1
- package/dist/assets/mcp-marketplace-page-ByzBQZcx.js +0 -40
- package/dist/assets/message-square-z_osm9c0.js +0 -1
- package/dist/assets/model-config-Dbr_0APb.js +0 -1
- package/dist/assets/play-Dv6Nr1Ew.js +0 -1
- package/dist/assets/plus-D8eKFY7h.js +0 -1
- package/dist/assets/provider-scoped-model-input-DFm6N2f7.js +0 -1
- package/dist/assets/providers-list-BJcLOjun.js +0 -1
- package/dist/assets/refresh-ccw-ByVwmnN_.js +0 -1
- package/dist/assets/refresh-cw-PcqoYB3K.js +0 -1
- package/dist/assets/remote-BOxo9iwd.js +0 -1
- package/dist/assets/runtime-config-page-CjLhnbSl.js +0 -1
- package/dist/assets/search-config-J4Htco-P.js +0 -1
- package/dist/assets/secrets-config-CUdERjco.js +0 -3
- package/dist/assets/sessions-config-page-DpK991fs.js +0 -2
- package/dist/assets/settings-drbWqzA4.js +0 -1
- package/dist/assets/skeleton-BK1SOSRA.js +0 -1
- package/dist/assets/theme-provider-0hxjiPc_.js +0 -2
- package/dist/assets/tooltip-Cj4yA0gH.js +0 -1
- package/dist/assets/trash-2-CBsHCfqq.js +0 -1
- package/dist/assets/use-config-38Ur-89i.js +0 -1
- package/dist/assets/use-confirm-dialog-DPQThaeU.js +0 -1
- package/dist/assets/use-infinite-scroll-loader-5Gf1xQi7.js +0 -1
- package/dist/assets/use-viewport-layout-D1XzKeip.js +0 -1
- package/dist/assets/x-CM-XDMpk.js +0 -1
- package/src/features/chat/components/config/sessions-config-detail-pane.tsx +0 -244
- package/src/features/chat/pages/sessions-config-page.test.tsx +0 -152
- package/src/features/chat/pages/sessions-config-page.tsx +0 -192
- /package/dist/assets/{config-hints-MogHYQ8G.js → config-hints-BNfpOL4J.js} +0 -0
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { useMemo, useState } from "react";
|
|
2
2
|
import {
|
|
3
|
-
useCreateAgent,
|
|
4
3
|
useDeleteAgent,
|
|
5
4
|
useAgents,
|
|
6
5
|
useUpdateAgent,
|
|
@@ -8,9 +7,7 @@ import {
|
|
|
8
7
|
import { useConfig, useConfigMeta } from "@/shared/hooks/use-config";
|
|
9
8
|
import type { AgentProfileView } from "@/shared/lib/api";
|
|
10
9
|
import {
|
|
11
|
-
AgentCreateDialog,
|
|
12
10
|
AgentEditDialog,
|
|
13
|
-
type AgentCreateFormState,
|
|
14
11
|
type AgentEditFormState,
|
|
15
12
|
} from "@/features/agents/components/agent-dialogs";
|
|
16
13
|
import {
|
|
@@ -24,7 +21,11 @@ import {
|
|
|
24
21
|
import { AgentAvatar } from "@/shared/components/common/agent-avatar";
|
|
25
22
|
import { Button } from "@/shared/components/ui/button";
|
|
26
23
|
import { Card, CardContent } from "@/shared/components/ui/card";
|
|
27
|
-
import {
|
|
24
|
+
import {
|
|
25
|
+
Popover,
|
|
26
|
+
PopoverContent,
|
|
27
|
+
PopoverTrigger,
|
|
28
|
+
} from "@/shared/components/ui/popover";
|
|
28
29
|
import { TagChip } from "@/shared/components/ui/tag-chip";
|
|
29
30
|
import { PageLayout } from "@/app/components/layout/page-layout";
|
|
30
31
|
import { t } from "@/shared/lib/i18n";
|
|
@@ -34,6 +35,7 @@ import {
|
|
|
34
35
|
Bot,
|
|
35
36
|
House,
|
|
36
37
|
MessageCircle,
|
|
38
|
+
MoreHorizontal,
|
|
37
39
|
Pencil,
|
|
38
40
|
Plus,
|
|
39
41
|
ShieldCheck,
|
|
@@ -41,86 +43,75 @@ import {
|
|
|
41
43
|
Trash2,
|
|
42
44
|
} from "lucide-react";
|
|
43
45
|
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
strip: "bg-[#efc37a]",
|
|
47
|
-
chip: "border-[#f2d7a7] bg-[#fff8eb] text-[#8d5a18]",
|
|
48
|
-
},
|
|
49
|
-
{
|
|
50
|
-
strip: "bg-[#8fd4c0]",
|
|
51
|
-
chip: "border-[#bde6da] bg-[#effbf7] text-[#156653]",
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
strip: "bg-[#b7c9fb]",
|
|
55
|
-
chip: "border-[#d7e2ff] bg-[#f4f7ff] text-[#2d4d8f]",
|
|
56
|
-
},
|
|
57
|
-
] as const;
|
|
58
|
-
|
|
59
|
-
function resolveAgentTone(index: number, builtIn: boolean) {
|
|
60
|
-
if (builtIn) {
|
|
61
|
-
return {
|
|
62
|
-
strip: "bg-[#e6b765]",
|
|
63
|
-
chip: "border-[#f2d19c] bg-[#fff8ec] text-[#90550d]",
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
return CARD_TONES[index % CARD_TONES.length];
|
|
67
|
-
}
|
|
46
|
+
const AGENT_CREATION_PROMPT =
|
|
47
|
+
"请直接创建一个默认示例 Agent,不要问我问题。创建完成后,简单告诉我它能做什么。";
|
|
68
48
|
|
|
69
49
|
function AgentsHero(props: { agentCount: number; onCreate: () => void }) {
|
|
70
50
|
const { agentCount, onCreate } = props;
|
|
71
51
|
|
|
72
52
|
return (
|
|
73
|
-
<section className="
|
|
74
|
-
<div className="
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
<div className="max-w-3xl space-y-3">
|
|
78
|
-
<div className="inline-flex items-center gap-2 rounded-full border border-white/70 bg-white/80 px-3 py-1 text-[11px] font-semibold tracking-[0.16em] text-[#9b6118]">
|
|
79
|
-
<Sparkles className="h-3.5 w-3.5" />
|
|
53
|
+
<section className="flex flex-col gap-3 border-b border-gray-200 pb-4 sm:flex-row sm:items-end sm:justify-between">
|
|
54
|
+
<div className="min-w-0 space-y-1">
|
|
55
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
56
|
+
<h1 className="text-xl font-semibold text-gray-950">
|
|
80
57
|
{t("agentsHeroEyebrow")}
|
|
81
|
-
</
|
|
82
|
-
<
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
</h1>
|
|
86
|
-
<p className="max-w-2xl text-sm leading-6 text-[#6d5841] sm:text-[15px] sm:leading-7">
|
|
87
|
-
{t("agentsHeroDescription")}
|
|
88
|
-
</p>
|
|
89
|
-
</div>
|
|
90
|
-
<div className="pt-1">
|
|
91
|
-
<div className="inline-flex items-center gap-3 rounded-2xl border border-[#f2d5a4] bg-white/82 px-3 py-2 text-[#7a4d12] shadow-[0_14px_30px_rgba(167,117,47,0.07)]">
|
|
92
|
-
<span className="text-[11px] font-semibold tracking-[0.14em]">
|
|
93
|
-
{t("agentsOverviewTotal")}
|
|
94
|
-
</span>
|
|
95
|
-
<span className="text-xl font-semibold tracking-[-0.04em] text-[#1f2937]">
|
|
96
|
-
{agentCount}
|
|
97
|
-
</span>
|
|
98
|
-
</div>
|
|
99
|
-
</div>
|
|
100
|
-
</div>
|
|
101
|
-
<div className="flex shrink-0 flex-col gap-3">
|
|
102
|
-
<Button
|
|
103
|
-
type="button"
|
|
104
|
-
variant="primary"
|
|
105
|
-
className="h-10 rounded-2xl px-5 text-sm font-semibold"
|
|
106
|
-
onClick={onCreate}
|
|
107
|
-
>
|
|
108
|
-
<Plus className="mr-2 h-4 w-4" />
|
|
109
|
-
{t("agentsCreateButton")}
|
|
110
|
-
</Button>
|
|
111
|
-
<NoticeCard
|
|
112
|
-
title={t("agentsCreateDialogHint")}
|
|
113
|
-
className="border-white/70 bg-white/72 text-xs leading-6 shadow-[0_18px_40px_rgba(167,117,47,0.08)]"
|
|
114
|
-
/>
|
|
58
|
+
</h1>
|
|
59
|
+
<span className="rounded-full border border-gray-200 bg-white px-2 py-0.5 text-xs font-medium text-gray-500">
|
|
60
|
+
{agentCount}
|
|
61
|
+
</span>
|
|
115
62
|
</div>
|
|
63
|
+
<p className="max-w-2xl text-sm leading-6 text-gray-500">
|
|
64
|
+
{t("agentsHeroDescription")}
|
|
65
|
+
</p>
|
|
116
66
|
</div>
|
|
67
|
+
<Button
|
|
68
|
+
type="button"
|
|
69
|
+
variant="primary"
|
|
70
|
+
className="h-9 shrink-0 rounded-xl px-4 text-sm font-semibold"
|
|
71
|
+
onClick={onCreate}
|
|
72
|
+
>
|
|
73
|
+
<Plus className="mr-2 h-4 w-4" />
|
|
74
|
+
{t("agentsCreateButton")}
|
|
75
|
+
</Button>
|
|
117
76
|
</section>
|
|
118
77
|
);
|
|
119
78
|
}
|
|
120
79
|
|
|
80
|
+
function AgentActionMenuItem(props: {
|
|
81
|
+
icon: typeof Pencil;
|
|
82
|
+
label: string;
|
|
83
|
+
disabled?: boolean;
|
|
84
|
+
destructive?: boolean;
|
|
85
|
+
onClick: () => void;
|
|
86
|
+
}) {
|
|
87
|
+
const {
|
|
88
|
+
icon: Icon,
|
|
89
|
+
label,
|
|
90
|
+
disabled = false,
|
|
91
|
+
destructive = false,
|
|
92
|
+
onClick,
|
|
93
|
+
} = props;
|
|
94
|
+
|
|
95
|
+
return (
|
|
96
|
+
<button
|
|
97
|
+
type="button"
|
|
98
|
+
className={cn(
|
|
99
|
+
"flex w-full items-center gap-2 rounded-lg px-3 py-2 text-left text-sm transition-colors disabled:cursor-not-allowed disabled:opacity-50",
|
|
100
|
+
destructive
|
|
101
|
+
? "text-destructive hover:bg-destructive/10"
|
|
102
|
+
: "text-gray-700 hover:bg-gray-100",
|
|
103
|
+
)}
|
|
104
|
+
onClick={onClick}
|
|
105
|
+
disabled={disabled}
|
|
106
|
+
>
|
|
107
|
+
<Icon className="h-4 w-4 shrink-0" />
|
|
108
|
+
<span>{label}</span>
|
|
109
|
+
</button>
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
121
113
|
function AgentListCard(props: {
|
|
122
114
|
agent: AgentProfileView;
|
|
123
|
-
index: number;
|
|
124
115
|
runtimeOptions: { value: string; label: string }[];
|
|
125
116
|
defaultRuntimeLabel: string;
|
|
126
117
|
updatePending: boolean;
|
|
@@ -131,7 +122,6 @@ function AgentListCard(props: {
|
|
|
131
122
|
}) {
|
|
132
123
|
const {
|
|
133
124
|
agent,
|
|
134
|
-
index,
|
|
135
125
|
runtimeOptions,
|
|
136
126
|
defaultRuntimeLabel,
|
|
137
127
|
updatePending,
|
|
@@ -140,7 +130,6 @@ function AgentListCard(props: {
|
|
|
140
130
|
onEdit,
|
|
141
131
|
onDelete,
|
|
142
132
|
} = props;
|
|
143
|
-
const tone = resolveAgentTone(index, Boolean(agent.builtIn));
|
|
144
133
|
const runtimeValue = agent.runtime?.trim() || agent.engine?.trim() || "";
|
|
145
134
|
const runtimeLabel = runtimeValue
|
|
146
135
|
? (runtimeOptions.find(
|
|
@@ -149,94 +138,94 @@ function AgentListCard(props: {
|
|
|
149
138
|
: defaultRuntimeLabel;
|
|
150
139
|
|
|
151
140
|
return (
|
|
152
|
-
<Card className="overflow-hidden border border-gray-200 bg-white shadow-
|
|
153
|
-
<
|
|
154
|
-
|
|
155
|
-
<div className="flex items-start gap-3">
|
|
141
|
+
<Card className="group overflow-hidden border border-gray-200 bg-white shadow-none transition-colors duration-200 hover:border-gray-300">
|
|
142
|
+
<CardContent className="relative flex h-full flex-col gap-3 px-3.5 py-3.5">
|
|
143
|
+
<div className="flex items-start gap-2.5 pr-16">
|
|
156
144
|
<AgentAvatar
|
|
157
145
|
agentId={agent.id}
|
|
158
146
|
displayName={agent.displayName}
|
|
159
147
|
avatarUrl={agent.avatarUrl}
|
|
160
|
-
className="h-
|
|
148
|
+
className="h-9 w-9 shrink-0"
|
|
161
149
|
/>
|
|
162
|
-
<div className="min-w-0 flex-1 space-y-
|
|
163
|
-
<div className="flex
|
|
164
|
-
<div className="truncate text-
|
|
150
|
+
<div className="min-w-0 flex-1 space-y-0.5">
|
|
151
|
+
<div className="flex min-w-0 items-center gap-2">
|
|
152
|
+
<div className="truncate text-sm font-semibold text-gray-950">
|
|
165
153
|
{agent.displayName?.trim() || agent.id}
|
|
166
154
|
</div>
|
|
167
155
|
{agent.builtIn ? (
|
|
168
|
-
<TagChip
|
|
156
|
+
<TagChip
|
|
157
|
+
tone="warning"
|
|
158
|
+
className="h-5 gap-1 border-amber-200 bg-amber-50 px-1.5 text-[10px] text-amber-700"
|
|
159
|
+
>
|
|
169
160
|
<ShieldCheck className="h-3 w-3" />
|
|
170
161
|
{t("agentsCardBuiltInTag")}
|
|
171
162
|
</TagChip>
|
|
172
163
|
) : null}
|
|
173
164
|
</div>
|
|
174
|
-
<div className="text-
|
|
175
|
-
@{agent.id}
|
|
176
|
-
</div>
|
|
165
|
+
<div className="truncate text-xs text-gray-400">@{agent.id}</div>
|
|
177
166
|
</div>
|
|
178
167
|
</div>
|
|
179
168
|
|
|
180
|
-
<
|
|
169
|
+
<div className="absolute right-2.5 top-2.5 flex items-center gap-1 opacity-100 transition-opacity md:opacity-0 md:group-hover:opacity-100 md:group-focus-within:opacity-100">
|
|
170
|
+
<Button
|
|
171
|
+
type="button"
|
|
172
|
+
variant="ghost"
|
|
173
|
+
size="icon"
|
|
174
|
+
className="h-8 w-8 rounded-lg text-gray-400 hover:text-gray-800"
|
|
175
|
+
aria-label={t("agentsCardStartChat")}
|
|
176
|
+
title={t("agentsCardStartChat")}
|
|
177
|
+
onClick={onStartChat}
|
|
178
|
+
>
|
|
179
|
+
<MessageCircle className="h-4 w-4" />
|
|
180
|
+
</Button>
|
|
181
|
+
<Popover>
|
|
182
|
+
<PopoverTrigger asChild>
|
|
183
|
+
<Button
|
|
184
|
+
type="button"
|
|
185
|
+
variant="ghost"
|
|
186
|
+
size="icon"
|
|
187
|
+
className="h-8 w-8 rounded-lg text-gray-400 hover:text-gray-800"
|
|
188
|
+
aria-label={t("chatSessionMoreActions")}
|
|
189
|
+
title={t("chatSessionMoreActions")}
|
|
190
|
+
>
|
|
191
|
+
<MoreHorizontal className="h-4 w-4" />
|
|
192
|
+
</Button>
|
|
193
|
+
</PopoverTrigger>
|
|
194
|
+
<PopoverContent align="end" className="w-44 p-1.5">
|
|
195
|
+
<AgentActionMenuItem
|
|
196
|
+
icon={Pencil}
|
|
197
|
+
label={t("agentsEditAction")}
|
|
198
|
+
onClick={onEdit}
|
|
199
|
+
disabled={updatePending}
|
|
200
|
+
/>
|
|
201
|
+
{!agent.builtIn ? (
|
|
202
|
+
<AgentActionMenuItem
|
|
203
|
+
icon={Trash2}
|
|
204
|
+
label={t("agentsRemoveAction")}
|
|
205
|
+
onClick={onDelete}
|
|
206
|
+
disabled={deletePending}
|
|
207
|
+
destructive
|
|
208
|
+
/>
|
|
209
|
+
) : null}
|
|
210
|
+
</PopoverContent>
|
|
211
|
+
</Popover>
|
|
212
|
+
</div>
|
|
213
|
+
|
|
214
|
+
<p className="line-clamp-2 min-h-10 text-sm leading-5 text-gray-600">
|
|
181
215
|
{agent.description?.trim() ||
|
|
182
216
|
(agent.builtIn
|
|
183
217
|
? t("agentsCardBuiltInSummary")
|
|
184
218
|
: t("agentsCardCustomSummary"))}
|
|
185
219
|
</p>
|
|
186
220
|
|
|
187
|
-
<div className="mt-auto
|
|
188
|
-
<div>
|
|
189
|
-
<
|
|
190
|
-
|
|
191
|
-
{t("agentsCardRuntimeLabel")}
|
|
192
|
-
</div>
|
|
193
|
-
<div className="mt-1.5 text-sm leading-6 text-[#475569]">
|
|
194
|
-
{runtimeLabel}
|
|
195
|
-
</div>
|
|
196
|
-
</div>
|
|
197
|
-
|
|
198
|
-
<div className="border-t border-gray-100 pt-3">
|
|
199
|
-
<div className="flex items-center gap-2 text-[11px] font-semibold uppercase tracking-[0.18em] text-[#94a3b8]">
|
|
200
|
-
<House className="h-3.5 w-3.5" />
|
|
201
|
-
{t("agentsCardHomeLabel")}
|
|
202
|
-
</div>
|
|
203
|
-
<div className="mt-1.5 break-all text-sm leading-6 text-[#475569]">
|
|
204
|
-
{agent.workspace ?? "-"}
|
|
205
|
-
</div>
|
|
221
|
+
<div className="mt-auto grid gap-2 border-t border-gray-100 pt-2 text-xs text-gray-500">
|
|
222
|
+
<div className="flex min-w-0 items-center gap-2">
|
|
223
|
+
<Sparkles className="h-3.5 w-3.5 shrink-0 text-gray-300" />
|
|
224
|
+
<span className="truncate">{runtimeLabel}</span>
|
|
206
225
|
</div>
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
<
|
|
210
|
-
type="button"
|
|
211
|
-
variant="primary"
|
|
212
|
-
className="h-9 rounded-xl px-4"
|
|
213
|
-
onClick={onStartChat}
|
|
214
|
-
>
|
|
215
|
-
<MessageCircle className="mr-2 h-4 w-4" />
|
|
216
|
-
{t("agentsCardStartChat")}
|
|
217
|
-
</Button>
|
|
218
|
-
<Button
|
|
219
|
-
type="button"
|
|
220
|
-
variant="ghost"
|
|
221
|
-
className="h-8 rounded-xl px-3 text-xs text-[#7b8794] hover:bg-[#f3f4f6] hover:text-[#475569]"
|
|
222
|
-
onClick={onEdit}
|
|
223
|
-
disabled={updatePending}
|
|
224
|
-
>
|
|
225
|
-
<Pencil className="mr-1.5 h-3.5 w-3.5" />
|
|
226
|
-
{t("agentsEditAction")}
|
|
227
|
-
</Button>
|
|
228
|
-
{!agent.builtIn ? (
|
|
229
|
-
<Button
|
|
230
|
-
type="button"
|
|
231
|
-
variant="ghost"
|
|
232
|
-
className="h-8 rounded-xl px-3 text-xs text-[#7b8794] hover:bg-[#f3f4f6] hover:text-[#475569]"
|
|
233
|
-
onClick={onDelete}
|
|
234
|
-
disabled={deletePending}
|
|
235
|
-
>
|
|
236
|
-
<Trash2 className="mr-1.5 h-3.5 w-3.5" />
|
|
237
|
-
{t("agentsRemoveAction")}
|
|
238
|
-
</Button>
|
|
239
|
-
) : null}
|
|
226
|
+
<div className="flex min-w-0 items-center gap-2">
|
|
227
|
+
<House className="h-3.5 w-3.5 shrink-0 text-gray-300" />
|
|
228
|
+
<span className="truncate">{agent.workspace ?? "-"}</span>
|
|
240
229
|
</div>
|
|
241
230
|
</div>
|
|
242
231
|
</CardContent>
|
|
@@ -250,10 +239,8 @@ export function AgentsPage() {
|
|
|
250
239
|
const configQuery = useConfig();
|
|
251
240
|
const configMetaQuery = useConfigMeta();
|
|
252
241
|
const sessionTypesQuery = useNcpChatSessionTypes();
|
|
253
|
-
const createAgent = useCreateAgent();
|
|
254
242
|
const updateAgent = useUpdateAgent();
|
|
255
243
|
const deleteAgent = useDeleteAgent();
|
|
256
|
-
const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false);
|
|
257
244
|
const [editingAgent, setEditingAgent] = useState<AgentProfileView | null>(
|
|
258
245
|
null,
|
|
259
246
|
);
|
|
@@ -294,25 +281,6 @@ export function AgentsPage() {
|
|
|
294
281
|
[defaultRuntime, runtimeOptions],
|
|
295
282
|
);
|
|
296
283
|
|
|
297
|
-
const handleCreate = async (form: AgentCreateFormState) => {
|
|
298
|
-
await createAgent.mutateAsync({
|
|
299
|
-
data: {
|
|
300
|
-
id: form.id,
|
|
301
|
-
...(form.displayName.trim()
|
|
302
|
-
? { displayName: form.displayName.trim() }
|
|
303
|
-
: {}),
|
|
304
|
-
...(form.description.trim()
|
|
305
|
-
? { description: form.description.trim() }
|
|
306
|
-
: {}),
|
|
307
|
-
...(form.avatar.trim() ? { avatar: form.avatar.trim() } : {}),
|
|
308
|
-
...(form.home.trim() ? { home: form.home.trim() } : {}),
|
|
309
|
-
...(form.model.trim() ? { model: form.model.trim() } : {}),
|
|
310
|
-
...(form.runtime.trim() ? { runtime: form.runtime.trim() } : {}),
|
|
311
|
-
},
|
|
312
|
-
});
|
|
313
|
-
setIsCreateDialogOpen(false);
|
|
314
|
-
};
|
|
315
|
-
|
|
316
284
|
const handleStartEdit = (agent: AgentProfileView) => {
|
|
317
285
|
setEditingAgent(agent);
|
|
318
286
|
};
|
|
@@ -344,7 +312,9 @@ export function AgentsPage() {
|
|
|
344
312
|
<PageLayout className="space-y-5">
|
|
345
313
|
<AgentsHero
|
|
346
314
|
agentCount={agents.length}
|
|
347
|
-
onCreate={() =>
|
|
315
|
+
onCreate={() =>
|
|
316
|
+
presenter.startAgentCreationDraft(AGENT_CREATION_PROMPT)
|
|
317
|
+
}
|
|
348
318
|
/>
|
|
349
319
|
|
|
350
320
|
<div className="grid gap-4 md:grid-cols-2 xl:grid-cols-3">
|
|
@@ -370,7 +340,9 @@ export function AgentsPage() {
|
|
|
370
340
|
type="button"
|
|
371
341
|
variant="primary"
|
|
372
342
|
className="mt-5 rounded-2xl px-5"
|
|
373
|
-
onClick={() =>
|
|
343
|
+
onClick={() =>
|
|
344
|
+
presenter.startAgentCreationDraft(AGENT_CREATION_PROMPT)
|
|
345
|
+
}
|
|
374
346
|
>
|
|
375
347
|
<Plus className="mr-2 h-4 w-4" />
|
|
376
348
|
{t("agentsCreateButton")}
|
|
@@ -378,11 +350,10 @@ export function AgentsPage() {
|
|
|
378
350
|
</CardContent>
|
|
379
351
|
</Card>
|
|
380
352
|
) : (
|
|
381
|
-
sortedAgents.map((agent
|
|
353
|
+
sortedAgents.map((agent) => (
|
|
382
354
|
<AgentListCard
|
|
383
355
|
key={agent.id}
|
|
384
356
|
agent={agent}
|
|
385
|
-
index={index}
|
|
386
357
|
runtimeOptions={runtimeOptions}
|
|
387
358
|
defaultRuntimeLabel={defaultRuntimeLabel}
|
|
388
359
|
updatePending={updateAgent.isPending}
|
|
@@ -395,16 +366,6 @@ export function AgentsPage() {
|
|
|
395
366
|
)}
|
|
396
367
|
</div>
|
|
397
368
|
|
|
398
|
-
<AgentCreateDialog
|
|
399
|
-
open={isCreateDialogOpen}
|
|
400
|
-
pending={createAgent.isPending}
|
|
401
|
-
providerCatalog={providerCatalog}
|
|
402
|
-
runtimeOptions={runtimeOptions}
|
|
403
|
-
defaultRuntime={defaultRuntime}
|
|
404
|
-
onOpenChange={setIsCreateDialogOpen}
|
|
405
|
-
onSubmit={handleCreate}
|
|
406
|
-
/>
|
|
407
|
-
|
|
408
369
|
<AgentEditDialog
|
|
409
370
|
agent={editingAgent}
|
|
410
371
|
pending={updateAgent.isPending}
|
|
@@ -10,7 +10,7 @@ import { nextclawClient } from '@/shared/lib/api';
|
|
|
10
10
|
import { useConfig, useConfigMeta, useConfigSchema, useExecuteConfigAction, useUpdateChannel } from '@/shared/hooks/use-config';
|
|
11
11
|
import type { ConfigActionManifest, ConfigUiHints } from '@/shared/lib/api';
|
|
12
12
|
import { ChannelFormFieldsSection } from '@/features/channels/components/channel-form-fields-section';
|
|
13
|
-
import {
|
|
13
|
+
import { QrChannelAuthSection } from '@/features/channels/components/config/weixin-channel-auth-section';
|
|
14
14
|
import { buildChannelFormDefinitions, type ChannelField, type ChannelFormBlock, type ChannelFormFieldSection } from '@/features/channels/utils/channel-form-fields.utils';
|
|
15
15
|
import { ConfigSplitDetailPane, ConfigSplitEmptyPane, ConfigSplitPaneBody, ConfigSplitPaneFooter, ConfigSplitPaneHeader } from '@/shared/components/config-split-page';
|
|
16
16
|
import { hintForPath } from '@/shared/lib/config-hints';
|
|
@@ -205,11 +205,12 @@ function ChannelFormBlocks(props: {
|
|
|
205
205
|
</details>
|
|
206
206
|
);
|
|
207
207
|
}
|
|
208
|
-
return block.sectionId === 'weixin-auth' ? (
|
|
209
|
-
<
|
|
208
|
+
return block.sectionId === 'weixin-auth' || block.sectionId === 'feishu-auth' ? (
|
|
209
|
+
<QrChannelAuthSection
|
|
210
210
|
key={`${block.type}-${block.sectionId}-${index}`}
|
|
211
211
|
channelConfig={props.channelConfig}
|
|
212
212
|
formData={props.formData}
|
|
213
|
+
channelName={props.channelName === 'feishu' ? 'feishu' : 'weixin'}
|
|
213
214
|
channelEnabled={props.enabled}
|
|
214
215
|
disabled={props.disabled}
|
|
215
216
|
/>
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { render, screen, waitFor } from '@testing-library/react';
|
|
2
2
|
import userEvent from '@testing-library/user-event';
|
|
3
3
|
import type * as ReactQueryModule from '@tanstack/react-query';
|
|
4
|
-
import { WeixinChannelAuthSection } from '@/features/channels/components/config/weixin-channel-auth-section';
|
|
4
|
+
import { QrChannelAuthSection, WeixinChannelAuthSection } from '@/features/channels/components/config/weixin-channel-auth-section';
|
|
5
5
|
|
|
6
6
|
const mocks = vi.hoisted(() => ({
|
|
7
7
|
startChannelAuthMutateAsync: vi.fn(),
|
|
@@ -117,4 +117,41 @@ describe('WeixinChannelAuthSection', () => {
|
|
|
117
117
|
).toBeTruthy();
|
|
118
118
|
expect(screen.getByRole('button', { name: 'Reconnect with QR' })).toBeTruthy();
|
|
119
119
|
});
|
|
120
|
+
|
|
121
|
+
it('starts feishu QR auth with the selected domain', async () => {
|
|
122
|
+
const user = userEvent.setup();
|
|
123
|
+
mocks.startChannelAuthMutateAsync.mockResolvedValue({
|
|
124
|
+
channel: 'feishu',
|
|
125
|
+
kind: 'qr_code',
|
|
126
|
+
sessionId: 'session-1',
|
|
127
|
+
qrCode: 'qr-token',
|
|
128
|
+
qrCodeUrl: 'https://accounts.feishu.cn/qr',
|
|
129
|
+
expiresAt: '2026-03-24T10:00:00.000Z',
|
|
130
|
+
intervalMs: 60_000,
|
|
131
|
+
note: '请扫码'
|
|
132
|
+
});
|
|
133
|
+
mocks.pollChannelAuthMutateAsync.mockImplementation(() => new Promise(() => {}));
|
|
134
|
+
|
|
135
|
+
render(
|
|
136
|
+
<QrChannelAuthSection
|
|
137
|
+
channelName="feishu"
|
|
138
|
+
channelConfig={{ enabled: false, domain: 'feishu' }}
|
|
139
|
+
formData={{ domain: 'lark', defaultAccountId: 'primary' }}
|
|
140
|
+
channelEnabled={false}
|
|
141
|
+
/>
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
await user.click(screen.getByRole('button', { name: 'Scan QR to connect Feishu' }));
|
|
145
|
+
|
|
146
|
+
await waitFor(() => {
|
|
147
|
+
expect(mocks.startChannelAuthMutateAsync).toHaveBeenCalledWith({
|
|
148
|
+
channel: 'feishu',
|
|
149
|
+
data: {
|
|
150
|
+
accountId: 'primary',
|
|
151
|
+
baseUrl: undefined,
|
|
152
|
+
domain: 'lark'
|
|
153
|
+
}
|
|
154
|
+
});
|
|
155
|
+
});
|
|
156
|
+
});
|
|
120
157
|
});
|