@morlay/ui-conversation-manager 0.1.10 → 0.1.11-alpha.2
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/README.md +2 -2
- package/dist/client.cjs +1288 -574
- package/dist/client.d.cts +11 -20
- package/dist/client.d.mts +11 -20
- package/dist/client.mjs +71 -76
- package/dist/index.cjs +1 -2
- package/dist/index.d.mts +1 -3
- package/dist/index.mjs +1 -2
- package/locale/en.json +1 -1
- package/locale/zh.json +1 -1
- package/package.json +15 -15
- package/src/client/ConversationManagerPage.tsx +32 -26
- package/src/client/controller.ts +10 -7
- package/src/client/locales.ts +18 -16
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
//
|
|
1
|
+
// 「对话管理」页面:已归档会话的搜索、取消归档、导出、删除,以及导入为新会话与整理数据(孤儿回收 + 统计重算)。
|
|
2
2
|
// 数据面:会话行读**我们自己的**列表路由(注入面 listRows,含归档;搜索 / 子代理过滤 / 分页都在后端),
|
|
3
3
|
// 动作面只读注入面。
|
|
4
4
|
// 形态:页面框架与上游一级页面同款(960px 居中列 + 标题行 + 过滤 chip 行 + 搜索行,见
|
|
@@ -45,8 +45,8 @@ export type ConversationManagerPageProps = PropsRuntime<"main"> &
|
|
|
45
45
|
|
|
46
46
|
type Translate = ConversationManagerPageProps["t"];
|
|
47
47
|
|
|
48
|
-
//
|
|
49
|
-
type
|
|
48
|
+
// 整理数据的三段状态:确认 → 运行(阻塞界面)→ 收尾。
|
|
49
|
+
type OrganizePhase = "idle" | "confirm" | "running";
|
|
50
50
|
|
|
51
51
|
interface ConversationRow {
|
|
52
52
|
id: SessionId;
|
|
@@ -146,7 +146,7 @@ export function ConversationManagerPage({
|
|
|
146
146
|
remove,
|
|
147
147
|
exportZip,
|
|
148
148
|
importZip,
|
|
149
|
-
|
|
149
|
+
organizeData,
|
|
150
150
|
loadUsage,
|
|
151
151
|
}: ConversationManagerPageProps): ReactNode {
|
|
152
152
|
// 数据面是**我们自己的**列表路由(完整语料,含归档):官方 `session/list` 按部署策略排除归档,
|
|
@@ -165,7 +165,7 @@ export function ConversationManagerPage({
|
|
|
165
165
|
const [usageLoading, setUsageLoading] = useState(false);
|
|
166
166
|
const [usageError, setUsageError] = useState<string | null>(null);
|
|
167
167
|
const [confirming, setConfirming] = useState<ConversationRow | null>(null);
|
|
168
|
-
const [
|
|
168
|
+
const [organizePhase, setOrganizePhase] = useState<OrganizePhase>("idle");
|
|
169
169
|
const [importing, setImporting] = useState(false);
|
|
170
170
|
const [notice, setNotice] = useState<string | null>(null);
|
|
171
171
|
const [failure, setFailure] = useState<string | null>(null);
|
|
@@ -236,18 +236,24 @@ export function ConversationManagerPage({
|
|
|
236
236
|
);
|
|
237
237
|
};
|
|
238
238
|
|
|
239
|
-
const
|
|
240
|
-
|
|
239
|
+
const startOrganize = (): void => {
|
|
240
|
+
setOrganizePhase("running");
|
|
241
241
|
setFailure(null);
|
|
242
242
|
setNotice(null);
|
|
243
|
-
void
|
|
243
|
+
void organizeData().then(
|
|
244
244
|
(result) => {
|
|
245
|
-
|
|
246
|
-
setNotice(
|
|
245
|
+
setOrganizePhase("idle");
|
|
246
|
+
setNotice(
|
|
247
|
+
t("organize.done", {
|
|
248
|
+
sessions: result.orphanSessions,
|
|
249
|
+
events: result.orphanEvents,
|
|
250
|
+
rebuilt: result.rebuiltSessions,
|
|
251
|
+
}),
|
|
252
|
+
);
|
|
247
253
|
void reloadRows();
|
|
248
254
|
},
|
|
249
255
|
(error: unknown) => {
|
|
250
|
-
|
|
256
|
+
setOrganizePhase("idle");
|
|
251
257
|
setFailure(failureText(error, t));
|
|
252
258
|
},
|
|
253
259
|
);
|
|
@@ -324,15 +330,15 @@ export function ConversationManagerPage({
|
|
|
324
330
|
variant="outline"
|
|
325
331
|
size="sm"
|
|
326
332
|
data-action="gc"
|
|
327
|
-
disabled={
|
|
328
|
-
aria-label={t("
|
|
333
|
+
disabled={organizePhase !== "idle"}
|
|
334
|
+
aria-label={t("organize.button")}
|
|
329
335
|
onClick={() => {
|
|
330
336
|
setFailure(null);
|
|
331
337
|
setNotice(null);
|
|
332
|
-
|
|
338
|
+
setOrganizePhase("confirm");
|
|
333
339
|
}}
|
|
334
340
|
>
|
|
335
|
-
{t("
|
|
341
|
+
{t("organize.button")}
|
|
336
342
|
</Button>
|
|
337
343
|
</div>
|
|
338
344
|
</div>
|
|
@@ -619,35 +625,35 @@ export function ConversationManagerPage({
|
|
|
619
625
|
}
|
|
620
626
|
/>
|
|
621
627
|
<Modal
|
|
622
|
-
open={
|
|
628
|
+
open={organizePhase === "confirm"}
|
|
623
629
|
onClose={() => {
|
|
624
|
-
|
|
630
|
+
setOrganizePhase("idle");
|
|
625
631
|
}}
|
|
626
|
-
title={t("
|
|
632
|
+
title={t("organize.title")}
|
|
627
633
|
closeLabel={t("close")}
|
|
628
|
-
description={t("
|
|
634
|
+
description={t("organize.description")}
|
|
629
635
|
footer={
|
|
630
636
|
<>
|
|
631
637
|
<Button
|
|
632
638
|
variant="ghost"
|
|
633
639
|
onClick={() => {
|
|
634
|
-
|
|
640
|
+
setOrganizePhase("idle");
|
|
635
641
|
}}
|
|
636
642
|
>
|
|
637
|
-
{t("
|
|
643
|
+
{t("organize.cancel")}
|
|
638
644
|
</Button>
|
|
639
|
-
<Button variant="primary" onClick={
|
|
640
|
-
{t("
|
|
645
|
+
<Button variant="primary" onClick={startOrganize}>
|
|
646
|
+
{t("organize.confirm")}
|
|
641
647
|
</Button>
|
|
642
648
|
</>
|
|
643
649
|
}
|
|
644
650
|
/>
|
|
645
651
|
{/* 运行期不给关闭手段:没有关闭按钮,mask 与 Escape 都只走空 onClose。 */}
|
|
646
|
-
<Modal open={
|
|
652
|
+
<Modal open={organizePhase === "running"} onClose={() => {}} headless title={t("organize.title")}>
|
|
647
653
|
<Stack align="center" gap={14} pad="blocking">
|
|
648
|
-
<Spinner label={t("
|
|
654
|
+
<Spinner label={t("organize.running")} />
|
|
649
655
|
<Text as="p" size="md">
|
|
650
|
-
{t("
|
|
656
|
+
{t("organize.running")}
|
|
651
657
|
</Text>
|
|
652
658
|
</Stack>
|
|
653
659
|
</Modal>
|
package/src/client/controller.ts
CHANGED
|
@@ -4,7 +4,7 @@ import type { SessionId } from "@deepseek-ai/dsh-session";
|
|
|
4
4
|
export const SESSION_DELETE_PATH = "/api/morlay/v1/session/delete";
|
|
5
5
|
export const SESSION_IMPORT_PATH = "/api/morlay/v1/session/import";
|
|
6
6
|
export const SESSION_EXPORT_PATH = "/api/morlay/v1/session/export";
|
|
7
|
-
export const
|
|
7
|
+
export const SESSION_ORGANIZE_PATH = "/api/morlay/v1/session/organize";
|
|
8
8
|
export const SESSION_USAGE_PATH = "/api/morlay/v1/session/usage";
|
|
9
9
|
|
|
10
10
|
// 管理面的会话行(**完整语料,含归档**):我们自己的路由,与官方 `session/list` 分开——那条按部署策略
|
|
@@ -98,10 +98,12 @@ export interface ConversationManagerPorts {
|
|
|
98
98
|
refresh(): Promise<void>;
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
//
|
|
102
|
-
export interface
|
|
101
|
+
// 一次「整理数据」的回报。
|
|
102
|
+
export interface ConversationManagerOrganizeResult {
|
|
103
103
|
orphanSessions: number;
|
|
104
104
|
orphanEvents: number;
|
|
105
|
+
// 统计表全量重算涉及的会话数。
|
|
106
|
+
rebuiltSessions: number;
|
|
105
107
|
stoppedAgents: number;
|
|
106
108
|
}
|
|
107
109
|
|
|
@@ -114,7 +116,7 @@ export interface ConversationManagerFace {
|
|
|
114
116
|
remove: (sessionId: SessionId) => Promise<void>;
|
|
115
117
|
exportZip: (sessionId: SessionId) => Promise<void>;
|
|
116
118
|
importZip: (file: File) => Promise<SessionId>;
|
|
117
|
-
|
|
119
|
+
organizeData: () => Promise<ConversationManagerOrganizeResult>;
|
|
118
120
|
loadUsage: (range: UsageRangeKey) => Promise<SessionUsageReport>;
|
|
119
121
|
}
|
|
120
122
|
|
|
@@ -175,7 +177,7 @@ export class ConversationManagerController {
|
|
|
175
177
|
remove: (sessionId) => this.remove(sessionId),
|
|
176
178
|
exportZip: (sessionId) => this.exportZip(sessionId),
|
|
177
179
|
importZip: (file) => this.importZip(file),
|
|
178
|
-
|
|
180
|
+
organizeData: () => this.organizeData(),
|
|
179
181
|
loadUsage: (range) => this.loadUsage(range),
|
|
180
182
|
};
|
|
181
183
|
}
|
|
@@ -228,12 +230,13 @@ export class ConversationManagerController {
|
|
|
228
230
|
return value["sessionId"] as SessionId;
|
|
229
231
|
}
|
|
230
232
|
|
|
231
|
-
private async
|
|
232
|
-
const value = await postJson(
|
|
233
|
+
private async organizeData(): Promise<ConversationManagerOrganizeResult> {
|
|
234
|
+
const value = await postJson(SESSION_ORGANIZE_PATH, {});
|
|
233
235
|
await this.ports.refresh();
|
|
234
236
|
return {
|
|
235
237
|
orphanSessions: typeof value["orphanSessions"] === "number" ? value["orphanSessions"] : 0,
|
|
236
238
|
orphanEvents: typeof value["orphanEvents"] === "number" ? value["orphanEvents"] : 0,
|
|
239
|
+
rebuiltSessions: typeof value["rebuiltSessions"] === "number" ? value["rebuiltSessions"] : 0,
|
|
237
240
|
stoppedAgents: typeof value["stoppedAgents"] === "number" ? value["stoppedAgents"] : 0,
|
|
238
241
|
};
|
|
239
242
|
}
|
package/src/client/locales.ts
CHANGED
|
@@ -54,14 +54,15 @@ export const zh = {
|
|
|
54
54
|
"page.previous": "上一页",
|
|
55
55
|
"page.next": "下一页",
|
|
56
56
|
"page.label": "第 {page} / {total} 页",
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"会先停止所有运行中的 Agent,期间界面不可操作;随后回收孤儿 subagent
|
|
61
|
-
"
|
|
62
|
-
"
|
|
63
|
-
"
|
|
64
|
-
"
|
|
57
|
+
"organize.button": "整理数据",
|
|
58
|
+
"organize.title": "整理数据",
|
|
59
|
+
"organize.description":
|
|
60
|
+
"会先停止所有运行中的 Agent,期间界面不可操作;随后回收孤儿 subagent 会话与孤儿数据,重算全部会话的统计数据(token 用量与活动计数),最后执行 VACUUM。",
|
|
61
|
+
"organize.confirm": "开始整理",
|
|
62
|
+
"organize.cancel": "取消",
|
|
63
|
+
"organize.running": "正在整理,请稍候…",
|
|
64
|
+
"organize.done":
|
|
65
|
+
"已回收 {sessions} 条孤儿会话、{events} 行孤儿数据,并重算 {rebuilt} 个会话的统计数据。",
|
|
65
66
|
import: "导入对话",
|
|
66
67
|
importing: "导入中…",
|
|
67
68
|
imported: "已导入为新会话。",
|
|
@@ -139,14 +140,15 @@ export const en = {
|
|
|
139
140
|
"page.previous": "Previous",
|
|
140
141
|
"page.next": "Next",
|
|
141
142
|
"page.label": "Page {page} / {total}",
|
|
142
|
-
"
|
|
143
|
-
"
|
|
144
|
-
"
|
|
145
|
-
"Stops every running Agent first — the UI is blocked meanwhile — then reclaims orphan subagent sessions and orphan rows, and runs VACUUM.",
|
|
146
|
-
"
|
|
147
|
-
"
|
|
148
|
-
"
|
|
149
|
-
"
|
|
143
|
+
"organize.button": "Organize data",
|
|
144
|
+
"organize.title": "Organize data",
|
|
145
|
+
"organize.description":
|
|
146
|
+
"Stops every running Agent first — the UI is blocked meanwhile — then reclaims orphan subagent sessions and orphan rows, recomputes usage and activity statistics for all sessions, and runs VACUUM.",
|
|
147
|
+
"organize.confirm": "Start",
|
|
148
|
+
"organize.cancel": "Cancel",
|
|
149
|
+
"organize.running": "Organizing, please wait…",
|
|
150
|
+
"organize.done":
|
|
151
|
+
"Reclaimed {sessions} orphan sessions and {events} orphan rows; recomputed statistics for {rebuilt} sessions.",
|
|
150
152
|
import: "Import conversation",
|
|
151
153
|
importing: "Importing…",
|
|
152
154
|
imported: "Imported as a new session.",
|