dsh-prime-memory 0.18.5 → 0.18.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 +11 -28
- package/dist/client.js +159 -1297
- package/dist/contract.d.ts +1 -109
- package/dist/hooks/recall.d.ts +1 -4
- package/dist/hooks/recall.js +1 -7
- package/dist/hooks/slot-recall.js +24 -1
- package/dist/index.js +4 -14
- package/dist/metadata-validators.d.ts +0 -5
- package/dist/metadata-validators.js +1 -11
- package/dist/pipeline/ruminate.d.ts +1 -11
- package/dist/pipeline/ruminate.js +1 -18
- package/dist/projection/slots.js +9 -14
- package/dist/stats.d.ts +2 -26
- package/dist/stats.js +13 -261
- package/dist/store/l1.d.ts +0 -34
- package/dist/store/l1.js +1 -68
- package/dist/store/sqlite.d.ts +0 -4
- package/dist/store/sqlite.js +0 -20
- package/dist/tools/index.d.ts +1 -4
- package/dist/tools/index.js +2 -224
- package/dist/types.d.ts +0 -4
- package/package.json +2 -1
- package/dist/room-review.d.ts +0 -196
- package/dist/room-review.js +0 -281
- package/dist/store/recall-usage.d.ts +0 -43
- package/dist/store/recall-usage.js +0 -149
- package/dist/store/rooms-registry.d.ts +0 -66
- package/dist/store/rooms-registry.js +0 -250
package/dist/client.js
CHANGED
|
@@ -32,7 +32,7 @@ var __defProp = Object.defineProperty;
|
|
|
32
32
|
module.exports = __toCommonJS(entry_exports);
|
|
33
33
|
|
|
34
34
|
// client/src/panel.tsx
|
|
35
|
-
var
|
|
35
|
+
var import_react17 = require("react");
|
|
36
36
|
|
|
37
37
|
// client/src/sidebar-icon.ts
|
|
38
38
|
var BOOK_ICON_SVG = '<svg data-mem-icon="1" viewBox="0 0 16 16" width="16" height="16" fill="none" xmlns="http://www.w3.org/2000/svg" style="flex-shrink:0"><path d="M8 3.4C6.6 2.5 4.6 2.4 2.9 3.1v9.3c1.7-.7 3.7-.6 5.1.3 1.4-.9 3.4-1 5.1-.3V3.1C11.4 2.4 9.4 2.5 8 3.4Z" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round"/><path d="M8 3.4v9.3" stroke="currentColor" stroke-width="1.2"/></svg>';
|
|
@@ -1645,8 +1645,8 @@ var __defProp = Object.defineProperty;
|
|
|
1645
1645
|
setOpen(false);
|
|
1646
1646
|
setIdx(-1);
|
|
1647
1647
|
if (refocus && wrapRef.current) {
|
|
1648
|
-
const
|
|
1649
|
-
if (
|
|
1648
|
+
const btn = wrapRef.current.querySelector("button");
|
|
1649
|
+
if (btn && btn.focus) btn.focus();
|
|
1650
1650
|
}
|
|
1651
1651
|
};
|
|
1652
1652
|
const pick = (id) => {
|
|
@@ -3287,11 +3287,10 @@ var __defProp = Object.defineProperty;
|
|
|
3287
3287
|
const [sceneFilter, setSceneFilter] = (0, import_react15.useState)("");
|
|
3288
3288
|
const [hallFilter, setHallFilter] = (0, import_react15.useState)([]);
|
|
3289
3289
|
const [tagFilter, setTagFilter] = (0, import_react15.useState)("");
|
|
3290
|
-
const [untaggedOnly, setUntaggedOnly] = (0, import_react15.useState)(false);
|
|
3291
|
-
const [orphanCount, setOrphanCount] = (0, import_react15.useState)(0);
|
|
3292
3290
|
const [retiredFilter, setRetiredFilter] = (0, import_react15.useState)("");
|
|
3291
|
+
const [rooms, setRooms] = (0, import_react15.useState)([]);
|
|
3293
3292
|
const [wingCatalog, setHallCatalog] = (0, import_react15.useState)(null);
|
|
3294
|
-
const [last, setLast] = (0, import_react15.useState)({ query: "", type: "", scene: "", halls: [], tag: "",
|
|
3293
|
+
const [last, setLast] = (0, import_react15.useState)({ query: "", type: "", scene: "", halls: [], tag: "", retired: "" });
|
|
3295
3294
|
const seqRef = (0, import_react15.useRef)(0);
|
|
3296
3295
|
const fetchPage = (0, import_react15.useCallback)(
|
|
3297
3296
|
(conds, offset, append) => {
|
|
@@ -3304,7 +3303,6 @@ var __defProp = Object.defineProperty;
|
|
|
3304
3303
|
if (conds.scene) payload.scene = conds.scene;
|
|
3305
3304
|
if (conds.halls.length > 0) payload.halls = conds.halls;
|
|
3306
3305
|
if (conds.tag) payload.tag = conds.tag;
|
|
3307
|
-
if (conds.untagged) payload.untagged = true;
|
|
3308
3306
|
const retiredSel = retiredSelOf(conds.retired);
|
|
3309
3307
|
if (retiredSel !== void 0) payload.retired = retiredSel;
|
|
3310
3308
|
rpc("dsh-memory/list-records", payload).then((r) => {
|
|
@@ -3316,7 +3314,6 @@ var __defProp = Object.defineProperty;
|
|
|
3316
3314
|
}
|
|
3317
3315
|
const v = r.value;
|
|
3318
3316
|
setItems((prev) => append ? prev.concat(v.items) : v.items);
|
|
3319
|
-
if (v.usageSummary) setUsageSummary(v.usageSummary);
|
|
3320
3317
|
if (!append) setSel(/* @__PURE__ */ new Set());
|
|
3321
3318
|
setHasMore(!!v.hasMore);
|
|
3322
3319
|
setTotal(v.total === void 0 || v.total === null ? null : v.total);
|
|
@@ -3332,24 +3329,24 @@ var __defProp = Object.defineProperty;
|
|
|
3332
3329
|
[rpc]
|
|
3333
3330
|
);
|
|
3334
3331
|
const search = () => {
|
|
3335
|
-
const conds = { query: query.trim(), type: typeFilter, scene: sceneFilter, halls: hallFilter, tag: tagFilter,
|
|
3332
|
+
const conds = { query: query.trim(), type: typeFilter, scene: sceneFilter, halls: hallFilter, tag: tagFilter, retired: retiredFilter };
|
|
3336
3333
|
setLast(conds);
|
|
3337
3334
|
fetchPage(conds, 0, false);
|
|
3338
3335
|
};
|
|
3339
3336
|
const applyRetiredFilter = (next) => {
|
|
3340
3337
|
setRetiredFilter(next);
|
|
3341
|
-
const conds = { query: query.trim(), type: typeFilter, scene: sceneFilter, halls: hallFilter, tag: tagFilter,
|
|
3338
|
+
const conds = { query: query.trim(), type: typeFilter, scene: sceneFilter, halls: hallFilter, tag: tagFilter, retired: next };
|
|
3342
3339
|
setLast(conds);
|
|
3343
3340
|
fetchPage(conds, 0, false);
|
|
3344
3341
|
};
|
|
3345
3342
|
const loadRooms = (0, import_react15.useCallback)(() => {
|
|
3346
3343
|
rpc("dsh-memory/rooms-get", {}).then((r) => {
|
|
3347
|
-
if (r && r.ok)
|
|
3344
|
+
if (r && r.ok) setRooms(r.value.rooms ?? []);
|
|
3348
3345
|
}).catch(() => {
|
|
3349
3346
|
});
|
|
3350
3347
|
}, [rpc]);
|
|
3351
3348
|
(0, import_react15.useEffect)(() => {
|
|
3352
|
-
fetchPage({ query: "", type: "", scene: "", halls: [], tag: "",
|
|
3349
|
+
fetchPage({ query: "", type: "", scene: "", halls: [], tag: "", retired: "" }, 0, false);
|
|
3353
3350
|
loadRooms();
|
|
3354
3351
|
}, [fetchPage, loadRooms]);
|
|
3355
3352
|
const loadHiPriv = (0, import_react15.useCallback)(() => {
|
|
@@ -3452,7 +3449,6 @@ var __defProp = Object.defineProperty;
|
|
|
3452
3449
|
unknown: "已退场"
|
|
3453
3450
|
};
|
|
3454
3451
|
const countText = total !== null ? "共 " + total + " 条" : items.length + " 条" + (hasMore ? "+" : "");
|
|
3455
|
-
const [usageSummary, setUsageSummary] = (0, import_react15.useState)(null);
|
|
3456
3452
|
const selCount = sel.size;
|
|
3457
3453
|
return /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { children: [
|
|
3458
3454
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: S.toolbar, children: [
|
|
@@ -3519,86 +3515,40 @@ var __defProp = Object.defineProperty;
|
|
|
3519
3515
|
}
|
|
3520
3516
|
)
|
|
3521
3517
|
] }),
|
|
3522
|
-
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: {
|
|
3523
|
-
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
title: untaggedOnly ? "取消孤儿筛选" : "只看没有任何 Room 绑定的记忆",
|
|
3528
|
-
onClick: () => {
|
|
3529
|
-
const next = !untaggedOnly;
|
|
3530
|
-
setUntaggedOnly(next);
|
|
3531
|
-
if (next) setTagFilter("");
|
|
3532
|
-
const conds = { query: query.trim(), type: typeFilter, scene: sceneFilter, halls: hallFilter, tag: next ? "" : tagFilter, untagged: next, retired: retiredFilter };
|
|
3533
|
-
setLast(conds);
|
|
3534
|
-
fetchPage(conds, 0, false);
|
|
3535
|
-
},
|
|
3536
|
-
style: {
|
|
3537
|
-
cursor: "pointer",
|
|
3538
|
-
fontSize: 12,
|
|
3539
|
-
padding: "2px 8px",
|
|
3540
|
-
borderRadius: 999,
|
|
3541
|
-
border: untaggedOnly ? "1px solid var(--dsh-mem-accent)" : "1px solid var(--dsh-mem-border)",
|
|
3542
|
-
background: untaggedOnly ? "var(--dsh-mem-bg-inset)" : "transparent",
|
|
3543
|
-
color: untaggedOnly ? "var(--dsh-mem-accent)" : "var(--dsh-mem-text-2)"
|
|
3544
|
-
},
|
|
3545
|
-
children: "无绑定 · " + orphanCount
|
|
3546
|
-
}
|
|
3547
|
-
),
|
|
3548
|
-
(tagFilter || untaggedOnly) && /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("span", { style: S.muted, children: [
|
|
3549
|
-
"筛选中:",
|
|
3550
|
-
untaggedOnly ? "无绑定" : tagFilter,
|
|
3551
|
-
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3518
|
+
rooms.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: { display: "flex", flexWrap: "wrap", gap: 6, alignItems: "center", marginBottom: 10 }, children: [
|
|
3519
|
+
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: S.muted, children: "Room 分类" }),
|
|
3520
|
+
rooms.slice(0, 40).map((r) => {
|
|
3521
|
+
const on = tagFilter === r.room;
|
|
3522
|
+
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3552
3523
|
"button",
|
|
3553
3524
|
{
|
|
3554
3525
|
type: "button",
|
|
3555
|
-
title: "
|
|
3526
|
+
title: on ? "取消按该 Room 筛选" : "按该 Room 筛选记录",
|
|
3556
3527
|
onClick: () => {
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
const conds = { query: query.trim(), type: typeFilter, scene: sceneFilter, halls: hallFilter, tag:
|
|
3528
|
+
const next = on ? "" : r.room;
|
|
3529
|
+
setTagFilter(next);
|
|
3530
|
+
const conds = { query: query.trim(), type: typeFilter, scene: sceneFilter, halls: hallFilter, tag: next, retired: retiredFilter };
|
|
3560
3531
|
setLast(conds);
|
|
3561
3532
|
fetchPage(conds, 0, false);
|
|
3562
3533
|
},
|
|
3563
|
-
style: {
|
|
3564
|
-
|
|
3565
|
-
|
|
3566
|
-
|
|
3567
|
-
|
|
3568
|
-
|
|
3569
|
-
|
|
3570
|
-
|
|
3571
|
-
|
|
3572
|
-
|
|
3573
|
-
onClick: () => {
|
|
3574
|
-
rpc("dsh-memory/rooms-export", { kind: "orphans" }).then((r) => {
|
|
3575
|
-
if (!r || !r.ok || !r.value?.csv) return;
|
|
3576
|
-
const blob = new Blob([r.value.csv], { type: "text/csv;charset=utf-8" });
|
|
3577
|
-
const url = URL.createObjectURL(blob);
|
|
3578
|
-
const a = document.createElement("a");
|
|
3579
|
-
a.href = url;
|
|
3580
|
-
a.download = "dsh-memory-room-orphans.csv";
|
|
3581
|
-
a.click();
|
|
3582
|
-
URL.revokeObjectURL(url);
|
|
3583
|
-
}).catch(() => void 0);
|
|
3584
|
-
},
|
|
3585
|
-
style: {
|
|
3586
|
-
cursor: "pointer",
|
|
3587
|
-
fontSize: 12,
|
|
3588
|
-
padding: "2px 8px",
|
|
3589
|
-
borderRadius: 6,
|
|
3590
|
-
border: "1px solid var(--dsh-mem-border)",
|
|
3591
|
-
background: "transparent",
|
|
3592
|
-
color: "var(--dsh-mem-text-2)"
|
|
3534
|
+
style: {
|
|
3535
|
+
cursor: "pointer",
|
|
3536
|
+
fontSize: 12,
|
|
3537
|
+
padding: "2px 8px",
|
|
3538
|
+
borderRadius: 999,
|
|
3539
|
+
border: on ? "1px solid var(--dsh-mem-accent)" : "1px solid var(--dsh-mem-border)",
|
|
3540
|
+
background: on ? "var(--dsh-mem-bg-inset)" : "transparent",
|
|
3541
|
+
color: on ? "var(--dsh-mem-accent)" : "var(--dsh-mem-text-2)"
|
|
3542
|
+
},
|
|
3543
|
+
children: r.room + " · " + r.count
|
|
3593
3544
|
},
|
|
3594
|
-
|
|
3595
|
-
|
|
3596
|
-
),
|
|
3597
|
-
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: S.muted, children: "
|
|
3598
|
-
] }),
|
|
3545
|
+
r.room
|
|
3546
|
+
);
|
|
3547
|
+
}),
|
|
3548
|
+
rooms.length > 40 ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: S.muted, children: "(仅显示前 40 / 共 " + rooms.length + ")" }) : null
|
|
3549
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: { ...S.muted, marginBottom: 10 }, children: "Room 分类:暂无(由反刍涌现的标签自动生成,无需手工建立)" }),
|
|
3599
3550
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsxs)("div", { style: { ...S.flexRow, marginBottom: 10 }, children: [
|
|
3600
3551
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: S.muted, children: loading ? "加载中…" : countText }),
|
|
3601
|
-
usageSummary ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: S.muted, title: "老化权重效果口径:参与召回尝试的记忆中,进 topN(被注入上下文)的比例", children: "召回使用 " + usageSummary.used + "/" + usageSummary.attempted + "(" + usageSummary.rate + "%)" }) : null,
|
|
3602
3552
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: S.muted, children: "退场筛查" }),
|
|
3603
3553
|
[["", "全部"], ["active", "仅活跃"], ["retired", "仅退场"]].map(([val, label]) => {
|
|
3604
3554
|
const on = retiredFilter === val;
|
|
@@ -3702,29 +3652,6 @@ var __defProp = Object.defineProperty;
|
|
|
3702
3652
|
}
|
|
3703
3653
|
) : null,
|
|
3704
3654
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: S.muted, children: "优先级 " + m.priority }),
|
|
3705
|
-
m.agingWeight != null ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3706
|
-
"span",
|
|
3707
|
-
{
|
|
3708
|
-
style: {
|
|
3709
|
-
fontSize: 11,
|
|
3710
|
-
padding: "1px 6px",
|
|
3711
|
-
borderRadius: 999,
|
|
3712
|
-
whiteSpace: "nowrap",
|
|
3713
|
-
border: "1px solid " + (m.agingWeight <= 0.6 ? "var(--dsh-mem-danger)" : "var(--dsh-mem-border)"),
|
|
3714
|
-
color: m.agingWeight <= 0.6 ? "var(--dsh-mem-danger)" : "var(--dsh-mem-text-2)"
|
|
3715
|
-
},
|
|
3716
|
-
title: "老化权重 " + Math.round(m.agingWeight * 100) + "%(读路径衰减系数 max(0.5, 0.5^(Δ天/半衰期)));越低越老",
|
|
3717
|
-
children: "老化 " + Math.round(m.agingWeight * 100) + "%"
|
|
3718
|
-
}
|
|
3719
|
-
) : null,
|
|
3720
|
-
m.usage ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
3721
|
-
"span",
|
|
3722
|
-
{
|
|
3723
|
-
style: S.muted,
|
|
3724
|
-
title: "召回使用 " + m.usage.used + "/" + m.usage.attempts + "(进 topN 才算 used)" + (m.usage.lastUsedAt ? ";最近使用 " + fmtTime(new Date(m.usage.lastUsedAt).toISOString()) : "") + (m.usage.lastAttemptAt ? ";最近尝试 " + fmtTime(new Date(m.usage.lastAttemptAt).toISOString()) : ""),
|
|
3725
|
-
children: "用 " + m.usage.used + "/" + m.usage.attempts
|
|
3726
|
-
}
|
|
3727
|
-
) : null,
|
|
3728
3655
|
m.score !== null && m.score !== void 0 ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: S.muted, children: "相关度 " + Number(m.score).toFixed(2) }) : null,
|
|
3729
3656
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("div", { style: S.grow }),
|
|
3730
3657
|
/* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: S.muted, children: fmtTime(m.updatedAt) }),
|
|
@@ -3847,1075 +3774,14 @@ var __defProp = Object.defineProperty;
|
|
|
3847
3774
|
] });
|
|
3848
3775
|
}
|
|
3849
3776
|
|
|
3850
|
-
// client/src/tabs/
|
|
3777
|
+
// client/src/tabs/ScenesTab.tsx
|
|
3851
3778
|
var import_react16 = require("react");
|
|
3852
3779
|
var import_jsx_runtime16 = require("react/jsx-runtime");
|
|
3853
|
-
function majorOf(slug) {
|
|
3854
|
-
const i = slug.indexOf("/");
|
|
3855
|
-
return i === -1 ? slug : slug.slice(0, i);
|
|
3856
|
-
}
|
|
3857
|
-
function suffixOf(slug) {
|
|
3858
|
-
const i = slug.indexOf("/");
|
|
3859
|
-
return i === -1 ? slug : slug.slice(i + 1);
|
|
3860
|
-
}
|
|
3861
|
-
function downloadCsv(csv, name) {
|
|
3862
|
-
const blob = new Blob([csv], { type: "text/csv;charset=utf-8" });
|
|
3863
|
-
const url = URL.createObjectURL(blob);
|
|
3864
|
-
const a = document.createElement("a");
|
|
3865
|
-
a.href = url;
|
|
3866
|
-
a.download = name;
|
|
3867
|
-
a.click();
|
|
3868
|
-
URL.revokeObjectURL(url);
|
|
3869
|
-
}
|
|
3870
|
-
var btn = {
|
|
3871
|
-
cursor: "pointer",
|
|
3872
|
-
fontSize: 12,
|
|
3873
|
-
padding: "2px 8px",
|
|
3874
|
-
borderRadius: 6,
|
|
3875
|
-
border: "1px solid var(--dsh-mem-border)",
|
|
3876
|
-
background: "transparent",
|
|
3877
|
-
color: "var(--dsh-mem-text-2)"
|
|
3878
|
-
};
|
|
3879
|
-
function RoomsTab(props) {
|
|
3880
|
-
const rpc = props.rpc;
|
|
3881
|
-
const [registry, setRegistry] = (0, import_react16.useState)([]);
|
|
3882
|
-
const [rooms, setRooms] = (0, import_react16.useState)([]);
|
|
3883
|
-
const [orphanCount, setOrphanCount] = (0, import_react16.useState)(0);
|
|
3884
|
-
const [busy, setBusy] = (0, import_react16.useState)(false);
|
|
3885
|
-
const [msg, setMsg] = (0, import_react16.useState)(null);
|
|
3886
|
-
const [error, setError] = (0, import_react16.useState)(null);
|
|
3887
|
-
const [hiPriv, setHiPriv] = (0, import_react16.useState)(false);
|
|
3888
|
-
const [hiPrivBusy, setHiPrivBusy] = (0, import_react16.useState)(false);
|
|
3889
|
-
const [regSlug, setRegSlug] = (0, import_react16.useState)("");
|
|
3890
|
-
const [regLabel, setRegLabel] = (0, import_react16.useState)("");
|
|
3891
|
-
const [regDesc, setRegDesc] = (0, import_react16.useState)("");
|
|
3892
|
-
const [form, setForm] = (0, import_react16.useState)(null);
|
|
3893
|
-
const [preview, setPreview] = (0, import_react16.useState)(null);
|
|
3894
|
-
const [grownOpen, setGrownOpen] = (0, import_react16.useState)(false);
|
|
3895
|
-
const [dragOverHall, setDragOverHall] = (0, import_react16.useState)(null);
|
|
3896
|
-
const [picking, setPicking] = (0, import_react16.useState)(null);
|
|
3897
|
-
const [editing, setEditing] = (0, import_react16.useState)(null);
|
|
3898
|
-
const [expandedRooms, setExpandedRooms] = (0, import_react16.useState)(/* @__PURE__ */ new Set());
|
|
3899
|
-
const [roomRecords, setRoomRecords] = (0, import_react16.useState)({});
|
|
3900
|
-
const [expandedHalls, setExpandedHalls] = (0, import_react16.useState)(() => {
|
|
3901
|
-
try {
|
|
3902
|
-
const v = window.localStorage.getItem("dsh.memory.halls.open");
|
|
3903
|
-
return v ? new Set(JSON.parse(v)) : /* @__PURE__ */ new Set();
|
|
3904
|
-
} catch {
|
|
3905
|
-
return /* @__PURE__ */ new Set();
|
|
3906
|
-
}
|
|
3907
|
-
});
|
|
3908
|
-
const [filter, setFilter] = (0, import_react16.useState)("");
|
|
3909
|
-
const dragRef = (0, import_react16.useRef)(null);
|
|
3910
|
-
const [ghost, setGhost] = (0, import_react16.useState)(null);
|
|
3911
|
-
const onDragLabelDown = (ev, slug) => {
|
|
3912
|
-
if (!hiPriv || busy || ev.button !== 0) return;
|
|
3913
|
-
ev.currentTarget.setPointerCapture(ev.pointerId);
|
|
3914
|
-
dragRef.current = { from: slug, x: ev.clientX, y: ev.clientY, active: false };
|
|
3915
|
-
};
|
|
3916
|
-
const onDragLabelMove = (ev) => {
|
|
3917
|
-
const d = dragRef.current;
|
|
3918
|
-
if (!d) return;
|
|
3919
|
-
if (!d.active && Math.hypot(ev.clientX - d.x, ev.clientY - d.y) > 6) d.active = true;
|
|
3920
|
-
if (!d.active) return;
|
|
3921
|
-
setGhost({ x: ev.clientX, y: ev.clientY, text: d.from });
|
|
3922
|
-
const hall = document.elementFromPoint(ev.clientX, ev.clientY)?.closest?.("[data-hall]")?.getAttribute("data-hall") ?? null;
|
|
3923
|
-
setDragOverHall(hall);
|
|
3924
|
-
};
|
|
3925
|
-
const onDragLabelUp = (ev) => {
|
|
3926
|
-
const d = dragRef.current;
|
|
3927
|
-
dragRef.current = null;
|
|
3928
|
-
setGhost(null);
|
|
3929
|
-
if (!d) return;
|
|
3930
|
-
if (!d.active) return;
|
|
3931
|
-
const hall = document.elementFromPoint(ev.clientX, ev.clientY)?.closest?.("[data-hall]")?.getAttribute("data-hall");
|
|
3932
|
-
setDragOverHall(null);
|
|
3933
|
-
if (hall) beginReclass(d.from, hall);
|
|
3934
|
-
};
|
|
3935
|
-
const loadAll = (0, import_react16.useCallback)(() => {
|
|
3936
|
-
rpc("dsh-memory/rooms-get", {}).then((r) => {
|
|
3937
|
-
if (r && r.ok) {
|
|
3938
|
-
setRooms(r.value.rooms ?? []);
|
|
3939
|
-
setRegistry(r.value.registry ?? []);
|
|
3940
|
-
setOrphanCount(r.value.orphanCount ?? 0);
|
|
3941
|
-
}
|
|
3942
|
-
}).catch(() => void 0);
|
|
3943
|
-
}, [rpc]);
|
|
3944
|
-
const loadHiPriv = (0, import_react16.useCallback)(() => {
|
|
3945
|
-
rpc("dsh-memory/settings-get", {}).then((r) => {
|
|
3946
|
-
if (r && r.ok && r.value) setHiPriv(!!r.value.settings.memoryMutate);
|
|
3947
|
-
}).catch(() => {
|
|
3948
|
-
});
|
|
3949
|
-
}, [rpc]);
|
|
3950
|
-
(0, import_react16.useEffect)(() => {
|
|
3951
|
-
loadAll();
|
|
3952
|
-
loadHiPriv();
|
|
3953
|
-
}, [loadAll, loadHiPriv]);
|
|
3954
|
-
const toggleHiPriv = () => {
|
|
3955
|
-
const next = !hiPriv;
|
|
3956
|
-
if (next && !window.confirm("开启高权限模式:模型获得写入/删除记忆工具,并解锁 Hall 页的分类管理操作。确定开启?")) return;
|
|
3957
|
-
setHiPrivBusy(true);
|
|
3958
|
-
rpc("dsh-memory/settings-set", { memoryMutate: next }).then((r) => {
|
|
3959
|
-
if (r && r.ok) setHiPriv(next);
|
|
3960
|
-
else if (r) setError(r.error ? r.error.message : "切换高权限模式失败");
|
|
3961
|
-
setHiPrivBusy(false);
|
|
3962
|
-
loadHiPriv();
|
|
3963
|
-
}).catch((e) => {
|
|
3964
|
-
setHiPrivBusy(false);
|
|
3965
|
-
setError(String(e && e.message || e));
|
|
3966
|
-
});
|
|
3967
|
-
};
|
|
3968
|
-
const run = (fn) => {
|
|
3969
|
-
if (busy) return;
|
|
3970
|
-
setBusy(true);
|
|
3971
|
-
setError(null);
|
|
3972
|
-
setMsg(null);
|
|
3973
|
-
fn().finally(() => setBusy(false));
|
|
3974
|
-
};
|
|
3975
|
-
const register = () => run(async () => {
|
|
3976
|
-
const r = await rpc("dsh-memory/room-register", {
|
|
3977
|
-
slug: regSlug.trim(),
|
|
3978
|
-
label: regLabel.trim() || void 0,
|
|
3979
|
-
description: regDesc.trim() || void 0
|
|
3980
|
-
});
|
|
3981
|
-
if (r && r.ok) {
|
|
3982
|
-
setMsg(r.value?.notice ?? `已注册:${regSlug.trim()}`);
|
|
3983
|
-
setRegSlug("");
|
|
3984
|
-
setRegLabel("");
|
|
3985
|
-
setRegDesc("");
|
|
3986
|
-
loadAll();
|
|
3987
|
-
} else setError(r && r.error ? r.error.message : "注册失败");
|
|
3988
|
-
});
|
|
3989
|
-
const adopt = (slug) => run(async () => {
|
|
3990
|
-
const r = await rpc("dsh-memory/room-register", { slug, source: "grown" });
|
|
3991
|
-
if (r && r.ok) {
|
|
3992
|
-
setMsg(`已收编:${slug}(source=grown)`);
|
|
3993
|
-
loadAll();
|
|
3994
|
-
} else setError(r && r.error ? r.error.message : "收编失败");
|
|
3995
|
-
});
|
|
3996
|
-
const previewMerge = (override) => run(async () => {
|
|
3997
|
-
const fm = override ?? form;
|
|
3998
|
-
if (!fm) return;
|
|
3999
|
-
const to = fm.to.trim();
|
|
4000
|
-
if (!to) {
|
|
4001
|
-
setError("目标 slug 不能为空");
|
|
4002
|
-
return;
|
|
4003
|
-
}
|
|
4004
|
-
if (to === fm.from) {
|
|
4005
|
-
setError("目标与源相同");
|
|
4006
|
-
return;
|
|
4007
|
-
}
|
|
4008
|
-
const r = await rpc("dsh-memory/room-admin", { action: fm.action, from: fm.from, to });
|
|
4009
|
-
if (r && r.ok) {
|
|
4010
|
-
setPreview({ action: fm.action, from: fm.from, to, notice: String(r.value?.notice ?? "") });
|
|
4011
|
-
} else setError(r && r.error ? r.error.message : "预览失败");
|
|
4012
|
-
});
|
|
4013
|
-
const beginReclass = (from, hall) => {
|
|
4014
|
-
if (!busy) {
|
|
4015
|
-
setMsg(null);
|
|
4016
|
-
setError(null);
|
|
4017
|
-
}
|
|
4018
|
-
if (!hall) {
|
|
4019
|
-
setError("尚无 hall:先注册一个(如 dsh-plugin),再归类。");
|
|
4020
|
-
return;
|
|
4021
|
-
}
|
|
4022
|
-
if (majorOf(from) === hall) {
|
|
4023
|
-
if (registry.some((e) => e.slug === from)) {
|
|
4024
|
-
setMsg(`${from} 已在 ${hall} 下。`);
|
|
4025
|
-
return;
|
|
4026
|
-
}
|
|
4027
|
-
setPicking(null);
|
|
4028
|
-
void adopt(from);
|
|
4029
|
-
return;
|
|
4030
|
-
}
|
|
4031
|
-
const f = { action: "rename", from, to: `${hall}/${suffixOf(from)}` };
|
|
4032
|
-
setForm(f);
|
|
4033
|
-
setPreview(null);
|
|
4034
|
-
void previewMerge(f);
|
|
4035
|
-
};
|
|
4036
|
-
const execMerge = () => run(async () => {
|
|
4037
|
-
if (!preview) return;
|
|
4038
|
-
if (preview.action === "rename" && !registry.some((e) => e.slug === preview.from)) {
|
|
4039
|
-
const rr = await rpc("dsh-memory/room-register", { slug: preview.from, source: "grown" });
|
|
4040
|
-
if (!rr || !rr.ok) {
|
|
4041
|
-
setError(rr && rr.error ? rr.error.message : "收编源失败");
|
|
4042
|
-
return;
|
|
4043
|
-
}
|
|
4044
|
-
}
|
|
4045
|
-
const r = await rpc("dsh-memory/room-admin", { action: preview.action, from: preview.from, to: preview.to, dryRun: false });
|
|
4046
|
-
if (r && r.ok) {
|
|
4047
|
-
setMsg(String(r.value?.notice ?? "完成"));
|
|
4048
|
-
setPreview(null);
|
|
4049
|
-
setForm(null);
|
|
4050
|
-
loadAll();
|
|
4051
|
-
} else setError(r && r.error ? r.error.message : "执行失败");
|
|
4052
|
-
});
|
|
4053
|
-
const retire = (slug, active, withRecords = false) => run(async () => {
|
|
4054
|
-
if (!active) {
|
|
4055
|
-
const tip = withRecords ? `退役 Room:${slug} 并退场其下全部记忆?(记录为软删,可在记忆页「已退场」区逐条恢复)` : `退役 Room:${slug}?(存量记录的 tags 不动,仅词表不再推荐;可随时恢复)`;
|
|
4056
|
-
if (!window.confirm(tip)) return;
|
|
4057
|
-
}
|
|
4058
|
-
const r = await rpc("dsh-memory/room-admin", { action: "retire", slug, active, withRecords: withRecords || void 0 });
|
|
4059
|
-
if (r && r.ok) {
|
|
4060
|
-
setMsg(String(r.value?.notice ?? "完成"));
|
|
4061
|
-
loadAll();
|
|
4062
|
-
if (expandedRooms.has(slug)) {
|
|
4063
|
-
const rr = await rpc("dsh-memory/list-records", { tag: slug, limit: 10, retired: false });
|
|
4064
|
-
if (rr && rr.ok) setRoomRecords((m) => ({ ...m, [slug]: { items: rr.value.items, total: rr.value.total ?? null } }));
|
|
4065
|
-
}
|
|
4066
|
-
} else setError(r && r.error ? r.error.message : "操作失败");
|
|
4067
|
-
});
|
|
4068
|
-
const saveEditing = () => run(async () => {
|
|
4069
|
-
if (!editing) return;
|
|
4070
|
-
const r = await rpc("dsh-memory/room-admin", { action: "update", slug: editing.slug, label: editing.label, description: editing.description });
|
|
4071
|
-
if (r && r.ok) {
|
|
4072
|
-
setMsg(String(r.value?.notice ?? "已更新"));
|
|
4073
|
-
setEditing(null);
|
|
4074
|
-
loadAll();
|
|
4075
|
-
} else setError(r && r.error ? r.error.message : "更新失败");
|
|
4076
|
-
});
|
|
4077
|
-
const toggleRoomExpand = (slug) => run(async () => {
|
|
4078
|
-
if (expandedRooms.has(slug)) {
|
|
4079
|
-
const next = new Set(expandedRooms);
|
|
4080
|
-
next.delete(slug);
|
|
4081
|
-
setExpandedRooms(next);
|
|
4082
|
-
return;
|
|
4083
|
-
}
|
|
4084
|
-
const r = await rpc("dsh-memory/list-records", { tag: slug, limit: 10, retired: false });
|
|
4085
|
-
if (r && r.ok) {
|
|
4086
|
-
const next = new Set(expandedRooms);
|
|
4087
|
-
next.add(slug);
|
|
4088
|
-
setExpandedRooms(next);
|
|
4089
|
-
setRoomRecords((m) => ({ ...m, [slug]: { items: r.value.items, total: r.value.total ?? null } }));
|
|
4090
|
-
} else setError(r && r.error ? r.error.message : "加载失败");
|
|
4091
|
-
});
|
|
4092
|
-
const exportRecords = (slug) => run(async () => {
|
|
4093
|
-
const r = await rpc("dsh-memory/rooms-export", { kind: "records", tag: slug });
|
|
4094
|
-
if (!r.ok) {
|
|
4095
|
-
setError(r.error.message);
|
|
4096
|
-
return;
|
|
4097
|
-
}
|
|
4098
|
-
if (r.value.csv) downloadCsv(r.value.csv, `dsh-memory-room-${slug.replace(/\//g, "-")}-records.csv`);
|
|
4099
|
-
else setError("导出为空");
|
|
4100
|
-
});
|
|
4101
|
-
const groups = (0, import_react16.useMemo)(() => {
|
|
4102
|
-
const countOf = new Map(rooms.map((r) => [r.room, r.count]));
|
|
4103
|
-
const byHall = /* @__PURE__ */ new Map();
|
|
4104
|
-
for (const e of registry) {
|
|
4105
|
-
if (e.status !== "active") continue;
|
|
4106
|
-
const hall = majorOf(e.slug);
|
|
4107
|
-
const list = byHall.get(hall);
|
|
4108
|
-
if (list) list.push(e);
|
|
4109
|
-
else byHall.set(hall, [e]);
|
|
4110
|
-
}
|
|
4111
|
-
return [...byHall.entries()].map(([hall, entries]) => ({
|
|
4112
|
-
hall,
|
|
4113
|
-
label: registry.find((e) => e.slug === hall)?.label,
|
|
4114
|
-
entries: [...entries].sort((a, b) => a.slug.localeCompare(b.slug)),
|
|
4115
|
-
total: entries.reduce((s2, e) => s2 + (countOf.get(e.slug) ?? 0), 0)
|
|
4116
|
-
})).sort((a, b) => a.hall.localeCompare(b.hall));
|
|
4117
|
-
}, [registry, rooms]);
|
|
4118
|
-
const grownOnly = (0, import_react16.useMemo)(() => rooms.filter((r) => !registry.some((e) => e.slug === r.room)), [rooms, registry]);
|
|
4119
|
-
const persistHalls = (next) => {
|
|
4120
|
-
try {
|
|
4121
|
-
window.localStorage.setItem("dsh.memory.halls.open", JSON.stringify([...next]));
|
|
4122
|
-
} catch {
|
|
4123
|
-
}
|
|
4124
|
-
};
|
|
4125
|
-
const toggleHall = (hall) => setExpandedHalls((cur) => {
|
|
4126
|
-
const next = new Set(cur);
|
|
4127
|
-
if (next.has(hall)) next.delete(hall);
|
|
4128
|
-
else next.add(hall);
|
|
4129
|
-
persistHalls(next);
|
|
4130
|
-
return next;
|
|
4131
|
-
});
|
|
4132
|
-
const setAllHalls = (open) => {
|
|
4133
|
-
const next = open ? new Set(groups.map((g) => g.hall)) : /* @__PURE__ */ new Set();
|
|
4134
|
-
setExpandedHalls(next);
|
|
4135
|
-
persistHalls(next);
|
|
4136
|
-
};
|
|
4137
|
-
const normFilter = filter.trim().toLowerCase();
|
|
4138
|
-
const visibleGroups = (0, import_react16.useMemo)(() => {
|
|
4139
|
-
if (!normFilter) return groups;
|
|
4140
|
-
return groups.map((g) => {
|
|
4141
|
-
const hallHit = g.hall.toLowerCase().includes(normFilter) || (g.label ?? "").toLowerCase().includes(normFilter);
|
|
4142
|
-
const entries = hallHit ? g.entries : g.entries.filter(
|
|
4143
|
-
(e) => e.slug.toLowerCase().includes(normFilter) || (e.label ?? "").toLowerCase().includes(normFilter) || (e.aliases ?? []).some((a) => a.toLowerCase().includes(normFilter))
|
|
4144
|
-
);
|
|
4145
|
-
return { ...g, entries };
|
|
4146
|
-
}).filter((g) => g.entries.length > 0);
|
|
4147
|
-
}, [groups, normFilter]);
|
|
4148
|
-
const visibleGrown = (0, import_react16.useMemo)(
|
|
4149
|
-
() => normFilter ? grownOnly.filter((r) => r.room.toLowerCase().includes(normFilter)) : grownOnly,
|
|
4150
|
-
[grownOnly, normFilter]
|
|
4151
|
-
);
|
|
4152
|
-
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { children: [
|
|
4153
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { ...S.flexRow, marginBottom: 8 }, children: [
|
|
4154
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: S.muted, children: "Hall = Room 大类 · 大类上限 200,小类「大类/小类」细分不占额度 · 与 Wing(域)筛选无关" }),
|
|
4155
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.grow }),
|
|
4156
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
4157
|
-
"button",
|
|
4158
|
-
{
|
|
4159
|
-
type: "button",
|
|
4160
|
-
title: "导出分类数据 CSV(Room 词表+计数)",
|
|
4161
|
-
onClick: () => run(async () => {
|
|
4162
|
-
const r = await rpc("dsh-memory/rooms-export", { kind: "rooms" });
|
|
4163
|
-
if (!r.ok) {
|
|
4164
|
-
setError(r.error.message);
|
|
4165
|
-
return;
|
|
4166
|
-
}
|
|
4167
|
-
if (r.value.csv) downloadCsv(r.value.csv, "dsh-memory-rooms.csv");
|
|
4168
|
-
}),
|
|
4169
|
-
style: btn,
|
|
4170
|
-
children: "导出词表"
|
|
4171
|
-
}
|
|
4172
|
-
),
|
|
4173
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
4174
|
-
"button",
|
|
4175
|
-
{
|
|
4176
|
-
type: "button",
|
|
4177
|
-
title: "导出无 Room 绑定的孤儿清单(含候选)",
|
|
4178
|
-
onClick: () => run(async () => {
|
|
4179
|
-
const r = await rpc("dsh-memory/rooms-export", { kind: "orphans" });
|
|
4180
|
-
if (!r.ok) {
|
|
4181
|
-
setError(r.error.message);
|
|
4182
|
-
return;
|
|
4183
|
-
}
|
|
4184
|
-
if (r.value.csv) downloadCsv(r.value.csv, "dsh-memory-room-orphans.csv");
|
|
4185
|
-
}),
|
|
4186
|
-
style: btn,
|
|
4187
|
-
children: [
|
|
4188
|
-
"导出孤儿 · ",
|
|
4189
|
-
orphanCount
|
|
4190
|
-
]
|
|
4191
|
-
}
|
|
4192
|
-
),
|
|
4193
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
4194
|
-
"button",
|
|
4195
|
-
{
|
|
4196
|
-
type: "button",
|
|
4197
|
-
style: {
|
|
4198
|
-
...btn,
|
|
4199
|
-
color: hiPriv ? "var(--dsh-mem-danger)" : void 0,
|
|
4200
|
-
border: hiPriv ? "1px solid var(--dsh-mem-danger)" : btn.border
|
|
4201
|
-
},
|
|
4202
|
-
disabled: hiPrivBusy,
|
|
4203
|
-
title: hiPriv ? "关闭高权限模式(收回模型写删工具与管理操作)" : "开启高权限模式以解锁分类管理操作",
|
|
4204
|
-
onClick: toggleHiPriv,
|
|
4205
|
-
children: hiPriv ? "高权限:开" : "高权限:关"
|
|
4206
|
-
}
|
|
4207
|
-
),
|
|
4208
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", style: btn, onClick: loadAll, title: "重拉注册表与计数", children: "刷新" })
|
|
4209
|
-
] }),
|
|
4210
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { display: "flex", gap: 6, alignItems: "center", marginBottom: 8, flexWrap: "wrap" }, children: [
|
|
4211
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
4212
|
-
"input",
|
|
4213
|
-
{
|
|
4214
|
-
value: filter,
|
|
4215
|
-
onChange: (e) => setFilter(e.target.value),
|
|
4216
|
-
placeholder: "搜索 hall/room(slug、显示名、别名)",
|
|
4217
|
-
style: { ...S.input, width: 250, fontSize: 12 }
|
|
4218
|
-
}
|
|
4219
|
-
),
|
|
4220
|
-
filter ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", style: btn, onClick: () => setFilter(""), children: "清除" }) : null,
|
|
4221
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: S.muted, children: `匹配 ${visibleGroups.reduce((s2, g) => s2 + g.entries.length, 0)} room / ${visibleGroups.length} hall` }),
|
|
4222
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.grow }),
|
|
4223
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", style: btn, title: "展开全部 hall 的子 room", onClick: () => setAllHalls(true), children: "展开全部" }),
|
|
4224
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", style: btn, title: "收起全部 hall(只留 hall 头)", onClick: () => setAllHalls(false), children: "收起全部" })
|
|
4225
|
-
] }),
|
|
4226
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { display: "flex", flexWrap: "wrap", gap: 6, alignItems: "center", marginBottom: 10 }, children: [
|
|
4227
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
4228
|
-
"input",
|
|
4229
|
-
{
|
|
4230
|
-
value: regSlug,
|
|
4231
|
-
onChange: (e) => setRegSlug(e.target.value),
|
|
4232
|
-
placeholder: "slug(如 dsh-plugin 或 dsh-plugin/merge)",
|
|
4233
|
-
disabled: !hiPriv || busy,
|
|
4234
|
-
style: { ...S.input, width: 210, fontSize: 12 }
|
|
4235
|
-
}
|
|
4236
|
-
),
|
|
4237
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
4238
|
-
"input",
|
|
4239
|
-
{
|
|
4240
|
-
value: regLabel,
|
|
4241
|
-
onChange: (e) => setRegLabel(e.target.value),
|
|
4242
|
-
placeholder: "名称(可中文)",
|
|
4243
|
-
disabled: !hiPriv || busy,
|
|
4244
|
-
style: { ...S.input, width: 110, fontSize: 12 }
|
|
4245
|
-
}
|
|
4246
|
-
),
|
|
4247
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
4248
|
-
"input",
|
|
4249
|
-
{
|
|
4250
|
-
value: regDesc,
|
|
4251
|
-
onChange: (e) => setRegDesc(e.target.value),
|
|
4252
|
-
placeholder: "归类说明(喂标注器)",
|
|
4253
|
-
disabled: !hiPriv || busy,
|
|
4254
|
-
style: { ...S.input, width: 170, fontSize: 12 }
|
|
4255
|
-
}
|
|
4256
|
-
),
|
|
4257
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
4258
|
-
"button",
|
|
4259
|
-
{
|
|
4260
|
-
type: "button",
|
|
4261
|
-
disabled: !hiPriv || busy || !regSlug.trim(),
|
|
4262
|
-
onClick: register,
|
|
4263
|
-
style: { ...btn, color: "var(--dsh-mem-accent)", borderColor: "var(--dsh-mem-accent)", opacity: !hiPriv || busy || !regSlug.trim() ? 0.5 : 1 },
|
|
4264
|
-
children: "注册"
|
|
4265
|
-
}
|
|
4266
|
-
),
|
|
4267
|
-
!hiPriv && /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: S.muted, children: "管理操作需先开启高权限模式" })
|
|
4268
|
-
] }),
|
|
4269
|
-
editing ? /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { position: "sticky", top: 0, zIndex: 5, background: "var(--dsh-mem-bg-inset)", display: "flex", alignItems: "center", gap: 6, marginBottom: 8, flexWrap: "wrap", padding: "6px 8px", border: "1px solid var(--dsh-mem-accent)", borderRadius: 8 }, children: [
|
|
4270
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { style: S.muted, children: [
|
|
4271
|
-
"编辑 ",
|
|
4272
|
-
editing.slug
|
|
4273
|
-
] }),
|
|
4274
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("input", { value: editing.label, onChange: (ev) => setEditing({ ...editing, label: ev.target.value }), placeholder: "显示名(可中文)", disabled: busy, style: { ...S.input, width: 140, fontSize: 12 } }),
|
|
4275
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("input", { value: editing.description, onChange: (ev) => setEditing({ ...editing, description: ev.target.value }), placeholder: "归类说明(喂标注器)", disabled: busy, style: { ...S.input, width: 200, fontSize: 12 } }),
|
|
4276
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", disabled: busy, onClick: saveEditing, style: { ...btn, color: "var(--dsh-mem-accent)", borderColor: "var(--dsh-mem-accent)" }, children: "保存" }),
|
|
4277
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", disabled: busy, onClick: () => setEditing(null), style: btn, children: "取消" })
|
|
4278
|
-
] }) : null,
|
|
4279
|
-
form ? /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { position: "sticky", top: 0, zIndex: 5, background: "var(--dsh-mem-bg-inset)", display: "flex", alignItems: "center", gap: 6, marginBottom: 8, flexWrap: "wrap", padding: "6px 8px", border: "1px solid var(--dsh-mem-accent)", borderRadius: 8 }, children: [
|
|
4280
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { style: S.muted, children: [
|
|
4281
|
-
form.action === "merge" ? "合并" : "归类/改名",
|
|
4282
|
-
" ",
|
|
4283
|
-
form.from,
|
|
4284
|
-
" →"
|
|
4285
|
-
] }),
|
|
4286
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
4287
|
-
"input",
|
|
4288
|
-
{
|
|
4289
|
-
value: form.to,
|
|
4290
|
-
onChange: (ev) => setForm({ ...form, to: ev.target.value }),
|
|
4291
|
-
placeholder: "目标 slug",
|
|
4292
|
-
disabled: busy,
|
|
4293
|
-
style: { ...S.input, width: 190, fontSize: 12 }
|
|
4294
|
-
}
|
|
4295
|
-
),
|
|
4296
|
-
form.action === "rename" ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: { display: "inline-flex", gap: 4, flexWrap: "wrap" }, children: groups.filter((gg) => gg.hall !== majorOf(form.from)).map((gg) => /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
4297
|
-
"button",
|
|
4298
|
-
{
|
|
4299
|
-
type: "button",
|
|
4300
|
-
title: `归入 ${gg.hall} 下(${gg.hall}/${suffixOf(form.from)})`,
|
|
4301
|
-
onClick: () => setForm({ ...form, to: `${gg.hall}/${suffixOf(form.from)}` }),
|
|
4302
|
-
style: { ...btn, borderRadius: 999, padding: "1px 8px" },
|
|
4303
|
-
children: gg.hall
|
|
4304
|
-
},
|
|
4305
|
-
gg.hall
|
|
4306
|
-
)) }) : null,
|
|
4307
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", disabled: busy, onClick: () => previewMerge(), style: { ...btn, color: "var(--dsh-mem-accent)", borderColor: "var(--dsh-mem-accent)" }, children: "预览" }),
|
|
4308
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", disabled: busy, onClick: () => {
|
|
4309
|
-
setForm(null);
|
|
4310
|
-
setPreview(null);
|
|
4311
|
-
setPicking(null);
|
|
4312
|
-
}, style: btn, children: "取消" }),
|
|
4313
|
-
picking ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: S.muted, children: "挑选中:点击目标 hall 头完成归类" }) : null,
|
|
4314
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: S.muted, children: "与反刍并发会互相覆盖,请在反刍空闲时执行。" })
|
|
4315
|
-
] }) : null,
|
|
4316
|
-
preview ? /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { position: "sticky", top: 0, zIndex: 5, background: "var(--dsh-mem-bg-inset)", marginBottom: 8, padding: "6px 8px", border: "1px solid var(--dsh-mem-danger)", borderRadius: 8, fontSize: 12 }, children: [
|
|
4317
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { children: preview.notice }),
|
|
4318
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { display: "flex", gap: 6, marginTop: 4 }, children: [
|
|
4319
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("button", { type: "button", disabled: busy, onClick: execMerge, style: { ...btn, color: "var(--dsh-mem-danger)", borderColor: "var(--dsh-mem-danger)" }, children: [
|
|
4320
|
-
"确认执行",
|
|
4321
|
-
preview.action === "merge" ? "合并" : "归类/改名"
|
|
4322
|
-
] }),
|
|
4323
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", disabled: busy, onClick: () => setPreview(null), style: btn, children: "再改改" })
|
|
4324
|
-
] })
|
|
4325
|
-
] }) : null,
|
|
4326
|
-
msg ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.hint, children: msg }) : null,
|
|
4327
|
-
error ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.error, children: error }) : null,
|
|
4328
|
-
ghost ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: { position: "fixed", left: ghost.x + 12, top: ghost.y + 12, zIndex: 9999, pointerEvents: "none", fontSize: 12, padding: "2px 10px", borderRadius: 999, border: "1px solid var(--dsh-mem-accent)", background: "var(--dsh-mem-bg-inset)", color: "var(--dsh-mem-accent)" }, children: ghost.text }) : null,
|
|
4329
|
-
visibleGroups.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { style: S.intro, children: normFilter ? "无匹配的 hall/room。" : "注册表为空。在上方注册 Hall/Room(如 dsh-plugin),或把自生长 slug「收编」进词表 —— 之后候选标注器会优先把相关记忆挂到这些 slug 上。" }) : visibleGroups.map((g) => {
|
|
4330
|
-
const hallOpen = !!normFilter || expandedHalls.has(g.hall);
|
|
4331
|
-
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { marginBottom: 10, border: "1px solid var(--dsh-mem-border)", borderRadius: 8, overflow: "hidden" }, children: [
|
|
4332
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
4333
|
-
"div",
|
|
4334
|
-
{
|
|
4335
|
-
"data-hall": g.hall,
|
|
4336
|
-
onDragOver: (ev) => {
|
|
4337
|
-
if (!hiPriv || busy) return;
|
|
4338
|
-
ev.preventDefault();
|
|
4339
|
-
ev.dataTransfer.dropEffect = "move";
|
|
4340
|
-
setDragOverHall(g.hall);
|
|
4341
|
-
},
|
|
4342
|
-
onDragLeave: () => setDragOverHall((cur) => cur === g.hall ? null : cur),
|
|
4343
|
-
onDrop: (ev) => {
|
|
4344
|
-
ev.preventDefault();
|
|
4345
|
-
setDragOverHall(null);
|
|
4346
|
-
if (!hiPriv || busy) return;
|
|
4347
|
-
const from = ev.dataTransfer.getData("text/dsh-room");
|
|
4348
|
-
if (from) beginReclass(from, g.hall);
|
|
4349
|
-
},
|
|
4350
|
-
onClick: () => {
|
|
4351
|
-
if (picking) {
|
|
4352
|
-
if (!busy) {
|
|
4353
|
-
const from = picking;
|
|
4354
|
-
setPicking(null);
|
|
4355
|
-
beginReclass(from, g.hall);
|
|
4356
|
-
}
|
|
4357
|
-
return;
|
|
4358
|
-
}
|
|
4359
|
-
toggleHall(g.hall);
|
|
4360
|
-
},
|
|
4361
|
-
style: {
|
|
4362
|
-
display: "flex",
|
|
4363
|
-
alignItems: "center",
|
|
4364
|
-
gap: 8,
|
|
4365
|
-
padding: "5px 10px",
|
|
4366
|
-
background: "var(--dsh-mem-bg-inset)",
|
|
4367
|
-
outline: dragOverHall === g.hall || picking !== null ? "2px dashed var(--dsh-mem-accent)" : void 0,
|
|
4368
|
-
outlineOffset: dragOverHall === g.hall || picking !== null ? "-2px" : void 0,
|
|
4369
|
-
cursor: "pointer"
|
|
4370
|
-
},
|
|
4371
|
-
title: picking ? "点击此 hall:把「" + picking + "」归入 " + g.hall + " 下(major/minor,预览后确认)" : hiPriv ? "拖入 room 归类到该 hall 下(major/minor;记录随迁,旧名进别名,预览后确认)" : void 0,
|
|
4372
|
-
children: [
|
|
4373
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
4374
|
-
"button",
|
|
4375
|
-
{
|
|
4376
|
-
type: "button",
|
|
4377
|
-
title: hallOpen ? "收起子 room" : "展开子 room(默认折叠)",
|
|
4378
|
-
onClick: (ev) => {
|
|
4379
|
-
ev.stopPropagation();
|
|
4380
|
-
toggleHall(g.hall);
|
|
4381
|
-
},
|
|
4382
|
-
style: { ...btn, borderRadius: 999, padding: "1px 7px", flexShrink: 0 },
|
|
4383
|
-
children: hallOpen ? "▾" : "▸"
|
|
4384
|
-
}
|
|
4385
|
-
),
|
|
4386
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { style: { fontSize: 12, fontWeight: 600 }, children: [
|
|
4387
|
-
g.hall,
|
|
4388
|
-
g.label ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: S.muted, children: " (" + g.label + ")" }) : null
|
|
4389
|
-
] }),
|
|
4390
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: S.muted, children: `合计 ${g.total} 条 · ${g.entries.length} 个 room` }),
|
|
4391
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.grow }),
|
|
4392
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
4393
|
-
"button",
|
|
4394
|
-
{
|
|
4395
|
-
type: "button",
|
|
4396
|
-
disabled: !hiPriv || busy,
|
|
4397
|
-
title: `预填注册表单为 ${g.hall}/…(注册该 hall 下的小类)`,
|
|
4398
|
-
onClick: (ev) => {
|
|
4399
|
-
ev.stopPropagation();
|
|
4400
|
-
setRegSlug(g.hall + "/");
|
|
4401
|
-
},
|
|
4402
|
-
style: btn,
|
|
4403
|
-
children: "+小类"
|
|
4404
|
-
}
|
|
4405
|
-
)
|
|
4406
|
-
]
|
|
4407
|
-
}
|
|
4408
|
-
),
|
|
4409
|
-
hallOpen ? g.entries.map((e) => {
|
|
4410
|
-
const standalone = e.slug === g.hall;
|
|
4411
|
-
const count = rooms.find((r) => r.room === e.slug)?.count ?? 0;
|
|
4412
|
-
const retired = e.status === "retired";
|
|
4413
|
-
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { padding: "4px 10px", borderTop: "1px solid var(--dsh-mem-border)", opacity: retired ? 0.55 : 1 }, children: [
|
|
4414
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
|
|
4415
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { flex: 1, minWidth: 0, display: "flex", flexWrap: "wrap", gap: "2px 8px", alignItems: "baseline" }, children: [
|
|
4416
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
4417
|
-
"button",
|
|
4418
|
-
{
|
|
4419
|
-
type: "button",
|
|
4420
|
-
title: expandedRooms.has(e.slug) ? "收起内容" : "展开查看该 Room 的记录内容(默认收起)",
|
|
4421
|
-
onClick: () => void toggleRoomExpand(e.slug),
|
|
4422
|
-
style: { ...btn, borderRadius: 999, padding: "1px 7px", flexShrink: 0 },
|
|
4423
|
-
children: expandedRooms.has(e.slug) ? "▾" : "▸"
|
|
4424
|
-
}
|
|
4425
|
-
),
|
|
4426
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
4427
|
-
"span",
|
|
4428
|
-
{
|
|
4429
|
-
style: { fontSize: 12, cursor: hiPriv && !busy ? "grab" : "default", touchAction: "none" },
|
|
4430
|
-
onPointerDown: (ev) => onDragLabelDown(ev, e.slug),
|
|
4431
|
-
onPointerMove: onDragLabelMove,
|
|
4432
|
-
onPointerUp: onDragLabelUp,
|
|
4433
|
-
title: hiPriv && !busy ? "按住拖到某个 hall 头上归类(major/minor;记录随迁,旧名进别名)" : e.description ? `${e.slug} — ${e.description}` : e.slug,
|
|
4434
|
-
children: [
|
|
4435
|
-
standalone ? e.slug : "· " + e.slug.slice(g.hall.length + 1),
|
|
4436
|
-
e.source === "pre-registered" ? " ⭐" : ""
|
|
4437
|
-
]
|
|
4438
|
-
}
|
|
4439
|
-
),
|
|
4440
|
-
e.label ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: S.muted, children: e.label }) : null,
|
|
4441
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: S.muted, children: count + " 条" }),
|
|
4442
|
-
retired ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: { ...S.muted, color: "var(--dsh-mem-danger)" }, children: "已退役" }) : null,
|
|
4443
|
-
(e.aliases ?? []).length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: { ...S.muted, wordBreak: "break-all" }, children: "别名: " + (e.aliases ?? []).join(", ") }) : null
|
|
4444
|
-
] }),
|
|
4445
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { display: "flex", gap: 6, flexShrink: 0, alignItems: "center" }, children: [
|
|
4446
|
-
!hiPriv ? null : /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(import_jsx_runtime16.Fragment, { children: [
|
|
4447
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", disabled: busy, title: "编辑显示名/归类说明", onClick: () => {
|
|
4448
|
-
setEditing({ slug: e.slug, label: e.label ?? "", description: e.description ?? "" });
|
|
4449
|
-
setForm(null);
|
|
4450
|
-
setPreview(null);
|
|
4451
|
-
setPicking(null);
|
|
4452
|
-
}, style: btn, children: "编辑" }),
|
|
4453
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
4454
|
-
"button",
|
|
4455
|
-
{
|
|
4456
|
-
type: "button",
|
|
4457
|
-
disabled: busy,
|
|
4458
|
-
title: picking === e.slug ? "再点一次取消挑选;然后点击目标 hall 头完成归类" : "归类到已有 hall 下:点击后选目标 hall(记录随迁,旧名进别名)",
|
|
4459
|
-
onClick: () => {
|
|
4460
|
-
if (picking === e.slug) {
|
|
4461
|
-
setPicking(null);
|
|
4462
|
-
return;
|
|
4463
|
-
}
|
|
4464
|
-
setForm({ action: "rename", from: e.slug, to: "" });
|
|
4465
|
-
setPreview(null);
|
|
4466
|
-
setPicking(e.slug);
|
|
4467
|
-
setMsg(null);
|
|
4468
|
-
setError(null);
|
|
4469
|
-
},
|
|
4470
|
-
style: { ...btn, ...picking === e.slug ? { color: "var(--dsh-mem-accent)", borderColor: "var(--dsh-mem-accent)" } : {} },
|
|
4471
|
-
children: picking === e.slug ? "选 hall…" : "归类"
|
|
4472
|
-
}
|
|
4473
|
-
),
|
|
4474
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", disabled: busy, title: `改名(= merge 1:1 + 注册表改名)`, onClick: () => {
|
|
4475
|
-
setForm({ action: "rename", from: e.slug, to: "" });
|
|
4476
|
-
setPreview(null);
|
|
4477
|
-
}, style: btn, children: "改名" }),
|
|
4478
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", disabled: busy, title: "合并到另一个 Room(dryRun 预览→确认实跑)", onClick: () => {
|
|
4479
|
-
setForm({ action: "merge", from: e.slug, to: "" });
|
|
4480
|
-
setPreview(null);
|
|
4481
|
-
}, style: btn, children: "合并" }),
|
|
4482
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", disabled: busy, title: retired ? "恢复该 Room 到词表" : "退役该 Room(存量 tags 不动)", onClick: () => retire(e.slug, retired), style: { ...btn, ...retired ? { color: "var(--dsh-mem-accent)", borderColor: "var(--dsh-mem-accent)" } : { color: "var(--dsh-mem-danger)", borderColor: "var(--dsh-mem-danger)" } }, children: retired ? "恢复" : "退役" }),
|
|
4483
|
-
!retired ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", disabled: busy, title: "退役并退场该 Room 下全部记忆(软删,可在「已退场」区恢复)", onClick: () => retire(e.slug, false, true), style: { ...btn, color: "var(--dsh-mem-danger)", borderColor: "var(--dsh-mem-danger)" }, children: "退场" }) : null
|
|
4484
|
-
] }),
|
|
4485
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", disabled: busy, title: "导出该 Room 的记录清单 CSV", onClick: () => exportRecords(e.slug), style: btn, children: "导出" })
|
|
4486
|
-
] })
|
|
4487
|
-
] }),
|
|
4488
|
-
expandedRooms.has(e.slug) ? /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { margin: "4px 0 2px", padding: "4px 8px", border: "1px dashed var(--dsh-mem-border)", borderRadius: 6 }, children: [
|
|
4489
|
-
(roomRecords[e.slug]?.items ?? []).map((it) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { fontSize: 11, padding: "3px 0", borderBottom: "1px solid var(--dsh-mem-border)" }, children: [
|
|
4490
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "dsh-mem-tag dsh-mem-tag-" + it.type, children: TYPE_LABELS[it.type] || it.type }),
|
|
4491
|
-
" ",
|
|
4492
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: S.muted, children: it.updatedAt ? fmtTime(it.updatedAt) : "" }),
|
|
4493
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: { marginTop: 2, wordBreak: "break-all", color: "var(--dsh-mem-text-2)" }, children: it.content.length > 120 ? it.content.slice(0, 120) + "…" : it.content })
|
|
4494
|
-
] }, it.id)),
|
|
4495
|
-
(roomRecords[e.slug]?.items.length ?? 0) === 0 ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.muted, children: "该 Room 暂无记录。" }) : null,
|
|
4496
|
-
(roomRecords[e.slug]?.total ?? 0) > (roomRecords[e.slug]?.items.length ?? 0) ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: { ...S.muted, fontSize: 11 }, children: "共 " + roomRecords[e.slug].total + " 条,仅显示前 " + roomRecords[e.slug].items.length + " 条" }) : null
|
|
4497
|
-
] }) : null
|
|
4498
|
-
] }, e.slug);
|
|
4499
|
-
}) : null
|
|
4500
|
-
] }, g.hall);
|
|
4501
|
-
}),
|
|
4502
|
-
visibleGrown.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { marginTop: 4 }, children: [
|
|
4503
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("button", { type: "button", onClick: () => setGrownOpen(!grownOpen), style: btn, title: grownOpen ? "收起未注册自生长 Room" : "展开未注册自生长 Room", children: [
|
|
4504
|
-
grownOpen ? "▾" : "▸",
|
|
4505
|
-
" 自生长未注册 · 共 ",
|
|
4506
|
-
visibleGrown.length
|
|
4507
|
-
] }),
|
|
4508
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: S.muted, children: "(只在 tags 里涌现,不在词表 —— 收编后标注器才会优先挂靠)" }),
|
|
4509
|
-
grownOpen ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: { display: "flex", flexWrap: "wrap", gap: 6, alignItems: "center", marginTop: 6 }, children: visibleGrown.map((r) => /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("span", { style: { display: "inline-flex", alignItems: "center", gap: 4 }, children: [
|
|
4510
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
4511
|
-
"span",
|
|
4512
|
-
{
|
|
4513
|
-
style: { ...btn, cursor: hiPriv && !busy ? "grab" : "default", borderRadius: 999, padding: "2px 8px", touchAction: "none" },
|
|
4514
|
-
onPointerDown: (ev) => onDragLabelDown(ev, r.room),
|
|
4515
|
-
onPointerMove: onDragLabelMove,
|
|
4516
|
-
onPointerUp: onDragLabelUp,
|
|
4517
|
-
title: hiPriv && !busy ? "自生长 slug(未注册)——按住拖到某个 hall 头上 = 收编并归为其子类" : "自生长 slug(未注册)",
|
|
4518
|
-
children: r.room + " · " + r.count
|
|
4519
|
-
}
|
|
4520
|
-
),
|
|
4521
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("button", { type: "button", disabled: !hiPriv || busy, title: "收编进注册表(source=grown,原地)", onClick: () => adopt(r.room), style: { ...btn, color: "var(--dsh-mem-accent)", borderColor: "var(--dsh-mem-accent)", opacity: !hiPriv || busy ? 0.5 : 1 }, children: "收编" }),
|
|
4522
|
-
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(
|
|
4523
|
-
"button",
|
|
4524
|
-
{
|
|
4525
|
-
type: "button",
|
|
4526
|
-
disabled: !hiPriv || busy,
|
|
4527
|
-
title: "归类到已有 hall 下:点击后选目标 hall(收编+子类一步,记录随迁)",
|
|
4528
|
-
onClick: () => {
|
|
4529
|
-
if (picking === r.room) {
|
|
4530
|
-
setPicking(null);
|
|
4531
|
-
return;
|
|
4532
|
-
}
|
|
4533
|
-
setForm({ action: "rename", from: r.room, to: "" });
|
|
4534
|
-
setPreview(null);
|
|
4535
|
-
setPicking(r.room);
|
|
4536
|
-
setMsg(null);
|
|
4537
|
-
setError(null);
|
|
4538
|
-
},
|
|
4539
|
-
style: { ...btn, opacity: !hiPriv || busy ? 0.5 : 1, ...picking === r.room ? { color: "var(--dsh-mem-accent)", borderColor: "var(--dsh-mem-accent)" } : {} },
|
|
4540
|
-
children: picking === r.room ? "选 hall…" : "归"
|
|
4541
|
-
}
|
|
4542
|
-
)
|
|
4543
|
-
] }, r.room)) }) : null
|
|
4544
|
-
] }) : null
|
|
4545
|
-
] });
|
|
4546
|
-
}
|
|
4547
|
-
|
|
4548
|
-
// client/src/tabs/RoomTab.tsx
|
|
4549
|
-
var import_react17 = require("react");
|
|
4550
|
-
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
4551
|
-
var btn2 = {
|
|
4552
|
-
cursor: "pointer",
|
|
4553
|
-
fontSize: 12,
|
|
4554
|
-
padding: "2px 8px",
|
|
4555
|
-
borderRadius: 6,
|
|
4556
|
-
border: "1px solid var(--dsh-mem-border)",
|
|
4557
|
-
background: "transparent",
|
|
4558
|
-
color: "var(--dsh-mem-text-2)"
|
|
4559
|
-
};
|
|
4560
|
-
function downloadCsv2(csv, name) {
|
|
4561
|
-
const blob = new Blob([csv], { type: "text/csv;charset=utf-8" });
|
|
4562
|
-
const url = URL.createObjectURL(blob);
|
|
4563
|
-
const a = document.createElement("a");
|
|
4564
|
-
a.href = url;
|
|
4565
|
-
a.download = name;
|
|
4566
|
-
a.click();
|
|
4567
|
-
URL.revokeObjectURL(url);
|
|
4568
|
-
}
|
|
4569
|
-
function RoomTab(props) {
|
|
4570
|
-
const rpc = props.rpc;
|
|
4571
|
-
const [registry, setRegistry] = (0, import_react17.useState)([]);
|
|
4572
|
-
const [counts, setCounts] = (0, import_react17.useState)([]);
|
|
4573
|
-
const [orphanCount, setOrphanCount] = (0, import_react17.useState)(0);
|
|
4574
|
-
const [busy, setBusy] = (0, import_react17.useState)(false);
|
|
4575
|
-
const [msg, setMsg] = (0, import_react17.useState)(null);
|
|
4576
|
-
const [error, setError] = (0, import_react17.useState)(null);
|
|
4577
|
-
const [hiPriv, setHiPriv] = (0, import_react17.useState)(false);
|
|
4578
|
-
const [hiPrivBusy, setHiPrivBusy] = (0, import_react17.useState)(false);
|
|
4579
|
-
const [reg, setReg] = (0, import_react17.useState)({ slug: "", label: "", description: "" });
|
|
4580
|
-
const [editing, setEditing] = (0, import_react17.useState)(null);
|
|
4581
|
-
const [renaming, setRenaming] = (0, import_react17.useState)(null);
|
|
4582
|
-
const [expanded, setExpanded] = (0, import_react17.useState)(/* @__PURE__ */ new Set());
|
|
4583
|
-
const [retiredFilter, setRetiredFilter] = (0, import_react17.useState)("");
|
|
4584
|
-
const [filter, setFilter] = (0, import_react17.useState)("");
|
|
4585
|
-
const [records, setRecords] = (0, import_react17.useState)({});
|
|
4586
|
-
const loadAll = (0, import_react17.useCallback)(() => {
|
|
4587
|
-
rpc("dsh-memory/rooms-get", {}).then((r) => {
|
|
4588
|
-
if (r && r.ok) {
|
|
4589
|
-
setCounts(r.value.rooms ?? []);
|
|
4590
|
-
setRegistry(r.value.registry ?? []);
|
|
4591
|
-
setOrphanCount(r.value.orphanCount ?? 0);
|
|
4592
|
-
}
|
|
4593
|
-
}).catch(() => void 0);
|
|
4594
|
-
}, [rpc]);
|
|
4595
|
-
const loadHiPriv = (0, import_react17.useCallback)(() => {
|
|
4596
|
-
rpc("dsh-memory/settings-get", {}).then((r) => {
|
|
4597
|
-
if (r && r.ok && r.value) setHiPriv(!!r.value.settings.memoryMutate);
|
|
4598
|
-
}).catch(() => {
|
|
4599
|
-
});
|
|
4600
|
-
}, [rpc]);
|
|
4601
|
-
(0, import_react17.useEffect)(() => {
|
|
4602
|
-
loadAll();
|
|
4603
|
-
loadHiPriv();
|
|
4604
|
-
}, [loadAll, loadHiPriv]);
|
|
4605
|
-
const toggleHiPriv = () => {
|
|
4606
|
-
const next = !hiPriv;
|
|
4607
|
-
if (next && !window.confirm("开启高权限模式:模型获得写入/删除记忆工具,并解锁 Room 管理操作。确定开启?")) return;
|
|
4608
|
-
rpc("dsh-memory/settings-set", { memoryMutate: next }).then((r) => {
|
|
4609
|
-
if (r && r.ok) setHiPriv(next);
|
|
4610
|
-
setHiPrivBusy(false);
|
|
4611
|
-
loadHiPriv();
|
|
4612
|
-
}).catch(() => setHiPrivBusy(false));
|
|
4613
|
-
};
|
|
4614
|
-
const run = (fn) => {
|
|
4615
|
-
if (busy) return;
|
|
4616
|
-
setBusy(true);
|
|
4617
|
-
setError(null);
|
|
4618
|
-
setMsg(null);
|
|
4619
|
-
fn().finally(() => setBusy(false));
|
|
4620
|
-
};
|
|
4621
|
-
const register = () => run(async () => {
|
|
4622
|
-
const r = await rpc("dsh-memory/room-register", { slug: reg.slug.trim(), label: reg.label.trim() || void 0, description: reg.description.trim() || void 0 });
|
|
4623
|
-
if (r && r.ok) {
|
|
4624
|
-
setMsg(r.value?.notice ?? `已注册:${reg.slug.trim()}`);
|
|
4625
|
-
setReg({ slug: "", label: "", description: "" });
|
|
4626
|
-
loadAll();
|
|
4627
|
-
} else setError(r && r.error ? r.error.message : "注册失败");
|
|
4628
|
-
});
|
|
4629
|
-
const adopt = (slug) => run(async () => {
|
|
4630
|
-
const r = await rpc("dsh-memory/room-register", { slug, source: "grown" });
|
|
4631
|
-
if (r && r.ok) {
|
|
4632
|
-
setMsg(`已收编:${slug}(source=grown)`);
|
|
4633
|
-
loadAll();
|
|
4634
|
-
} else setError(r && r.error ? r.error.message : "收编失败");
|
|
4635
|
-
});
|
|
4636
|
-
const previewRename = () => run(async () => {
|
|
4637
|
-
if (!renaming) return;
|
|
4638
|
-
const to = renaming.to.trim();
|
|
4639
|
-
if (!to) {
|
|
4640
|
-
setError("目标 slug 不能为空");
|
|
4641
|
-
return;
|
|
4642
|
-
}
|
|
4643
|
-
if (to === renaming.slug) {
|
|
4644
|
-
setError("目标与源相同");
|
|
4645
|
-
return;
|
|
4646
|
-
}
|
|
4647
|
-
if (!registry.some((e) => e.slug === renaming.slug)) {
|
|
4648
|
-
const rr = await rpc("dsh-memory/room-register", { slug: renaming.slug, source: "grown" });
|
|
4649
|
-
if (!rr || !rr.ok) {
|
|
4650
|
-
setError(rr && rr.error ? rr.error.message : "收编源失败");
|
|
4651
|
-
return;
|
|
4652
|
-
}
|
|
4653
|
-
loadAll();
|
|
4654
|
-
}
|
|
4655
|
-
const r = await rpc("dsh-memory/room-admin", { action: "rename", from: renaming.slug, to });
|
|
4656
|
-
if (r && r.ok) setMsg(String(r.value?.notice ?? ""));
|
|
4657
|
-
else setError(r && r.error ? r.error.message : "预览失败");
|
|
4658
|
-
});
|
|
4659
|
-
const execRename = () => run(async () => {
|
|
4660
|
-
if (!renaming) return;
|
|
4661
|
-
if (!registry.some((e) => e.slug === renaming.slug)) {
|
|
4662
|
-
await rpc("dsh-memory/room-register", { slug: renaming.slug, source: "grown" });
|
|
4663
|
-
}
|
|
4664
|
-
const r = await rpc("dsh-memory/room-admin", { action: "rename", from: renaming.slug, to: renaming.to.trim(), dryRun: false });
|
|
4665
|
-
if (r && r.ok) {
|
|
4666
|
-
setMsg(String(r.value?.notice ?? "完成"));
|
|
4667
|
-
setRenaming(null);
|
|
4668
|
-
loadAll();
|
|
4669
|
-
} else setError(r && r.error ? r.error.message : "执行失败");
|
|
4670
|
-
});
|
|
4671
|
-
const saveEditing = () => run(async () => {
|
|
4672
|
-
if (!editing) return;
|
|
4673
|
-
const r = await rpc("dsh-memory/room-admin", { action: "update", slug: editing.slug, label: editing.label, description: editing.description });
|
|
4674
|
-
if (r && r.ok) {
|
|
4675
|
-
setMsg(String(r.value?.notice ?? "已更新"));
|
|
4676
|
-
setEditing(null);
|
|
4677
|
-
loadAll();
|
|
4678
|
-
} else setError(r && r.error ? r.error.message : "更新失败");
|
|
4679
|
-
});
|
|
4680
|
-
const retire = (slug, active, withRecords = false) => run(async () => {
|
|
4681
|
-
if (!active) {
|
|
4682
|
-
const tip = withRecords ? `退役 Room:${slug} 并退场其下全部记忆?(记录为软删,可在记忆页「已退场」区逐条恢复)` : `退役 Room:${slug}?(存量记录的 tags 不动,仅词表不再推荐;可随时恢复)`;
|
|
4683
|
-
if (!window.confirm(tip)) return;
|
|
4684
|
-
}
|
|
4685
|
-
const r = await rpc("dsh-memory/room-admin", { action: "retire", slug, active, withRecords: withRecords || void 0 });
|
|
4686
|
-
if (r && r.ok) {
|
|
4687
|
-
setMsg(String(r.value?.notice ?? "完成"));
|
|
4688
|
-
loadAll();
|
|
4689
|
-
if (expanded.has(slug)) {
|
|
4690
|
-
const rr = await rpc("dsh-memory/list-records", { tag: slug, limit: 10, retired: false });
|
|
4691
|
-
if (rr && rr.ok) setRecords((m) => ({ ...m, [slug]: { items: rr.value.items, total: rr.value.total ?? null } }));
|
|
4692
|
-
}
|
|
4693
|
-
} else setError(r && r.error ? r.error.message : "操作失败");
|
|
4694
|
-
});
|
|
4695
|
-
const exportRecords = (slug) => run(async () => {
|
|
4696
|
-
const r = await rpc("dsh-memory/rooms-export", { kind: "records", tag: slug });
|
|
4697
|
-
if (!r.ok) {
|
|
4698
|
-
setError(r.error.message);
|
|
4699
|
-
return;
|
|
4700
|
-
}
|
|
4701
|
-
if (r.value.csv) {
|
|
4702
|
-
const blob = new Blob([r.value.csv], { type: "text/csv;charset=utf-8" });
|
|
4703
|
-
const url = URL.createObjectURL(blob);
|
|
4704
|
-
const a = document.createElement("a");
|
|
4705
|
-
a.href = url;
|
|
4706
|
-
a.download = `dsh-memory-room-${slug.replace(/\//g, "-")}-records.csv`;
|
|
4707
|
-
a.click();
|
|
4708
|
-
URL.revokeObjectURL(url);
|
|
4709
|
-
}
|
|
4710
|
-
});
|
|
4711
|
-
const toggleExpand = (slug) => run(async () => {
|
|
4712
|
-
if (expanded.has(slug)) {
|
|
4713
|
-
const next = new Set(expanded);
|
|
4714
|
-
next.delete(slug);
|
|
4715
|
-
setExpanded(next);
|
|
4716
|
-
return;
|
|
4717
|
-
}
|
|
4718
|
-
const r = await rpc("dsh-memory/list-records", { tag: slug, limit: 10, retired: false });
|
|
4719
|
-
if (r && r.ok) {
|
|
4720
|
-
const next = new Set(expanded);
|
|
4721
|
-
next.add(slug);
|
|
4722
|
-
setExpanded(next);
|
|
4723
|
-
setRecords((m) => ({ ...m, [slug]: { items: r.value.items, total: r.value.total ?? null } }));
|
|
4724
|
-
} else setError(r && r.error ? r.error.message : "加载失败");
|
|
4725
|
-
});
|
|
4726
|
-
const countOf = (slug) => counts.find((c) => c.room === slug)?.count ?? 0;
|
|
4727
|
-
const rows = [
|
|
4728
|
-
...registry.map((e) => ({ slug: e.slug, count: countOf(e.slug), entry: e })),
|
|
4729
|
-
...counts.filter((c) => !registry.some((e) => e.slug === c.room)).map((c) => ({ slug: c.room, count: c.count }))
|
|
4730
|
-
].filter((row2) => {
|
|
4731
|
-
if (retiredFilter === "active") return row2.entry?.status !== "retired";
|
|
4732
|
-
if (retiredFilter === "retired") return row2.entry?.status === "retired";
|
|
4733
|
-
return true;
|
|
4734
|
-
});
|
|
4735
|
-
const normFilter = filter.trim().toLowerCase();
|
|
4736
|
-
const visibleRows = normFilter ? rows.filter(
|
|
4737
|
-
(row2) => row2.slug.toLowerCase().includes(normFilter) || (row2.entry?.label ?? "").toLowerCase().includes(normFilter) || (row2.entry?.aliases ?? []).some((a) => a.toLowerCase().includes(normFilter))
|
|
4738
|
-
) : rows;
|
|
4739
|
-
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { children: [
|
|
4740
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: { ...S.flexRow, marginBottom: 8, flexWrap: "wrap" }, children: [
|
|
4741
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: S.muted, children: "Room 级管理:存在(注册/收编/退役)· 名称(显示名/说明/改名)· 条目(展开浏览) · 归类到 hall 请到「Hall」页" }),
|
|
4742
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.grow }),
|
|
4743
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("button", { type: "button", style: btn2, title: "导出无 Room 绑定的孤儿清单(含候选)", onClick: () => run(async () => {
|
|
4744
|
-
const r = await rpc("dsh-memory/rooms-export", { kind: "orphans" });
|
|
4745
|
-
if (!r.ok) {
|
|
4746
|
-
setError(r.error.message);
|
|
4747
|
-
return;
|
|
4748
|
-
}
|
|
4749
|
-
if (r.value.csv) downloadCsv2(r.value.csv, "dsh-memory-room-orphans.csv");
|
|
4750
|
-
}), children: [
|
|
4751
|
-
"导出孤儿 · ",
|
|
4752
|
-
orphanCount
|
|
4753
|
-
] }),
|
|
4754
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
4755
|
-
"button",
|
|
4756
|
-
{
|
|
4757
|
-
type: "button",
|
|
4758
|
-
style: { ...btn2, color: hiPriv ? "var(--dsh-mem-danger)" : void 0, border: hiPriv ? "1px solid var(--dsh-mem-danger)" : btn2.border },
|
|
4759
|
-
disabled: hiPrivBusy,
|
|
4760
|
-
title: hiPriv ? "关闭高权限模式" : "开启高权限模式以解锁 Room 管理操作",
|
|
4761
|
-
onClick: toggleHiPriv,
|
|
4762
|
-
children: hiPriv ? "高权限:开" : "高权限:关"
|
|
4763
|
-
}
|
|
4764
|
-
),
|
|
4765
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", style: btn2, onClick: loadAll, children: "刷新" })
|
|
4766
|
-
] }),
|
|
4767
|
-
editing ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: { position: "sticky", top: 0, zIndex: 5, background: "var(--dsh-mem-bg-inset)", display: "flex", alignItems: "center", gap: 6, marginBottom: 8, flexWrap: "wrap", padding: "6px 8px", border: "1px solid var(--dsh-mem-accent)", borderRadius: 8 }, children: [
|
|
4768
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { style: S.muted, children: [
|
|
4769
|
-
"编辑 ",
|
|
4770
|
-
editing.slug
|
|
4771
|
-
] }),
|
|
4772
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("input", { value: editing.label, onChange: (e) => setEditing({ ...editing, label: e.target.value }), placeholder: "显示名(可中文)", disabled: busy, style: { ...S.input, width: 140, fontSize: 12 } }),
|
|
4773
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("input", { value: editing.description, onChange: (e) => setEditing({ ...editing, description: e.target.value }), placeholder: "归类说明(喂标注器)", disabled: busy, style: { ...S.input, width: 200, fontSize: 12 } }),
|
|
4774
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", disabled: busy, onClick: saveEditing, style: { ...btn2, color: "var(--dsh-mem-accent)", borderColor: "var(--dsh-mem-accent)" }, children: "保存" }),
|
|
4775
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", disabled: busy, onClick: () => setEditing(null), style: btn2, children: "取消" })
|
|
4776
|
-
] }) : null,
|
|
4777
|
-
renaming ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: { position: "sticky", top: 0, zIndex: 5, background: "var(--dsh-mem-bg-inset)", display: "flex", alignItems: "center", gap: 6, marginBottom: 8, flexWrap: "wrap", padding: "6px 8px", border: "1px solid var(--dsh-mem-accent)", borderRadius: 8 }, children: [
|
|
4778
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { style: S.muted, children: [
|
|
4779
|
-
"改名 ",
|
|
4780
|
-
renaming.slug,
|
|
4781
|
-
" →"
|
|
4782
|
-
] }),
|
|
4783
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("input", { value: renaming.to, onChange: (e) => setRenaming({ ...renaming, to: e.target.value }), placeholder: "新 slug(可两级:hall/子类)", disabled: busy, style: { ...S.input, width: 200, fontSize: 12 } }),
|
|
4784
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", disabled: busy, onClick: previewRename, style: { ...btn2, color: "var(--dsh-mem-accent)", borderColor: "var(--dsh-mem-accent)" }, children: "预览" }),
|
|
4785
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", disabled: busy, onClick: execRename, style: { ...btn2, color: "var(--dsh-mem-danger)", borderColor: "var(--dsh-mem-danger)" }, children: "确认执行" }),
|
|
4786
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", disabled: busy, onClick: () => setRenaming(null), style: btn2, children: "取消" }),
|
|
4787
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: S.muted, children: "记录随迁;与反刍并发会互相覆盖,请在反刍空闲时执行。" })
|
|
4788
|
-
] }) : null,
|
|
4789
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, marginBottom: 8, flexWrap: "wrap" }, children: [
|
|
4790
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: S.muted, children: "退场筛选" }),
|
|
4791
|
-
[["", "全部"], ["active", "活跃"], ["retired", "已退役"]].map(([val, label]) => {
|
|
4792
|
-
const on = retiredFilter === val;
|
|
4793
|
-
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
4794
|
-
"button",
|
|
4795
|
-
{
|
|
4796
|
-
type: "button",
|
|
4797
|
-
title: val === "" ? "全部 room" : val === "active" ? "只看词表未退役的 room" : "只看已退役的 room",
|
|
4798
|
-
onClick: () => setRetiredFilter(val),
|
|
4799
|
-
style: {
|
|
4800
|
-
cursor: "pointer",
|
|
4801
|
-
fontSize: 12,
|
|
4802
|
-
padding: "2px 10px",
|
|
4803
|
-
borderRadius: 999,
|
|
4804
|
-
border: on ? "1px solid var(--dsh-mem-accent)" : "1px solid var(--dsh-mem-border)",
|
|
4805
|
-
background: on ? "var(--dsh-mem-bg-inset)" : "transparent",
|
|
4806
|
-
color: on ? "var(--dsh-mem-accent)" : "var(--dsh-mem-text-2)"
|
|
4807
|
-
},
|
|
4808
|
-
children: label
|
|
4809
|
-
},
|
|
4810
|
-
val
|
|
4811
|
-
);
|
|
4812
|
-
}),
|
|
4813
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.grow }),
|
|
4814
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
4815
|
-
"input",
|
|
4816
|
-
{
|
|
4817
|
-
value: filter,
|
|
4818
|
-
onChange: (e) => setFilter(e.target.value),
|
|
4819
|
-
placeholder: "搜索 room(slug、显示名、别名)",
|
|
4820
|
-
style: { ...S.input, width: 230, fontSize: 12 }
|
|
4821
|
-
}
|
|
4822
|
-
),
|
|
4823
|
-
filter ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", style: btn2, onClick: () => setFilter(""), children: "清除" }) : null
|
|
4824
|
-
] }),
|
|
4825
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: { display: "flex", flexWrap: "wrap", gap: 6, alignItems: "center", marginBottom: 10 }, children: [
|
|
4826
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("input", { value: reg.slug, onChange: (e) => setReg({ ...reg, slug: e.target.value }), placeholder: "slug(如 dsh-plugin 或 dsh-plugin/merge)", disabled: !hiPriv || busy, style: { ...S.input, width: 210, fontSize: 12 } }),
|
|
4827
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("input", { value: reg.label, onChange: (e) => setReg({ ...reg, label: e.target.value }), placeholder: "名称(可中文)", disabled: !hiPriv || busy, style: { ...S.input, width: 110, fontSize: 12 } }),
|
|
4828
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("input", { value: reg.description, onChange: (e) => setReg({ ...reg, description: e.target.value }), placeholder: "归类说明(喂标注器)", disabled: !hiPriv || busy, style: { ...S.input, width: 170, fontSize: 12 } }),
|
|
4829
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", disabled: !hiPriv || busy || !reg.slug.trim(), onClick: register, style: { ...btn2, color: "var(--dsh-mem-accent)", borderColor: "var(--dsh-mem-accent)", opacity: !hiPriv || busy || !reg.slug.trim() ? 0.5 : 1 }, children: "注册" }),
|
|
4830
|
-
!hiPriv && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: S.muted, children: "管理操作需先开启高权限模式" })
|
|
4831
|
-
] }),
|
|
4832
|
-
msg ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.hint, children: msg }) : null,
|
|
4833
|
-
error ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.error, children: error }) : null,
|
|
4834
|
-
visibleRows.length === 0 ? normFilter ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { style: S.intro, children: "无匹配的 Room。" }) : /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { style: S.intro, children: "暂无 Room:对话/反刍会从标签涌现,或在上方注册。" }) : visibleRows.map((row2) => {
|
|
4835
|
-
const e = row2.entry;
|
|
4836
|
-
const retired = e?.status === "retired";
|
|
4837
|
-
const grownOnly = !e;
|
|
4838
|
-
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: { marginBottom: 6, border: "1px solid var(--dsh-mem-border)", borderRadius: 8 }, children: [
|
|
4839
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: { display: "flex", alignItems: "center", gap: 8, padding: "4px 10px" }, children: [
|
|
4840
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
4841
|
-
"button",
|
|
4842
|
-
{
|
|
4843
|
-
type: "button",
|
|
4844
|
-
title: expanded.has(row2.slug) ? "收起记忆条目" : "展开查看该 Room 的记忆条目(默认收起)",
|
|
4845
|
-
onClick: () => void toggleExpand(row2.slug),
|
|
4846
|
-
style: { ...btn2, borderRadius: 999, padding: "1px 7px", flexShrink: 0 },
|
|
4847
|
-
children: expanded.has(row2.slug) ? "▾" : "▸"
|
|
4848
|
-
}
|
|
4849
|
-
),
|
|
4850
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: { flex: 1, minWidth: 0, display: "flex", flexWrap: "wrap", gap: "2px 8px", alignItems: "baseline" }, children: [
|
|
4851
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { style: { fontSize: 12, opacity: retired ? 0.6 : 1 }, children: [
|
|
4852
|
-
row2.slug,
|
|
4853
|
-
e?.source === "pre-registered" ? " ⭐" : ""
|
|
4854
|
-
] }),
|
|
4855
|
-
e?.label ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: S.muted, children: e.label }) : null,
|
|
4856
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: S.muted, children: row2.count + " 条" }),
|
|
4857
|
-
grownOnly ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: S.muted, children: "(自生长未注册)" }) : null,
|
|
4858
|
-
retired ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: { ...S.muted, color: "var(--dsh-mem-danger)" }, children: "已退役" }) : null,
|
|
4859
|
-
(e?.aliases ?? []).length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: { ...S.muted, wordBreak: "break-all" }, children: "别名: " + (e?.aliases ?? []).join(", ") }) : null
|
|
4860
|
-
] }),
|
|
4861
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: { display: "flex", gap: 6, flexShrink: 0, alignItems: "center" }, children: [
|
|
4862
|
-
!hiPriv || grownOnly ? null : /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
|
|
4863
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", disabled: busy, title: "编辑显示名/归类说明", onClick: () => {
|
|
4864
|
-
setEditing({ slug: row2.slug, label: e?.label ?? "", description: e?.description ?? "" });
|
|
4865
|
-
setRenaming(null);
|
|
4866
|
-
}, style: btn2, children: "编辑" }),
|
|
4867
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", disabled: busy, title: "改名(可两级 slug;记录随迁,旧名进别名)", onClick: () => {
|
|
4868
|
-
setRenaming({ slug: row2.slug, to: "" });
|
|
4869
|
-
setEditing(null);
|
|
4870
|
-
}, style: btn2, children: "改名" }),
|
|
4871
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
4872
|
-
"button",
|
|
4873
|
-
{
|
|
4874
|
-
type: "button",
|
|
4875
|
-
disabled: busy,
|
|
4876
|
-
title: retired ? "恢复该 Room 到词表" : "退役该 Room(存量 tags 不动)",
|
|
4877
|
-
onClick: () => retire(row2.slug, retired),
|
|
4878
|
-
style: { ...btn2, ...retired ? { color: "var(--dsh-mem-accent)", borderColor: "var(--dsh-mem-accent)" } : { color: "var(--dsh-mem-danger)", borderColor: "var(--dsh-mem-danger)" } },
|
|
4879
|
-
children: retired ? "恢复" : "退役"
|
|
4880
|
-
}
|
|
4881
|
-
),
|
|
4882
|
-
!retired ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", disabled: busy, title: "退役并退场该 Room 下全部记忆(软删,可在「已退场」区恢复)", onClick: () => retire(row2.slug, false, true), style: { ...btn2, color: "var(--dsh-mem-danger)", borderColor: "var(--dsh-mem-danger)" }, children: "退场" }) : null
|
|
4883
|
-
] }),
|
|
4884
|
-
grownOnly ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(import_jsx_runtime17.Fragment, { children: [
|
|
4885
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", disabled: !hiPriv || busy, title: "收编进注册表(source=grown)", onClick: () => adopt(row2.slug), style: { ...btn2, color: "var(--dsh-mem-accent)", borderColor: "var(--dsh-mem-accent)", opacity: !hiPriv || busy ? 0.5 : 1 }, children: "收编" }),
|
|
4886
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", disabled: !hiPriv || busy, title: "退场该 Room 下全部记忆(软删,可在「已退场」区恢复)", onClick: () => {
|
|
4887
|
-
setRenaming(null);
|
|
4888
|
-
retire(row2.slug, false, true);
|
|
4889
|
-
}, style: { ...btn2, color: "var(--dsh-mem-danger)", borderColor: "var(--dsh-mem-danger)", opacity: !hiPriv || busy ? 0.5 : 1 }, children: "退场" })
|
|
4890
|
-
] }) : null,
|
|
4891
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("button", { type: "button", disabled: busy, title: "导出该 Room 的记录清单 CSV", onClick: () => exportRecords(row2.slug), style: btn2, children: "导出" })
|
|
4892
|
-
] })
|
|
4893
|
-
] }),
|
|
4894
|
-
expanded.has(row2.slug) ? /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: { margin: "0 10px 6px", padding: "4px 8px", border: "1px dashed var(--dsh-mem-border)", borderRadius: 6 }, children: [
|
|
4895
|
-
(records[row2.slug]?.items ?? []).map((it) => /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { style: { fontSize: 11, padding: "3px 0", borderBottom: "1px solid var(--dsh-mem-border)" }, children: [
|
|
4896
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { className: "dsh-mem-tag dsh-mem-tag-" + it.type, children: TYPE_LABELS[it.type] || it.type }),
|
|
4897
|
-
" ",
|
|
4898
|
-
it.retired ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: { ...S.muted, color: "var(--dsh-mem-danger)" }, children: "[已退场]" }) : null,
|
|
4899
|
-
" ",
|
|
4900
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { style: S.muted, children: it.updatedAt ? fmtTime(it.updatedAt) : "" }),
|
|
4901
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: { marginTop: 2, wordBreak: "break-all", color: "var(--dsh-mem-text-2)", opacity: it.retired ? 0.55 : 1 }, children: it.content.length > 140 ? it.content.slice(0, 140) + "…" : it.content })
|
|
4902
|
-
] }, it.id)),
|
|
4903
|
-
(records[row2.slug]?.items.length ?? 0) === 0 ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.muted, children: "该 Room 暂无记忆条目。" }) : null,
|
|
4904
|
-
(records[row2.slug]?.total ?? 0) > (records[row2.slug]?.items.length ?? 0) ? /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: { ...S.muted, fontSize: 11 }, children: "共 " + records[row2.slug].total + " 条,仅显示前 " + records[row2.slug].items.length + " 条" }) : null
|
|
4905
|
-
] }) : null
|
|
4906
|
-
] }, row2.slug);
|
|
4907
|
-
})
|
|
4908
|
-
] });
|
|
4909
|
-
}
|
|
4910
|
-
|
|
4911
|
-
// client/src/tabs/ScenesTab.tsx
|
|
4912
|
-
var import_react18 = require("react");
|
|
4913
|
-
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
4914
3780
|
function SceneCard(props) {
|
|
4915
3781
|
const s = props.s;
|
|
4916
|
-
const [open, setOpen] = (0,
|
|
4917
|
-
return /* @__PURE__ */ (0,
|
|
4918
|
-
/* @__PURE__ */ (0,
|
|
3782
|
+
const [open, setOpen] = (0, import_react16.useState)(false);
|
|
3783
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { className: "dsh-mem-card dsh-mem-card-hover", style: S.card, children: [
|
|
3784
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)(
|
|
4919
3785
|
"div",
|
|
4920
3786
|
{
|
|
4921
3787
|
style: { ...S.sceneHead, cursor: "pointer", userSelect: "none" },
|
|
@@ -4923,23 +3789,23 @@ var __defProp = Object.defineProperty;
|
|
|
4923
3789
|
setOpen(!open);
|
|
4924
3790
|
},
|
|
4925
3791
|
children: [
|
|
4926
|
-
/* @__PURE__ */ (0,
|
|
4927
|
-
/* @__PURE__ */ (0,
|
|
4928
|
-
s.heat ? /* @__PURE__ */ (0,
|
|
4929
|
-
/* @__PURE__ */ (0,
|
|
4930
|
-
/* @__PURE__ */ (0,
|
|
3792
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { className: "dsh-mem-scene-chev", style: { transform: open ? "rotate(90deg)" : "none" }, children: "▸" }),
|
|
3793
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: S.sceneTitle, children: s.path }),
|
|
3794
|
+
s.heat ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: S.muted, children: "热度 " + s.heat }) : null,
|
|
3795
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.grow }),
|
|
3796
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: S.muted, children: "更新 " + fmtTime(s.updated) })
|
|
4931
3797
|
]
|
|
4932
3798
|
}
|
|
4933
3799
|
),
|
|
4934
|
-
s.summary ? /* @__PURE__ */ (0,
|
|
4935
|
-
open ? /* @__PURE__ */ (0,
|
|
3800
|
+
s.summary ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: { ...S.muted, marginBottom: 6 }, children: s.summary }) : null,
|
|
3801
|
+
open ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("pre", { style: S.pre, children: s.content || "(空)" }) : null
|
|
4936
3802
|
] });
|
|
4937
3803
|
}
|
|
4938
3804
|
function ScenesTab(props) {
|
|
4939
3805
|
const rpc = props.rpc;
|
|
4940
|
-
const [items, setItems] = (0,
|
|
4941
|
-
const [error, setError] = (0,
|
|
4942
|
-
const load = (0,
|
|
3806
|
+
const [items, setItems] = (0, import_react16.useState)(null);
|
|
3807
|
+
const [error, setError] = (0, import_react16.useState)(null);
|
|
3808
|
+
const load = (0, import_react16.useCallback)(() => {
|
|
4943
3809
|
rpc("dsh-memory/scenes", {}).then((r) => {
|
|
4944
3810
|
if (r && r.ok) {
|
|
4945
3811
|
setItems(r.value.items);
|
|
@@ -4949,58 +3815,54 @@ var __defProp = Object.defineProperty;
|
|
|
4949
3815
|
setError(String(e && e.message || e));
|
|
4950
3816
|
});
|
|
4951
3817
|
}, [rpc]);
|
|
4952
|
-
(0,
|
|
3818
|
+
(0, import_react16.useEffect)(() => {
|
|
4953
3819
|
load();
|
|
4954
3820
|
}, [load]);
|
|
4955
|
-
return /* @__PURE__ */ (0,
|
|
4956
|
-
/* @__PURE__ */ (0,
|
|
4957
|
-
/* @__PURE__ */ (0,
|
|
4958
|
-
/* @__PURE__ */ (0,
|
|
4959
|
-
/* @__PURE__ */ (0,
|
|
3821
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { children: [
|
|
3822
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("div", { style: { ...S.flexRow, marginBottom: 10 }, children: [
|
|
3823
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("span", { style: S.muted, children: items ? items.length + " 个场景块" : "加载中…" }),
|
|
3824
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.grow }),
|
|
3825
|
+
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(NButton, { onClick: load, children: "刷新" })
|
|
4960
3826
|
] }),
|
|
4961
|
-
error ? /* @__PURE__ */ (0,
|
|
4962
|
-
items && items.length === 0 ? /* @__PURE__ */ (0,
|
|
3827
|
+
error ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("div", { style: S.error, children: error }) : null,
|
|
3828
|
+
items && items.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime16.jsx)("p", { style: S.intro, children: "暂无场景块。累计 5 条新记忆后 L2 会自动整合出第一个场景。" }) : null,
|
|
4963
3829
|
(items || []).map((s) => {
|
|
4964
|
-
return /* @__PURE__ */ (0,
|
|
3830
|
+
return /* @__PURE__ */ (0, import_jsx_runtime16.jsx)(SceneCard, { s }, s.path);
|
|
4965
3831
|
})
|
|
4966
3832
|
] });
|
|
4967
3833
|
}
|
|
4968
3834
|
|
|
4969
3835
|
// client/src/panel.tsx
|
|
4970
|
-
var
|
|
3836
|
+
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
4971
3837
|
var TABS = [
|
|
4972
3838
|
["overview", "概览"],
|
|
4973
3839
|
["records", "记忆"],
|
|
4974
3840
|
["conflicts", "冲突"],
|
|
4975
3841
|
["scenes", "场景"],
|
|
4976
|
-
["rooms", "Hall"],
|
|
4977
|
-
["room", "Room"],
|
|
4978
3842
|
["persona", "画像"],
|
|
4979
3843
|
["cost", "成本"],
|
|
4980
3844
|
["log", "日志"]
|
|
4981
3845
|
];
|
|
4982
3846
|
function MemoryPanel(props) {
|
|
4983
3847
|
const rpc = props.rpc;
|
|
4984
|
-
const [tab, setTab] = (0,
|
|
3848
|
+
const [tab, setTab] = (0, import_react17.useState)("overview");
|
|
4985
3849
|
ensureThemeStyle();
|
|
4986
|
-
(0,
|
|
3850
|
+
(0, import_react17.useEffect)(() => {
|
|
4987
3851
|
watchSidebarIcon();
|
|
4988
3852
|
}, []);
|
|
4989
3853
|
let body;
|
|
4990
|
-
if (tab === "overview") body = /* @__PURE__ */ (0,
|
|
4991
|
-
else if (tab === "records") body = /* @__PURE__ */ (0,
|
|
4992
|
-
else if (tab === "conflicts") body = /* @__PURE__ */ (0,
|
|
4993
|
-
else if (tab === "scenes") body = /* @__PURE__ */ (0,
|
|
4994
|
-
else if (tab === "
|
|
4995
|
-
else if (tab === "
|
|
4996
|
-
else
|
|
4997
|
-
|
|
4998
|
-
|
|
4999
|
-
|
|
5000
|
-
/* @__PURE__ */ (0,
|
|
5001
|
-
|
|
5002
|
-
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: S.tabbar, children: TABS.map((t) => {
|
|
5003
|
-
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
3854
|
+
if (tab === "overview") body = /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(OverviewTab, { rpc });
|
|
3855
|
+
else if (tab === "records") body = /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(RecordsTab, { rpc });
|
|
3856
|
+
else if (tab === "conflicts") body = /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ConflictsTab, { rpc });
|
|
3857
|
+
else if (tab === "scenes") body = /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(ScenesTab, { rpc });
|
|
3858
|
+
else if (tab === "persona") body = /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(PersonaTab, { rpc });
|
|
3859
|
+
else if (tab === "cost") body = /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(CostTab, { rpc });
|
|
3860
|
+
else body = /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(LogTab, { rpc });
|
|
3861
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "dsh-mem-root", style: S.section, children: [
|
|
3862
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("h2", { style: S.heading, children: "记忆 (Memory)" }),
|
|
3863
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("p", { style: S.intro, children: "L0~L3 分层蒸馏记忆:浏览被记住的内容,控制记忆模式开关。" }),
|
|
3864
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { style: S.tabbar, children: TABS.map((t) => {
|
|
3865
|
+
return /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
5004
3866
|
"button",
|
|
5005
3867
|
{
|
|
5006
3868
|
className: tab === t[0] ? "dsh-mem-tab dsh-mem-tab-on" : "dsh-mem-tab",
|
|
@@ -5017,7 +3879,7 @@ var __defProp = Object.defineProperty;
|
|
|
5017
3879
|
}
|
|
5018
3880
|
|
|
5019
3881
|
// client/src/pill/MemoryModePill.tsx
|
|
5020
|
-
var
|
|
3882
|
+
var import_react20 = require("react");
|
|
5021
3883
|
|
|
5022
3884
|
// src/util/context-occupancy.ts
|
|
5023
3885
|
var CONTEXT_METER_CIRCUMFERENCE = 34.55751918948772;
|
|
@@ -5333,23 +4195,23 @@ var __defProp = Object.defineProperty;
|
|
|
5333
4195
|
}
|
|
5334
4196
|
|
|
5335
4197
|
// client/src/pill/WingWheel.tsx
|
|
5336
|
-
var
|
|
4198
|
+
var import_react19 = require("react");
|
|
5337
4199
|
|
|
5338
4200
|
// client/src/pill/SessionInfoArea.tsx
|
|
5339
|
-
var
|
|
5340
|
-
var
|
|
4201
|
+
var import_react18 = require("react");
|
|
4202
|
+
var import_jsx_runtime18 = require("react/jsx-runtime");
|
|
5341
4203
|
function sinfoCell(val, label, title) {
|
|
5342
|
-
return /* @__PURE__ */ (0,
|
|
5343
|
-
/* @__PURE__ */ (0,
|
|
5344
|
-
/* @__PURE__ */ (0,
|
|
4204
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { title: title || void 0, children: [
|
|
4205
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "dsh-mem-sinfo-val", children: val }),
|
|
4206
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "dsh-mem-sinfo-label", children: label })
|
|
5345
4207
|
] });
|
|
5346
4208
|
}
|
|
5347
4209
|
function SessionInfoArea(props) {
|
|
5348
4210
|
const rpc = props.rpc;
|
|
5349
4211
|
const sessionId = props.sessionId;
|
|
5350
|
-
const [stats, setStats] = (0,
|
|
5351
|
-
const busyRef = (0,
|
|
5352
|
-
(0,
|
|
4212
|
+
const [stats, setStats] = (0, import_react18.useState)(void 0);
|
|
4213
|
+
const busyRef = (0, import_react18.useRef)(false);
|
|
4214
|
+
(0, import_react18.useEffect)(() => {
|
|
5353
4215
|
if (!rpc || !sessionId) return void 0;
|
|
5354
4216
|
let alive = true;
|
|
5355
4217
|
let timer = null;
|
|
@@ -5382,7 +4244,7 @@ var __defProp = Object.defineProperty;
|
|
|
5382
4244
|
}, [rpc, sessionId]);
|
|
5383
4245
|
if (stats === null) return null;
|
|
5384
4246
|
if (stats === void 0) {
|
|
5385
|
-
return /* @__PURE__ */ (0,
|
|
4247
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "dsh-mem-sinfo", children: /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "dsh-mem-sinfo-grid", children: [
|
|
5386
4248
|
sinfoCell("…", "召回命中"),
|
|
5387
4249
|
sinfoCell("…", "攒批进度"),
|
|
5388
4250
|
sinfoCell("…", "本会话记忆"),
|
|
@@ -5431,21 +4293,21 @@ var __defProp = Object.defineProperty;
|
|
|
5431
4293
|
else if (stats.retrieval === "none") note = "检索不可用(FTS 与向量均失效)";
|
|
5432
4294
|
}
|
|
5433
4295
|
const ago = fmtAgo(gl.lastExtractAt);
|
|
5434
|
-
return /* @__PURE__ */ (0,
|
|
5435
|
-
warn ? /* @__PURE__ */ (0,
|
|
5436
|
-
/* @__PURE__ */ (0,
|
|
4296
|
+
return /* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "dsh-mem-sinfo", children: [
|
|
4297
|
+
warn ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "dsh-mem-sinfo-warn", children: warn }) : null,
|
|
4298
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsxs)("div", { className: "dsh-mem-sinfo-grid", children: [
|
|
5437
4299
|
sinfoCell(rcVal, rcLabel, rcTitle),
|
|
5438
4300
|
sinfoCell(dVal, dLabel, dTitle),
|
|
5439
4301
|
sinfoCell(String(di.producedRecords || 0), "本会话记忆", pTitle),
|
|
5440
4302
|
sinfoCell(stats.l0Count != null ? String(stats.l0Count) : "…", "会话消息")
|
|
5441
4303
|
] }),
|
|
5442
|
-
note ? /* @__PURE__ */ (0,
|
|
5443
|
-
/* @__PURE__ */ (0,
|
|
4304
|
+
note ? /* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "dsh-mem-sinfo-note", children: note }) : null,
|
|
4305
|
+
/* @__PURE__ */ (0, import_jsx_runtime18.jsx)("div", { className: "dsh-mem-sinfo-sum", children: "待蒸馏 " + (gl.pendingTotal || 0) + " · 上次蒸馏 " + (ago || "尚未蒸馏") })
|
|
5444
4306
|
] });
|
|
5445
4307
|
}
|
|
5446
4308
|
|
|
5447
4309
|
// client/src/pill/WingWheel.tsx
|
|
5448
|
-
var
|
|
4310
|
+
var import_jsx_runtime19 = require("react/jsx-runtime");
|
|
5449
4311
|
var SIZE = 196;
|
|
5450
4312
|
var CENTER = SIZE / 2;
|
|
5451
4313
|
var R = 64;
|
|
@@ -5488,17 +4350,17 @@ var __defProp = Object.defineProperty;
|
|
|
5488
4350
|
function WingWheel(props) {
|
|
5489
4351
|
ensureThemeStyle();
|
|
5490
4352
|
const isOff = props.mode === "off";
|
|
5491
|
-
const [overview, setOverview] = (0,
|
|
5492
|
-
const [backfillBusy, setBackfillBusy] = (0,
|
|
5493
|
-
const [localError, setLocalError] = (0,
|
|
5494
|
-
const timersRef = (0,
|
|
5495
|
-
(0,
|
|
4353
|
+
const [overview, setOverview] = (0, import_react19.useState)(null);
|
|
4354
|
+
const [backfillBusy, setBackfillBusy] = (0, import_react19.useState)(false);
|
|
4355
|
+
const [localError, setLocalError] = (0, import_react19.useState)(null);
|
|
4356
|
+
const timersRef = (0, import_react19.useRef)([]);
|
|
4357
|
+
(0, import_react19.useEffect)(
|
|
5496
4358
|
() => () => {
|
|
5497
4359
|
for (const t of timersRef.current) window.clearTimeout(t);
|
|
5498
4360
|
},
|
|
5499
4361
|
[]
|
|
5500
4362
|
);
|
|
5501
|
-
(0,
|
|
4363
|
+
(0, import_react19.useEffect)(() => {
|
|
5502
4364
|
let alive = true;
|
|
5503
4365
|
props.rpc("dsh-memory/wing-overview", {}).then((r) => {
|
|
5504
4366
|
if (!alive) return;
|
|
@@ -5544,28 +4406,28 @@ var __defProp = Object.defineProperty;
|
|
|
5544
4406
|
finish();
|
|
5545
4407
|
});
|
|
5546
4408
|
};
|
|
5547
|
-
const boxRef = (0,
|
|
5548
|
-
const startRef = (0,
|
|
5549
|
-
const movedRef = (0,
|
|
5550
|
-
const downIndexRef = (0,
|
|
5551
|
-
const dragTargetRef = (0,
|
|
5552
|
-
const [drag, setDrag] = (0,
|
|
4409
|
+
const boxRef = (0, import_react19.useRef)(null);
|
|
4410
|
+
const startRef = (0, import_react19.useRef)(null);
|
|
4411
|
+
const movedRef = (0, import_react19.useRef)(false);
|
|
4412
|
+
const downIndexRef = (0, import_react19.useRef)(null);
|
|
4413
|
+
const dragTargetRef = (0, import_react19.useRef)(null);
|
|
4414
|
+
const [drag, setDrag] = (0, import_react19.useState)(null);
|
|
5553
4415
|
const lockedIndex = (() => {
|
|
5554
4416
|
if (props.halls.length !== 1 || !overview) return null;
|
|
5555
4417
|
const i = overview.corners.findIndex((c) => c.id === props.halls[0]);
|
|
5556
4418
|
return i >= 0 ? i : null;
|
|
5557
4419
|
})();
|
|
5558
4420
|
const activeCorner = drag ? drag.index : lockedIndex;
|
|
5559
|
-
const blockPosRef = (0,
|
|
4421
|
+
const blockPosRef = (0, import_react19.useRef)(
|
|
5560
4422
|
activeCorner != null ? cornerXY(activeCorner) : { x: CENTER, y: CENTER }
|
|
5561
4423
|
);
|
|
5562
|
-
const blockTargetRef = (0,
|
|
5563
|
-
const [blockPos, setBlockPos] = (0,
|
|
5564
|
-
(0,
|
|
4424
|
+
const blockTargetRef = (0, import_react19.useRef)(blockPosRef.current);
|
|
4425
|
+
const [blockPos, setBlockPos] = (0, import_react19.useState)(blockPosRef.current);
|
|
4426
|
+
(0, import_react19.useEffect)(() => {
|
|
5565
4427
|
blockTargetRef.current = activeCorner != null ? cornerXY(activeCorner) : { x: CENTER, y: CENTER };
|
|
5566
4428
|
}, [activeCorner]);
|
|
5567
|
-
const reducedMotionRef = (0,
|
|
5568
|
-
(0,
|
|
4429
|
+
const reducedMotionRef = (0, import_react19.useRef)(false);
|
|
4430
|
+
(0, import_react19.useEffect)(() => {
|
|
5569
4431
|
const mq = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
5570
4432
|
const apply2 = () => {
|
|
5571
4433
|
reducedMotionRef.current = mq.matches;
|
|
@@ -5574,7 +4436,7 @@ var __defProp = Object.defineProperty;
|
|
|
5574
4436
|
mq.addEventListener("change", apply2);
|
|
5575
4437
|
return () => mq.removeEventListener("change", apply2);
|
|
5576
4438
|
}, []);
|
|
5577
|
-
(0,
|
|
4439
|
+
(0, import_react19.useEffect)(() => {
|
|
5578
4440
|
let raf = 0;
|
|
5579
4441
|
const loop = () => {
|
|
5580
4442
|
const cur = blockPosRef.current;
|
|
@@ -5663,8 +4525,8 @@ var __defProp = Object.defineProperty;
|
|
|
5663
4525
|
}).join(" ");
|
|
5664
4526
|
const grayStyle = isOff ? { opacity: 0.45, pointerEvents: "none" } : {};
|
|
5665
4527
|
const boundariesDisabled = props.halls.length === 0 || isOff;
|
|
5666
|
-
return /* @__PURE__ */ (0,
|
|
5667
|
-
/* @__PURE__ */ (0,
|
|
4528
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { width: SIZE }, children: [
|
|
4529
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
5668
4530
|
"div",
|
|
5669
4531
|
{
|
|
5670
4532
|
ref: boxRef,
|
|
@@ -5674,7 +4536,7 @@ var __defProp = Object.defineProperty;
|
|
|
5674
4536
|
onPointerUp: onBoxUp,
|
|
5675
4537
|
onPointerCancel: onBoxUp,
|
|
5676
4538
|
children: [
|
|
5677
|
-
/* @__PURE__ */ (0,
|
|
4539
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
5678
4540
|
"svg",
|
|
5679
4541
|
{
|
|
5680
4542
|
width: SIZE,
|
|
@@ -5682,7 +4544,7 @@ var __defProp = Object.defineProperty;
|
|
|
5682
4544
|
style: { position: "absolute", inset: 0, pointerEvents: "none" },
|
|
5683
4545
|
"aria-hidden": "true",
|
|
5684
4546
|
children: [
|
|
5685
|
-
/* @__PURE__ */ (0,
|
|
4547
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
5686
4548
|
"polygon",
|
|
5687
4549
|
{
|
|
5688
4550
|
points: polyPoints,
|
|
@@ -5693,7 +4555,7 @@ var __defProp = Object.defineProperty;
|
|
|
5693
4555
|
opacity: 0.45
|
|
5694
4556
|
}
|
|
5695
4557
|
),
|
|
5696
|
-
/* @__PURE__ */ (0,
|
|
4558
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
5697
4559
|
"polygon",
|
|
5698
4560
|
{
|
|
5699
4561
|
points: polyPoints,
|
|
@@ -5704,7 +4566,7 @@ var __defProp = Object.defineProperty;
|
|
|
5704
4566
|
),
|
|
5705
4567
|
[0, 1, 2, 3, 4, 5, 6, 7].map((i) => {
|
|
5706
4568
|
const p = cornerPos(i);
|
|
5707
|
-
return /* @__PURE__ */ (0,
|
|
4569
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
5708
4570
|
"line",
|
|
5709
4571
|
{
|
|
5710
4572
|
x1: CENTER,
|
|
@@ -5720,7 +4582,7 @@ var __defProp = Object.defineProperty;
|
|
|
5720
4582
|
]
|
|
5721
4583
|
}
|
|
5722
4584
|
),
|
|
5723
|
-
/* @__PURE__ */ (0,
|
|
4585
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
5724
4586
|
"div",
|
|
5725
4587
|
{
|
|
5726
4588
|
"aria-hidden": "true",
|
|
@@ -5739,7 +4601,7 @@ var __defProp = Object.defineProperty;
|
|
|
5739
4601
|
}
|
|
5740
4602
|
}
|
|
5741
4603
|
),
|
|
5742
|
-
/* @__PURE__ */ (0,
|
|
4604
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
5743
4605
|
"button",
|
|
5744
4606
|
{
|
|
5745
4607
|
type: "button",
|
|
@@ -5773,7 +4635,7 @@ var __defProp = Object.defineProperty;
|
|
|
5773
4635
|
const dim = activeCorner != null && !active;
|
|
5774
4636
|
const empty = count === 0;
|
|
5775
4637
|
const p = cornerPos(i);
|
|
5776
|
-
return /* @__PURE__ */ (0,
|
|
4638
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
5777
4639
|
"div",
|
|
5778
4640
|
{
|
|
5779
4641
|
title: id ? `「${label}」${count ?? 0} 条
|
|
@@ -5802,8 +4664,8 @@ var __defProp = Object.defineProperty;
|
|
|
5802
4664
|
zIndex: 2
|
|
5803
4665
|
},
|
|
5804
4666
|
children: [
|
|
5805
|
-
/* @__PURE__ */ (0,
|
|
5806
|
-
/* @__PURE__ */ (0,
|
|
4667
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { children: label }),
|
|
4668
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: { fontSize: 8, opacity: 0.75, fontVariantNumeric: "tabular-nums" }, children: count === null ? " " : empty ? "空角" : `${count} 条` })
|
|
5807
4669
|
]
|
|
5808
4670
|
},
|
|
5809
4671
|
id ?? i
|
|
@@ -5812,7 +4674,7 @@ var __defProp = Object.defineProperty;
|
|
|
5812
4674
|
]
|
|
5813
4675
|
}
|
|
5814
4676
|
),
|
|
5815
|
-
/* @__PURE__ */ (0,
|
|
4677
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
5816
4678
|
"div",
|
|
5817
4679
|
{
|
|
5818
4680
|
title: props.halls.length === 0 ? "选定某个角(单 Wing)后,这两项才生效" : "锁定 Wing 时两类无角记忆是否参与召回",
|
|
@@ -5826,9 +4688,9 @@ var __defProp = Object.defineProperty;
|
|
|
5826
4688
|
pointerEvents: boundariesDisabled ? "none" : void 0
|
|
5827
4689
|
},
|
|
5828
4690
|
children: [
|
|
5829
|
-
/* @__PURE__ */ (0,
|
|
5830
|
-
/* @__PURE__ */ (0,
|
|
5831
|
-
/* @__PURE__ */ (0,
|
|
4691
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: overview ? `另有 ${overview.unlabeled} 条未打标` : "未打标" }),
|
|
4692
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 6 }, children: [
|
|
4693
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
5832
4694
|
Segmented,
|
|
5833
4695
|
{
|
|
5834
4696
|
value: props.hallIncludeUnlabeled ? "in" : "ex",
|
|
@@ -5839,7 +4701,7 @@ var __defProp = Object.defineProperty;
|
|
|
5839
4701
|
onChange: (key) => props.onCommitWingBoundaries({ includeUnlabeled: key === "in" })
|
|
5840
4702
|
}
|
|
5841
4703
|
),
|
|
5842
|
-
/* @__PURE__ */ (0,
|
|
4704
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
5843
4705
|
Segmented,
|
|
5844
4706
|
{
|
|
5845
4707
|
value: props.hallIncludeGeneral ? "in" : "ex",
|
|
@@ -5854,7 +4716,7 @@ var __defProp = Object.defineProperty;
|
|
|
5854
4716
|
]
|
|
5855
4717
|
}
|
|
5856
4718
|
),
|
|
5857
|
-
/* @__PURE__ */ (0,
|
|
4719
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Row, { label: "会话", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
5858
4720
|
Segmented,
|
|
5859
4721
|
{
|
|
5860
4722
|
value: isOff ? "off" : "on",
|
|
@@ -5869,7 +4731,7 @@ var __defProp = Object.defineProperty;
|
|
|
5869
4731
|
onChange: (key) => props.onCommit(key === "off" ? "off" : "auto")
|
|
5870
4732
|
}
|
|
5871
4733
|
) }),
|
|
5872
|
-
props.recall !== void 0 && props.onCommitRecall ? /* @__PURE__ */ (0,
|
|
4734
|
+
props.recall !== void 0 && props.onCommitRecall ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(Row, { label: "注入", children: /* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
5873
4735
|
Segmented,
|
|
5874
4736
|
{
|
|
5875
4737
|
value: props.recall === null ? "follow" : props.recall ? "on" : "off",
|
|
@@ -5882,7 +4744,7 @@ var __defProp = Object.defineProperty;
|
|
|
5882
4744
|
onChange: (key) => props.onCommitRecall(key === "on" ? true : key === "off" ? false : null)
|
|
5883
4745
|
}
|
|
5884
4746
|
) }) : null,
|
|
5885
|
-
/* @__PURE__ */ (0,
|
|
4747
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
5886
4748
|
"div",
|
|
5887
4749
|
{
|
|
5888
4750
|
style: {
|
|
@@ -5893,8 +4755,8 @@ var __defProp = Object.defineProperty;
|
|
|
5893
4755
|
marginTop: 10
|
|
5894
4756
|
},
|
|
5895
4757
|
children: [
|
|
5896
|
-
/* @__PURE__ */ (0,
|
|
5897
|
-
/* @__PURE__ */ (0,
|
|
4758
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: { fontSize: 11, color: "var(--dsh-mem-text-3)" }, children: overview ? `未打标 ${overview.unlabeled} 条` : "未打标计数加载中" }),
|
|
4759
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(
|
|
5898
4760
|
ActionButton,
|
|
5899
4761
|
{
|
|
5900
4762
|
label: backfillBusy ? "回填中…" : "回填",
|
|
@@ -5906,12 +4768,12 @@ var __defProp = Object.defineProperty;
|
|
|
5906
4768
|
]
|
|
5907
4769
|
}
|
|
5908
4770
|
),
|
|
5909
|
-
props.error || localError ? /* @__PURE__ */ (0,
|
|
5910
|
-
/* @__PURE__ */ (0,
|
|
4771
|
+
props.error || localError ? /* @__PURE__ */ (0, import_jsx_runtime19.jsx)("div", { style: { fontSize: 11, color: "var(--dsh-mem-danger)", marginTop: 8 }, children: props.error || localError }) : null,
|
|
4772
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)(SessionInfoArea, { rpc: props.rpc, sessionId: props.sessionId })
|
|
5911
4773
|
] });
|
|
5912
4774
|
}
|
|
5913
4775
|
function Row(props) {
|
|
5914
|
-
return /* @__PURE__ */ (0,
|
|
4776
|
+
return /* @__PURE__ */ (0, import_jsx_runtime19.jsxs)(
|
|
5915
4777
|
"div",
|
|
5916
4778
|
{
|
|
5917
4779
|
style: {
|
|
@@ -5921,7 +4783,7 @@ var __defProp = Object.defineProperty;
|
|
|
5921
4783
|
marginTop: 10
|
|
5922
4784
|
},
|
|
5923
4785
|
children: [
|
|
5924
|
-
/* @__PURE__ */ (0,
|
|
4786
|
+
/* @__PURE__ */ (0, import_jsx_runtime19.jsx)("span", { style: { fontSize: 12, color: "var(--dsh-mem-text-3)" }, children: props.label }),
|
|
5925
4787
|
props.children
|
|
5926
4788
|
]
|
|
5927
4789
|
}
|
|
@@ -5929,9 +4791,9 @@ var __defProp = Object.defineProperty;
|
|
|
5929
4791
|
}
|
|
5930
4792
|
var LABEL_FALLBACK = ["工作", "人际", "学习", "创作娱乐", "居家", "健康", "财务", "出行"];
|
|
5931
4793
|
function useViewportClamp(popRef) {
|
|
5932
|
-
const shiftRef = (0,
|
|
5933
|
-
const [shiftX, setShiftX] = (0,
|
|
5934
|
-
(0,
|
|
4794
|
+
const shiftRef = (0, import_react19.useRef)(0);
|
|
4795
|
+
const [shiftX, setShiftX] = (0, import_react19.useState)(0);
|
|
4796
|
+
(0, import_react19.useEffect)(() => {
|
|
5935
4797
|
const clamp = () => {
|
|
5936
4798
|
const el = popRef.current;
|
|
5937
4799
|
if (!el) return;
|
|
@@ -5961,24 +4823,24 @@ var __defProp = Object.defineProperty;
|
|
|
5961
4823
|
}
|
|
5962
4824
|
|
|
5963
4825
|
// client/src/pill/MemoryModePill.tsx
|
|
5964
|
-
var
|
|
4826
|
+
var import_jsx_runtime20 = require("react/jsx-runtime");
|
|
5965
4827
|
function MemoryModePill(props) {
|
|
5966
4828
|
const rpc = props.rpc;
|
|
5967
4829
|
const sessionId = props.sessionId || props.session && props.session.sessionId;
|
|
5968
|
-
const [mode, setMode] = (0,
|
|
5969
|
-
const [recall, setRecall] = (0,
|
|
5970
|
-
const [recallResolved, setRecallResolved] = (0,
|
|
5971
|
-
const [halls, setWings] = (0,
|
|
5972
|
-
const [hallIncludeUnlabeled, setWingIncludeUnlabeled] = (0,
|
|
5973
|
-
const [hallIncludeGeneral, setWingIncludeGeneral] = (0,
|
|
5974
|
-
const [wingLabels, setHallLabels] = (0,
|
|
5975
|
-
const [error, setError] = (0,
|
|
5976
|
-
const [open, setOpen] = (0,
|
|
5977
|
-
const wrapRef = (0,
|
|
5978
|
-
const popRef = (0,
|
|
4830
|
+
const [mode, setMode] = (0, import_react20.useState)(null);
|
|
4831
|
+
const [recall, setRecall] = (0, import_react20.useState)(null);
|
|
4832
|
+
const [recallResolved, setRecallResolved] = (0, import_react20.useState)(true);
|
|
4833
|
+
const [halls, setWings] = (0, import_react20.useState)([]);
|
|
4834
|
+
const [hallIncludeUnlabeled, setWingIncludeUnlabeled] = (0, import_react20.useState)(true);
|
|
4835
|
+
const [hallIncludeGeneral, setWingIncludeGeneral] = (0, import_react20.useState)(false);
|
|
4836
|
+
const [wingLabels, setHallLabels] = (0, import_react20.useState)({});
|
|
4837
|
+
const [error, setError] = (0, import_react20.useState)(null);
|
|
4838
|
+
const [open, setOpen] = (0, import_react20.useState)(false);
|
|
4839
|
+
const wrapRef = (0, import_react20.useRef)(null);
|
|
4840
|
+
const popRef = (0, import_react20.useRef)(null);
|
|
5979
4841
|
const shiftX = useViewportClamp(popRef);
|
|
5980
|
-
const seqRef = (0,
|
|
5981
|
-
const load = (0,
|
|
4842
|
+
const seqRef = (0, import_react20.useRef)(0);
|
|
4843
|
+
const load = (0, import_react20.useCallback)(() => {
|
|
5982
4844
|
if (!sessionId || !rpc) return;
|
|
5983
4845
|
const token = ++seqRef.current;
|
|
5984
4846
|
setError(null);
|
|
@@ -6003,13 +4865,13 @@ var __defProp = Object.defineProperty;
|
|
|
6003
4865
|
}).catch(() => {
|
|
6004
4866
|
});
|
|
6005
4867
|
}, [sessionId, rpc]);
|
|
6006
|
-
(0,
|
|
4868
|
+
(0, import_react20.useEffect)(() => {
|
|
6007
4869
|
load();
|
|
6008
4870
|
}, [load]);
|
|
6009
|
-
(0,
|
|
4871
|
+
(0, import_react20.useEffect)(() => {
|
|
6010
4872
|
watchSidebarIcon();
|
|
6011
4873
|
}, []);
|
|
6012
|
-
(0,
|
|
4874
|
+
(0, import_react20.useEffect)(() => {
|
|
6013
4875
|
initOccupancyIndicator(
|
|
6014
4876
|
(endpoint, payload) => rpc(endpoint, payload)
|
|
6015
4877
|
);
|
|
@@ -6017,7 +4879,7 @@ var __defProp = Object.defineProperty;
|
|
|
6017
4879
|
watchContextMeter();
|
|
6018
4880
|
noteOccupancySession(sessionId ?? null);
|
|
6019
4881
|
}, [sessionId, rpc]);
|
|
6020
|
-
(0,
|
|
4882
|
+
(0, import_react20.useEffect)(() => {
|
|
6021
4883
|
if (!open) return;
|
|
6022
4884
|
const onDown = (e) => {
|
|
6023
4885
|
if (wrapRef.current && !wrapRef.current.contains(e.target)) setOpen(false);
|
|
@@ -6157,8 +5019,8 @@ var __defProp = Object.defineProperty;
|
|
|
6157
5019
|
pillStyle.boxShadow = "0 0 12px color-mix(in srgb, " + info.color + " 30%, transparent)";
|
|
6158
5020
|
pillStyle["--dsh-mem-pill-tint"] = info.color;
|
|
6159
5021
|
}
|
|
6160
|
-
return /* @__PURE__ */ (0,
|
|
6161
|
-
/* @__PURE__ */ (0,
|
|
5022
|
+
return /* @__PURE__ */ (0, import_jsx_runtime20.jsxs)("div", { ref: wrapRef, style: { position: "relative", display: "inline-flex" }, children: [
|
|
5023
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsxs)(
|
|
6162
5024
|
"button",
|
|
6163
5025
|
{
|
|
6164
5026
|
type: "button",
|
|
@@ -6171,11 +5033,11 @@ var __defProp = Object.defineProperty;
|
|
|
6171
5033
|
style: pillStyle,
|
|
6172
5034
|
children: [
|
|
6173
5035
|
"记忆 · ",
|
|
6174
|
-
/* @__PURE__ */ (0,
|
|
5036
|
+
/* @__PURE__ */ (0, import_jsx_runtime20.jsx)("span", { children: faceLabel })
|
|
6175
5037
|
]
|
|
6176
5038
|
}
|
|
6177
5039
|
),
|
|
6178
|
-
open ? /* @__PURE__ */ (0,
|
|
5040
|
+
open ? /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
6179
5041
|
"div",
|
|
6180
5042
|
{
|
|
6181
5043
|
ref: popRef,
|
|
@@ -6186,12 +5048,12 @@ var __defProp = Object.defineProperty;
|
|
|
6186
5048
|
transform: "translateX(calc(-50% + " + shiftX + "px))",
|
|
6187
5049
|
zIndex: 1e3
|
|
6188
5050
|
},
|
|
6189
|
-
children: /* @__PURE__ */ (0,
|
|
5051
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
6190
5052
|
"div",
|
|
6191
5053
|
{
|
|
6192
5054
|
className: "dsh-mem-popover",
|
|
6193
5055
|
style: { position: "relative", padding: "10px 12px" },
|
|
6194
|
-
children: /* @__PURE__ */ (0,
|
|
5056
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime20.jsx)(
|
|
6195
5057
|
WingWheel,
|
|
6196
5058
|
{
|
|
6197
5059
|
mode: mode || "auto",
|