@memtensor/memos-local-openclaw-plugin 1.0.4-beta.0 → 1.0.4-beta.1
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/dist/client/connector.d.ts +4 -0
- package/dist/client/connector.d.ts.map +1 -1
- package/dist/client/connector.js +92 -0
- package/dist/client/connector.js.map +1 -1
- package/dist/config.js +9 -9
- package/dist/config.js.map +1 -1
- package/dist/hub/server.d.ts.map +1 -1
- package/dist/hub/server.js +27 -22
- package/dist/hub/server.js.map +1 -1
- package/dist/hub/user-manager.d.ts +1 -0
- package/dist/hub/user-manager.d.ts.map +1 -1
- package/dist/hub/user-manager.js +13 -0
- package/dist/hub/user-manager.js.map +1 -1
- package/dist/storage/sqlite.d.ts.map +1 -1
- package/dist/storage/sqlite.js +20 -94
- package/dist/storage/sqlite.js.map +1 -1
- package/dist/viewer/html.d.ts.map +1 -1
- package/dist/viewer/html.js +386 -207
- package/dist/viewer/html.js.map +1 -1
- package/dist/viewer/server.d.ts +2 -0
- package/dist/viewer/server.d.ts.map +1 -1
- package/dist/viewer/server.js +104 -15
- package/dist/viewer/server.js.map +1 -1
- package/package.json +1 -1
- package/src/client/connector.ts +94 -0
- package/src/config.ts +9 -9
- package/src/hub/server.ts +28 -22
- package/src/hub/user-manager.ts +13 -0
- package/src/storage/sqlite.ts +20 -94
- package/src/viewer/html.ts +386 -207
- package/src/viewer/server.ts +98 -15
package/dist/viewer/html.js
CHANGED
|
@@ -8,7 +8,8 @@ function viewerHTML(pluginVersion) {
|
|
|
8
8
|
<head>
|
|
9
9
|
<meta charset="UTF-8">
|
|
10
10
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
11
|
-
<
|
|
11
|
+
<link rel="icon" href="https://statics.memtensor.com.cn/logo/color-m.svg" type="image/svg+xml">
|
|
12
|
+
<title>MemOS 记忆</title>
|
|
12
13
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
13
14
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
14
15
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
@@ -61,8 +62,9 @@ function viewerHTML(pluginVersion) {
|
|
|
61
62
|
[data-theme="light"] .analytics-card.amber .ac-value{color:#d97706}
|
|
62
63
|
[data-theme="light"] .analytics-section{background:#fff;border-color:var(--border);box-shadow:0 1px 3px rgba(0,0,0,.04)}
|
|
63
64
|
[data-theme="light"] .analytics-section::before{background:none}
|
|
64
|
-
[data-theme="light"] .chart-bar{box-shadow:
|
|
65
|
-
[data-theme="light"] .chart-bar:hover{box-shadow:0
|
|
65
|
+
[data-theme="light"] .chart-bar{box-shadow:0 1px 4px rgba(99,102,241,.12)}
|
|
66
|
+
[data-theme="light"] .chart-bar:hover{box-shadow:0 3px 12px rgba(79,70,229,.2)}
|
|
67
|
+
[data-theme="light"] .chart-bars::before{opacity:.3}
|
|
66
68
|
[data-theme="light"] .tool-chart-tooltip{background:rgba(17,24,39,.92);color:#e8eaed;border-color:rgba(99,102,241,.3);box-shadow:0 8px 24px rgba(0,0,0,.2)}
|
|
67
69
|
[data-theme="light"] .tool-chart-tooltip .tt-time{color:#a5b4fc}
|
|
68
70
|
[data-theme="light"] .tool-chart-tooltip .tt-val{color:#e8eaed}
|
|
@@ -108,9 +110,15 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
108
110
|
/* ─── App Layout (dark dashboard, same as www) ─── */
|
|
109
111
|
.app{display:none;flex-direction:column;min-height:100vh}
|
|
110
112
|
.topbar{background:rgba(11,13,17,.88);border-bottom:1px solid var(--border);padding:0 28px;height:56px;display:flex;align-items:center;position:sticky;top:0;z-index:100;backdrop-filter:blur(12px)}
|
|
111
|
-
.topbar .brand{display:flex;align-items:center;gap:
|
|
112
|
-
.topbar .brand .icon{width:
|
|
113
|
+
.topbar .brand{display:flex;align-items:center;gap:8px;font-weight:700;font-size:15px;color:var(--text);letter-spacing:-.02em;flex-shrink:0}
|
|
114
|
+
.topbar .brand .icon{width:24px;height:24px;display:flex;align-items:center;justify-content:center;font-size:18px;background:none;border-radius:0}
|
|
115
|
+
.topbar .brand .brand-title{font-size:13px;font-weight:500;opacity:.7}
|
|
116
|
+
.topbar .brand .brand-col{display:flex;flex-direction:column;gap:0}
|
|
117
|
+
.topbar .brand .brand-powered{font-size:9px;font-weight:500;color:var(--text-sec);opacity:.55;letter-spacing:.02em;line-height:1}
|
|
113
118
|
.topbar .brand .sub{font-weight:400;color:var(--text-muted);font-size:11px}
|
|
119
|
+
.memos-logo{display:inline-flex;align-items:center}
|
|
120
|
+
.memos-logo svg{height:28px;width:28px}
|
|
121
|
+
.brand-sep{width:1px;height:20px;background:var(--border);opacity:.5;margin:0 2px}
|
|
114
122
|
.version-badge{font-size:10px;font-weight:600;color:var(--text-muted);background:rgba(255,255,255,.08);border:1px solid rgba(255,255,255,.1);padding:1px 7px;border-radius:6px;margin-left:6px;letter-spacing:.02em;user-select:all}
|
|
115
123
|
[data-theme="light"] .version-badge{background:rgba(0,0,0,.05);border-color:rgba(0,0,0,.08);color:var(--text-sec)}
|
|
116
124
|
.topbar-center{flex:1;display:flex;justify-content:center}
|
|
@@ -289,20 +297,67 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
289
297
|
.memory-card.dedup-inactive{opacity:.55;border-style:dashed}
|
|
290
298
|
.memory-card.dedup-inactive:hover{opacity:.85}
|
|
291
299
|
.dedup-target-link{font-size:11px;color:var(--pri);cursor:pointer;text-decoration:underline;margin-left:4px}
|
|
292
|
-
.memory-modal-overlay{position:fixed;inset:0;background:rgba(
|
|
300
|
+
.memory-modal-overlay{position:fixed;inset:0;background:rgba(5,8,16,.75);z-index:9999;display:none;align-items:center;justify-content:center;backdrop-filter:blur(12px) saturate(1.2)}
|
|
293
301
|
.memory-modal-overlay.show{display:flex}
|
|
294
|
-
.memory-modal{background:
|
|
295
|
-
|
|
296
|
-
.memory-modal
|
|
297
|
-
|
|
298
|
-
.
|
|
299
|
-
|
|
300
|
-
.modal
|
|
301
|
-
.modal
|
|
302
|
-
.modal-
|
|
303
|
-
.modal-
|
|
304
|
-
|
|
305
|
-
.modal-
|
|
302
|
+
[data-theme="light"] .memory-modal-overlay{background:rgba(0,0,0,.45)}
|
|
303
|
+
.memory-modal{position:relative;background:linear-gradient(160deg,#0d1117 0%,#161b22 50%,#0d1117 100%);border:1px solid rgba(99,102,241,.2);border-radius:20px;width:min(600px,92vw);max-height:82vh;display:flex;flex-direction:column;box-shadow:0 32px 100px rgba(0,0,0,.6),0 0 60px rgba(99,102,241,.08),inset 0 1px 0 rgba(255,255,255,.06);animation:mmSlideIn .35s cubic-bezier(.22,1,.36,1);overflow:hidden}
|
|
304
|
+
[data-theme="light"] .memory-modal{background:linear-gradient(160deg,#ffffff 0%,#f8f9fc 50%,#ffffff 100%);border-color:rgba(99,102,241,.15);box-shadow:0 32px 100px rgba(0,0,0,.12),0 0 40px rgba(99,102,241,.06)}
|
|
305
|
+
@keyframes mmSlideIn{from{opacity:0;transform:scale(.92) translateY(20px)}to{opacity:1;transform:scale(1) translateY(0)}}
|
|
306
|
+
.memory-modal::before{content:'';position:absolute;top:0;left:0;right:0;height:3px;background:linear-gradient(90deg,#6366f1,#8b5cf6,#ec4899,#f43f5e,#6366f1);background-size:200% 100%;animation:mmGradientMove 3s linear infinite;border-radius:20px 20px 0 0;z-index:1}
|
|
307
|
+
@keyframes mmGradientMove{0%{background-position:0% 50%}100%{background-position:200% 50%}}
|
|
308
|
+
.memory-modal::after{content:'';position:absolute;inset:0;background:radial-gradient(ellipse at 20% 0%,rgba(99,102,241,.06) 0%,transparent 60%),radial-gradient(ellipse at 80% 100%,rgba(236,72,153,.04) 0%,transparent 60%);pointer-events:none;border-radius:20px}
|
|
309
|
+
[data-theme="light"] .memory-modal::after{background:radial-gradient(ellipse at 20% 0%,rgba(99,102,241,.04) 0%,transparent 60%),radial-gradient(ellipse at 80% 100%,rgba(236,72,153,.03) 0%,transparent 60%)}
|
|
310
|
+
.memory-modal-title{position:relative;z-index:2;display:flex;align-items:center;justify-content:space-between;padding:18px 24px 14px;font-size:12px;font-weight:700;color:var(--text-sec);letter-spacing:.06em;text-transform:uppercase}
|
|
311
|
+
.memory-modal-title .mm-tl{display:flex;align-items:center;gap:8px}
|
|
312
|
+
.memory-modal-title .mm-tl-icon{width:28px;height:28px;border-radius:8px;background:linear-gradient(135deg,rgba(99,102,241,.15),rgba(139,92,246,.1));display:flex;align-items:center;justify-content:center;font-size:14px;border:1px solid rgba(99,102,241,.2)}
|
|
313
|
+
[data-theme="light"] .memory-modal-title .mm-tl-icon{background:linear-gradient(135deg,rgba(99,102,241,.1),rgba(139,92,246,.06));border-color:rgba(99,102,241,.12)}
|
|
314
|
+
.memory-modal-title .mm-close{width:30px;height:30px;display:flex;align-items:center;justify-content:center;border-radius:10px;border:1px solid rgba(255,255,255,.06);background:rgba(255,255,255,.04);color:var(--text-sec);cursor:pointer;font-size:16px;transition:all .2s}
|
|
315
|
+
.memory-modal-title .mm-close:hover{background:rgba(255,77,77,.12);border-color:rgba(255,77,77,.2);color:#f87171;transform:rotate(90deg)}
|
|
316
|
+
[data-theme="light"] .memory-modal-title .mm-close{border-color:rgba(0,0,0,.06);background:rgba(0,0,0,.03)}
|
|
317
|
+
[data-theme="light"] .memory-modal-title .mm-close:hover{background:rgba(255,77,77,.08);border-color:rgba(255,77,77,.15)}
|
|
318
|
+
.memory-modal-body{position:relative;z-index:2;padding:0;overflow-y:auto;flex:1}
|
|
319
|
+
.mm-hero{padding:0 24px 20px}
|
|
320
|
+
.mm-hero-row{display:flex;align-items:center;gap:8px;flex-wrap:wrap;margin-bottom:14px}
|
|
321
|
+
.mm-role-chip{display:inline-flex;align-items:center;gap:5px;font-size:10px;font-weight:700;letter-spacing:.05em;text-transform:uppercase;padding:4px 12px;border-radius:20px;background:linear-gradient(135deg,rgba(99,102,241,.15),rgba(139,92,246,.1));color:#a5b4fc;border:1px solid rgba(99,102,241,.2)}
|
|
322
|
+
.mm-role-chip.user{background:linear-gradient(135deg,rgba(16,185,129,.15),rgba(52,211,153,.1));color:#6ee7b7;border-color:rgba(16,185,129,.2)}
|
|
323
|
+
.mm-role-chip.assistant{background:linear-gradient(135deg,rgba(99,102,241,.15),rgba(139,92,246,.1));color:#a5b4fc;border-color:rgba(99,102,241,.2)}
|
|
324
|
+
.mm-role-chip.system{background:linear-gradient(135deg,rgba(251,191,36,.15),rgba(245,158,11,.1));color:#fcd34d;border-color:rgba(251,191,36,.2)}
|
|
325
|
+
[data-theme="light"] .mm-role-chip{color:#6366f1}
|
|
326
|
+
[data-theme="light"] .mm-role-chip.user{color:#059669}
|
|
327
|
+
[data-theme="light"] .mm-role-chip.assistant{color:#6366f1}
|
|
328
|
+
[data-theme="light"] .mm-role-chip.system{color:#d97706}
|
|
329
|
+
.mm-dedup-chip{display:inline-flex;align-items:center;gap:4px;font-size:10px;font-weight:600;padding:3px 10px;border-radius:20px;text-transform:uppercase;letter-spacing:.04em}
|
|
330
|
+
.mm-dedup-chip.duplicate{background:rgba(239,68,68,.12);color:#fca5a5;border:1px solid rgba(239,68,68,.2)}
|
|
331
|
+
.mm-dedup-chip.merged{background:rgba(251,191,36,.12);color:#fcd34d;border:1px solid rgba(251,191,36,.2)}
|
|
332
|
+
[data-theme="light"] .mm-dedup-chip.duplicate{color:#dc2626}
|
|
333
|
+
[data-theme="light"] .mm-dedup-chip.merged{color:#d97706}
|
|
334
|
+
.mm-id{font-family:'SF Mono',Consolas,'Courier New',monospace;font-size:10px;color:var(--text-muted);background:rgba(255,255,255,.04);border:1px solid rgba(255,255,255,.06);padding:3px 10px;border-radius:20px;cursor:pointer;transition:all .2s;display:inline-flex;align-items:center;gap:4px}
|
|
335
|
+
.mm-id::before{content:'\u{1F517}';font-size:9px}
|
|
336
|
+
.mm-id:hover{background:rgba(99,102,241,.12);border-color:rgba(99,102,241,.25);color:var(--text)}
|
|
337
|
+
[data-theme="light"] .mm-id{background:rgba(0,0,0,.03);border-color:rgba(0,0,0,.06)}
|
|
338
|
+
[data-theme="light"] .mm-id:hover{background:rgba(99,102,241,.08);border-color:rgba(99,102,241,.15)}
|
|
339
|
+
.mm-summary{font-size:15px;font-weight:600;color:var(--text);line-height:1.6;letter-spacing:-.01em;padding:16px 20px;background:rgba(255,255,255,.02);border-radius:12px;border:1px solid rgba(255,255,255,.04);position:relative}
|
|
340
|
+
.mm-summary::before{content:'';position:absolute;left:0;top:12px;bottom:12px;width:3px;border-radius:2px;background:linear-gradient(180deg,#6366f1,#8b5cf6)}
|
|
341
|
+
[data-theme="light"] .mm-summary{background:rgba(99,102,241,.02);border-color:rgba(99,102,241,.06)}
|
|
342
|
+
.mm-section{padding:0 24px 16px}
|
|
343
|
+
.mm-section-label{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.08em;color:var(--text-muted);margin-bottom:8px;display:flex;align-items:center;gap:6px}
|
|
344
|
+
.mm-section-label::before{content:'';width:6px;height:6px;border-radius:50%;background:linear-gradient(135deg,#6366f1,#8b5cf6);flex-shrink:0}
|
|
345
|
+
.mm-content{font-family:'SF Mono',Consolas,'Courier New',monospace;font-size:12px;line-height:1.75;color:var(--text);white-space:pre-wrap;word-break:break-all;background:rgba(0,0,0,.3);border-radius:12px;padding:16px 18px;max-height:240px;overflow-y:auto;margin:0;border:1px solid rgba(255,255,255,.04);position:relative}
|
|
346
|
+
[data-theme="light"] .mm-content{background:rgba(0,0,0,.03);border-color:rgba(0,0,0,.06)}
|
|
347
|
+
.mm-meta{display:grid;grid-template-columns:repeat(auto-fill,minmax(160px,1fr));gap:8px;padding:16px 24px;border-top:1px solid rgba(255,255,255,.04);background:rgba(0,0,0,.1)}
|
|
348
|
+
[data-theme="light"] .mm-meta{border-top-color:rgba(0,0,0,.04);background:rgba(0,0,0,.015)}
|
|
349
|
+
.mm-meta-chip{display:flex;flex-direction:column;gap:3px;font-size:11px;color:var(--text-sec);background:rgba(255,255,255,.03);border:1px solid rgba(255,255,255,.04);padding:10px 12px;border-radius:10px;transition:all .2s}
|
|
350
|
+
.mm-meta-chip:hover{background:rgba(255,255,255,.06);border-color:rgba(99,102,241,.15)}
|
|
351
|
+
[data-theme="light"] .mm-meta-chip{background:rgba(0,0,0,.02);border-color:rgba(0,0,0,.04)}
|
|
352
|
+
[data-theme="light"] .mm-meta-chip:hover{background:rgba(99,102,241,.04);border-color:rgba(99,102,241,.1)}
|
|
353
|
+
.mm-meta-chip strong{color:var(--text-muted);font-weight:600;font-size:9px;text-transform:uppercase;letter-spacing:.06em}
|
|
354
|
+
.mm-meta-chip span{color:var(--text);font-weight:500;font-size:12px;word-break:break-all}
|
|
355
|
+
.mm-dedup{padding:0 24px 16px}
|
|
356
|
+
.mm-dedup-box{background:linear-gradient(135deg,rgba(251,191,36,.06),rgba(245,158,11,.03));border:1px solid rgba(251,191,36,.12);border-radius:12px;padding:14px 16px;font-size:12px;color:var(--text-sec);line-height:1.6;display:flex;align-items:flex-start;gap:8px}
|
|
357
|
+
.mm-dedup-box::before{content:'\u26A0\uFE0F';flex-shrink:0;font-size:14px}
|
|
358
|
+
.mm-footer{padding:12px 24px 16px;display:flex;align-items:center;justify-content:center}
|
|
359
|
+
.mm-footer .dedup-target-link{font-size:11px;color:#818cf8;cursor:pointer;padding:6px 16px;border-radius:8px;border:1px solid rgba(99,102,241,.2);background:rgba(99,102,241,.06);transition:all .2s;font-weight:500}
|
|
360
|
+
.mm-footer .dedup-target-link:hover{background:rgba(99,102,241,.12);border-color:rgba(99,102,241,.3)}
|
|
306
361
|
[data-theme="light"] .merge-history{background:rgba(0,0,0,.04)}
|
|
307
362
|
[data-theme="light"] .merge-history-item{border-bottom-color:rgba(0,0,0,.06)}
|
|
308
363
|
.card-merged-info{margin-top:8px;padding:8px 12px;background:rgba(16,185,129,.06);border:1px dashed rgba(16,185,129,.2);border-radius:8px;font-size:12px;line-height:1.6;color:var(--text-sec)}
|
|
@@ -742,8 +797,8 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
742
797
|
.test-result.ok{color:#22c55e}
|
|
743
798
|
.test-result.fail{color:var(--rose)}
|
|
744
799
|
.test-result.loading{color:var(--text-muted)}
|
|
745
|
-
.settings-actions{display:flex;gap:12px;justify-content:flex-end;align-items:center;margin-top:
|
|
746
|
-
.settings-actions .btn{min-width:
|
|
800
|
+
.settings-actions{display:flex;gap:12px;justify-content:flex-end;align-items:center;margin-top:20px;padding-top:16px;border-top:1px solid var(--border);flex-wrap:nowrap}
|
|
801
|
+
.settings-actions .btn{flex:0 0 auto;min-width:0;padding:8px 24px;font-size:13px}
|
|
747
802
|
.settings-actions .btn-primary{background:rgba(99,102,241,.08);color:var(--pri);border:1px solid rgba(99,102,241,.25);font-weight:600}
|
|
748
803
|
.settings-actions .btn-primary:hover{background:rgba(99,102,241,.14);border-color:var(--pri)}
|
|
749
804
|
[data-theme="light"] .settings-actions .btn-primary{background:rgba(79,70,229,.06);color:#4f46e5;border:1px solid rgba(79,70,229,.2)}
|
|
@@ -809,18 +864,20 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
809
864
|
.analytics-section::before{display:none}
|
|
810
865
|
.analytics-section h3{font-size:11px;font-weight:600;color:var(--text-muted);text-transform:uppercase;letter-spacing:.08em;margin-bottom:16px;display:flex;align-items:center;gap:8px}
|
|
811
866
|
.analytics-section h3 .icon{font-size:14px;opacity:.6}
|
|
812
|
-
.chart-bars{display:flex;align-items:flex-end;gap:
|
|
813
|
-
.chart-
|
|
814
|
-
.chart-bar-
|
|
815
|
-
.chart-bar-
|
|
867
|
+
.chart-bars{display:flex;align-items:flex-end;gap:1px;padding:12px 4px 4px;min-height:200px;position:relative;width:100%}
|
|
868
|
+
.chart-bars::before{content:'';position:absolute;left:0;right:0;bottom:24px;height:1px;background:var(--border);opacity:.4}
|
|
869
|
+
.chart-bar-wrap{flex:1 1 0;min-width:0;max-width:32px;display:flex;flex-direction:column;align-items:center;gap:4px;position:relative;cursor:pointer}
|
|
870
|
+
.chart-bar-col{width:100%;height:160px;display:flex;flex-direction:column;justify-content:flex-end;align-items:center}
|
|
871
|
+
.chart-bar-wrap:hover .chart-bar{opacity:1;filter:brightness(1.2);transform:scaleY(1.02);transform-origin:bottom}
|
|
816
872
|
.chart-bar-wrap:hover .chart-bar-label{color:var(--text)}
|
|
817
873
|
.chart-bar-wrap:hover .chart-tip{opacity:1;transform:translateX(-50%) translateY(0)}
|
|
818
|
-
.chart-tip{position:absolute;top:-
|
|
819
|
-
.chart-
|
|
820
|
-
.chart-bar
|
|
821
|
-
.chart-bar.
|
|
822
|
-
.chart-bar.
|
|
823
|
-
.chart-bar
|
|
874
|
+
.chart-tip{position:absolute;top:-8px;left:50%;transform:translateX(-50%) translateY(6px);background:rgba(15,18,25,.95);border:1px solid rgba(99,102,241,.3);color:#e8eaed;padding:3px 10px;border-radius:8px;font-size:10px;font-weight:600;white-space:nowrap;z-index:5;pointer-events:none;box-shadow:0 4px 16px rgba(0,0,0,.3);opacity:0;transition:all .2s cubic-bezier(.22,1,.36,1)}
|
|
875
|
+
[data-theme="light"] .chart-tip{background:rgba(17,24,39,.9)}
|
|
876
|
+
.chart-bar{width:100%;max-width:20px;min-width:4px;border-radius:3px 3px 1px 1px;background:linear-gradient(180deg,#818cf8 0%,#6366f1 100%);opacity:.85;transition:all .25s cubic-bezier(.22,1,.36,1);box-shadow:0 1px 4px rgba(99,102,241,.12)}
|
|
877
|
+
.chart-bar.violet{background:linear-gradient(180deg,#8b5cf6 0%,#6366f1 100%)}
|
|
878
|
+
.chart-bar.green{background:linear-gradient(180deg,#34d399 0%,#10b981 100%);box-shadow:0 1px 4px rgba(16,185,129,.12)}
|
|
879
|
+
.chart-bar.zero{width:100%;max-width:20px;min-width:4px;height:2px!important;background:var(--border);opacity:.25;border-radius:1px;box-shadow:none}
|
|
880
|
+
.chart-bar-label{font-size:8px;color:var(--text-muted);white-space:nowrap;overflow:hidden;text-overflow:ellipsis;max-width:40px;text-align:center;transition:color .15s;letter-spacing:0}
|
|
824
881
|
.chart-legend{display:flex;gap:14px;margin-top:12px;flex-wrap:wrap;font-size:11px;color:var(--text-sec);font-weight:500}
|
|
825
882
|
.chart-legend span{display:inline-flex;align-items:center;gap:5px}
|
|
826
883
|
.chart-legend .dot{width:8px;height:8px;border-radius:2px}
|
|
@@ -874,7 +931,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
874
931
|
[data-theme="light"] .auth-theme-toggle .theme-icon-dark{display:none}
|
|
875
932
|
|
|
876
933
|
@media(max-width:1100px){.analytics-cards{grid-template-columns:repeat(3,1fr)}}
|
|
877
|
-
@media(max-width:900px){.main-content{flex-direction:column;padding:20px}.sidebar{width:100%}.sidebar .stats-grid{grid-template-columns:repeat(4,1fr)}.analytics-cards{grid-template-columns:repeat(2,1fr)}.topbar{padding:0 16px;gap:8px}.topbar .brand
|
|
934
|
+
@media(max-width:900px){.main-content{flex-direction:column;padding:20px}.sidebar{width:100%}.sidebar .stats-grid{grid-template-columns:repeat(4,1fr)}.analytics-cards{grid-template-columns:repeat(2,1fr)}.topbar{padding:0 16px;gap:8px}.topbar .brand .brand-title{display:none}.topbar .brand .brand-powered{display:none}.topbar-center{justify-content:flex-start}}
|
|
878
935
|
</style>
|
|
879
936
|
</head>
|
|
880
937
|
<body>
|
|
@@ -886,7 +943,9 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
886
943
|
<button class="auth-theme-toggle" onclick="toggleLang()" aria-label="Switch language"><span data-i18n="lang.switch">EN</span></button>
|
|
887
944
|
</div>
|
|
888
945
|
<div class="auth-card">
|
|
889
|
-
<div class="logo"
|
|
946
|
+
<div class="logo" style="display:flex;flex-direction:column;align-items:center;gap:10px">
|
|
947
|
+
<svg width="56" height="56" viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient id="aLG" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" stop-color="#ff4d4d"/><stop offset="100%" stop-color="#991b1b"/></linearGradient></defs><path d="M60 10C30 10 15 35 15 55C15 75 30 95 45 100L45 110L55 110L55 100C55 100 60 102 65 100L65 110L75 110L75 100C90 95 105 75 105 55C105 35 90 10 60 10Z" fill="url(#aLG)"/><path d="M20 45C5 40 0 50 5 60C10 70 20 65 25 55C28 48 25 45 20 45Z" fill="url(#aLG)"/><path d="M100 45C115 40 120 50 115 60C110 70 100 65 95 55C92 48 95 45 100 45Z" fill="url(#aLG)"/><path d="M45 15Q35 5 30 8" stroke="#ff4d4d" stroke-width="2" stroke-linecap="round"/><path d="M75 15Q85 5 90 8" stroke="#ff4d4d" stroke-width="2" stroke-linecap="round"/><circle cx="45" cy="35" r="6" fill="#050810"/><circle cx="75" cy="35" r="6" fill="#050810"/><circle cx="46" cy="34" r="2" fill="#00e5cc"/><circle cx="76" cy="34" r="2" fill="#00e5cc"/></svg>
|
|
948
|
+
</div>
|
|
890
949
|
<h1 data-i18n="title">OpenClaw Memory</h1>
|
|
891
950
|
<p style="font-size:12px;color:var(--text-sec);margin-bottom:6px" data-i18n="subtitle">Powered by MemOS</p>
|
|
892
951
|
<p data-i18n="setup.desc">Set a password to protect your memories</p>
|
|
@@ -904,7 +963,9 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
904
963
|
<button class="auth-theme-toggle" onclick="toggleLang()" aria-label="Switch language"><span data-i18n="lang.switch">EN</span></button>
|
|
905
964
|
</div>
|
|
906
965
|
<div class="auth-card">
|
|
907
|
-
<div class="logo"
|
|
966
|
+
<div class="logo" style="display:flex;flex-direction:column;align-items:center;gap:10px">
|
|
967
|
+
<svg width="56" height="56" viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient id="bLG" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" stop-color="#ff4d4d"/><stop offset="100%" stop-color="#991b1b"/></linearGradient></defs><path d="M60 10C30 10 15 35 15 55C15 75 30 95 45 100L45 110L55 110L55 100C55 100 60 102 65 100L65 110L75 110L75 100C90 95 105 75 105 55C105 35 90 10 60 10Z" fill="url(#bLG)"/><path d="M20 45C5 40 0 50 5 60C10 70 20 65 25 55C28 48 25 45 20 45Z" fill="url(#bLG)"/><path d="M100 45C115 40 120 50 115 60C110 70 100 65 95 55C92 48 95 45 100 45Z" fill="url(#bLG)"/><path d="M45 15Q35 5 30 8" stroke="#ff4d4d" stroke-width="2" stroke-linecap="round"/><path d="M75 15Q85 5 90 8" stroke="#ff4d4d" stroke-width="2" stroke-linecap="round"/><circle cx="45" cy="35" r="6" fill="#050810"/><circle cx="75" cy="35" r="6" fill="#050810"/><circle cx="46" cy="34" r="2" fill="#00e5cc"/><circle cx="76" cy="34" r="2" fill="#00e5cc"/></svg>
|
|
968
|
+
</div>
|
|
908
969
|
<h1 data-i18n="title">OpenClaw Memory</h1>
|
|
909
970
|
<p style="font-size:12px;color:var(--text-sec);margin-bottom:6px" data-i18n="subtitle">Powered by MemOS</p>
|
|
910
971
|
<p data-i18n="login.desc">Enter your password to access memories</p>
|
|
@@ -956,8 +1017,8 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
956
1017
|
<div class="app" id="app">
|
|
957
1018
|
<div class="topbar">
|
|
958
1019
|
<div class="brand">
|
|
959
|
-
<
|
|
960
|
-
<span data-i18n="title">
|
|
1020
|
+
<span class="memos-logo"><svg width="28" height="28" viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient id="topLG" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" stop-color="#ff4d4d"/><stop offset="100%" stop-color="#991b1b"/></linearGradient></defs><path d="M60 10C30 10 15 35 15 55C15 75 30 95 45 100L45 110L55 110L55 100C55 100 60 102 65 100L65 110L75 110L75 100C90 95 105 75 105 55C105 35 90 10 60 10Z" fill="url(#topLG)"/><path d="M20 45C5 40 0 50 5 60C10 70 20 65 25 55C28 48 25 45 20 45Z" fill="url(#topLG)"/><path d="M100 45C115 40 120 50 115 60C110 70 100 65 95 55C92 48 95 45 100 45Z" fill="url(#topLG)"/><path d="M45 15Q35 5 30 8" stroke="#ff4d4d" stroke-width="2" stroke-linecap="round"/><path d="M75 15Q85 5 90 8" stroke="#ff4d4d" stroke-width="2" stroke-linecap="round"/><circle cx="45" cy="35" r="6" fill="#050810"/><circle cx="75" cy="35" r="6" fill="#050810"/><circle cx="46" cy="34" r="2" fill="#00e5cc"/><circle cx="76" cy="34" r="2" fill="#00e5cc"/></svg></span>
|
|
1021
|
+
<div class="brand-col"><span data-i18n="title" class="brand-title">MemOS</span><span data-i18n="subtitle" class="brand-powered">Powered by MemOS</span></div>${vBadge}
|
|
961
1022
|
</div>
|
|
962
1023
|
<div class="topbar-center">
|
|
963
1024
|
<nav class="nav-tabs">
|
|
@@ -1009,9 +1070,8 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1009
1070
|
<option value="public" data-i18n="filter.public">Public</option>
|
|
1010
1071
|
</select>
|
|
1011
1072
|
<select id="memorySearchScope" class="filter-select" onchange="onMemoryScopeChange()">
|
|
1012
|
-
<option value="local">Local</option>
|
|
1013
|
-
<option value="
|
|
1014
|
-
<option value="all">All</option>
|
|
1073
|
+
<option value="local" data-i18n="scope.local">Local</option>
|
|
1074
|
+
<option value="all" data-i18n="scope.hub">Hub</option>
|
|
1015
1075
|
</select>
|
|
1016
1076
|
</div>
|
|
1017
1077
|
<div class="search-meta" id="searchMeta"></div>
|
|
@@ -1054,9 +1114,8 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1054
1114
|
<button class="filter-chip" data-task-status="completed" onclick="setTaskStatusFilter(this,'completed')" data-i18n="tasks.status.completed">Completed</button>
|
|
1055
1115
|
<button class="filter-chip" data-task-status="skipped" onclick="setTaskStatusFilter(this,'skipped')" data-i18n="tasks.status.skipped">Skipped</button>
|
|
1056
1116
|
<select id="taskSearchScope" class="scope-select" onchange="onTaskScopeChange()">
|
|
1057
|
-
<option value="local">Local</option>
|
|
1058
|
-
<option value="
|
|
1059
|
-
<option value="all">All</option>
|
|
1117
|
+
<option value="local" data-i18n="scope.local">Local</option>
|
|
1118
|
+
<option value="all" data-i18n="scope.hub">Hub</option>
|
|
1060
1119
|
</select>
|
|
1061
1120
|
<button class="btn btn-sm btn-ghost" onclick="loadTasks()" style="margin-left:auto" data-i18n="refresh">\u21BB Refresh</button>
|
|
1062
1121
|
</div>
|
|
@@ -1098,8 +1157,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1098
1157
|
<input type="text" id="skillSearchInput" placeholder="Search skills..." data-i18n-ph="skills.search.placeholder" oninput="debounceSkillSearch()">
|
|
1099
1158
|
<select id="skillSearchScope" class="scope-select" onchange="onSkillScopeChange()">
|
|
1100
1159
|
<option value="local" data-i18n="scope.local">Local</option>
|
|
1101
|
-
<option value="
|
|
1102
|
-
<option value="all" data-i18n="scope.all">All</option>
|
|
1160
|
+
<option value="all" data-i18n="scope.hub">Hub</option>
|
|
1103
1161
|
</select>
|
|
1104
1162
|
</div>
|
|
1105
1163
|
<div class="search-meta" id="skillSearchMeta"></div>
|
|
@@ -1414,16 +1472,11 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1414
1472
|
<button class="btn btn-sm" id="btnRoleHub" onclick="selectSharingRole('hub')" data-i18n="settings.hub.role.hub">Hub (Server)</button>
|
|
1415
1473
|
<button class="btn btn-sm" id="btnRoleClient" onclick="selectSharingRole('client')" data-i18n="settings.hub.role.client">Client (Connect to Hub)</button>
|
|
1416
1474
|
</div>
|
|
1417
|
-
<div class="field-hint" style="margin-top:6px" data-i18n="settings.hub.role.hint">Hub: this device runs the central server. Client: connect to an existing Hub.</div>
|
|
1475
|
+
<div class="field-hint" style="margin-top:6px" data-i18n="settings.hub.role.hint">Hub: this device runs the central server. Client: connect to an existing Hub. The two modes are mutually exclusive.</div>
|
|
1418
1476
|
</div>
|
|
1419
1477
|
|
|
1420
1478
|
<div id="hubModeConfig" style="display:none">
|
|
1421
|
-
<
|
|
1422
|
-
<div style="font-weight:700;color:var(--text);margin-bottom:4px" data-i18n="settings.hub.hubSteps.title">Quick Setup (3 steps)</div>
|
|
1423
|
-
<div><span style="color:var(--accent)">1.</span> <span data-i18n="settings.hub.hubSteps.s1">Fill in Team Name below (or keep default)</span></div>
|
|
1424
|
-
<div><span style="color:var(--accent)">2.</span> <span data-i18n="settings.hub.hubSteps.s2">Click "Save Settings", then restart OpenClaw gateway</span></div>
|
|
1425
|
-
<div><span style="color:var(--accent)">3.</span> <span data-i18n="settings.hub.hubSteps.s3">Share the Hub Address and Team Token below with your team members</span></div>
|
|
1426
|
-
</div>
|
|
1479
|
+
<input type="hidden" id="cfgHubTeamToken" value="">
|
|
1427
1480
|
<div class="settings-grid">
|
|
1428
1481
|
<div class="settings-field">
|
|
1429
1482
|
<label data-i18n="settings.hub.port">Hub Port</label>
|
|
@@ -1435,15 +1488,13 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1435
1488
|
<input type="text" id="cfgHubTeamName" placeholder="My Team">
|
|
1436
1489
|
<div class="field-hint" data-i18n="settings.hub.teamName.hint">Your team display name</div>
|
|
1437
1490
|
</div>
|
|
1438
|
-
<div class="settings-field full-width">
|
|
1439
|
-
<label data-i18n="settings.hub.teamToken">Team Token</label>
|
|
1440
|
-
<input type="text" id="cfgHubTeamToken" readonly style="background:var(--bg);cursor:pointer" onclick="this.select();document.execCommand('copy');toast(t('settings.hub.tokenCopied'),'success')">
|
|
1441
|
-
<div class="field-hint" data-i18n="settings.hub.teamToken.hint">Auto-generated secret for clients to join. Click to copy. Share this with your team members.</div>
|
|
1442
|
-
</div>
|
|
1443
1491
|
</div>
|
|
1444
|
-
<div id="hubShareInfo"
|
|
1445
|
-
<div
|
|
1446
|
-
<div id="hubShareInfoContent"
|
|
1492
|
+
<div id="hubShareInfo" style="display:none;margin-top:14px;background:var(--bg);border:1px solid var(--border);border-radius:10px;padding:14px 18px">
|
|
1493
|
+
<div style="font-size:11px;font-weight:600;color:var(--text-muted);text-transform:uppercase;letter-spacing:.04em;margin-bottom:10px" data-i18n="settings.hub.shareInfo.title">Share this info with your team members:</div>
|
|
1494
|
+
<div id="hubShareInfoContent" style="display:grid;grid-template-columns:auto 1fr;gap:6px 12px;font-size:12px;align-items:center"></div>
|
|
1495
|
+
</div>
|
|
1496
|
+
<div style="margin-top:16px;display:flex;align-items:center;gap:12px">
|
|
1497
|
+
<button class="btn btn-sm btn-primary" onclick="switchView('admin')" id="hubAdminEntryBtn" style="display:none" data-i18n="sharing.openAdmin">\u{1F6E1} Open Admin Panel</button>
|
|
1447
1498
|
</div>
|
|
1448
1499
|
</div>
|
|
1449
1500
|
|
|
@@ -1465,11 +1516,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1465
1516
|
<input type="text" id="cfgClientTeamToken" placeholder="">
|
|
1466
1517
|
<div class="field-hint" data-i18n="settings.hub.teamTokenClient.hint">Get this from your Hub admin to join the team</div>
|
|
1467
1518
|
</div>
|
|
1468
|
-
<
|
|
1469
|
-
<label data-i18n="settings.hub.userToken">User Token</label>
|
|
1470
|
-
<input type="text" id="cfgClientUserToken" placeholder="">
|
|
1471
|
-
<div class="field-hint" data-i18n="settings.hub.userToken.hint">Usually auto-obtained after joining. Leave blank in most cases.</div>
|
|
1472
|
-
</div>
|
|
1519
|
+
<input type="hidden" id="cfgClientUserToken" value="">
|
|
1473
1520
|
</div>
|
|
1474
1521
|
<div style="margin-top:12px">
|
|
1475
1522
|
<button class="btn btn-sm btn-primary" id="btnTestHubConn" onclick="testHubConnection()" data-i18n="settings.hub.testConnection">Test Connection</button>
|
|
@@ -1538,13 +1585,11 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1538
1585
|
</div>
|
|
1539
1586
|
<div class="admin-tabs" id="adminTabsBar">
|
|
1540
1587
|
<button class="admin-tab active" onclick="switchAdminTab('users',this)"><span class="at-icon">\u{1F465}</span> <span data-i18n="admin.tab.users">Users</span> <span class="at-count" id="adminTabCountUsers">0</span></button>
|
|
1541
|
-
<button class="admin-tab" onclick="switchAdminTab('groups',this)"><span class="at-icon">\u{1F4C2}</span> <span data-i18n="admin.tab.groups">Groups</span> <span class="at-count" id="adminTabCountGroups">0</span></button>
|
|
1542
1588
|
<button class="admin-tab" onclick="switchAdminTab('sharedMemories',this)"><span class="at-icon">\u{1F4AD}</span> <span data-i18n="admin.tab.sharedMemories">Shared Memories</span> <span class="at-count" id="adminTabCountMemories">0</span></button>
|
|
1543
1589
|
<button class="admin-tab" onclick="switchAdminTab('memories',this)"><span class="at-icon">\u{1F4CB}</span> <span data-i18n="admin.tab.memories">Shared Tasks</span> <span class="at-count" id="adminTabCountTasks">0</span></button>
|
|
1544
1590
|
<button class="admin-tab" onclick="switchAdminTab('skills',this)"><span class="at-icon">\u{1F9E0}</span> <span data-i18n="admin.tab.skills">Shared Skills</span> <span class="at-count" id="adminTabCountSkills">0</span></button>
|
|
1545
1591
|
</div>
|
|
1546
1592
|
<div class="admin-panel active" id="adminUsersPanel"></div>
|
|
1547
|
-
<div class="admin-panel" id="adminGroupsPanel"></div>
|
|
1548
1593
|
<div class="admin-panel" id="adminSharedMemoriesPanel"></div>
|
|
1549
1594
|
<div class="admin-panel" id="adminMemoriesPanel"></div>
|
|
1550
1595
|
<div class="admin-panel" id="adminSkillsPanel"></div>
|
|
@@ -1749,7 +1794,7 @@ let _embeddingWarningShown=false;
|
|
|
1749
1794
|
/* ─── i18n ─── */
|
|
1750
1795
|
const I18N={
|
|
1751
1796
|
en:{
|
|
1752
|
-
'title':'
|
|
1797
|
+
'title':'MemOS',
|
|
1753
1798
|
'subtitle':'Powered by MemOS',
|
|
1754
1799
|
'setup.desc':'Set a password to protect your memories',
|
|
1755
1800
|
'setup.pw':'Enter a password (4+ characters)',
|
|
@@ -2069,7 +2114,7 @@ const I18N={
|
|
|
2069
2114
|
'settings.hub.role':'Role',
|
|
2070
2115
|
'settings.hub.role.hub':'Hub (Server)',
|
|
2071
2116
|
'settings.hub.role.client':'Client (Connect to Hub)',
|
|
2072
|
-
'settings.hub.role.hint':'Hub = run the server; Client = connect to one.',
|
|
2117
|
+
'settings.hub.role.hint':'Hub = run the server; Client = connect to one. These two modes are mutually exclusive.',
|
|
2073
2118
|
'settings.hub.port':'Hub Port',
|
|
2074
2119
|
'settings.hub.port.hint':'Port for Hub service. Default: 18800',
|
|
2075
2120
|
'settings.hub.teamName':'Team Name',
|
|
@@ -2106,13 +2151,31 @@ const I18N={
|
|
|
2106
2151
|
'sidebar.hub':'\u{1F310} Team Sharing',
|
|
2107
2152
|
'sharing.sidebar.connected':'Connected',
|
|
2108
2153
|
'sharing.sidebar.disconnected':'Disconnected',
|
|
2154
|
+
'sharing.sidebar.pending':'Pending Approval',
|
|
2155
|
+
'sharing.sidebar.rejected':'Rejected',
|
|
2109
2156
|
'sharing.sidebar.starting':'Starting...',
|
|
2110
2157
|
'sharing.sidebar.notConfigured':'Not configured',
|
|
2111
2158
|
'sharing.sidebar.identity':'Identity:',
|
|
2112
2159
|
'sharing.sidebar.admin':'Admin',
|
|
2113
2160
|
'sharing.sidebar.targetHub':'Target Hub:',
|
|
2161
|
+
'sharing.pendingApproval.hint':'Your join request has been submitted. Please wait for the Hub admin to approve.',
|
|
2162
|
+
'sharing.rejected.hint':'Your join request was rejected by the Hub admin. Please contact the admin or retry.',
|
|
2163
|
+
'sharing.retryJoin':'Retry Join',
|
|
2164
|
+
'sharing.retryJoin.hint':'Clears local data and re-submits the join request',
|
|
2165
|
+
'sharing.retryJoin.confirm':'This will clear your current connection and re-submit a join request. Continue?',
|
|
2166
|
+
'sharing.retryJoin.success':'Join request re-submitted. Waiting for admin approval.',
|
|
2167
|
+
'sharing.retryJoin.fail':'Failed to retry join',
|
|
2168
|
+
'sharing.cannotJoinSelf':'Cannot join your own Hub. Please enter a remote Hub address.',
|
|
2169
|
+
'scope.hub':'Hub',
|
|
2170
|
+
'memory.detail.title':'Memory Detail',
|
|
2171
|
+
'memory.detail.loading':'Loading...',
|
|
2172
|
+
'memory.detail.notFound':'Memory not found',
|
|
2173
|
+
'memory.detail.copyId':'Click to copy ID',
|
|
2174
|
+
'memory.detail.created':'Created ',
|
|
2175
|
+
'memory.detail.updated':'Updated ',
|
|
2176
|
+
'memory.detail.viewTarget':'View target: ',
|
|
2114
2177
|
'admin.title':'Hub Admin Panel',
|
|
2115
|
-
'admin.subtitle':'Manage team members
|
|
2178
|
+
'admin.subtitle':'Manage team members and shared resources',
|
|
2116
2179
|
'admin.refresh':'\u21BB Refresh',
|
|
2117
2180
|
'admin.tab.users':'Users',
|
|
2118
2181
|
'admin.tab.groups':'Groups',
|
|
@@ -2158,6 +2221,7 @@ const I18N={
|
|
|
2158
2221
|
'admin.membersCount':'Members ({n}):',
|
|
2159
2222
|
'admin.noMembersYet':'No members yet.',
|
|
2160
2223
|
'admin.loadFailed':'Failed to load admin data: ',
|
|
2224
|
+
'admin.noPermission':'You do not have admin permissions to access this panel.',
|
|
2161
2225
|
'admin.groupsFailed':'Failed to load groups: ',
|
|
2162
2226
|
'toast.userApproved':'User approved',
|
|
2163
2227
|
'toast.userRejected':'User rejected',
|
|
@@ -2286,7 +2350,7 @@ const I18N={
|
|
|
2286
2350
|
'update.dismiss':'Dismiss'
|
|
2287
2351
|
},
|
|
2288
2352
|
zh:{
|
|
2289
|
-
'title':'
|
|
2353
|
+
'title':'MemOS 记忆',
|
|
2290
2354
|
'subtitle':'由 MemOS 驱动',
|
|
2291
2355
|
'setup.desc':'设置密码以保护你的记忆数据',
|
|
2292
2356
|
'setup.pw':'输入密码(至少4位)',
|
|
@@ -2606,7 +2670,7 @@ const I18N={
|
|
|
2606
2670
|
'settings.hub.role':'角色',
|
|
2607
2671
|
'settings.hub.role.hub':'Hub(服务端)',
|
|
2608
2672
|
'settings.hub.role.client':'Client(连接到 Hub)',
|
|
2609
|
-
'settings.hub.role.hint':'Hub = 本机做服务端;Client =
|
|
2673
|
+
'settings.hub.role.hint':'Hub = 本机做服务端;Client = 连接别人的服务端。两种模式互斥,不能同时使用。',
|
|
2610
2674
|
'settings.hub.port':'Hub 端口',
|
|
2611
2675
|
'settings.hub.port.hint':'Hub 服务端口,默认 18800',
|
|
2612
2676
|
'settings.hub.teamName':'团队名称',
|
|
@@ -2643,13 +2707,31 @@ const I18N={
|
|
|
2643
2707
|
'sidebar.hub':'\u{1F310} 团队共享',
|
|
2644
2708
|
'sharing.sidebar.connected':'已连接',
|
|
2645
2709
|
'sharing.sidebar.disconnected':'已断开',
|
|
2710
|
+
'sharing.sidebar.pending':'等待审核',
|
|
2711
|
+
'sharing.sidebar.rejected':'已拒绝',
|
|
2646
2712
|
'sharing.sidebar.starting':'启动中...',
|
|
2647
2713
|
'sharing.sidebar.notConfigured':'未配置',
|
|
2648
2714
|
'sharing.sidebar.identity':'身份:',
|
|
2649
2715
|
'sharing.sidebar.admin':'管理员',
|
|
2650
2716
|
'sharing.sidebar.targetHub':'目标 Hub:',
|
|
2717
|
+
'sharing.pendingApproval.hint':'加入申请已提交,请等待 Hub 管理员审核通过。',
|
|
2718
|
+
'sharing.rejected.hint':'您的加入申请已被 Hub 管理员拒绝,请联系管理员或重新申请。',
|
|
2719
|
+
'sharing.retryJoin':'重新申请',
|
|
2720
|
+
'sharing.retryJoin.hint':'清除本地连接数据并重新提交加入申请',
|
|
2721
|
+
'sharing.retryJoin.confirm':'这将清除当前连接数据并重新提交加入申请,是否继续?',
|
|
2722
|
+
'sharing.retryJoin.success':'加入申请已重新提交,请等待管理员审核。',
|
|
2723
|
+
'sharing.retryJoin.fail':'重新申请失败',
|
|
2724
|
+
'sharing.cannotJoinSelf':'不能加入自己的 Hub,请输入远程 Hub 地址。',
|
|
2725
|
+
'scope.hub':'Hub',
|
|
2726
|
+
'memory.detail.title':'记忆详情',
|
|
2727
|
+
'memory.detail.loading':'加载中...',
|
|
2728
|
+
'memory.detail.notFound':'未找到该记忆',
|
|
2729
|
+
'memory.detail.copyId':'点击复制 ID',
|
|
2730
|
+
'memory.detail.created':'创建于 ',
|
|
2731
|
+
'memory.detail.updated':'更新于 ',
|
|
2732
|
+
'memory.detail.viewTarget':'查看目标: ',
|
|
2651
2733
|
'admin.title':'Hub 管理面板',
|
|
2652
|
-
'admin.subtitle':'
|
|
2734
|
+
'admin.subtitle':'管理团队成员和共享资源',
|
|
2653
2735
|
'admin.refresh':'\u21BB 刷新',
|
|
2654
2736
|
'admin.tab.users':'用户',
|
|
2655
2737
|
'admin.tab.groups':'分组',
|
|
@@ -2695,6 +2777,7 @@ const I18N={
|
|
|
2695
2777
|
'admin.membersCount':'成员({n}):',
|
|
2696
2778
|
'admin.noMembersYet':'暂无成员。',
|
|
2697
2779
|
'admin.loadFailed':'加载管理数据失败:',
|
|
2780
|
+
'admin.noPermission':'您没有管理员权限,无法访问此面板。',
|
|
2698
2781
|
'admin.groupsFailed':'加载分组失败:',
|
|
2699
2782
|
'toast.userApproved':'用户已批准',
|
|
2700
2783
|
'toast.userRejected':'用户已拒绝',
|
|
@@ -2938,6 +3021,20 @@ function selectSharingRole(role){
|
|
|
2938
3021
|
document.getElementById('btnRoleClient').className='btn btn-sm'+(role==='client'?' btn-primary':'');
|
|
2939
3022
|
document.getElementById('hubModeConfig').style.display=role==='hub'?'block':'none';
|
|
2940
3023
|
document.getElementById('clientModeConfig').style.display=role==='client'?'block':'none';
|
|
3024
|
+
var sp=document.getElementById('sharingStatusPanel');
|
|
3025
|
+
var tp=document.getElementById('sharingTeamPanel');
|
|
3026
|
+
var ap=document.getElementById('sharingAdminPanel');
|
|
3027
|
+
if(role==='client'){
|
|
3028
|
+
if(sp) sp.style.display='none';
|
|
3029
|
+
if(tp) tp.style.display='none';
|
|
3030
|
+
if(ap) ap.style.display='none';
|
|
3031
|
+
var adminTab=document.querySelector('.tab[data-view="admin"]');
|
|
3032
|
+
if(adminTab) adminTab.style.display='none';
|
|
3033
|
+
}else{
|
|
3034
|
+
if(sp) sp.style.display='';
|
|
3035
|
+
if(tp) tp.style.display='';
|
|
3036
|
+
if(ap) ap.style.display='';
|
|
3037
|
+
}
|
|
2941
3038
|
if(role==='hub'){
|
|
2942
3039
|
var tk=document.getElementById('cfgHubTeamToken');
|
|
2943
3040
|
if(!tk.value.trim()) tk.value=_genToken(18);
|
|
@@ -2950,16 +3047,20 @@ function updateHubShareInfo(){
|
|
|
2950
3047
|
var panel=document.getElementById('hubShareInfo');
|
|
2951
3048
|
var content=document.getElementById('hubShareInfoContent');
|
|
2952
3049
|
if(!panel||!content) return;
|
|
2953
|
-
var
|
|
3050
|
+
var tokenEl=document.getElementById('cfgHubTeamToken');
|
|
3051
|
+
var token=tokenEl?tokenEl.value.trim():'';
|
|
2954
3052
|
var port=document.getElementById('cfgHubPort').value.trim()||'18800';
|
|
2955
3053
|
if(!token||_sharingRole!=='hub'){panel.style.display='none';return;}
|
|
2956
3054
|
panel.style.display='block';
|
|
3055
|
+
var cpStyle='cursor:pointer;background:rgba(99,102,241,.06);border:1px solid rgba(99,102,241,.15);border-radius:6px;padding:4px 10px;font-family:var(--mono);font-size:12px;color:var(--text);transition:all .15s;user-select:all';
|
|
2957
3056
|
var renderShare=function(ip){
|
|
2958
3057
|
var addr=ip?(ip+':'+esc(port)):('<'+t('settings.hub.shareInfo.yourIP')+'>:'+esc(port));
|
|
2959
3058
|
var tip=t('settings.hub.shareInfo.clickCopy');
|
|
2960
3059
|
content.innerHTML=
|
|
2961
|
-
'<span
|
|
2962
|
-
'<span
|
|
3060
|
+
'<span style="font-size:11px;color:var(--text-muted);font-weight:500">Hub '+t('settings.hub.hubAddress')+'</span>'+
|
|
3061
|
+
'<span style="'+cpStyle+'" onclick="navigator.clipboard.writeText(this.textContent);toast('Copied!','success')" title="'+tip+'">'+addr+'</span>'+
|
|
3062
|
+
'<span style="font-size:11px;color:var(--text-muted);font-weight:500">Team Token</span>'+
|
|
3063
|
+
'<span style="'+cpStyle+'" onclick="navigator.clipboard.writeText(this.textContent);toast('Copied!','success')" title="'+tip+'">'+esc(token)+'</span>';
|
|
2963
3064
|
};
|
|
2964
3065
|
if(_cachedLocalIP){renderShare(_cachedLocalIP);return;}
|
|
2965
3066
|
renderShare('');
|
|
@@ -2973,6 +3074,15 @@ async function testHubConnection(){
|
|
|
2973
3074
|
var addr=document.getElementById('cfgClientHubAddress').value.trim();
|
|
2974
3075
|
if(!addr){result.innerHTML='<span style="color:var(--rose)">\u274C '+t('settings.hub.test.noAddr')+'</span>';return;}
|
|
2975
3076
|
btn.disabled=true;result.innerHTML=t('settings.hub.test.testing');
|
|
3077
|
+
try{
|
|
3078
|
+
var ipsData=await fetch('/api/local-ips').then(function(r){return r.json();});
|
|
3079
|
+
var localAddrs=['127.0.0.1','localhost','0.0.0.0'].concat(ipsData.ips||[]);
|
|
3080
|
+
var parsed=new URL(addr.indexOf('://')>-1?addr:'http://'+addr);
|
|
3081
|
+
if(localAddrs.indexOf(parsed.hostname)>=0){
|
|
3082
|
+
result.innerHTML='<span style="color:var(--rose)">\u274C '+t('sharing.cannotJoinSelf')+'</span>';
|
|
3083
|
+
btn.disabled=false;return;
|
|
3084
|
+
}
|
|
3085
|
+
}catch(e){}
|
|
2976
3086
|
try{
|
|
2977
3087
|
var url=addr.match(/^https?:\\/\\//)?addr:'http://'+addr;
|
|
2978
3088
|
url=url.replace(/\\/+$/,'');
|
|
@@ -2981,7 +3091,8 @@ async function testHubConnection(){
|
|
|
2981
3091
|
if(d.ok){
|
|
2982
3092
|
result.innerHTML='<span style="color:var(--green)">\u2705 '+t('settings.hub.test.ok')+(d.teamName?' — '+esc(d.teamName):'')+'</span>';
|
|
2983
3093
|
}else{
|
|
2984
|
-
|
|
3094
|
+
var errMsg=d.error==='cannot_join_self'?t('sharing.cannotJoinSelf'):(d.error||t('settings.hub.test.fail'));
|
|
3095
|
+
result.innerHTML='<span style="color:var(--rose)">\u274C '+errMsg+'</span>';
|
|
2985
3096
|
}
|
|
2986
3097
|
}catch(e){
|
|
2987
3098
|
result.innerHTML='<span style="color:var(--rose)">\u274C '+esc(String(e))+'</span>';
|
|
@@ -3090,6 +3201,7 @@ function renderSharingSidebar(data){
|
|
|
3090
3201
|
if(!statusEl||!hintEl) return;
|
|
3091
3202
|
if(!data||!data.enabled){
|
|
3092
3203
|
if(section) section.style.display='none';
|
|
3204
|
+
window._isHubAdmin=false;
|
|
3093
3205
|
return;
|
|
3094
3206
|
}
|
|
3095
3207
|
if(section) section.style.display='block';
|
|
@@ -3098,25 +3210,43 @@ function renderSharingSidebar(data){
|
|
|
3098
3210
|
if(!badgeEl)return;
|
|
3099
3211
|
badgeEl.innerHTML='<span style="display:inline-flex;align-items:center;gap:4px;font-size:10px;font-weight:600;padding:2px 8px;border-radius:9999px;background:'+color+'15;color:'+color+'"><span style="display:inline-block;width:6px;height:6px;border-radius:50%;background:'+color+(glow?';box-shadow:0 0 4px '+color:'')+'"></span>'+esc(text)+'</span>';
|
|
3100
3212
|
}
|
|
3101
|
-
if(
|
|
3102
|
-
|
|
3213
|
+
if(data.role==='hub'){
|
|
3214
|
+
setBadge('#34d399',t('sharing.sidebar.connected'),true);
|
|
3215
|
+
statusEl.innerHTML='';
|
|
3216
|
+
hintEl.textContent='';
|
|
3217
|
+
var adminTab=document.querySelector('.tab[data-view="admin"]');
|
|
3218
|
+
if(adminTab) adminTab.style.display='';
|
|
3219
|
+
}else if(conn.pendingApproval&&conn.user){
|
|
3220
|
+
setBadge('#fbbf24',t('sharing.sidebar.pending'),false);
|
|
3221
|
+
var html='<div class="info-grid">';
|
|
3222
|
+
html+='<span class="label">'+t('sharing.sidebar.identity')+'</span><span class="value">'+esc(conn.user.username)+'</span>';
|
|
3223
|
+
if(conn.teamName) html+='<span class="label">'+t('sharing.team')+'</span><span class="value">'+esc(conn.teamName)+'</span>';
|
|
3224
|
+
html+='</div>';
|
|
3225
|
+
statusEl.innerHTML=html;
|
|
3226
|
+
hintEl.textContent=t('sharing.pendingApproval.hint');
|
|
3227
|
+
var adminTab=document.querySelector('.tab[data-view="admin"]');
|
|
3228
|
+
if(adminTab) adminTab.style.display='none';
|
|
3229
|
+
}else if(conn.rejected&&conn.user){
|
|
3230
|
+
setBadge('#ef4444',t('sharing.sidebar.rejected'),false);
|
|
3231
|
+
var html='<div class="info-grid">';
|
|
3232
|
+
html+='<span class="label">'+t('sharing.sidebar.identity')+'</span><span class="value">'+esc(conn.user.username||'-')+'</span>';
|
|
3233
|
+
if(conn.teamName) html+='<span class="label">'+t('sharing.team')+'</span><span class="value">'+esc(conn.teamName)+'</span>';
|
|
3234
|
+
html+='</div>';
|
|
3235
|
+
statusEl.innerHTML=html;
|
|
3236
|
+
hintEl.textContent=t('sharing.rejected.hint');
|
|
3237
|
+
var adminTab=document.querySelector('.tab[data-view="admin"]');
|
|
3238
|
+
if(adminTab) adminTab.style.display='none';
|
|
3239
|
+
}else if(conn.connected&&conn.user){
|
|
3103
3240
|
var isAdmin=conn.user.role==='admin';
|
|
3104
3241
|
setBadge('#34d399',t('sharing.sidebar.connected'),true);
|
|
3105
3242
|
var html='<div class="info-grid">';
|
|
3106
3243
|
html+='<span class="label">'+t('sharing.sidebar.identity')+'</span><span class="value">'+esc(conn.user.username)+(isAdmin?' <span class="role-badge admin">'+t('sharing.sidebar.admin')+'</span>':'')+'</span>';
|
|
3107
3244
|
html+='<span class="label">'+t('sharing.team')+'</span><span class="value">'+esc(conn.teamName||'-')+'</span>';
|
|
3108
|
-
if(groups) html+='<span class="label">'+t('sharing.groups')+'</span><span class="value">'+esc(groups)+'</span>';
|
|
3109
3245
|
html+='</div>';
|
|
3110
3246
|
statusEl.innerHTML=html;
|
|
3111
3247
|
hintEl.innerHTML='';
|
|
3112
3248
|
var adminTab=document.querySelector('.tab[data-view="admin"]');
|
|
3113
3249
|
if(adminTab) adminTab.style.display=isAdmin?'':'none';
|
|
3114
|
-
}else if(data.role==='hub'){
|
|
3115
|
-
setBadge('#fbbf24',t('sharing.sidebar.starting'),false);
|
|
3116
|
-
statusEl.innerHTML='';
|
|
3117
|
-
hintEl.textContent=t('sharing.hubMode.hint');
|
|
3118
|
-
var adminTab=document.querySelector('.tab[data-view="admin"]');
|
|
3119
|
-
if(adminTab) adminTab.style.display=(data.admin&&data.admin.canManageUsers)?'':'none';
|
|
3120
3250
|
}else if(data.clientConfigured){
|
|
3121
3251
|
setBadge('#ef4444',t('sharing.sidebar.disconnected'),false);
|
|
3122
3252
|
statusEl.innerHTML='<div style="font-size:11px;color:var(--text-muted)">'+t('sharing.sidebar.targetHub')+' '+esc(data.hubUrl||'')+'</div>';
|
|
@@ -3139,49 +3269,75 @@ function renderSharingSettings(data){
|
|
|
3139
3269
|
}
|
|
3140
3270
|
var conn=data.connection||{};
|
|
3141
3271
|
var user=conn.user||{};
|
|
3142
|
-
var
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
var
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
'</span>';
|
|
3272
|
+
var actualRole=data.role||_sharingRole||'client';
|
|
3273
|
+
if(data.role) _sharingRole=data.role;
|
|
3274
|
+
var isAdmin=(data.admin&&data.admin.canManageUsers)||(conn.connected&&user.role==='admin')||(actualRole==='hub');
|
|
3275
|
+
window._isHubAdmin=isAdmin;
|
|
3276
|
+
var adminTab=document.querySelector('.tab[data-view="admin"]');
|
|
3277
|
+
if(adminTab) adminTab.style.display=isAdmin?'':'none';
|
|
3278
|
+
var hubAdminBtn=document.getElementById('hubAdminEntryBtn');
|
|
3279
|
+
|
|
3280
|
+
if(actualRole==='hub'){
|
|
3281
|
+
statusEl.innerHTML='';teamEl.innerHTML='';adminEl.innerHTML='';
|
|
3282
|
+
if(hubAdminBtn) hubAdminBtn.style.display=isAdmin?'':'none';
|
|
3283
|
+
return;
|
|
3155
3284
|
}
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
if(
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3285
|
+
|
|
3286
|
+
if(actualRole==='client'){
|
|
3287
|
+
statusEl.style.display='none';teamEl.style.display='none';adminEl.style.display='none';
|
|
3288
|
+
if(adminTab) adminTab.style.display='none';
|
|
3289
|
+
if(hubAdminBtn) hubAdminBtn.style.display='none';
|
|
3290
|
+
|
|
3291
|
+
var connBadge;
|
|
3292
|
+
if(conn.pendingApproval){
|
|
3293
|
+
connBadge='<span class="hic-badge pending"><span class="hic-dot amber"></span>'+t('sharing.sidebar.pending')+'</span>';
|
|
3294
|
+
}else if(conn.rejected){
|
|
3295
|
+
connBadge='<span class="hic-badge disconnected"><span class="hic-dot red"></span>'+t('sharing.sidebar.rejected')+'</span>';
|
|
3296
|
+
}else if(conn.connected){
|
|
3297
|
+
connBadge='<span class="hic-badge connected"><span class="hic-dot green"></span>'+t('sharing.sidebar.connected')+'</span>';
|
|
3298
|
+
}else{
|
|
3299
|
+
connBadge='<span class="hic-badge disconnected"><span class="hic-dot red"></span>'+t('sharing.sidebar.disconnected')+'</span>';
|
|
3169
3300
|
}
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3301
|
+
statusEl.style.display='';
|
|
3302
|
+
var sh='<div class="hub-info-card hic-status"><div class="hic-title"><span class="hic-icon">\u{1F517}</span>'+t('settings.hub.connection')+' '+connBadge+'</div><div class="hic-grid">';
|
|
3303
|
+
if(conn.pendingApproval&&user.username){
|
|
3304
|
+
sh+='<span class="hic-label">'+t('sharing.user')+'</span><span class="hic-value">'+esc(user.username)+'</span>';
|
|
3305
|
+
sh+='</div><div class="hic-empty" style="color:#f59e0b">'+t('sharing.pendingApproval.hint')+'</div></div>';
|
|
3306
|
+
}else if(conn.rejected){
|
|
3307
|
+
if(user.username) sh+='<span class="hic-label">'+t('sharing.user')+'</span><span class="hic-value">'+esc(user.username)+'</span>';
|
|
3308
|
+
sh+='</div><div class="hic-empty" style="color:#ef4444">'+t('sharing.rejected.hint')+'</div>'+
|
|
3309
|
+
'<div style="margin-top:10px;padding:0 16px 14px"><button class="btn btn-sm btn-primary" onclick="retryHubJoin()">'+t('sharing.retryJoin')+'</button>'+
|
|
3310
|
+
'<span style="font-size:11px;color:var(--text-muted);margin-left:8px">'+t('sharing.retryJoin.hint')+'</span></div></div>';
|
|
3311
|
+
}else if(conn.connected&&user.username){
|
|
3312
|
+
sh+='<span class="hic-label">'+t('sharing.user')+'</span><span class="hic-value" style="display:flex;align-items:center;gap:6px">'+
|
|
3313
|
+
'<input type="text" id="hubUsernameInput" value="'+esc(user.username)+'" style="border:1px solid var(--border);border-radius:6px;padding:3px 8px;font-size:12px;background:var(--bg);color:var(--text);width:120px;font-family:inherit" />'+
|
|
3314
|
+
'<button class="btn btn-sm" onclick="updateHubUsername()" style="padding:2px 10px;font-size:11px">'+t('sharing.saveUsername')+'</button>'+
|
|
3315
|
+
'</span>';
|
|
3316
|
+
sh+='<span class="hic-label">'+t('sharing.team')+'</span><span class="hic-value">'+esc(conn.teamName||'-')+'</span>';
|
|
3317
|
+
sh+='</div></div>';
|
|
3318
|
+
}else{
|
|
3319
|
+
sh+='</div></div>';
|
|
3320
|
+
}
|
|
3321
|
+
statusEl.innerHTML=sh;
|
|
3322
|
+
teamEl.innerHTML='';adminEl.innerHTML='';
|
|
3323
|
+
return;
|
|
3174
3324
|
}
|
|
3175
|
-
teamEl.innerHTML=th;
|
|
3176
3325
|
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3326
|
+
statusEl.innerHTML='';teamEl.innerHTML='';adminEl.innerHTML='';
|
|
3327
|
+
}
|
|
3328
|
+
|
|
3329
|
+
async function retryHubJoin(){
|
|
3330
|
+
if(!confirm(t('sharing.retryJoin.confirm'))) return;
|
|
3331
|
+
try{
|
|
3332
|
+
var r=await fetch('/api/sharing/retry-join',{method:'POST',headers:{'Content-Type':'application/json'}});
|
|
3333
|
+
var d=await r.json();
|
|
3334
|
+
if(d.ok){
|
|
3335
|
+
toast(t('sharing.retryJoin.success'),'success');
|
|
3336
|
+
setTimeout(function(){location.reload();},1500);
|
|
3337
|
+
}else{
|
|
3338
|
+
toast(d.error||t('sharing.retryJoin.fail'),'error');
|
|
3339
|
+
}
|
|
3340
|
+
}catch(e){toast(t('sharing.retryJoin.fail')+': '+e.message,'error');}
|
|
3185
3341
|
}
|
|
3186
3342
|
|
|
3187
3343
|
async function updateHubUsername(){
|
|
@@ -3215,6 +3371,7 @@ async function updateHubUsername(){
|
|
|
3215
3371
|
}
|
|
3216
3372
|
|
|
3217
3373
|
async function loadSharingPendingUsers(){
|
|
3374
|
+
if(_sharingRole==='client') return;
|
|
3218
3375
|
var el=document.getElementById('sharingAdminPanel');
|
|
3219
3376
|
if(!el) return;
|
|
3220
3377
|
el.innerHTML=t('sharing.loading');
|
|
@@ -3422,24 +3579,27 @@ function switchAdminTab(tab,btn){
|
|
|
3422
3579
|
}
|
|
3423
3580
|
|
|
3424
3581
|
async function loadAdminData(){
|
|
3582
|
+
if(!window._isHubAdmin){
|
|
3583
|
+
var statsEl=document.getElementById('adminStats');
|
|
3584
|
+
if(statsEl) statsEl.innerHTML='<div class="admin-empty">'+t('admin.noPermission')+'</div>';
|
|
3585
|
+
return;
|
|
3586
|
+
}
|
|
3425
3587
|
try{
|
|
3426
|
-
var [usersR,
|
|
3588
|
+
var [usersR,tasksR,skillsR,pendingR,memoriesR]=await Promise.all([
|
|
3427
3589
|
fetch('/api/sharing/users').then(function(r){return r.json();}),
|
|
3428
|
-
fetch('/api/sharing/groups').then(function(r){return r.json();}),
|
|
3429
3590
|
fetch('/api/admin/shared-tasks').then(function(r){return r.json();}),
|
|
3430
3591
|
fetch('/api/admin/shared-skills').then(function(r){return r.json();}),
|
|
3431
3592
|
fetch('/api/sharing/pending-users').then(function(r){return r.json();}),
|
|
3432
3593
|
fetch('/api/admin/shared-memories').then(function(r){return r.json();})
|
|
3433
3594
|
]);
|
|
3434
3595
|
adminDataCache.users=Array.isArray(usersR.users)?usersR.users:[];
|
|
3435
|
-
adminDataCache.groups=
|
|
3596
|
+
adminDataCache.groups=[];
|
|
3436
3597
|
adminDataCache.tasks=Array.isArray(tasksR.tasks)?tasksR.tasks:[];
|
|
3437
3598
|
adminDataCache.skills=Array.isArray(skillsR.skills)?skillsR.skills:[];
|
|
3438
3599
|
adminDataCache.memories=Array.isArray(memoriesR.memories)?memoriesR.memories:[];
|
|
3439
3600
|
var pending=Array.isArray(pendingR.users)?pendingR.users:[];
|
|
3440
3601
|
renderAdminStats(pending.length);
|
|
3441
3602
|
renderAdminUsers(adminDataCache.users, pending);
|
|
3442
|
-
renderAdminGroups(adminDataCache.groups);
|
|
3443
3603
|
renderAdminMemories(adminDataCache.tasks);
|
|
3444
3604
|
renderAdminSkills(adminDataCache.skills);
|
|
3445
3605
|
renderAdminSharedMemories(adminDataCache.memories);
|
|
@@ -3455,12 +3615,10 @@ function renderAdminStats(pendingCount){
|
|
|
3455
3615
|
el.innerHTML=
|
|
3456
3616
|
'<div class="admin-stat-box"><span class="as-icon">\u{1F465}</span><div class="val">'+adminDataCache.users.length+'</div><div class="lbl">'+t('admin.stat.activeUsers')+'</div></div>'+
|
|
3457
3617
|
'<div class="admin-stat-box"><span class="as-icon">\u{23F3}</span><div class="val">'+pendingCount+'</div><div class="lbl">'+t('admin.stat.pending')+'</div></div>'+
|
|
3458
|
-
'<div class="admin-stat-box"><span class="as-icon">\u{1F4C2}</span><div class="val">'+adminDataCache.groups.length+'</div><div class="lbl">'+t('admin.stat.groups')+'</div></div>'+
|
|
3459
3618
|
'<div class="admin-stat-box"><span class="as-icon">\u{1F4CB}</span><div class="val">'+adminDataCache.tasks.length+'</div><div class="lbl">'+t('admin.stat.sharedTasks')+'</div></div>'+
|
|
3460
3619
|
'<div class="admin-stat-box"><span class="as-icon">\u{1F9E0}</span><div class="val">'+adminDataCache.skills.length+'</div><div class="lbl">'+t('admin.stat.sharedSkills')+'</div></div>'+
|
|
3461
3620
|
'<div class="admin-stat-box"><span class="as-icon">\u{1F4AD}</span><div class="val">'+(adminDataCache.memories||[]).length+'</div><div class="lbl">'+t('admin.stat.sharedMemories')+'</div></div>';
|
|
3462
3621
|
var tc=document.getElementById('adminTabCountUsers');if(tc)tc.textContent=adminDataCache.users.length+pendingCount;
|
|
3463
|
-
tc=document.getElementById('adminTabCountGroups');if(tc)tc.textContent=adminDataCache.groups.length;
|
|
3464
3622
|
tc=document.getElementById('adminTabCountMemories');if(tc)tc.textContent=(adminDataCache.memories||[]).length;
|
|
3465
3623
|
tc=document.getElementById('adminTabCountTasks');if(tc)tc.textContent=adminDataCache.tasks.length;
|
|
3466
3624
|
tc=document.getElementById('adminTabCountSkills');if(tc)tc.textContent=adminDataCache.skills.length;
|
|
@@ -3623,10 +3781,9 @@ function renderAdminMemories(tasks){
|
|
|
3623
3781
|
for(var i=0;i<tasks.length;i++){
|
|
3624
3782
|
var tk=tasks[i];
|
|
3625
3783
|
html+='<div class="admin-card" onclick="openHubTaskDetailFromCache(\\\'admin\\\','+i+')" style="cursor:pointer"><div class="admin-card-header"><div class="admin-card-title">'+esc(tk.title||tk.id)+'</div>'+
|
|
3626
|
-
'
|
|
3784
|
+
'</div>'+
|
|
3627
3785
|
'<div class="admin-card-meta">'+
|
|
3628
3786
|
t('admin.owner')+esc(tk.ownerName||tk.sourceUserId||'unknown')+
|
|
3629
|
-
(tk.groupName?' \u00B7 '+t('admin.group')+esc(tk.groupName):'')+
|
|
3630
3787
|
(tk.chunkCount!=null?' \u00B7 '+t('admin.chunks')+tk.chunkCount:'')+
|
|
3631
3788
|
' \u00B7 '+t('admin.updated')+new Date(tk.updatedAt||tk.createdAt).toLocaleDateString()+
|
|
3632
3789
|
'</div>'+
|
|
@@ -3658,11 +3815,10 @@ function renderAdminSkills(skills){
|
|
|
3658
3815
|
for(var i=0;i<skills.length;i++){
|
|
3659
3816
|
var s=skills[i];
|
|
3660
3817
|
html+='<div class="admin-card" onclick="openHubSkillDetailFromCache(\\\'admin\\\','+i+')" style="cursor:pointer"><div class="admin-card-header"><div class="admin-card-title">'+esc(s.name||s.id)+'</div>'+
|
|
3661
|
-
'
|
|
3818
|
+
'</div>'+
|
|
3662
3819
|
'<div class="admin-card-meta">'+
|
|
3663
3820
|
(s.description?esc(s.description)+'<br>':'')+
|
|
3664
3821
|
t('admin.owner')+esc(s.ownerName||s.sourceUserId||'unknown')+
|
|
3665
|
-
(s.groupName?' \u00B7 '+t('admin.group')+esc(s.groupName):'')+
|
|
3666
3822
|
(s.version!=null?' \u00B7 '+t('admin.version')+s.version:'')+
|
|
3667
3823
|
(s.qualityScore!=null?' \u00B7 '+t('admin.quality')+s.qualityScore:'')+
|
|
3668
3824
|
'</div>'+
|
|
@@ -3694,10 +3850,9 @@ function renderAdminSharedMemories(memories){
|
|
|
3694
3850
|
for(var i=0;i<memories.length;i++){
|
|
3695
3851
|
var m=memories[i];
|
|
3696
3852
|
html+='<div class="admin-card" onclick="openHubMemoryDetail(\\\'admin\\\','+i+')" style="cursor:pointer"><div class="admin-card-header"><div class="admin-card-title">'+esc(m.summary||m.content?.slice(0,80)||m.id)+'</div>'+
|
|
3697
|
-
'
|
|
3853
|
+
'</div>'+
|
|
3698
3854
|
'<div class="admin-card-meta">'+
|
|
3699
3855
|
t('admin.owner')+esc(m.ownerName||m.sourceUserId||'unknown')+
|
|
3700
|
-
(m.groupName?' \u00B7 '+t('admin.group')+esc(m.groupName):'')+
|
|
3701
3856
|
(m.kind?' \u00B7 Kind: '+esc(m.kind):'')+
|
|
3702
3857
|
(m.role?' \u00B7 Role: '+esc(m.role):'')+
|
|
3703
3858
|
' \u00B7 '+t('admin.updated')+new Date(m.updatedAt||m.createdAt).toLocaleDateString()+
|
|
@@ -3886,21 +4041,16 @@ function renderTaskShareActions(task){
|
|
|
3886
4041
|
const isShared=!!current;
|
|
3887
4042
|
var statusHtml='';
|
|
3888
4043
|
if(isShared){
|
|
3889
|
-
|
|
3890
|
-
statusHtml='<span style="display:inline-flex;align-items:center;gap:4px;padding:3px 10px;background:#22c55e22;border:1px solid #22c55e44;border-radius:12px;font-size:12px;color:#22c55e">\u2713 '+t('share.alreadyShared')+' ('+scopeLabel+')</span>';
|
|
4044
|
+
statusHtml='<span style="display:inline-flex;align-items:center;gap:4px;padding:3px 10px;background:#22c55e22;border:1px solid #22c55e44;border-radius:12px;font-size:12px;color:#22c55e">\u2713 '+t('share.alreadyShared')+'</span>';
|
|
3891
4045
|
}
|
|
3892
4046
|
el.innerHTML=statusHtml+
|
|
3893
|
-
'<select id="taskShareScope" class="filter-select" style="min-width:120px">'+
|
|
3894
|
-
'<option value="group"'+(current==='group'?' selected':'')+'>Share to Group</option>'+
|
|
3895
|
-
'<option value="public"'+(current==='public'?' selected':'')+'>Share to Public</option>'+
|
|
3896
|
-
'</select>'+
|
|
3897
4047
|
'<button class="btn btn-sm" onclick="shareCurrentTask()">'+(isShared?t('share.updateBtn'):t('share.shareBtn'))+'</button>'+
|
|
3898
4048
|
(isShared?'<button class="btn btn-sm btn-ghost" onclick="unshareCurrentTask()">'+t('share.unshareBtn')+'</button>':'');
|
|
3899
4049
|
}
|
|
3900
4050
|
|
|
3901
4051
|
async function shareCurrentTask(){
|
|
3902
4052
|
if(!currentTaskDetail) return;
|
|
3903
|
-
const visibility=
|
|
4053
|
+
const visibility='public';
|
|
3904
4054
|
try{
|
|
3905
4055
|
const r=await fetch('/api/sharing/tasks/share',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({taskId:currentTaskDetail.id,visibility:visibility})});
|
|
3906
4056
|
const d=await r.json();
|
|
@@ -3925,21 +4075,16 @@ function renderSkillShareActions(skill){
|
|
|
3925
4075
|
const isShared=!!current;
|
|
3926
4076
|
var statusHtml='';
|
|
3927
4077
|
if(isShared){
|
|
3928
|
-
|
|
3929
|
-
statusHtml='<span style="display:inline-flex;align-items:center;gap:4px;padding:3px 10px;background:#22c55e22;border:1px solid #22c55e44;border-radius:12px;font-size:12px;color:#22c55e">\u2713 '+t('share.alreadyShared')+' ('+scopeLabel+')</span>';
|
|
4078
|
+
statusHtml='<span style="display:inline-flex;align-items:center;gap:4px;padding:3px 10px;background:#22c55e22;border:1px solid #22c55e44;border-radius:12px;font-size:12px;color:#22c55e">\u2713 '+t('share.alreadyShared')+'</span>';
|
|
3930
4079
|
}
|
|
3931
4080
|
el.innerHTML=statusHtml+
|
|
3932
|
-
'<select id="skillShareScope" class="filter-select" style="min-width:120px">'+
|
|
3933
|
-
'<option value="group"'+(current==='group'?' selected':'')+'>Share to Group</option>'+
|
|
3934
|
-
'<option value="public"'+(current==='public'?' selected':'')+'>Share to Public</option>'+
|
|
3935
|
-
'</select>'+
|
|
3936
4081
|
'<button class="btn btn-sm" onclick="shareCurrentSkill()">'+(isShared?t('share.updateBtn'):t('share.shareBtn'))+'</button>'+
|
|
3937
4082
|
(isShared?'<button class="btn btn-sm btn-ghost" onclick="unshareCurrentSkill()">'+t('share.unshareBtn')+'</button>':'');
|
|
3938
4083
|
}
|
|
3939
4084
|
|
|
3940
4085
|
async function shareCurrentSkill(){
|
|
3941
4086
|
if(!currentSkillDetail) return;
|
|
3942
|
-
const visibility=
|
|
4087
|
+
const visibility='public';
|
|
3943
4088
|
try{
|
|
3944
4089
|
const r=await fetch('/api/sharing/skills/share',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({skillId:currentSkillDetail.id,visibility:visibility})});
|
|
3945
4090
|
const d=await r.json();
|
|
@@ -5191,6 +5336,7 @@ async function saveConfig(){
|
|
|
5191
5336
|
cfg.sharing.hub={port:hubPort?Number(hubPort):18800};
|
|
5192
5337
|
if(hubTeamName) cfg.sharing.hub.teamName=hubTeamName;
|
|
5193
5338
|
if(hubTeamToken) cfg.sharing.hub.teamToken=hubTeamToken;
|
|
5339
|
+
cfg.sharing.client={hubAddress:'',userToken:'',teamToken:''};
|
|
5194
5340
|
}
|
|
5195
5341
|
if(sharingEnabled&&_sharingRole==='client'){
|
|
5196
5342
|
var clientAddr=document.getElementById('cfgClientHubAddress').value.trim();
|
|
@@ -5200,6 +5346,17 @@ async function saveConfig(){
|
|
|
5200
5346
|
if(clientAddr) cfg.sharing.client.hubAddress=clientAddr;
|
|
5201
5347
|
if(clientTeamToken) cfg.sharing.client.teamToken=clientTeamToken;
|
|
5202
5348
|
if(clientUserToken) cfg.sharing.client.userToken=clientUserToken;
|
|
5349
|
+
cfg.sharing.hub={port:18800,teamName:'',teamToken:''};
|
|
5350
|
+
if(clientAddr){
|
|
5351
|
+
try{
|
|
5352
|
+
var ips=await fetch('/api/local-ips').then(function(r){return r.json();});
|
|
5353
|
+
var localAddrs=['127.0.0.1','localhost','0.0.0.0'].concat(ips.ips||[]);
|
|
5354
|
+
var parsed=new URL(clientAddr.indexOf('://')>-1?clientAddr:'http://'+clientAddr);
|
|
5355
|
+
if(localAddrs.indexOf(parsed.hostname)>=0){
|
|
5356
|
+
done();toast(t('sharing.cannotJoinSelf'),'error');return;
|
|
5357
|
+
}
|
|
5358
|
+
}catch(e){}
|
|
5359
|
+
}
|
|
5203
5360
|
}
|
|
5204
5361
|
|
|
5205
5362
|
// 1) Embedding model is required
|
|
@@ -5377,7 +5534,7 @@ function fillDays(rows,days){
|
|
|
5377
5534
|
const row=map.get(dateStr)||{};
|
|
5378
5535
|
out.push({date:dateStr,count:row.count??0,list:row.list??0,search:row.search??0,total:(row.list??0)+(row.search??0)});
|
|
5379
5536
|
}
|
|
5380
|
-
if(days>
|
|
5537
|
+
if(days>60){
|
|
5381
5538
|
const weeks=[];let i=0;
|
|
5382
5539
|
while(i<out.length){
|
|
5383
5540
|
const chunk=out.slice(i,i+7);
|
|
@@ -5395,19 +5552,23 @@ function fillDays(rows,days){
|
|
|
5395
5552
|
}
|
|
5396
5553
|
|
|
5397
5554
|
function renderBars(el,data,valueKey,H){
|
|
5398
|
-
|
|
5399
|
-
if(vals.every(v
|
|
5400
|
-
|
|
5401
|
-
|
|
5402
|
-
|
|
5403
|
-
el.innerHTML=data.map(r
|
|
5404
|
-
|
|
5405
|
-
|
|
5555
|
+
var vals=data.map(function(d){return d[valueKey]??0;});
|
|
5556
|
+
if(vals.every(function(v){return v===0;})){el.innerHTML='<div style="color:var(--text-muted);font-size:13px;padding:40px;text-align:center">'+t('chart.nodata')+'</div>';return;}
|
|
5557
|
+
var max=Math.max(1,Math.max.apply(null,vals));
|
|
5558
|
+
var n=data.length;
|
|
5559
|
+
var labelStep=n<=7?1:(n<=14?2:5);
|
|
5560
|
+
el.innerHTML=data.map(function(r,idx){
|
|
5561
|
+
var v=r[valueKey]??0;
|
|
5562
|
+
var rawDate=r.date.includes('~')?r.date:(r.date.length>5?r.date.slice(5):'');
|
|
5563
|
+
var showLabel=(idx%labelStep===0)||(idx===n-1);
|
|
5564
|
+
var label=showLabel?rawDate:'';
|
|
5565
|
+
var tipDate=r.date.length>=10?r.date.slice(5,10):'';
|
|
5566
|
+
var tipText=tipDate?(tipDate+': '+v):(''+v);
|
|
5406
5567
|
if(v===0){
|
|
5407
|
-
return '<div class="chart-bar-wrap"
|
|
5568
|
+
return '<div class="chart-bar-wrap"><div class="chart-tip">'+tipText+'</div><div class="chart-bar-col"><div class="chart-bar zero" style="height:3px"></div></div><div class="chart-bar-label">'+label+'</div></div>';
|
|
5408
5569
|
}
|
|
5409
|
-
|
|
5410
|
-
return '<div class="chart-bar-wrap"
|
|
5570
|
+
var h=Math.max(8,Math.round((v/max)*H));
|
|
5571
|
+
return '<div class="chart-bar-wrap"><div class="chart-tip">'+tipText+'</div><div class="chart-bar-col"><div class="chart-bar" style="height:'+h+'px"></div></div><div class="chart-bar-label">'+label+'</div></div>';
|
|
5411
5572
|
}).join('');
|
|
5412
5573
|
}
|
|
5413
5574
|
|
|
@@ -5418,25 +5579,31 @@ function renderChartWrites(rows){
|
|
|
5418
5579
|
}
|
|
5419
5580
|
|
|
5420
5581
|
function renderChartCalls(rows){
|
|
5421
|
-
|
|
5422
|
-
|
|
5423
|
-
|
|
5424
|
-
if(vals.every(v
|
|
5425
|
-
|
|
5426
|
-
|
|
5427
|
-
|
|
5428
|
-
|
|
5582
|
+
var el=document.getElementById('chartCalls');
|
|
5583
|
+
var filled=fillDays(rows?.map(function(r){return {date:r.date,list:r.list,search:r.search};}),metricsDays);
|
|
5584
|
+
var vals=filled.map(function(f){return f.total;});
|
|
5585
|
+
if(vals.every(function(v){return v===0;})){el.innerHTML='<div style="color:var(--text-muted);font-size:13px;padding:40px;text-align:center">'+t('chart.nocalls')+'</div>';return;}
|
|
5586
|
+
var max=Math.max(1,Math.max.apply(null,vals));
|
|
5587
|
+
var H=160;
|
|
5588
|
+
var n=filled.length;
|
|
5589
|
+
var labelStep=n<=7?1:(n<=14?2:5);
|
|
5590
|
+
el.innerHTML=filled.map(function(r,idx){
|
|
5591
|
+
var rawDate=r.date.includes('~')?r.date:(r.date.length>5?r.date.slice(5):'');
|
|
5592
|
+
var showLabel=(idx%labelStep===0)||(idx===n-1);
|
|
5593
|
+
var label=showLabel?rawDate:'';
|
|
5594
|
+
var tipDate=r.date.length>=10?r.date.slice(5,10):'';
|
|
5429
5595
|
if(r.total===0){
|
|
5430
|
-
|
|
5596
|
+
var tipZero=tipDate?(tipDate+': 0'):'0';
|
|
5597
|
+
return '<div class="chart-bar-wrap"><div class="chart-tip">'+tipZero+'</div><div class="chart-bar-col"><div class="chart-bar zero" style="height:3px"></div></div><div class="chart-bar-label">'+label+'</div></div>';
|
|
5431
5598
|
}
|
|
5432
|
-
|
|
5433
|
-
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
|
-
|
|
5599
|
+
var totalH=Math.max(8,Math.round((r.total/max)*H));
|
|
5600
|
+
var listH=r.list?Math.max(4,Math.round((r.list/r.total)*totalH)):0;
|
|
5601
|
+
var searchH=r.search?totalH-listH:0;
|
|
5602
|
+
var tip=(tipDate?tipDate+' - ':'')+'List: '+r.list+', Search: '+r.search;
|
|
5603
|
+
var bars='';
|
|
5437
5604
|
if(searchH>0) bars+='<div class="chart-bar violet" style="height:'+searchH+'px"></div>';
|
|
5438
5605
|
if(listH>0) bars+='<div class="chart-bar" style="height:'+listH+'px"></div>';
|
|
5439
|
-
return '<div class="chart-bar-wrap"><div class="chart-tip">'+tip+'</div><div class="chart-bar-col"><div style="display:flex;flex-direction:column;gap:1px">'+bars+'</div></div><div class="chart-bar-label">'+label+'</div></div>';
|
|
5606
|
+
return '<div class="chart-bar-wrap"><div class="chart-tip">'+tip+'</div><div class="chart-bar-col"><div style="display:flex;flex-direction:column;gap:1px;align-items:center;width:100%">'+bars+'</div></div><div class="chart-bar-label">'+label+'</div></div>';
|
|
5440
5607
|
}).join('');
|
|
5441
5608
|
}
|
|
5442
5609
|
|
|
@@ -6014,38 +6181,50 @@ function scrollToMemory(targetId){
|
|
|
6014
6181
|
}
|
|
6015
6182
|
showMemoryModal(targetId);
|
|
6016
6183
|
}
|
|
6184
|
+
function fmtModalDate(v){
|
|
6185
|
+
if(!v) return '-';
|
|
6186
|
+
var d=new Date(v);
|
|
6187
|
+
if(isNaN(d.getTime())) return '-';
|
|
6188
|
+
return d.toLocaleString(dateLoc());
|
|
6189
|
+
}
|
|
6017
6190
|
async function showMemoryModal(chunkId){
|
|
6018
|
-
|
|
6019
|
-
|
|
6020
|
-
body.innerHTML='<div style="text-align:center;padding:
|
|
6191
|
+
var overlay=document.getElementById('memoryModal');
|
|
6192
|
+
var body=document.getElementById('memoryModalBody');
|
|
6193
|
+
body.innerHTML='<div style="text-align:center;padding:56px;color:var(--text-sec)"><div class="spinner" style="margin:0 auto 14px"></div><div style="font-size:12px;letter-spacing:.04em">'+t('memory.detail.loading')+'</div></div>';
|
|
6021
6194
|
overlay.classList.add('show');
|
|
6022
6195
|
try{
|
|
6023
|
-
|
|
6024
|
-
if(!res.ok){body.innerHTML='<div style="text-align:center;padding:
|
|
6025
|
-
|
|
6026
|
-
|
|
6027
|
-
|
|
6028
|
-
|
|
6029
|
-
|
|
6030
|
-
|
|
6031
|
-
|
|
6032
|
-
|
|
6033
|
-
|
|
6034
|
-
|
|
6035
|
-
|
|
6036
|
-
|
|
6037
|
-
|
|
6038
|
-
|
|
6039
|
-
|
|
6040
|
-
|
|
6041
|
-
|
|
6042
|
-
if(
|
|
6043
|
-
|
|
6044
|
-
if(m.
|
|
6045
|
-
if(m.
|
|
6046
|
-
|
|
6047
|
-
|
|
6048
|
-
|
|
6196
|
+
var res=await fetch('/api/memory/'+encodeURIComponent(chunkId));
|
|
6197
|
+
if(!res.ok){body.innerHTML='<div style="text-align:center;padding:56px"><div style="font-size:32px;margin-bottom:12px">\u{1F50D}</div><div style="color:#f87171;font-size:13px">'+t('memory.detail.notFound')+'</div></div>';return;}
|
|
6198
|
+
var data=await res.json();
|
|
6199
|
+
var m=data.memory;
|
|
6200
|
+
var role=(m.role||'unknown').toUpperCase();
|
|
6201
|
+
var roleCls=(m.role||'').toLowerCase();
|
|
6202
|
+
var ds=m.dedup_status||'active';
|
|
6203
|
+
var h='<div class="mm-hero">';
|
|
6204
|
+
h+='<div class="mm-hero-row">';
|
|
6205
|
+
h+='<span class="mm-role-chip '+roleCls+'">'+role+'</span>';
|
|
6206
|
+
if(ds!=='active') h+='<span class="mm-dedup-chip '+(ds==='duplicate'?'duplicate':'merged')+'">'+(ds==='duplicate'?'\u274C':'\u{1F504}')+' '+ds+'</span>';
|
|
6207
|
+
h+='<span class="mm-id" onclick="navigator.clipboard.writeText(\\''+esc(m.id)+'\\');toast(\\'ID copied\\',\\'success\\')" title="'+t('memory.detail.copyId')+'">'+esc(m.id.slice(0,12))+'</span>';
|
|
6208
|
+
h+='</div>';
|
|
6209
|
+
if(m.summary) h+='<div class="mm-summary">'+esc(m.summary)+'</div>';
|
|
6210
|
+
h+='</div>';
|
|
6211
|
+
if(m.content){
|
|
6212
|
+
h+='<div class="mm-section"><div class="mm-section-label">Content</div><pre class="mm-content">'+esc(m.content)+'</pre></div>';
|
|
6213
|
+
}
|
|
6214
|
+
h+='<div class="mm-meta">';
|
|
6215
|
+
if(m.session_key) h+='<div class="mm-meta-chip"><strong>Session</strong><span>'+esc(m.session_key.slice(0,12))+'</span></div>';
|
|
6216
|
+
h+='<div class="mm-meta-chip"><strong>'+t('memory.detail.created')+'</strong><span>'+fmtModalDate(m.created_at)+'</span></div>';
|
|
6217
|
+
if(m.updated_at) h+='<div class="mm-meta-chip"><strong>'+t('memory.detail.updated')+'</strong><span>'+fmtModalDate(m.updated_at)+'</span></div>';
|
|
6218
|
+
if(m.kind) h+='<div class="mm-meta-chip"><strong>Kind</strong><span>'+esc(m.kind)+'</span></div>';
|
|
6219
|
+
h+='</div>';
|
|
6220
|
+
if(m.dedup_reason){
|
|
6221
|
+
h+='<div class="mm-dedup"><div class="mm-dedup-box">'+esc(m.dedup_reason)+'</div></div>';
|
|
6222
|
+
}
|
|
6223
|
+
if(m.dedup_target&&m.dedup_target!==chunkId){
|
|
6224
|
+
h+='<div class="mm-footer"><span class="dedup-target-link" onclick="closeMemoryModal();scrollToMemory(\\''+m.dedup_target+'\\')">'+t('memory.detail.viewTarget')+' '+m.dedup_target.slice(0,8)+'...</span></div>';
|
|
6225
|
+
}
|
|
6226
|
+
body.innerHTML=h;
|
|
6227
|
+
}catch(e){body.innerHTML='<div style="text-align:center;padding:56px"><div style="font-size:32px;margin-bottom:12px">\u26A0\uFE0F</div><div style="color:#f87171;font-size:13px">'+esc(String(e))+'</div></div>';}
|
|
6049
6228
|
}
|
|
6050
6229
|
function closeMemoryModal(){document.getElementById('memoryModal').classList.remove('show');}
|
|
6051
6230
|
|
|
@@ -6843,8 +7022,8 @@ checkAuth();
|
|
|
6843
7022
|
<div class="memory-modal-overlay" id="memoryModal" onclick="if(event.target===this)closeMemoryModal()">
|
|
6844
7023
|
<div class="memory-modal">
|
|
6845
7024
|
<div class="memory-modal-title">
|
|
6846
|
-
<span>Memory Detail</span>
|
|
6847
|
-
<button class="
|
|
7025
|
+
<div class="mm-tl"><div class="mm-tl-icon">\u{1F9E0}</div><span data-i18n="memory.detail.title">Memory Detail</span></div>
|
|
7026
|
+
<button class="mm-close" onclick="closeMemoryModal()" title="Close">×</button>
|
|
6848
7027
|
</div>
|
|
6849
7028
|
<div class="memory-modal-body" id="memoryModalBody"></div>
|
|
6850
7029
|
</div>
|