@memtensor/memos-local-openclaw-plugin 1.0.4-beta.7 → 1.0.4-beta.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/capture/index.d.ts.map +1 -1
- package/dist/capture/index.js +6 -0
- package/dist/capture/index.js.map +1 -1
- package/dist/client/connector.d.ts.map +1 -1
- package/dist/client/connector.js +61 -7
- package/dist/client/connector.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +0 -2
- package/dist/config.js.map +1 -1
- package/dist/hub/server.d.ts +7 -0
- package/dist/hub/server.d.ts.map +1 -1
- package/dist/hub/server.js +171 -8
- package/dist/hub/server.js.map +1 -1
- package/dist/ingest/providers/index.d.ts.map +1 -1
- package/dist/ingest/providers/index.js +37 -6
- package/dist/ingest/providers/index.js.map +1 -1
- package/dist/recall/engine.d.ts.map +1 -1
- package/dist/recall/engine.js +78 -1
- package/dist/recall/engine.js.map +1 -1
- package/dist/shared/llm-call.d.ts +1 -0
- package/dist/shared/llm-call.d.ts.map +1 -1
- package/dist/shared/llm-call.js +82 -8
- package/dist/shared/llm-call.js.map +1 -1
- package/dist/skill/evolver.d.ts +2 -0
- package/dist/skill/evolver.d.ts.map +1 -1
- package/dist/skill/evolver.js +3 -0
- package/dist/skill/evolver.js.map +1 -1
- package/dist/storage/sqlite.d.ts +5 -1
- package/dist/storage/sqlite.d.ts.map +1 -1
- package/dist/storage/sqlite.js +13 -4
- package/dist/storage/sqlite.js.map +1 -1
- package/dist/telemetry.d.ts +12 -5
- package/dist/telemetry.d.ts.map +1 -1
- package/dist/telemetry.js +135 -38
- package/dist/telemetry.js.map +1 -1
- package/dist/types.d.ts +1 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/viewer/html.d.ts.map +1 -1
- package/dist/viewer/html.js +735 -285
- package/dist/viewer/html.js.map +1 -1
- package/dist/viewer/server.d.ts +16 -0
- package/dist/viewer/server.d.ts.map +1 -1
- package/dist/viewer/server.js +349 -21
- package/dist/viewer/server.js.map +1 -1
- package/index.ts +26 -2
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -2
- package/scripts/postinstall.cjs +1 -1
- package/src/capture/index.ts +8 -0
- package/src/client/connector.ts +62 -7
- package/src/config.ts +0 -2
- package/src/hub/server.ts +168 -8
- package/src/ingest/providers/index.ts +41 -7
- package/src/recall/engine.ts +73 -1
- package/src/shared/llm-call.ts +97 -9
- package/src/skill/evolver.ts +5 -0
- package/src/storage/sqlite.ts +19 -6
- package/src/telemetry.ts +152 -39
- package/src/types.ts +1 -2
- package/src/viewer/html.ts +735 -285
- package/src/viewer/server.ts +322 -21
package/src/viewer/html.ts
CHANGED
|
@@ -12,6 +12,7 @@ return `<!DOCTYPE html>
|
|
|
12
12
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
13
13
|
<style>
|
|
14
14
|
*{margin:0;padding:0;box-sizing:border-box}
|
|
15
|
+
html{overflow-y:scroll}
|
|
15
16
|
:root{
|
|
16
17
|
--bg:#0b0d11;--bg-card:#12141a;--bg-card-hover:#1a1d25;
|
|
17
18
|
--border:rgba(255,255,255,.08);--border-glow:rgba(255,255,255,.14);
|
|
@@ -106,7 +107,8 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
106
107
|
|
|
107
108
|
/* ─── App Layout (dark dashboard, same as www) ─── */
|
|
108
109
|
.app{display:none;flex-direction:column;min-height:100vh}
|
|
109
|
-
.topbar{background:rgba(11,13,17,.88);border-bottom:1px solid var(--border);
|
|
110
|
+
.topbar{background:rgba(11,13,17,.88);border-bottom:1px solid var(--border);height:56px;display:flex;align-items:center;position:sticky;top:0;z-index:100;backdrop-filter:blur(12px)}
|
|
111
|
+
.topbar-inner{display:flex;align-items:center;width:100%;max-width:1400px;margin:0 auto;padding:0 32px}
|
|
110
112
|
.topbar .brand{display:flex;align-items:center;gap:8px;font-weight:700;font-size:15px;color:var(--text);letter-spacing:-.02em;flex-shrink:0}
|
|
111
113
|
.topbar .brand .icon{width:24px;height:24px;display:flex;align-items:center;justify-content:center;font-size:18px;background:none;border-radius:0}
|
|
112
114
|
.topbar .brand .brand-title{font-size:13px;font-weight:500;opacity:.7}
|
|
@@ -192,50 +194,90 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
192
194
|
.pending-user-name{font-size:14px;font-weight:700;color:var(--text)}
|
|
193
195
|
.pending-user-meta{font-size:12px;color:var(--text-sec);margin-top:4px}
|
|
194
196
|
.pending-user-actions{display:flex;gap:8px;margin-top:10px}
|
|
195
|
-
/* ─── Admin Panel ─── */
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
.admin-
|
|
204
|
-
.admin-
|
|
205
|
-
.admin-
|
|
206
|
-
.admin-
|
|
207
|
-
.admin-
|
|
208
|
-
.admin-
|
|
209
|
-
.admin-
|
|
210
|
-
.admin-stat-
|
|
211
|
-
.admin-stat-box:
|
|
212
|
-
.admin-stat-box
|
|
213
|
-
.admin-stat-box
|
|
214
|
-
.admin-stat-box
|
|
215
|
-
.admin-
|
|
216
|
-
.admin-
|
|
217
|
-
.admin-
|
|
218
|
-
.admin-
|
|
197
|
+
/* ─── Admin Panel (Cyber) ─── */
|
|
198
|
+
@keyframes adminGlow{0%,100%{opacity:.6}50%{opacity:1}}
|
|
199
|
+
@keyframes adminPulse{0%{box-shadow:0 0 0 0 rgba(99,102,241,.4)}70%{box-shadow:0 0 0 8px rgba(99,102,241,0)}100%{box-shadow:0 0 0 0 rgba(99,102,241,0)}}
|
|
200
|
+
@keyframes adminScanline{0%{background-position:0 0}100%{background-position:0 100%}}
|
|
201
|
+
@keyframes adminSlideIn{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}
|
|
202
|
+
@keyframes adminCountUp{from{opacity:0;transform:translateY(8px) scale(.8)}to{opacity:1;transform:translateY(0) scale(1)}}
|
|
203
|
+
@keyframes pendingPulse{0%,100%{border-color:rgba(251,191,36,.3)}50%{border-color:rgba(251,191,36,.7)}}
|
|
204
|
+
@keyframes dotBreathe{0%,100%{transform:scale(1);opacity:.8}50%{transform:scale(1.3);opacity:1}}
|
|
205
|
+
.admin-header{position:relative;padding:32px 32px 24px;background:linear-gradient(135deg,rgba(99,102,241,.06) 0%,rgba(6,182,212,.04) 50%,rgba(139,92,246,.06) 100%);border:1px solid rgba(99,102,241,.15);border-radius:20px;margin-bottom:24px;overflow:hidden}
|
|
206
|
+
.admin-header::before{content:'';position:absolute;top:0;left:0;right:0;height:2px;background:linear-gradient(90deg,transparent,var(--pri),var(--cyan),var(--violet),transparent);animation:adminGlow 3s ease-in-out infinite}
|
|
207
|
+
.admin-header::after{content:'';position:absolute;inset:0;background:repeating-linear-gradient(0deg,transparent,transparent 2px,rgba(99,102,241,.015) 2px,rgba(99,102,241,.015) 4px);background-size:100% 8px;animation:adminScanline 8s linear infinite;pointer-events:none}
|
|
208
|
+
.admin-header-top{display:flex;justify-content:space-between;align-items:center;position:relative;z-index:1}
|
|
209
|
+
.admin-header h2{font-size:18px;font-weight:800;color:var(--text);display:flex;align-items:center;gap:12px;margin:0;letter-spacing:-.01em}
|
|
210
|
+
.admin-header h2 .ah-icon{width:40px;height:40px;border-radius:12px;background:linear-gradient(135deg,var(--pri),var(--violet));display:flex;align-items:center;justify-content:center;font-size:20px;box-shadow:0 4px 20px rgba(99,102,241,.3),inset 0 1px 0 rgba(255,255,255,.15);animation:adminPulse 2.5s infinite}
|
|
211
|
+
.admin-header-sub{font-size:11px;color:var(--text-muted);margin-top:6px;position:relative;z-index:1;letter-spacing:.02em}
|
|
212
|
+
.admin-stat-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:10px;margin-top:20px;position:relative;z-index:1}
|
|
213
|
+
.admin-stat-box{position:relative;text-align:center;padding:18px 10px 16px;background:rgba(var(--bg-card-rgb,30,30,40),.6);backdrop-filter:blur(12px);border:1px solid rgba(99,102,241,.12);border-radius:14px;overflow:hidden;transition:all .25s cubic-bezier(.4,0,.2,1)}
|
|
214
|
+
.admin-stat-box:hover{border-color:rgba(99,102,241,.35);transform:translateY(-2px);box-shadow:0 8px 24px rgba(99,102,241,.12)}
|
|
215
|
+
.admin-stat-box::before{content:'';position:absolute;top:0;left:0;right:0;height:2px;opacity:.8}
|
|
216
|
+
.admin-stat-box:nth-child(1)::before{background:linear-gradient(90deg,transparent,#22c55e,transparent)}
|
|
217
|
+
.admin-stat-box:nth-child(2)::before{background:linear-gradient(90deg,transparent,#fbbf24,transparent)}
|
|
218
|
+
.admin-stat-box:nth-child(3)::before{background:linear-gradient(90deg,transparent,#8b5cf6,transparent)}
|
|
219
|
+
.admin-stat-box:nth-child(4)::before{background:linear-gradient(90deg,transparent,#06b6d4,transparent)}
|
|
220
|
+
.admin-stat-box:nth-child(5)::before{background:linear-gradient(90deg,transparent,#6366f1,transparent)}
|
|
221
|
+
.admin-stat-box:nth-child(6)::before{background:linear-gradient(90deg,transparent,#f43f5e,transparent)}
|
|
222
|
+
.admin-stat-box::after{content:'';position:absolute;inset:0;background:radial-gradient(circle at 50% 0%,rgba(99,102,241,.06),transparent 70%);pointer-events:none}
|
|
223
|
+
.admin-stat-box .as-icon{font-size:18px;margin-bottom:6px;display:block;filter:drop-shadow(0 2px 4px rgba(0,0,0,.15))}
|
|
224
|
+
.admin-stat-box .val{font-size:26px;font-weight:800;color:var(--text);font-variant-numeric:tabular-nums;animation:adminCountUp .4s ease-out;text-shadow:0 0 20px rgba(99,102,241,.15)}
|
|
225
|
+
.admin-stat-box .lbl{font-size:10px;color:var(--text-muted);margin-top:4px;letter-spacing:.05em;text-transform:uppercase}
|
|
226
|
+
.admin-tabs{display:flex;gap:3px;padding:3px;background:rgba(99,102,241,.03);border:1px solid rgba(99,102,241,.1);border-radius:14px;overflow-x:auto;-webkit-overflow-scrolling:touch;margin-bottom:24px;backdrop-filter:blur(8px)}
|
|
227
|
+
.admin-tab{position:relative;display:flex;align-items:center;gap:6px;padding:10px 18px;border:none;background:transparent;color:var(--text-muted);font-size:13px;font-weight:500;cursor:pointer;border-radius:11px;transition:all .25s cubic-bezier(.4,0,.2,1);white-space:nowrap;font-family:inherit}
|
|
228
|
+
.admin-tab:hover{background:rgba(99,102,241,.08);color:var(--text)}
|
|
229
|
+
.admin-tab.active{background:linear-gradient(135deg,rgba(99,102,241,.12),rgba(139,92,246,.08));color:var(--text);font-weight:600;box-shadow:0 2px 12px rgba(99,102,241,.1),inset 0 1px 0 rgba(255,255,255,.05);border:1px solid rgba(99,102,241,.15)}
|
|
219
230
|
.admin-tab .at-icon{font-size:14px;line-height:1}
|
|
220
|
-
.admin-tab .at-count{font-size:10px;font-weight:700;padding:
|
|
221
|
-
.admin-tab.active .at-count{background:rgba(99,102,241,.15)}
|
|
231
|
+
.admin-tab .at-count{font-size:10px;font-weight:700;padding:2px 7px;border-radius:8px;background:rgba(99,102,241,.12);color:var(--pri);min-width:18px;text-align:center;transition:all .2s}
|
|
232
|
+
.admin-tab.active .at-count{background:rgba(99,102,241,.2);box-shadow:0 0 8px rgba(99,102,241,.15)}
|
|
222
233
|
.admin-panel{display:none}
|
|
223
|
-
.admin-panel.active{display:block}
|
|
224
|
-
.admin-card{border:1px solid var(--border);border-radius:
|
|
234
|
+
.admin-panel.active{display:block;animation:adminSlideIn .3s ease-out}
|
|
235
|
+
.admin-card{border:1px solid var(--border);border-radius:14px;padding:18px 20px;background:var(--bg-card);margin-bottom:12px;transition:all .25s cubic-bezier(.4,0,.2,1);position:relative;overflow:hidden}
|
|
225
236
|
.admin-card-clickable{cursor:pointer}
|
|
226
|
-
.admin-card::before{content:'';position:absolute;top:0;left:0;bottom:0;width:3px;border-radius:3px 0 0 3px;background:var(--pri);opacity:.
|
|
227
|
-
.admin-card:hover{border-color:rgba(99,102,241,.25);box-shadow:0
|
|
237
|
+
.admin-card::before{content:'';position:absolute;top:0;left:0;bottom:0;width:3px;border-radius:3px 0 0 3px;background:var(--pri);opacity:.4;transition:opacity .2s}
|
|
238
|
+
.admin-card:hover{border-color:rgba(99,102,241,.25);box-shadow:0 4px 20px rgba(99,102,241,.06);transform:translateY(-1px)}
|
|
239
|
+
.admin-card:hover::before{opacity:.8}
|
|
228
240
|
.admin-card-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:6px}
|
|
229
241
|
.admin-card-title{font-size:14px;font-weight:700;color:var(--text);flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
230
242
|
.admin-card-meta{font-size:12px;color:var(--text-muted);line-height:1.5}
|
|
231
|
-
.au-contrib{display:flex;gap:
|
|
232
|
-
.au-contrib-item{font-size:12px;color:var(--text-sec);display:flex;align-items:center;gap:
|
|
233
|
-
.au-contrib-num{font-size:
|
|
234
|
-
.au-info{display:flex;flex-wrap:wrap;gap:6px
|
|
235
|
-
.au-info-item{color:var(--text-muted);white-space:nowrap}
|
|
243
|
+
.au-contrib{display:flex;gap:20px;padding:12px 0;margin:8px 0;border-top:1px solid rgba(99,102,241,.08);border-bottom:1px solid rgba(99,102,241,.08)}
|
|
244
|
+
.au-contrib-item{font-size:12px;color:var(--text-sec);display:flex;align-items:center;gap:5px}
|
|
245
|
+
.au-contrib-num{font-size:20px;font-weight:800;line-height:1;font-variant-numeric:tabular-nums}
|
|
246
|
+
.au-info{display:flex;flex-wrap:wrap;gap:6px 16px;padding:8px 0;font-size:11px}
|
|
247
|
+
.au-info-item{color:var(--text-muted);white-space:nowrap;display:inline-flex;align-items:center;gap:3px}
|
|
248
|
+
.au-status-dot{display:inline-block;width:8px;height:8px;border-radius:50%;margin-right:5px;vertical-align:middle;flex-shrink:0;transition:all .3s}
|
|
249
|
+
.au-status-dot.online{background:#22c55e;box-shadow:0 0 8px rgba(34,197,94,.6),0 0 16px rgba(34,197,94,.2);animation:dotBreathe 2s ease-in-out infinite}
|
|
250
|
+
.au-status-dot.offline{background:#6b7280;box-shadow:none}
|
|
251
|
+
.au-status-text{font-size:11px;font-weight:600;letter-spacing:.02em}
|
|
252
|
+
.au-status-text.online{color:#22c55e;text-shadow:0 0 8px rgba(34,197,94,.3)}
|
|
253
|
+
.au-status-text.offline{color:#6b7280}
|
|
254
|
+
.au-group-header{font-size:13px;font-weight:700;color:var(--text-sec);margin:20px 0 10px;display:flex;align-items:center;gap:8px;letter-spacing:.02em}
|
|
255
|
+
.au-group-header:first-child{margin-top:0}
|
|
256
|
+
.au-group-header .au-group-dot{display:inline-block;width:8px;height:8px;border-radius:50%}
|
|
257
|
+
.au-group-header .au-group-dot.online{background:#22c55e;box-shadow:0 0 6px rgba(34,197,94,.5)}
|
|
258
|
+
.au-group-header .au-group-dot.offline{background:#6b7280}
|
|
259
|
+
.au-group-header .au-group-count{font-size:12px;font-weight:400;color:var(--text-muted)}
|
|
260
|
+
.au-card.au-offline{opacity:.55}
|
|
261
|
+
.au-card.au-offline:hover{opacity:.8}
|
|
262
|
+
.au-card.au-offline::before{background:#6b7280}
|
|
263
|
+
.au-card.au-online::before{background:#22c55e;box-shadow:0 0 8px rgba(34,197,94,.3)}
|
|
264
|
+
.admin-pending-section{position:relative;margin-bottom:20px;padding:20px;border-radius:16px;border:1px solid rgba(251,191,36,.25);background:linear-gradient(135deg,rgba(251,191,36,.04),rgba(245,158,11,.02));animation:pendingPulse 3s ease-in-out infinite;overflow:hidden}
|
|
265
|
+
.admin-pending-section::before{content:'';position:absolute;top:0;left:0;right:0;height:2px;background:linear-gradient(90deg,transparent,#fbbf24,#f59e0b,transparent)}
|
|
266
|
+
.admin-pending-section h3{font-size:14px;font-weight:700;color:#fbbf24;margin:0 0 14px;display:flex;align-items:center;gap:8px}
|
|
267
|
+
.admin-pending-section h3 .pending-count{display:inline-flex;align-items:center;justify-content:center;min-width:22px;height:22px;padding:0 6px;border-radius:11px;background:rgba(251,191,36,.2);font-size:12px;font-weight:800;color:#fbbf24}
|
|
268
|
+
.admin-pending-card{border:1px solid rgba(251,191,36,.15);border-radius:12px;padding:16px 18px;background:rgba(251,191,36,.03);margin-bottom:8px;transition:all .2s;position:relative;overflow:hidden}
|
|
269
|
+
.admin-pending-card::before{content:'';position:absolute;top:0;left:0;bottom:0;width:3px;background:linear-gradient(180deg,#fbbf24,#f59e0b);border-radius:3px 0 0 3px}
|
|
270
|
+
.admin-pending-card:hover{border-color:rgba(251,191,36,.35);box-shadow:0 4px 16px rgba(251,191,36,.08)}
|
|
271
|
+
.admin-pending-card .apc-name{font-size:14px;font-weight:700;color:var(--text)}
|
|
272
|
+
.admin-pending-card .apc-meta{font-size:11px;color:var(--text-muted);margin-top:4px;display:flex;align-items:center;gap:6px}
|
|
273
|
+
.admin-pending-card .apc-actions{display:flex;gap:8px;margin-top:12px}
|
|
274
|
+
.admin-pending-card .apc-actions .btn-approve{background:linear-gradient(135deg,#22c55e,#16a34a);color:#fff;border:none;padding:6px 18px;border-radius:8px;font-size:12px;font-weight:600;cursor:pointer;transition:all .2s;box-shadow:0 2px 8px rgba(34,197,94,.25)}
|
|
275
|
+
.admin-pending-card .apc-actions .btn-approve:hover{transform:translateY(-1px);box-shadow:0 4px 16px rgba(34,197,94,.35)}
|
|
276
|
+
.admin-pending-card .apc-actions .btn-reject{background:transparent;color:var(--rose);border:1px solid rgba(244,63,94,.2);padding:6px 14px;border-radius:8px;font-size:12px;font-weight:500;cursor:pointer;transition:all .2s}
|
|
277
|
+
.admin-pending-card .apc-actions .btn-reject:hover{background:rgba(244,63,94,.06);border-color:rgba(244,63,94,.4)}
|
|
236
278
|
.admin-card-tags{display:flex;gap:5px;margin:8px 0;align-items:center}
|
|
237
279
|
.admin-card-tags-left{display:flex;flex-wrap:wrap;gap:5px;align-items:center;flex:1;min-width:0}
|
|
238
|
-
.admin-card-tag{display:inline-flex;align-items:center;gap:3px;padding:
|
|
280
|
+
.admin-card-tag{display:inline-flex;align-items:center;gap:3px;padding:3px 10px;border-radius:6px;font-size:11px;font-weight:600;letter-spacing:.01em}
|
|
239
281
|
.admin-card-tag.tag-role{background:rgba(99,102,241,.1);color:var(--pri)}
|
|
240
282
|
.admin-card-tag.tag-kind{background:rgba(245,158,11,.1);color:#f59e0b}
|
|
241
283
|
.admin-card-tag.tag-owner{background:rgba(34,197,94,.1);color:#22c55e}
|
|
@@ -243,16 +285,16 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
243
285
|
.admin-card-tag.tag-version{background:rgba(139,92,246,.1);color:#8b5cf6}
|
|
244
286
|
.admin-card-tag.tag-visibility{background:rgba(99,102,241,.08);color:var(--pri)}
|
|
245
287
|
.admin-card-tag.tag-group{background:rgba(139,92,246,.08);color:#8b5cf6}
|
|
246
|
-
.admin-card-preview{font-size:12px;color:var(--text-sec);line-height:1.5;margin:8px 0;padding:
|
|
247
|
-
.admin-card-actions{display:inline-flex;gap:
|
|
288
|
+
.admin-card-preview{font-size:12px;color:var(--text-sec);line-height:1.5;margin:8px 0;padding:10px 12px;background:rgba(99,102,241,.02);border-radius:10px;border:1px solid rgba(99,102,241,.08);max-height:60px;overflow:hidden;white-space:pre-wrap;word-break:break-all}
|
|
289
|
+
.admin-card-actions{display:inline-flex;gap:6px;margin-left:auto;align-items:center;flex-shrink:0}
|
|
248
290
|
.admin-card-time{font-size:11px;color:var(--text-muted)}
|
|
249
|
-
.admin-card-detail{display:none;margin-top:0;padding:20px 24px 24px;border-top:1px dashed
|
|
291
|
+
.admin-card-detail{display:none;margin-top:0;padding:20px 24px 24px;border-top:1px dashed rgba(99,102,241,.12);background:linear-gradient(180deg,rgba(99,102,241,.02) 0%,transparent 60%);animation:adminDetailIn .25s ease}
|
|
250
292
|
@keyframes adminDetailIn{from{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:translateY(0)}}
|
|
251
293
|
.admin-card.expanded .admin-card-detail{display:block}
|
|
252
|
-
.admin-card.expanded{border-color:rgba(99,102,241,.3);box-shadow:0 4px 24px rgba(99,102,241,.
|
|
294
|
+
.admin-card.expanded{border-color:rgba(99,102,241,.3);box-shadow:0 4px 24px rgba(99,102,241,.1),0 0 0 1px rgba(99,102,241,.08)}
|
|
253
295
|
.admin-card-detail-meta{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:18px;font-size:12px;color:var(--text-muted)}
|
|
254
|
-
.admin-card-detail-meta .meta-item{display:inline-flex;align-items:center;gap:4px;padding:5px 12px;background:
|
|
255
|
-
.admin-card-detail-meta .meta-item:hover{border-color:rgba(99,102,241,.25);background:rgba(99,102,241,.
|
|
296
|
+
.admin-card-detail-meta .meta-item{display:inline-flex;align-items:center;gap:4px;padding:5px 12px;background:rgba(99,102,241,.03);border:1px solid rgba(99,102,241,.08);border-radius:20px;font-size:11px;color:var(--text-sec);transition:all .2s}
|
|
297
|
+
.admin-card-detail-meta .meta-item:hover{border-color:rgba(99,102,241,.25);background:rgba(99,102,241,.06)}
|
|
256
298
|
.admin-card-detail-section{margin-top:20px}
|
|
257
299
|
.admin-card-detail-section .detail-label{font-size:11px;font-weight:700;color:var(--pri);margin-bottom:12px;text-transform:uppercase;letter-spacing:.06em;display:flex;align-items:center;gap:8px}
|
|
258
300
|
.admin-card-detail-section .detail-label::before{content:'';width:3px;height:14px;border-radius:2px;background:linear-gradient(180deg,var(--pri),rgba(99,102,241,.3))}
|
|
@@ -286,18 +328,20 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
286
328
|
.admin-toolbar{display:flex;align-items:center;gap:10px;margin-bottom:14px;flex-wrap:wrap}
|
|
287
329
|
.admin-toolbar h3{font-size:14px;font-weight:600;color:var(--text);white-space:nowrap;margin:0;margin-right:auto;line-height:32px}
|
|
288
330
|
.admin-toolbar select{box-sizing:border-box;height:32px;font-size:12px;border:1px solid var(--border);border-radius:8px;background:var(--bg-card);color:var(--text);vertical-align:middle;margin:0;padding:0 10px}
|
|
289
|
-
.admin-badge{display:inline-flex;align-items:center;gap:4px;font-size:10px;font-weight:700;padding:3px 10px;border-radius:999px;letter-spacing:.
|
|
290
|
-
.admin-badge.admin{background:rgba(
|
|
291
|
-
.admin-badge.member{background:rgba(
|
|
292
|
-
.admin-badge.pending{background:rgba(
|
|
331
|
+
.admin-badge{display:inline-flex;align-items:center;gap:4px;font-size:10px;font-weight:700;padding:3px 10px;border-radius:999px;letter-spacing:.03em;text-transform:uppercase}
|
|
332
|
+
.admin-badge.admin{background:linear-gradient(135deg,rgba(34,197,94,.15),rgba(16,185,129,.1));color:#22c55e;box-shadow:0 0 8px rgba(34,197,94,.1)}
|
|
333
|
+
.admin-badge.member{background:rgba(99,102,241,.08);color:var(--text-muted)}
|
|
334
|
+
.admin-badge.pending{background:linear-gradient(135deg,rgba(251,191,36,.2),rgba(245,158,11,.1));color:#fbbf24;box-shadow:0 0 8px rgba(251,191,36,.1)}
|
|
293
335
|
.admin-badge.public{background:rgba(99,102,241,.1);color:var(--pri)}
|
|
294
336
|
.admin-badge.group{background:rgba(139,92,246,.1);color:var(--violet)}
|
|
295
|
-
.admin-empty{font-size:13px;color:var(--text-muted);padding:
|
|
296
|
-
.admin-empty .ae-icon{font-size:
|
|
337
|
+
.admin-empty{font-size:13px;color:var(--text-muted);padding:48px 24px;text-align:center;border:1px dashed rgba(99,102,241,.15);border-radius:16px;background:rgba(99,102,241,.02)}
|
|
338
|
+
.admin-empty .ae-icon{font-size:32px;display:block;margin-bottom:10px;opacity:.4}
|
|
297
339
|
[data-theme="light"] .admin-badge.admin{background:rgba(5,150,105,.1);color:#059669}
|
|
298
340
|
[data-theme="light"] .admin-badge.member{background:rgba(0,0,0,.06);color:#6b7280}
|
|
299
341
|
[data-theme="light"] .admin-badge.pending{background:rgba(245,158,11,.1);color:#d97706}
|
|
300
|
-
[data-theme="light"] .admin-header{background:linear-gradient(135deg,rgba(99,102,241,.
|
|
342
|
+
[data-theme="light"] .admin-header{background:linear-gradient(135deg,rgba(99,102,241,.04) 0%,rgba(6,182,212,.03) 50%,rgba(139,92,246,.04) 100%)}
|
|
343
|
+
[data-theme="light"] .admin-stat-box{background:rgba(255,255,255,.8)}
|
|
344
|
+
[data-theme="light"] .admin-pending-section{background:linear-gradient(135deg,rgba(251,191,36,.03),rgba(245,158,11,.015))}
|
|
301
345
|
.confirm-overlay{display:none;position:fixed;inset:0;align-items:center;justify-content:center;background:rgba(0,0,0,.45);backdrop-filter:blur(4px);z-index:9999;padding:20px}
|
|
302
346
|
.confirm-overlay.show{display:flex}
|
|
303
347
|
.confirm-panel{width:min(400px,90vw);background:var(--bg-card);border:1px solid var(--border);border-radius:16px;box-shadow:0 20px 60px rgba(0,0,0,.2);overflow:hidden;animation:confirmIn .2s ease}
|
|
@@ -539,8 +583,10 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
539
583
|
.pagination .pg-info{font-size:12px;color:var(--text-sec);padding:0 12px}
|
|
540
584
|
|
|
541
585
|
/* ─── Tasks 视图 ─── */
|
|
542
|
-
.
|
|
543
|
-
.
|
|
586
|
+
.view-container{flex:1;min-width:0}
|
|
587
|
+
.view-container>.vp{display:none;flex-direction:column}
|
|
588
|
+
.view-container>.vp.show{display:flex}
|
|
589
|
+
.tasks-view{flex:1;min-width:0;flex-direction:column;gap:16px}
|
|
544
590
|
.tasks-header{display:flex;flex-direction:column;gap:14px}
|
|
545
591
|
.tasks-stats{display:flex;gap:16px}
|
|
546
592
|
.tasks-stat{display:flex;align-items:center;gap:8px;background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius);padding:12px 18px;flex:1;transition:all .2s}
|
|
@@ -618,8 +664,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
618
664
|
[data-theme="light"] .tasks-stat{background:#fff}
|
|
619
665
|
|
|
620
666
|
/* ─── Skills ─── */
|
|
621
|
-
.skills-view{
|
|
622
|
-
.skills-view.show{display:flex}
|
|
667
|
+
.skills-view{flex:1;min-width:0;flex-direction:column;gap:16px}
|
|
623
668
|
.skill-card{background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius-lg);padding:18px 20px;cursor:pointer;transition:all .25s;position:relative;overflow:hidden}
|
|
624
669
|
.skill-card:hover{border-color:var(--border-glow);background:var(--bg-card-hover);transform:translateY(-1px);box-shadow:var(--shadow)}
|
|
625
670
|
.skill-card::before{content:'';position:absolute;top:0;left:0;bottom:0;width:3px;border-radius:3px 0 0 3px;background:var(--violet)}
|
|
@@ -693,9 +738,8 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
693
738
|
.nav-tabs .tab.active{color:var(--text);background:rgba(255,255,255,.1);border-color:var(--border);box-shadow:0 1px 4px rgba(0,0,0,.15)}
|
|
694
739
|
[data-theme="light"] .nav-tabs{background:rgba(0,0,0,.05)}
|
|
695
740
|
[data-theme="light"] .nav-tabs .tab.active{background:#fff;border-color:rgba(0,0,0,.1);box-shadow:0 1px 3px rgba(0,0,0,.08);color:var(--text)}
|
|
696
|
-
.analytics-view,.settings-view,.logs-view,.migrate-view,.admin-view{
|
|
697
|
-
.analytics-view
|
|
698
|
-
.feed-wrap,.tasks-view,.skills-view,.analytics-view,.settings-view,.logs-view,.migrate-view,.admin-view{max-width:960px}
|
|
741
|
+
.analytics-view,.settings-view,.logs-view,.migrate-view,.admin-view{flex:1;min-width:0;flex-direction:column;gap:20px}
|
|
742
|
+
.feed-wrap,.tasks-view,.skills-view,.analytics-view,.settings-view,.logs-view,.migrate-view,.admin-view{max-width:960px;margin:0 auto}
|
|
699
743
|
|
|
700
744
|
/* ─── Logs ─── */
|
|
701
745
|
.logs-toolbar{display:flex;align-items:center;justify-content:space-between;padding:8px 0}
|
|
@@ -897,7 +941,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
897
941
|
.test-result.ok{color:#22c55e}
|
|
898
942
|
.test-result.fail{color:var(--rose)}
|
|
899
943
|
.test-result.loading{color:var(--text-muted)}
|
|
900
|
-
.settings-actions{display:flex;gap:12px;justify-content:flex-end;align-items:center;margin-top:20px;padding-top:16px;
|
|
944
|
+
.settings-actions{display:flex;gap:12px;justify-content:flex-end;align-items:center;margin-top:20px;padding-top:16px;flex-wrap:nowrap}
|
|
901
945
|
.settings-actions .btn{flex:0 0 auto;min-width:0;padding:8px 24px;font-size:13px}
|
|
902
946
|
.settings-actions .btn-primary{background:rgba(99,102,241,.08);color:var(--pri);border:1px solid rgba(99,102,241,.25);font-weight:600}
|
|
903
947
|
.settings-actions .btn-primary:hover{background:rgba(99,102,241,.14);border-color:var(--pri)}
|
|
@@ -968,8 +1012,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
968
1012
|
.migrate-log-item .log-meta .tag.error{background:rgba(239,68,68,.1);color:#ef4444}
|
|
969
1013
|
.migrate-log-item .log-meta .tag.duplicate{background:rgba(245,158,11,.1);color:#f59e0b}
|
|
970
1014
|
@keyframes migrateFadeIn{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}
|
|
971
|
-
.feed-wrap{flex:1;min-width:0;
|
|
972
|
-
.feed-wrap.hide{display:none}
|
|
1015
|
+
.feed-wrap{flex:1;min-width:0;flex-direction:column}
|
|
973
1016
|
.analytics-view{flex-direction:column;gap:20px}
|
|
974
1017
|
.analytics-cards{display:grid;grid-template-columns:repeat(4,1fr);gap:14px}
|
|
975
1018
|
.analytics-card{position:relative;overflow:hidden;border-radius:var(--radius-lg);padding:18px 16px;transition:all .2s ease;border:1px solid var(--border);background:var(--bg-card)}
|
|
@@ -1053,7 +1096,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1053
1096
|
[data-theme="light"] .auth-theme-toggle .theme-icon-dark{display:none}
|
|
1054
1097
|
|
|
1055
1098
|
@media(max-width:1100px){.analytics-cards{grid-template-columns:repeat(3,1fr)}}
|
|
1056
|
-
@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}}
|
|
1099
|
+
@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-inner{padding:0 16px;gap:8px}.topbar .brand .brand-title{display:none}.topbar .brand .brand-powered{display:none}.topbar-center{justify-content:flex-start}}
|
|
1057
1100
|
</style>
|
|
1058
1101
|
</head>
|
|
1059
1102
|
<body>
|
|
@@ -1138,6 +1181,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1138
1181
|
<!-- ─── Main App ─── -->
|
|
1139
1182
|
<div class="app" id="app">
|
|
1140
1183
|
<div class="topbar">
|
|
1184
|
+
<div class="topbar-inner">
|
|
1141
1185
|
<div class="brand">
|
|
1142
1186
|
<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>
|
|
1143
1187
|
<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}
|
|
@@ -1164,10 +1208,10 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1164
1208
|
<div class="notif-panel-body" id="notifPanelBody"><div class="notif-empty" data-i18n="notif.empty">No notifications</div></div>
|
|
1165
1209
|
</div>
|
|
1166
1210
|
</div>
|
|
1167
|
-
<button class="btn btn-ghost btn-sm" onclick="loadAll()" data-i18n="refresh">\u21BB Refresh</button>
|
|
1168
1211
|
<button class="btn btn-ghost btn-sm" onclick="doLogout()" data-i18n="logout">Logout</button>
|
|
1169
1212
|
</div>
|
|
1170
1213
|
</div>
|
|
1214
|
+
</div>
|
|
1171
1215
|
|
|
1172
1216
|
<div class="main-content">
|
|
1173
1217
|
<div class="sidebar" id="sidebar">
|
|
@@ -1189,18 +1233,19 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1189
1233
|
<button class="btn btn-sm btn-ghost" style="width:100%;margin-top:20px;justify-content:center;color:var(--text-muted);font-size:11px" onclick="clearAll()" data-i18n="sidebar.clear">\u{1F5D1} Clear All Data</button>
|
|
1190
1234
|
</div>
|
|
1191
1235
|
|
|
1192
|
-
<div class="
|
|
1236
|
+
<div class="view-container">
|
|
1237
|
+
<div class="feed-wrap vp show" id="feedWrap">
|
|
1193
1238
|
<div class="feed">
|
|
1194
1239
|
<div class="search-bar">
|
|
1195
1240
|
<span class="search-icon">\u{1F50D}</span>
|
|
1196
1241
|
<input type="text" id="searchInput" data-i18n-ph="search.placeholder" placeholder="Search memories (supports semantic search)..." oninput="debounceSearch()">
|
|
1197
1242
|
<select id="filterOwner" class="filter-select" onchange="onOwnerFilterChange()">
|
|
1198
|
-
<option value="" data-i18n="filter.
|
|
1199
|
-
<option value="public" data-i18n="filter.public">Public</option>
|
|
1243
|
+
<option value="" data-i18n="filter.allagents">All agents</option>
|
|
1200
1244
|
</select>
|
|
1201
1245
|
<select id="memorySearchScope" class="filter-select" onchange="onMemoryScopeChange()">
|
|
1202
|
-
<option value="local" data-i18n="scope.
|
|
1203
|
-
<option value="
|
|
1246
|
+
<option value="local" data-i18n="scope.thisAgent">This Agent</option>
|
|
1247
|
+
<option value="allLocal" data-i18n="scope.thisDevice">This Device</option>
|
|
1248
|
+
<option value="hub" data-i18n="scope.hub">Team</option>
|
|
1204
1249
|
</select>
|
|
1205
1250
|
</div>
|
|
1206
1251
|
<div class="search-meta" id="searchMeta"></div>
|
|
@@ -1229,7 +1274,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1229
1274
|
<div class="pagination" id="pagination"></div>
|
|
1230
1275
|
</div>
|
|
1231
1276
|
</div>
|
|
1232
|
-
<div class="tasks-view" id="tasksView">
|
|
1277
|
+
<div class="tasks-view vp" id="tasksView">
|
|
1233
1278
|
<div class="tasks-header">
|
|
1234
1279
|
<div class="tasks-stats">
|
|
1235
1280
|
<div class="tasks-stat"><span class="tasks-stat-value" id="tasksTotalCount">-</span><span class="tasks-stat-label" data-i18n="tasks.total">Total Tasks</span></div>
|
|
@@ -1243,10 +1288,10 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1243
1288
|
<button class="filter-chip" data-task-status="completed" onclick="setTaskStatusFilter(this,'completed')" data-i18n="tasks.status.completed">Completed</button>
|
|
1244
1289
|
<button class="filter-chip" data-task-status="skipped" onclick="setTaskStatusFilter(this,'skipped')" data-i18n="tasks.status.skipped">Skipped</button>
|
|
1245
1290
|
<select id="taskSearchScope" class="scope-select" onchange="onTaskScopeChange()">
|
|
1246
|
-
<option value="local" data-i18n="scope.
|
|
1247
|
-
<option value="
|
|
1291
|
+
<option value="local" data-i18n="scope.thisAgent">This Agent</option>
|
|
1292
|
+
<option value="allLocal" data-i18n="scope.thisDevice">This Device</option>
|
|
1293
|
+
<option value="hub" data-i18n="scope.hub">Team</option>
|
|
1248
1294
|
</select>
|
|
1249
|
-
<button class="btn btn-sm btn-ghost" onclick="loadTasks()" style="margin-left:auto" data-i18n="refresh">\u21BB Refresh</button>
|
|
1250
1295
|
</div>
|
|
1251
1296
|
</div>
|
|
1252
1297
|
<div class="tasks-list" id="tasksList"><div class="spinner"></div></div>
|
|
@@ -1280,13 +1325,14 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1280
1325
|
<div class="content" id="sharedMemoryContent"></div>
|
|
1281
1326
|
</div>
|
|
1282
1327
|
</div>
|
|
1283
|
-
<div class="skills-view" id="skillsView">
|
|
1328
|
+
<div class="skills-view vp" id="skillsView">
|
|
1284
1329
|
<div class="search-bar">
|
|
1285
1330
|
<span class="search-icon">🔍</span>
|
|
1286
1331
|
<input type="text" id="skillSearchInput" placeholder="Search skills..." data-i18n-ph="skills.search.placeholder" oninput="debounceSkillSearch()">
|
|
1287
1332
|
<select id="skillSearchScope" class="scope-select" onchange="onSkillScopeChange()">
|
|
1288
|
-
<option value="local" data-i18n="scope.
|
|
1289
|
-
<option value="
|
|
1333
|
+
<option value="local" data-i18n="scope.thisAgent">This Agent</option>
|
|
1334
|
+
<option value="allLocal" data-i18n="scope.thisDevice">This Device</option>
|
|
1335
|
+
<option value="hub" data-i18n="scope.hub">Team</option>
|
|
1290
1336
|
</select>
|
|
1291
1337
|
</div>
|
|
1292
1338
|
<div class="search-meta" id="skillSearchMeta"></div>
|
|
@@ -1309,7 +1355,6 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1309
1355
|
<option value="public" data-i18n="filter.public">Public</option>
|
|
1310
1356
|
<option value="private" data-i18n="filter.private">Private</option>
|
|
1311
1357
|
</select>
|
|
1312
|
-
<button class="btn btn-sm btn-ghost" onclick="loadSkills()" style="margin-left:auto" data-i18n="refresh">\u21BB Refresh</button>
|
|
1313
1358
|
</div>
|
|
1314
1359
|
</div>
|
|
1315
1360
|
<div class="tasks-list" id="skillsList"><div class="spinner"></div></div>
|
|
@@ -1342,7 +1387,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1342
1387
|
<div id="skillDetailActions" style="display:flex;gap:8px;margin-top:16px;padding-top:12px;border-top:1px solid var(--border)"></div>
|
|
1343
1388
|
</div>
|
|
1344
1389
|
</div>
|
|
1345
|
-
<div class="analytics-view" id="analyticsView">
|
|
1390
|
+
<div class="analytics-view vp" id="analyticsView">
|
|
1346
1391
|
<div class="metrics-toolbar" style="margin-bottom:0">
|
|
1347
1392
|
<span style="font-size:12px;color:var(--text-sec);font-weight:600" data-i18n="range">Range</span>
|
|
1348
1393
|
<button class="range-btn" data-days="7" onclick="setMetricsDays(7)">7 <span data-i18n="range.days">days</span></button>
|
|
@@ -1386,7 +1431,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1386
1431
|
</div>
|
|
1387
1432
|
|
|
1388
1433
|
<!-- ─── Logs View ─── -->
|
|
1389
|
-
<div class="logs-view" id="logsView">
|
|
1434
|
+
<div class="logs-view vp" id="logsView">
|
|
1390
1435
|
<div class="logs-toolbar">
|
|
1391
1436
|
<div class="logs-toolbar-left">
|
|
1392
1437
|
<select id="logToolFilter" onchange="onLogFilterChange()" style="font-size:12px;padding:4px 8px;border-radius:6px;border:1px solid var(--border);background:var(--card);color:var(--text);min-width:120px">
|
|
@@ -1403,7 +1448,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1403
1448
|
</div>
|
|
1404
1449
|
|
|
1405
1450
|
<!-- ─── Settings View ─── -->
|
|
1406
|
-
<div class="settings-view" id="settingsView">
|
|
1451
|
+
<div class="settings-view vp" id="settingsView">
|
|
1407
1452
|
<div class="settings-tabs-bar">
|
|
1408
1453
|
<button class="settings-tab-btn active" data-tab="models" onclick="switchSettingsTab('models',this)"><span class="stab-dot"></span><span data-i18n="settings.models">AI Models</span></button>
|
|
1409
1454
|
<button class="settings-tab-btn" data-tab="hub" onclick="switchSettingsTab('hub',this)"><span class="stab-dot"></span><span data-i18n="settings.hub">Team Sharing</span></button>
|
|
@@ -1569,7 +1614,6 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1569
1614
|
</div>
|
|
1570
1615
|
</div>
|
|
1571
1616
|
|
|
1572
|
-
<div class="settings-card-divider"></div>
|
|
1573
1617
|
<div class="settings-actions">
|
|
1574
1618
|
<span class="settings-saved" id="modelsSaved">\u2713 <span data-i18n="settings.saved">Saved</span></span>
|
|
1575
1619
|
<button class="btn btn-ghost" onclick="loadConfig()" data-i18n="settings.reset">Reset</button>
|
|
@@ -1658,6 +1702,11 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1658
1702
|
<input type="text" id="cfgHubTeamName" placeholder="My Team">
|
|
1659
1703
|
<div class="field-hint" data-i18n="settings.hub.teamName.hint">Your team display name</div>
|
|
1660
1704
|
</div>
|
|
1705
|
+
<div class="settings-field">
|
|
1706
|
+
<label data-i18n="settings.hub.adminName">Admin Name</label>
|
|
1707
|
+
<input type="text" id="cfgHubAdminName" placeholder="" maxlength="32">
|
|
1708
|
+
<div class="field-hint" data-i18n="settings.hub.adminName.hint">Your display name as team admin</div>
|
|
1709
|
+
</div>
|
|
1661
1710
|
</div>
|
|
1662
1711
|
<div id="hubShareInfo" style="display:none;margin-top:14px;background:var(--bg);border:1px solid var(--border);border-radius:10px;padding:14px 18px">
|
|
1663
1712
|
<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>
|
|
@@ -1686,6 +1735,11 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1686
1735
|
<input type="text" id="cfgClientTeamToken" placeholder="">
|
|
1687
1736
|
<div class="field-hint" data-i18n="settings.hub.teamTokenClient.hint">Get this from your team admin to join</div>
|
|
1688
1737
|
</div>
|
|
1738
|
+
<div class="settings-field">
|
|
1739
|
+
<label data-i18n="settings.hub.nickname">Nickname</label>
|
|
1740
|
+
<input type="text" id="cfgClientNickname" placeholder="" maxlength="32">
|
|
1741
|
+
<div class="field-hint" data-i18n="settings.hub.nickname.hint">Your display name in the team. If empty, uses system username.</div>
|
|
1742
|
+
</div>
|
|
1689
1743
|
<input type="hidden" id="cfgClientUserToken" value="">
|
|
1690
1744
|
</div>
|
|
1691
1745
|
<div style="margin-top:12px">
|
|
@@ -1740,7 +1794,6 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1740
1794
|
</div>
|
|
1741
1795
|
<div class="field-hint" style="margin-top:6px" data-i18n="settings.telemetry.hint">Anonymous usage analytics to help improve the plugin. Only sends tool names, latencies, and version info. No memory content, queries, or personal data is ever sent.</div>
|
|
1742
1796
|
|
|
1743
|
-
<div class="settings-card-divider"></div>
|
|
1744
1797
|
<div class="settings-actions">
|
|
1745
1798
|
<span class="settings-saved" id="generalSaved">\u2713 <span data-i18n="settings.saved">Saved</span></span>
|
|
1746
1799
|
<button class="btn btn-ghost" onclick="loadConfig()" data-i18n="settings.reset">Reset</button>
|
|
@@ -1755,13 +1808,12 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1755
1808
|
</div>
|
|
1756
1809
|
|
|
1757
1810
|
<!-- ─── Admin Page ─── -->
|
|
1758
|
-
<div class="admin-view" id="adminView">
|
|
1811
|
+
<div class="admin-view vp" id="adminView">
|
|
1759
1812
|
<div id="adminNotEnabled" style="display:none"></div>
|
|
1760
1813
|
<div id="adminMainContent">
|
|
1761
1814
|
<div class="admin-header">
|
|
1762
1815
|
<div class="admin-header-top">
|
|
1763
|
-
<h2><span class="ah-icon">\u{
|
|
1764
|
-
<button class="btn btn-sm btn-ghost" onclick="loadAdminData()" style="backdrop-filter:blur(8px)" data-i18n="admin.refresh">\u21BB Refresh</button>
|
|
1816
|
+
<h2><span class="ah-icon">\u{26A1}</span> <span data-i18n="admin.title">Team Admin Panel</span></h2>
|
|
1765
1817
|
</div>
|
|
1766
1818
|
<div class="admin-header-sub" data-i18n="admin.subtitle">Manage team members and shared resources</div>
|
|
1767
1819
|
<div class="admin-stat-row" id="adminStats"></div>
|
|
@@ -1780,7 +1832,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1780
1832
|
</div>
|
|
1781
1833
|
|
|
1782
1834
|
<!-- ─── Import Page ─── -->
|
|
1783
|
-
<div class="migrate-view" id="migrateView">
|
|
1835
|
+
<div class="migrate-view vp" id="migrateView">
|
|
1784
1836
|
<div class="settings-section" style="border:1px solid rgba(99,102,241,.15)">
|
|
1785
1837
|
<h3><span class="icon">\u{1F4E5}</span> <span data-i18n="migrate.title">Import OpenClaw Memory</span></h3>
|
|
1786
1838
|
<p style="font-size:12px;color:var(--text-sec);margin-bottom:12px;line-height:1.6" data-i18n="migrate.desc">Migrate your existing OpenClaw built-in memories and conversation history into this plugin. The import process uses smart deduplication to avoid duplicates.</p>
|
|
@@ -1950,6 +2002,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1950
2002
|
|
|
1951
2003
|
</div>
|
|
1952
2004
|
|
|
2005
|
+
</div>
|
|
1953
2006
|
</div>
|
|
1954
2007
|
</div>
|
|
1955
2008
|
|
|
@@ -1973,7 +2026,9 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1973
2026
|
<script>
|
|
1974
2027
|
let activeSession=null,activeRole='',editingId=null,searchTimer=null,memoryCache={},currentPage=1,totalPages=1,totalCount=0,PAGE_SIZE=40,metricsDays=30;
|
|
1975
2028
|
let memorySearchScope='local',skillSearchScope='local',taskSearchScope='local';
|
|
2029
|
+
let _lastMemoriesFingerprint='',_lastTasksFingerprint='',_lastSkillsFingerprint='';
|
|
1976
2030
|
let _embeddingWarningShown=false;
|
|
2031
|
+
let _currentAgentOwner='agent:main';
|
|
1977
2032
|
|
|
1978
2033
|
/* ─── i18n ─── */
|
|
1979
2034
|
const I18N={
|
|
@@ -2024,6 +2079,8 @@ const I18N={
|
|
|
2024
2079
|
'skills.load.error':'Failed to load skills',
|
|
2025
2080
|
'skills.hub.title':'\u{1F310} Team Skills',
|
|
2026
2081
|
'scope.local':'Local',
|
|
2082
|
+
'scope.thisAgent':'This Agent',
|
|
2083
|
+
'scope.thisDevice':'This Device',
|
|
2027
2084
|
'scope.group':'Group',
|
|
2028
2085
|
'scope.all':'All',
|
|
2029
2086
|
'skills.visibility.public':'Shared Locally',
|
|
@@ -2052,6 +2109,15 @@ const I18N={
|
|
|
2052
2109
|
'notif.removed.memory':'Your shared memory was removed by admin',
|
|
2053
2110
|
'notif.removed.task':'Your shared task was removed by admin',
|
|
2054
2111
|
'notif.removed.skill':'Your shared skill was removed by admin',
|
|
2112
|
+
'notif.shared.memory':'A new memory was shared',
|
|
2113
|
+
'notif.shared.task':'A new task was shared',
|
|
2114
|
+
'notif.shared.skill':'A new skill was shared',
|
|
2115
|
+
'notif.unshared.memory':'A memory was unshared',
|
|
2116
|
+
'notif.unshared.task':'A task was unshared',
|
|
2117
|
+
'notif.unshared.skill':'A skill was unshared',
|
|
2118
|
+
'notif.userJoin':'New user requests to join the team',
|
|
2119
|
+
'notif.userOnline':'User came online',
|
|
2120
|
+
'notif.userOffline':'User went offline',
|
|
2055
2121
|
'notif.clearAll':'Clear all',
|
|
2056
2122
|
'notif.timeAgo.just':'just now',
|
|
2057
2123
|
'notif.timeAgo.min':'{n}m ago',
|
|
@@ -2075,6 +2141,7 @@ const I18N={
|
|
|
2075
2141
|
'filter.newest':'Newest first',
|
|
2076
2142
|
'filter.oldest':'Oldest first',
|
|
2077
2143
|
'filter.allowners':'All owners',
|
|
2144
|
+
'filter.allagents':'All agents',
|
|
2078
2145
|
'filter.allsessions':'All sessions',
|
|
2079
2146
|
'filter.public':'Public',
|
|
2080
2147
|
'filter.private':'Private',
|
|
@@ -2323,6 +2390,8 @@ const I18N={
|
|
|
2323
2390
|
'settings.hub.port.hint':'Port for team server. Default: 18800',
|
|
2324
2391
|
'settings.hub.teamName':'Team Name',
|
|
2325
2392
|
'settings.hub.teamName.hint':'Display name for your team',
|
|
2393
|
+
'settings.hub.adminName':'Admin Name',
|
|
2394
|
+
'settings.hub.adminName.hint':'Your display name as team admin',
|
|
2326
2395
|
'settings.hub.teamToken':'Team Token',
|
|
2327
2396
|
'settings.hub.teamToken.hint':'Auto-generated secret for clients to join. Click to copy. Share this with your team members.',
|
|
2328
2397
|
'settings.hub.tokenCopied':'Team Token copied!',
|
|
@@ -2342,10 +2411,13 @@ const I18N={
|
|
|
2342
2411
|
'settings.hub.hubAddress.hint':'Team server address, e.g. 192.168.1.100:18800',
|
|
2343
2412
|
'settings.hub.teamTokenClient':'Team Token',
|
|
2344
2413
|
'settings.hub.teamTokenClient.hint':'Get this from your team admin to join',
|
|
2414
|
+
'settings.hub.nickname':'Nickname',
|
|
2415
|
+
'settings.hub.nickname.hint':'Your display name in the team. If empty, uses system username.',
|
|
2345
2416
|
'settings.hub.userToken':'User Token',
|
|
2346
2417
|
'settings.hub.userToken.hint':'Usually auto-obtained after joining. Only fill if given by admin.',
|
|
2347
2418
|
'settings.hub.testConnection':'Test Connection',
|
|
2348
2419
|
'settings.hub.test.noAddr':'Please enter server address first',
|
|
2420
|
+
'settings.hub.teamToken.required':'Please enter team token',
|
|
2349
2421
|
'settings.hub.test.testing':'Testing...',
|
|
2350
2422
|
'settings.hub.test.ok':'Connected successfully',
|
|
2351
2423
|
'settings.hub.test.fail':'Connection failed',
|
|
@@ -2380,6 +2452,7 @@ const I18N={
|
|
|
2380
2452
|
'memory.detail.viewTarget':'View target: ',
|
|
2381
2453
|
'admin.title':'Team Admin Panel',
|
|
2382
2454
|
'admin.subtitle':'Manage team members and shared resources',
|
|
2455
|
+
'admin.subtitle.member':'Browse shared memories, tasks and skills from your team',
|
|
2383
2456
|
'admin.refresh':'\u21BB Refresh',
|
|
2384
2457
|
'admin.tab.users':'Users',
|
|
2385
2458
|
'admin.tab.tasks':'Shared Tasks',
|
|
@@ -2395,6 +2468,12 @@ const I18N={
|
|
|
2395
2468
|
'admin.pendingApproval':'Pending Approval',
|
|
2396
2469
|
'admin.activeUsers':'Active Users',
|
|
2397
2470
|
'admin.noActiveUsers':'No active users.',
|
|
2471
|
+
'admin.onlineUsers':'Online',
|
|
2472
|
+
'admin.offlineUsers':'Offline',
|
|
2473
|
+
'admin.online':'Online',
|
|
2474
|
+
'admin.offline':'Offline',
|
|
2475
|
+
'admin.offlineFor':'Offline for {time}',
|
|
2476
|
+
'admin.onlineNow':'Online now',
|
|
2398
2477
|
'admin.approve':'Approve',
|
|
2399
2478
|
'admin.reject':'Reject',
|
|
2400
2479
|
'admin.device':'Device: ',
|
|
@@ -2411,6 +2490,7 @@ const I18N={
|
|
|
2411
2490
|
'admin.demoteMember':'Demote to Member',
|
|
2412
2491
|
'admin.editName':'Edit Name',
|
|
2413
2492
|
'admin.lastAdminHint':'Last admin — cannot remove or demote',
|
|
2493
|
+
'admin.ownerHint':'Hub owner — cannot be demoted or removed',
|
|
2414
2494
|
'admin.editNamePrompt':'Enter new username:',
|
|
2415
2495
|
'confirm.promoteAdmin':'Promote this user to admin? They will be able to manage all team members and resources.',
|
|
2416
2496
|
'confirm.demoteMember':'Demote this admin to member?',
|
|
@@ -2471,6 +2551,7 @@ const I18N={
|
|
|
2471
2551
|
'admin.groupsFailed':'Failed to load groups: ',
|
|
2472
2552
|
'toast.userApproved':'User approved',
|
|
2473
2553
|
'sharing.approved.toast':'Your join request has been approved!',
|
|
2554
|
+
'sharing.rejected.toast':'Your join request was rejected by the admin.',
|
|
2474
2555
|
'toast.userRejected':'User rejected',
|
|
2475
2556
|
'toast.approveFail':'Approve failed',
|
|
2476
2557
|
'toast.rejectFail':'Reject failed',
|
|
@@ -2631,6 +2712,8 @@ const I18N={
|
|
|
2631
2712
|
'sharing.disable.confirm.hub':'You are about to shut down the team server.\\n\\nWhat will happen:\\n\\u2022 All connected team members will be disconnected\\n\\u2022 They will no longer be able to sync memories, tasks, or skills\\n\\u2022 Shared data is preserved and will be available when you re-enable\\n\\nAre you sure?',
|
|
2632
2713
|
'sharing.disable.confirm.client':'You are about to disconnect from the team.\\n\\nWhat will happen:\\n\\u2022 You will no longer receive shared memories, tasks, or skills from the team\\n\\u2022 Your local data is preserved and will not be affected\\n\\u2022 You can reconnect later by re-enabling sharing\\n\\nAre you sure?',
|
|
2633
2714
|
'sharing.disable.restartAlert':'Sharing has been disabled. Please restart the OpenClaw gateway for the change to take effect.\\n\\nRun: openclaw gateway stop && openclaw gateway start',
|
|
2715
|
+
'sharing.switch.hubToClient':'You are about to switch from Server to Client mode.\\n\\nWhat will happen:\\n\\u2022 The Hub server will shut down after restart\\n\\u2022 All connected team members will be disconnected\\n\\u2022 Shared data on the Hub is preserved for future use\\n\\u2022 You will join the specified remote team as a client\\n\\nAre you sure?',
|
|
2716
|
+
'sharing.switch.clientToHub':'You are about to switch from Client to Server mode.\\n\\nWhat will happen:\\n\\u2022 You will disconnect from the current team\\n\\u2022 A new Hub server will start after restart\\n\\u2022 Your local data is not affected\\n\\nAre you sure?',
|
|
2634
2717
|
'admin.notEnabled.title':'Team sharing is not enabled',
|
|
2635
2718
|
'admin.notEnabled.desc':'The Admin Panel is used to manage team members, shared memories, tasks, and skills. To use this feature, you need to enable team sharing first.',
|
|
2636
2719
|
'admin.notEnabled.setupHub':'Set Up as Team Server',
|
|
@@ -2705,6 +2788,8 @@ const I18N={
|
|
|
2705
2788
|
'skills.load.error':'加载技能失败',
|
|
2706
2789
|
'skills.hub.title':'\u{1F310} 团队共享技能',
|
|
2707
2790
|
'scope.local':'本地',
|
|
2791
|
+
'scope.thisAgent':'当前智能体',
|
|
2792
|
+
'scope.thisDevice':'本机全部',
|
|
2708
2793
|
'scope.group':'团队',
|
|
2709
2794
|
'scope.all':'全部',
|
|
2710
2795
|
'skills.visibility.public':'本机共享',
|
|
@@ -2733,6 +2818,15 @@ const I18N={
|
|
|
2733
2818
|
'notif.removed.memory':'你共享的记忆被管理员移除',
|
|
2734
2819
|
'notif.removed.task':'你共享的任务被管理员移除',
|
|
2735
2820
|
'notif.removed.skill':'你共享的技能被管理员移除',
|
|
2821
|
+
'notif.shared.memory':'有新的记忆被共享',
|
|
2822
|
+
'notif.shared.task':'有新的任务被共享',
|
|
2823
|
+
'notif.shared.skill':'有新的技能被共享',
|
|
2824
|
+
'notif.unshared.memory':'有记忆取消了共享',
|
|
2825
|
+
'notif.unshared.task':'有任务取消了共享',
|
|
2826
|
+
'notif.unshared.skill':'有技能取消了共享',
|
|
2827
|
+
'notif.userJoin':'有新用户申请加入团队',
|
|
2828
|
+
'notif.userOnline':'用户上线了',
|
|
2829
|
+
'notif.userOffline':'用户下线了',
|
|
2736
2830
|
'notif.clearAll':'清除全部',
|
|
2737
2831
|
'notif.timeAgo.just':'刚刚',
|
|
2738
2832
|
'notif.timeAgo.min':'{n}分钟前',
|
|
@@ -2756,6 +2850,7 @@ const I18N={
|
|
|
2756
2850
|
'filter.newest':'最新优先',
|
|
2757
2851
|
'filter.oldest':'最早优先',
|
|
2758
2852
|
'filter.allowners':'所有归属',
|
|
2853
|
+
'filter.allagents':'全部智能体',
|
|
2759
2854
|
'filter.allsessions':'全部会话',
|
|
2760
2855
|
'filter.public':'公开',
|
|
2761
2856
|
'filter.private':'私有',
|
|
@@ -3004,6 +3099,8 @@ const I18N={
|
|
|
3004
3099
|
'settings.hub.port.hint':'团队服务端口,默认 18800',
|
|
3005
3100
|
'settings.hub.teamName':'团队名称',
|
|
3006
3101
|
'settings.hub.teamName.hint':'你的团队显示名称',
|
|
3102
|
+
'settings.hub.adminName':'管理员名称',
|
|
3103
|
+
'settings.hub.adminName.hint':'你在团队中的显示名称',
|
|
3007
3104
|
'settings.hub.teamToken':'团队令牌',
|
|
3008
3105
|
'settings.hub.teamToken.hint':'自动生成的密钥,点击可复制。请将此令牌分享给团队成员。',
|
|
3009
3106
|
'settings.hub.tokenCopied':'团队令牌已复制!',
|
|
@@ -3023,10 +3120,13 @@ const I18N={
|
|
|
3023
3120
|
'settings.hub.hubAddress.hint':'团队服务器地址,如 192.168.1.100:18800',
|
|
3024
3121
|
'settings.hub.teamTokenClient':'团队令牌',
|
|
3025
3122
|
'settings.hub.teamTokenClient.hint':'向团队管理员获取此令牌以加入团队',
|
|
3123
|
+
'settings.hub.nickname':'昵称',
|
|
3124
|
+
'settings.hub.nickname.hint':'你在团队中的显示名称。留空则使用系统用户名。',
|
|
3026
3125
|
'settings.hub.userToken':'用户令牌',
|
|
3027
3126
|
'settings.hub.userToken.hint':'通常在加入团队后自动获取,无需手动填写。',
|
|
3028
3127
|
'settings.hub.testConnection':'测试连接',
|
|
3029
3128
|
'settings.hub.test.noAddr':'请先输入服务器地址',
|
|
3129
|
+
'settings.hub.teamToken.required':'请输入团队令牌',
|
|
3030
3130
|
'settings.hub.test.testing':'测试中...',
|
|
3031
3131
|
'settings.hub.test.ok':'连接成功',
|
|
3032
3132
|
'settings.hub.test.fail':'连接失败',
|
|
@@ -3061,6 +3161,7 @@ const I18N={
|
|
|
3061
3161
|
'memory.detail.viewTarget':'查看目标: ',
|
|
3062
3162
|
'admin.title':'团队管理面板',
|
|
3063
3163
|
'admin.subtitle':'管理团队成员和共享资源',
|
|
3164
|
+
'admin.subtitle.member':'浏览团队共享的记忆、任务和技能',
|
|
3064
3165
|
'admin.refresh':'\u21BB 刷新',
|
|
3065
3166
|
'admin.tab.users':'用户',
|
|
3066
3167
|
'admin.tab.tasks':'共享任务',
|
|
@@ -3076,6 +3177,12 @@ const I18N={
|
|
|
3076
3177
|
'admin.pendingApproval':'待审批',
|
|
3077
3178
|
'admin.activeUsers':'活跃用户',
|
|
3078
3179
|
'admin.noActiveUsers':'暂无活跃用户。',
|
|
3180
|
+
'admin.onlineUsers':'在线',
|
|
3181
|
+
'admin.offlineUsers':'离线',
|
|
3182
|
+
'admin.online':'在线',
|
|
3183
|
+
'admin.offline':'离线',
|
|
3184
|
+
'admin.offlineFor':'离线 {time}',
|
|
3185
|
+
'admin.onlineNow':'当前在线',
|
|
3079
3186
|
'admin.approve':'批准',
|
|
3080
3187
|
'admin.reject':'拒绝',
|
|
3081
3188
|
'admin.device':'设备:',
|
|
@@ -3092,6 +3199,7 @@ const I18N={
|
|
|
3092
3199
|
'admin.demoteMember':'降为成员',
|
|
3093
3200
|
'admin.editName':'编辑名称',
|
|
3094
3201
|
'admin.lastAdminHint':'唯一管理员 — 无法删除或降级',
|
|
3202
|
+
'admin.ownerHint':'Hub 创建者 — 不可降级或移除',
|
|
3095
3203
|
'admin.editNamePrompt':'请输入新用户名:',
|
|
3096
3204
|
'confirm.promoteAdmin':'确定要将此用户提升为管理员吗?管理员可以管理所有团队成员和资源。',
|
|
3097
3205
|
'confirm.demoteMember':'确定要将此管理员降为普通成员吗?',
|
|
@@ -3152,6 +3260,7 @@ const I18N={
|
|
|
3152
3260
|
'admin.groupsFailed':'加载分组失败:',
|
|
3153
3261
|
'toast.userApproved':'用户已批准',
|
|
3154
3262
|
'sharing.approved.toast':'您的加入申请已通过审核!',
|
|
3263
|
+
'sharing.rejected.toast':'您的加入申请已被管理员拒绝。',
|
|
3155
3264
|
'toast.userRejected':'用户已拒绝',
|
|
3156
3265
|
'toast.approveFail':'批准失败',
|
|
3157
3266
|
'toast.rejectFail':'拒绝失败',
|
|
@@ -3312,6 +3421,8 @@ const I18N={
|
|
|
3312
3421
|
'sharing.disable.confirm.hub':'你即将关闭团队服务。\\n\\n关闭后将会:\\n\\u2022 所有已连接的团队成员将断开连接\\n\\u2022 他们将无法继续同步记忆、任务和技能\\n\\u2022 已共享的数据会保留,重新开启后仍可使用\\n\\n确定要关闭吗?',
|
|
3313
3422
|
'sharing.disable.confirm.client':'你即将断开与团队的连接。\\n\\n断开后将会:\\n\\u2022 你将无法再接收团队共享的记忆、任务和技能\\n\\u2022 你的本地数据不受影响,会完整保留\\n\\u2022 之后可以随时重新开启共享来恢复连接\\n\\n确定要断开吗?',
|
|
3314
3423
|
'sharing.disable.restartAlert':'共享已关闭。请重启 OpenClaw 网关使更改生效。\\n\\n执行命令:openclaw gateway stop && openclaw gateway start',
|
|
3424
|
+
'sharing.switch.hubToClient':'你即将从服务端模式切换为客户端模式。\\n\\n切换后将会:\\n\\u2022 Hub 服务将在重启后关闭\\n\\u2022 所有已连接的团队成员将断开连接\\n\\u2022 Hub 上的共享数据会保留,以后可恢复使用\\n\\u2022 你将作为客户端加入指定的远程团队\\n\\n确定要切换吗?',
|
|
3425
|
+
'sharing.switch.clientToHub':'你即将从客户端模式切换为服务端模式。\\n\\n切换后将会:\\n\\u2022 你将断开与当前团队的连接\\n\\u2022 重启后将启动新的 Hub 服务\\n\\u2022 你的本地数据不受影响\\n\\n确定要切换吗?',
|
|
3315
3426
|
'admin.notEnabled.title':'团队共享尚未开启',
|
|
3316
3427
|
'admin.notEnabled.desc':'管理面板用于管理团队成员、共享的记忆、任务和技能。使用此功能前,需要先开启团队共享。',
|
|
3317
3428
|
'admin.notEnabled.setupHub':'配置为团队服务端',
|
|
@@ -3549,59 +3660,49 @@ function switchSettingsTab(tab,btn){
|
|
|
3549
3660
|
});
|
|
3550
3661
|
}
|
|
3551
3662
|
|
|
3663
|
+
var _activeView='memories';
|
|
3552
3664
|
function switchView(view){
|
|
3665
|
+
_activeView=view;
|
|
3553
3666
|
document.querySelectorAll('.nav-tabs .tab').forEach(t=>t.classList.toggle('active',t.dataset.view===view));
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
const settingsView=document.getElementById('settingsView');
|
|
3560
|
-
const migrateView=document.getElementById('migrateView');
|
|
3561
|
-
const adminView=document.getElementById('adminView');
|
|
3562
|
-
const sidebar=document.getElementById('sidebar');
|
|
3563
|
-
feedWrap.classList.add('hide');
|
|
3564
|
-
analyticsView.classList.remove('show');
|
|
3565
|
-
tasksView.classList.remove('show');
|
|
3566
|
-
skillsView.classList.remove('show');
|
|
3567
|
-
logsView.classList.remove('show');
|
|
3568
|
-
settingsView.classList.remove('show');
|
|
3569
|
-
migrateView.classList.remove('show');
|
|
3570
|
-
if(adminView) adminView.classList.remove('show');
|
|
3667
|
+
var viewMap={memories:'feedWrap',tasks:'tasksView',skills:'skillsView',analytics:'analyticsView',logs:'logsView',settings:'settingsView',import:'migrateView',admin:'adminView'};
|
|
3668
|
+
for(var k in viewMap){
|
|
3669
|
+
var el=document.getElementById(viewMap[k]);
|
|
3670
|
+
if(el) el.classList.toggle('show',k===view);
|
|
3671
|
+
}
|
|
3571
3672
|
var sessionSection=document.getElementById('sidebarSessionSection');
|
|
3572
|
-
if(
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
} else if(view==='tasks'||view==='skills'){
|
|
3576
|
-
if(sessionSection){sessionSection.style.visibility='hidden';sessionSection.style.pointerEvents='none';}
|
|
3577
|
-
if(view==='tasks'){tasksView.classList.add('show');loadTasks();}
|
|
3578
|
-
else{skillsView.classList.add('show');loadSkills();}
|
|
3579
|
-
} else {
|
|
3580
|
-
if(sessionSection){sessionSection.style.visibility='hidden';sessionSection.style.pointerEvents='none';}
|
|
3581
|
-
if(view==='analytics'){
|
|
3582
|
-
analyticsView.classList.add('show');
|
|
3583
|
-
loadMetrics();
|
|
3584
|
-
} else if(view==='logs'){
|
|
3585
|
-
logsView.classList.add('show');
|
|
3586
|
-
loadLogs();
|
|
3587
|
-
} else if(view==='settings'){
|
|
3588
|
-
settingsView.classList.add('show');
|
|
3589
|
-
loadConfig();
|
|
3590
|
-
loadModelHealth();
|
|
3591
|
-
} else if(view==='import'){
|
|
3592
|
-
migrateView.classList.add('show');
|
|
3593
|
-
if(!window._migrateRunning) migrateScan(false);
|
|
3594
|
-
} else if(view==='admin'){
|
|
3595
|
-
if(adminView){adminView.classList.add('show');loadAdminData();}
|
|
3596
|
-
}
|
|
3673
|
+
if(sessionSection){
|
|
3674
|
+
if(view==='memories'){sessionSection.style.visibility='';sessionSection.style.pointerEvents='';}
|
|
3675
|
+
else{sessionSection.style.visibility='hidden';sessionSection.style.pointerEvents='none';}
|
|
3597
3676
|
}
|
|
3677
|
+
if(view==='tasks') loadTasks();
|
|
3678
|
+
else if(view==='skills') loadSkills();
|
|
3679
|
+
else if(view==='analytics') loadMetrics();
|
|
3680
|
+
else if(view==='logs') loadLogs();
|
|
3681
|
+
else if(view==='settings'){loadConfig();loadModelHealth();}
|
|
3682
|
+
else if(view==='import'){if(!window._migrateRunning) migrateScan(false);}
|
|
3683
|
+
else if(view==='admin'){loadAdminData();}
|
|
3598
3684
|
}
|
|
3599
3685
|
|
|
3600
3686
|
function onMemoryScopeChange(){
|
|
3601
3687
|
memorySearchScope=document.getElementById('memorySearchScope')?.value||'local';
|
|
3688
|
+
currentPage=1;
|
|
3689
|
+
activeSession=null;activeRole='';
|
|
3690
|
+
_lastMemoriesFingerprint='';
|
|
3691
|
+
var isHub=memorySearchScope==='hub';
|
|
3692
|
+
var isLocal=memorySearchScope==='local';
|
|
3693
|
+
var ownerSel=document.getElementById('filterOwner');
|
|
3694
|
+
var filterBar=document.getElementById('filterBar');
|
|
3695
|
+
var dateFilter=document.querySelector('.date-filter');
|
|
3696
|
+
if(ownerSel) ownerSel.style.display=(isHub||isLocal)?'none':'';
|
|
3697
|
+
if(filterBar) filterBar.style.display=isHub?'none':'';
|
|
3698
|
+
if(dateFilter) dateFilter.style.display=isHub?'none':'';
|
|
3602
3699
|
if(document.getElementById('searchInput').value.trim()) doSearch(document.getElementById('searchInput').value);
|
|
3603
|
-
else if(
|
|
3604
|
-
else {
|
|
3700
|
+
else if(isHub) { document.getElementById('sharingSearchMeta').textContent=''; loadHubMemories(); }
|
|
3701
|
+
else {
|
|
3702
|
+
document.getElementById('sharingSearchMeta').textContent='';
|
|
3703
|
+
var ownerArg=isLocal?_currentAgentOwner:undefined;
|
|
3704
|
+
loadStats(ownerArg); loadMemories();
|
|
3705
|
+
}
|
|
3605
3706
|
}
|
|
3606
3707
|
|
|
3607
3708
|
function onSkillScopeChange(){
|
|
@@ -3616,6 +3717,7 @@ function onTaskScopeChange(){
|
|
|
3616
3717
|
}
|
|
3617
3718
|
|
|
3618
3719
|
var _clientPendingPollTimer=null;
|
|
3720
|
+
var _lastSharingConnStatus='';
|
|
3619
3721
|
async function loadSharingStatus(forcePending){
|
|
3620
3722
|
try{
|
|
3621
3723
|
const r=await fetch('/api/sharing/status');
|
|
@@ -3625,13 +3727,26 @@ async function loadSharingStatus(forcePending){
|
|
|
3625
3727
|
renderSharingSettings(d);
|
|
3626
3728
|
updateTeamGuide(d);
|
|
3627
3729
|
if(forcePending && d && d.admin && d.admin.canManageUsers) loadSharingPendingUsers();
|
|
3628
|
-
|
|
3629
|
-
|
|
3730
|
+
if(!d||!d.enabled){
|
|
3731
|
+
if(_clientPendingPollTimer){clearInterval(_clientPendingPollTimer);_clientPendingPollTimer=null;}
|
|
3732
|
+
_lastSharingConnStatus='';
|
|
3733
|
+
return;
|
|
3734
|
+
}
|
|
3735
|
+
var conn=d.connection||{};
|
|
3736
|
+
var curStatus=conn.rejected?'rejected':conn.pendingApproval?'pending':conn.connected?'connected':'none';
|
|
3737
|
+
if(_lastSharingConnStatus==='pending'&&curStatus==='rejected'){
|
|
3738
|
+
toast(t('sharing.rejected.toast'),'error');
|
|
3739
|
+
}
|
|
3740
|
+
if(_lastSharingConnStatus==='pending'&&curStatus==='connected'){
|
|
3741
|
+
toast(t('sharing.approved.toast'),'success');
|
|
3742
|
+
}
|
|
3743
|
+
_lastSharingConnStatus=curStatus;
|
|
3744
|
+
if(curStatus==='pending'&&!_clientPendingPollTimer){
|
|
3630
3745
|
_clientPendingPollTimer=setInterval(function(){loadSharingStatus(false);},10000);
|
|
3631
|
-
}
|
|
3746
|
+
}
|
|
3747
|
+
if(curStatus!=='pending'&&_clientPendingPollTimer){
|
|
3632
3748
|
clearInterval(_clientPendingPollTimer);
|
|
3633
3749
|
_clientPendingPollTimer=null;
|
|
3634
|
-
if(conn.connected) toast(t('sharing.approved.toast'),'success');
|
|
3635
3750
|
}
|
|
3636
3751
|
}catch(e){
|
|
3637
3752
|
renderSharingSidebar(null);
|
|
@@ -3640,12 +3755,17 @@ async function loadSharingStatus(forcePending){
|
|
|
3640
3755
|
}
|
|
3641
3756
|
}
|
|
3642
3757
|
|
|
3758
|
+
var _lastSidebarFingerprint='';
|
|
3643
3759
|
function renderSharingSidebar(data){
|
|
3644
3760
|
var section=document.getElementById('sidebarSharingSection');
|
|
3645
3761
|
var statusEl=document.getElementById('sharingSidebarStatus');
|
|
3646
3762
|
var hintEl=document.getElementById('sharingSidebarHint');
|
|
3647
3763
|
var badgeEl=document.getElementById('sharingSidebarConnBadge');
|
|
3648
3764
|
if(!statusEl||!hintEl) return;
|
|
3765
|
+
var conn=data&&data.connection||{};
|
|
3766
|
+
var fp=JSON.stringify({e:!!data&&!!data.enabled,r:data&&data.role,pa:!!conn.pendingApproval,rj:!!conn.rejected,c:!!conn.connected,u:conn.user&&conn.user.username,tn:conn.teamName,cc:!!data&&!!data.clientConfigured,hu:data&&data.hubUrl});
|
|
3767
|
+
if(fp===_lastSidebarFingerprint) return;
|
|
3768
|
+
_lastSidebarFingerprint=fp;
|
|
3649
3769
|
if(!data||!data.enabled){
|
|
3650
3770
|
if(section) section.style.display='none';
|
|
3651
3771
|
window._isHubAdmin=false;
|
|
@@ -3697,12 +3817,17 @@ function renderSharingSidebar(data){
|
|
|
3697
3817
|
}
|
|
3698
3818
|
}
|
|
3699
3819
|
|
|
3820
|
+
var _lastSettingsFingerprint='';
|
|
3700
3821
|
function renderSharingSettings(data){
|
|
3701
3822
|
var statusEl=document.getElementById('sharingStatusPanel');
|
|
3702
3823
|
var teamEl=document.getElementById('sharingTeamPanel');
|
|
3703
3824
|
var adminEl=document.getElementById('sharingAdminPanel');
|
|
3704
3825
|
var panelsWrap=document.getElementById('sharingPanelsWrap');
|
|
3705
3826
|
if(!statusEl||!teamEl||!adminEl) return;
|
|
3827
|
+
var conn2=data&&data.connection||{};
|
|
3828
|
+
var fp2=JSON.stringify({e:!!data&&!!data.enabled,r:data&&data.role,pa:!!conn2.pendingApproval,rj:!!conn2.rejected,c:!!conn2.connected,u:conn2.user&&conn2.user.username,ur:conn2.user&&conn2.user.role,tn:conn2.teamName,cc:!!data&&!!data.clientConfigured,cm:data&&data.admin&&data.admin.canManageUsers});
|
|
3829
|
+
if(fp2===_lastSettingsFingerprint) return;
|
|
3830
|
+
_lastSettingsFingerprint=fp2;
|
|
3706
3831
|
if(!data||!data.enabled){
|
|
3707
3832
|
statusEl.innerHTML='';teamEl.innerHTML='';adminEl.innerHTML='';
|
|
3708
3833
|
if(panelsWrap) panelsWrap.style.display='none';
|
|
@@ -3719,8 +3844,12 @@ function renderSharingSettings(data){
|
|
|
3719
3844
|
var hubAdminBtn=document.getElementById('hubAdminEntryBtn');
|
|
3720
3845
|
|
|
3721
3846
|
if(actualRole==='hub'){
|
|
3722
|
-
|
|
3847
|
+
teamEl.innerHTML='';adminEl.innerHTML='';statusEl.innerHTML='';statusEl.style.display='none';
|
|
3723
3848
|
if(hubAdminBtn) hubAdminBtn.style.display=isAdmin?'':'none';
|
|
3849
|
+
var hubUser=conn.user||{};
|
|
3850
|
+
var hubName=hubUser.username||'admin';
|
|
3851
|
+
var adminNameInput=document.getElementById('cfgHubAdminName');
|
|
3852
|
+
if(adminNameInput) adminNameInput.value=hubName;
|
|
3724
3853
|
return;
|
|
3725
3854
|
}
|
|
3726
3855
|
|
|
@@ -3912,6 +4041,9 @@ function guideGoToHub(role){
|
|
|
3912
4041
|
|
|
3913
4042
|
/* ─── Hub Admin Panel ─── */
|
|
3914
4043
|
var adminDataCache={users:[],groups:[],tasks:[],skills:[],memories:[]};
|
|
4044
|
+
var _lastAdminFingerprint='';
|
|
4045
|
+
var hubTasksCache=[];
|
|
4046
|
+
var hubSkillsCache=[];
|
|
3915
4047
|
var ADMIN_PAGE_SIZE=20;
|
|
3916
4048
|
var adminPage={users:0,tasks:0,skills:0,memories:0};
|
|
3917
4049
|
|
|
@@ -3933,12 +4065,9 @@ function adminPaginateHtml(total,page,refilterFn){
|
|
|
3933
4065
|
}
|
|
3934
4066
|
|
|
3935
4067
|
var _adminPollTimer=null;
|
|
3936
|
-
function startAdminPoll(){
|
|
3937
|
-
if(_adminPollTimer) return;
|
|
3938
|
-
_adminPollTimer=setInterval(function(){pollAdminPending();},30000);
|
|
3939
|
-
pollAdminPending();
|
|
3940
|
-
}
|
|
4068
|
+
function startAdminPoll(){ startLivePoller(); }
|
|
3941
4069
|
async function pollAdminPending(){
|
|
4070
|
+
if(!window._isHubAdmin) return;
|
|
3942
4071
|
try{
|
|
3943
4072
|
var r=await fetch('/api/sharing/pending-users');
|
|
3944
4073
|
var d=await r.json();
|
|
@@ -3988,24 +4117,44 @@ async function loadAdminData(){
|
|
|
3988
4117
|
}
|
|
3989
4118
|
if(notEnabledEl) notEnabledEl.style.display='none';
|
|
3990
4119
|
if(mainEl) mainEl.style.display='';
|
|
3991
|
-
|
|
3992
|
-
var statsEl=document.getElementById('adminStats');
|
|
3993
|
-
if(statsEl) statsEl.innerHTML='<div class="admin-empty">'+t('admin.noPermission')+'</div>';
|
|
3994
|
-
return;
|
|
3995
|
-
}
|
|
4120
|
+
var isAdmin=!!window._isHubAdmin;
|
|
3996
4121
|
try{
|
|
3997
|
-
var
|
|
3998
|
-
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
|
|
4005
|
-
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
|
|
4122
|
+
var fetches;
|
|
4123
|
+
if(isAdmin){
|
|
4124
|
+
fetches=await Promise.all([
|
|
4125
|
+
fetch('/api/sharing/users').then(function(r){return r.json();}),
|
|
4126
|
+
fetch('/api/admin/shared-tasks').then(function(r){return r.json();}),
|
|
4127
|
+
fetch('/api/admin/shared-skills').then(function(r){return r.json();}),
|
|
4128
|
+
fetch('/api/sharing/pending-users').then(function(r){return r.json();}),
|
|
4129
|
+
fetch('/api/admin/shared-memories').then(function(r){return r.json();})
|
|
4130
|
+
]);
|
|
4131
|
+
}else{
|
|
4132
|
+
fetches=await Promise.all([
|
|
4133
|
+
Promise.resolve({users:[]}),
|
|
4134
|
+
fetch('/api/sharing/tasks/list?limit=500').then(function(r){return r.json();}),
|
|
4135
|
+
fetch('/api/sharing/skills/list?limit=500').then(function(r){return r.json();}),
|
|
4136
|
+
Promise.resolve({users:[]}),
|
|
4137
|
+
fetch('/api/sharing/memories/list?limit=500').then(function(r){return r.json();})
|
|
4138
|
+
]);
|
|
4139
|
+
}
|
|
4140
|
+
var usersR=fetches[0],tasksR=fetches[1],skillsR=fetches[2],pendingR=fetches[3],memoriesR=fetches[4];
|
|
4141
|
+
var _newUsers=Array.isArray(usersR.users)?usersR.users:[];
|
|
4142
|
+
var _newTasks=Array.isArray(tasksR.tasks)?tasksR.tasks:[];
|
|
4143
|
+
var _newSkills=Array.isArray(skillsR.skills)?skillsR.skills:[];
|
|
4144
|
+
var _newMemories=Array.isArray(memoriesR.memories)?memoriesR.memories:[];
|
|
4145
|
+
var pending=isAdmin?(Array.isArray(pendingR.users)?pendingR.users:[]):[];
|
|
4146
|
+
var _fp=_newUsers.length+':'+_newTasks.length+':'+_newSkills.length+':'+_newMemories.length+':'+pending.length
|
|
4147
|
+
+':'+_newUsers.map(function(u){return u.id+'|'+(u.isOnline?1:0)+'|'+(u.role||'')}).join(',')
|
|
4148
|
+
+':'+_newMemories.map(function(m){return m.id}).join(',')
|
|
4149
|
+
+':'+_newTasks.map(function(t){return t.id+'|'+(t.status||'')}).join(',')
|
|
4150
|
+
+':'+_newSkills.map(function(s){return s.id+'|'+(s.status||'')}).join(',')
|
|
4151
|
+
+':'+pending.map(function(p){return p.id}).join(',');
|
|
4152
|
+
if(_fp===_lastAdminFingerprint) return;
|
|
4153
|
+
_lastAdminFingerprint=_fp;
|
|
4154
|
+
adminDataCache.users=_newUsers;
|
|
4155
|
+
adminDataCache.tasks=_newTasks;
|
|
4156
|
+
adminDataCache.skills=_newSkills;
|
|
4157
|
+
adminDataCache.memories=_newMemories;
|
|
4009
4158
|
adminDataCache._pending=pending;
|
|
4010
4159
|
var badge=document.getElementById('adminPendingBadge');
|
|
4011
4160
|
if(badge){if(pending.length>0){badge.textContent=pending.length;badge.style.display='inline';}else{badge.style.display='none';}}
|
|
@@ -4014,18 +4163,48 @@ async function loadAdminData(){
|
|
|
4014
4163
|
renderAdminTasks(adminDataCache.tasks);
|
|
4015
4164
|
renderAdminSkills(adminDataCache.skills);
|
|
4016
4165
|
renderAdminMemories(adminDataCache.memories);
|
|
4166
|
+
updateAdminTabsVisibility();
|
|
4017
4167
|
}catch(e){
|
|
4018
4168
|
var statsEl=document.getElementById('adminStats');
|
|
4019
4169
|
if(statsEl) statsEl.innerHTML='<div class="admin-empty">'+t('admin.loadFailed')+esc(String(e))+'</div>';
|
|
4020
4170
|
}
|
|
4021
4171
|
}
|
|
4172
|
+
function updateAdminTabsVisibility(){
|
|
4173
|
+
var bar=document.getElementById('adminTabsBar');
|
|
4174
|
+
if(!bar) return;
|
|
4175
|
+
var tabs=bar.querySelectorAll('.admin-tab');
|
|
4176
|
+
var isAdmin=!!window._isHubAdmin;
|
|
4177
|
+
tabs.forEach(function(tab){
|
|
4178
|
+
var onclick=tab.getAttribute('onclick')||'';
|
|
4179
|
+
if(onclick.indexOf("'users'")!==-1){
|
|
4180
|
+
tab.style.display=isAdmin?'':'none';
|
|
4181
|
+
}
|
|
4182
|
+
});
|
|
4183
|
+
if(!isAdmin){
|
|
4184
|
+
var usersPanel=document.getElementById('adminUsersPanel');
|
|
4185
|
+
if(usersPanel&&usersPanel.classList.contains('active')){
|
|
4186
|
+
usersPanel.classList.remove('active');
|
|
4187
|
+
var memPanel=document.getElementById('adminMemoriesPanel');
|
|
4188
|
+
if(memPanel) memPanel.classList.add('active');
|
|
4189
|
+
tabs.forEach(function(tab){
|
|
4190
|
+
tab.classList.remove('active');
|
|
4191
|
+
var onclick=tab.getAttribute('onclick')||'';
|
|
4192
|
+
if(onclick.indexOf("'memories'")!==-1) tab.classList.add('active');
|
|
4193
|
+
});
|
|
4194
|
+
}
|
|
4195
|
+
}
|
|
4196
|
+
var subEl=document.querySelector('.admin-header-sub');
|
|
4197
|
+
if(subEl) subEl.textContent=isAdmin?t('admin.subtitle'):t('admin.subtitle.member');
|
|
4198
|
+
}
|
|
4022
4199
|
|
|
4023
4200
|
function renderAdminStats(pendingCount){
|
|
4024
4201
|
var el=document.getElementById('adminStats');
|
|
4025
4202
|
if(!el) return;
|
|
4203
|
+
var isAdmin=!!window._isHubAdmin;
|
|
4204
|
+
var onlineCount=adminDataCache.users.filter(function(u){return !!u.isOnline;}).length;
|
|
4026
4205
|
el.innerHTML=
|
|
4027
|
-
'<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>'+
|
|
4028
|
-
'<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>'+
|
|
4206
|
+
(isAdmin?'<div class="admin-stat-box"><span class="as-icon">\u{1F465}</span><div class="val">'+onlineCount+' / '+adminDataCache.users.length+'</div><div class="lbl">'+t('admin.stat.activeUsers')+'</div></div>'+
|
|
4207
|
+
'<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>':'')+
|
|
4029
4208
|
'<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>'+
|
|
4030
4209
|
'<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>'+
|
|
4031
4210
|
'<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>';
|
|
@@ -4035,82 +4214,122 @@ function renderAdminStats(pendingCount){
|
|
|
4035
4214
|
tc=document.getElementById('adminTabCountSkills');if(tc)tc.textContent=adminDataCache.skills.length;
|
|
4036
4215
|
}
|
|
4037
4216
|
|
|
4217
|
+
function auRelativeTime(ts){
|
|
4218
|
+
if(!ts) return t('admin.neverActive');
|
|
4219
|
+
var diff=Date.now()-ts;
|
|
4220
|
+
if(diff<60000) return t('notif.timeAgo.just');
|
|
4221
|
+
if(diff<3600000) return t('notif.timeAgo.min').replace('{n}',Math.floor(diff/60000));
|
|
4222
|
+
if(diff<86400000) return t('notif.timeAgo.hour').replace('{n}',Math.floor(diff/3600000));
|
|
4223
|
+
return t('notif.timeAgo.day').replace('{n}',Math.floor(diff/86400000));
|
|
4224
|
+
}
|
|
4225
|
+
|
|
4226
|
+
function renderAdminUserCard(u,adminCount){
|
|
4227
|
+
var uid=escAttr(u.id);
|
|
4228
|
+
var uname=escAttr(u.username||'');
|
|
4229
|
+
var online=!!u.isOnline;
|
|
4230
|
+
var statusCls=online?'online':'offline';
|
|
4231
|
+
|
|
4232
|
+
var statusIndicator='<span class="au-status-dot '+statusCls+'"></span>';
|
|
4233
|
+
var statusLabel=online
|
|
4234
|
+
?'<span class="au-status-text online">'+t('admin.onlineNow')+'</span>'
|
|
4235
|
+
:'<span class="au-status-text offline">'+auRelativeTime(u.lastActiveAt)+'</span>';
|
|
4236
|
+
|
|
4237
|
+
var titleDisplay='<span class="admin-card-title" id="au_name_'+uid+'">'+statusIndicator+esc(u.username||u.id)+
|
|
4238
|
+
' <button onclick="adminStartEditName(this,"'+uid+'","'+uname+'")" style="background:none;border:none;cursor:pointer;color:var(--text-muted);padding:2px;font-size:13px;vertical-align:middle;opacity:.5;transition:opacity .15s" onmouseenter="this.style.opacity=1" onmouseleave="this.style.opacity=.5" title="'+t('admin.editName')+'">\u270E</button></span>';
|
|
4239
|
+
|
|
4240
|
+
var editRow='<div id="au_edit_'+uid+'" style="display:none;align-items:center;gap:6px">'+
|
|
4241
|
+
'<input id="au_input_'+uid+'" type="text" value="'+uname+'" style="flex:1;padding:5px 10px;border:1px solid var(--pri);border-radius:8px;font-size:13px;font-weight:600;background:var(--bg);color:var(--text);outline:none;min-width:0" onkeydown="if(event.key==="Enter")adminSaveEditName("'+uid+'");if(event.key==="Escape")adminCancelEditName("'+uid+'")">'+
|
|
4242
|
+
'<button onclick="adminSaveEditName("'+uid+'")" class="btn btn-sm btn-primary" style="padding:4px 12px;font-size:11px;white-space:nowrap">\u2713</button>'+
|
|
4243
|
+
'<button onclick="adminCancelEditName("'+uid+'")" class="btn btn-sm btn-ghost" style="padding:4px 8px;font-size:11px;color:var(--text-muted)">\u2717</button></div>';
|
|
4244
|
+
|
|
4245
|
+
var mc=u.memoryCount||0, tc=u.taskCount||0, sc=u.skillCount||0;
|
|
4246
|
+
var contribHtml='<div class="au-contrib">'+
|
|
4247
|
+
'<span class="au-contrib-item"><span class="au-contrib-num" style="color:var(--pri)">'+mc+'</span> '+t('admin.contrib.memories')+'</span>'+
|
|
4248
|
+
'<span class="au-contrib-item"><span class="au-contrib-num" style="color:var(--green)">'+tc+'</span> '+t('admin.contrib.tasks')+'</span>'+
|
|
4249
|
+
'<span class="au-contrib-item"><span class="au-contrib-num" style="color:var(--amber)">'+sc+'</span> '+t('admin.contrib.skills')+'</span>'+
|
|
4250
|
+
'</div>';
|
|
4251
|
+
|
|
4252
|
+
var infoRows=[];
|
|
4253
|
+
if(u.deviceName) infoRows.push('<span class="au-info-item">\u{1F4BB} '+t('admin.device')+esc(u.deviceName)+'</span>');
|
|
4254
|
+
if(u.lastIp) infoRows.push('<span class="au-info-item">\u{1F310} '+t('admin.ip')+esc(u.lastIp)+'</span>');
|
|
4255
|
+
if(u.createdAt) infoRows.push('<span class="au-info-item">\u{1F4C5} '+t('admin.joined')+formatDateTimeSeconds(u.createdAt)+'</span>');
|
|
4256
|
+
if(u.approvedAt) infoRows.push('<span class="au-info-item">\u2705 '+t('admin.approved')+formatDateTimeSeconds(u.approvedAt)+'</span>');
|
|
4257
|
+
var lastAct=u.lastActiveAt||u.approvedAt||u.createdAt;
|
|
4258
|
+
infoRows.push('<span class="au-info-item">\u{1F552} '+t('admin.lastActive')+(lastAct?formatDateTimeSeconds(lastAct):t('admin.neverActive'))+'</span>');
|
|
4259
|
+
var infoHtml='<div class="au-info">'+infoRows.join('')+'</div>';
|
|
4260
|
+
|
|
4261
|
+
var actions='';
|
|
4262
|
+
if(u.isOwner){
|
|
4263
|
+
actions+='<span style="font-size:11px;color:var(--text-muted);padding:4px 0">'+t('admin.ownerHint')+'</span>';
|
|
4264
|
+
}else if(u.role!=='admin'){
|
|
4265
|
+
actions+='<button class="btn btn-sm btn-ghost" onclick="adminToggleRole("'+uid+'","admin")" style="color:var(--accent)">'+t('admin.promoteAdmin')+'</button>';
|
|
4266
|
+
actions+='<button class="btn btn-sm btn-ghost" onclick="adminRemoveUser("'+uid+'","'+uname+'")" style="color:var(--rose)">'+t('admin.remove')+'</button>';
|
|
4267
|
+
}else if(adminCount>1){
|
|
4268
|
+
actions+='<button class="btn btn-sm btn-ghost" onclick="adminToggleRole("'+uid+'","member")">'+t('admin.demoteMember')+'</button>';
|
|
4269
|
+
actions+='<button class="btn btn-sm btn-ghost" onclick="adminRemoveUser("'+uid+'","'+uname+'")" style="color:var(--rose)">'+t('admin.remove')+'</button>';
|
|
4270
|
+
}else{
|
|
4271
|
+
actions+='<span style="font-size:11px;color:var(--text-muted);padding:4px 0">'+t('admin.lastAdminHint')+'</span>';
|
|
4272
|
+
}
|
|
4273
|
+
var ownerBadge=u.isOwner?' <span style="font-size:9px;background:linear-gradient(135deg,#fbbf24,#f59e0b);color:#000;padding:2px 8px;border-radius:6px;font-weight:800;vertical-align:middle;margin-left:4px;letter-spacing:.04em;text-transform:uppercase;box-shadow:0 2px 8px rgba(251,191,36,.3)">Owner</span>':'';
|
|
4274
|
+
|
|
4275
|
+
return '<div class="admin-card au-card au-'+statusCls+'"><div class="admin-card-header"><div style="flex:1;min-width:0;display:flex;align-items:center;gap:8px;flex-wrap:wrap">'+
|
|
4276
|
+
'<div style="flex:1;min-width:0">'+titleDisplay+editRow+'</div>'+statusLabel+
|
|
4277
|
+
'</div>'+
|
|
4278
|
+
'<div style="display:flex;align-items:center;gap:6px"><span class="admin-badge '+(u.role==='admin'?'admin':'member')+'">'+esc(u.role||'member')+'</span>'+ownerBadge+'</div></div>'+
|
|
4279
|
+
contribHtml+infoHtml+
|
|
4280
|
+
(actions?'<div class="admin-card-actions" style="border-top:1px solid rgba(99,102,241,.08);padding-top:12px;margin-top:6px">'+actions+'</div>':'')+
|
|
4281
|
+
'</div>';
|
|
4282
|
+
}
|
|
4283
|
+
|
|
4038
4284
|
function renderAdminUsers(users,pending){
|
|
4039
4285
|
var el=document.getElementById('adminUsersPanel');
|
|
4040
4286
|
if(!el) return;
|
|
4287
|
+
var isAdmin=!!window._isHubAdmin;
|
|
4288
|
+
if(!isAdmin){
|
|
4289
|
+
el.innerHTML='<div class="admin-empty" style="padding:32px;text-align:center;color:var(--text-sec)">'+t('admin.noPermission')+'</div>';
|
|
4290
|
+
return;
|
|
4291
|
+
}
|
|
4041
4292
|
var html='';
|
|
4042
4293
|
if(pending&&pending.length>0){
|
|
4043
|
-
html+='<div
|
|
4294
|
+
html+='<div class="admin-pending-section"><h3>'+t('admin.pendingApproval')+' <span class="pending-count">'+pending.length+'</span></h3>';
|
|
4044
4295
|
for(var p=0;p<pending.length;p++){
|
|
4045
4296
|
var pu=pending[p];
|
|
4046
|
-
html+='<div class="admin-
|
|
4047
|
-
'<div class="
|
|
4048
|
-
'<div class="
|
|
4049
|
-
|
|
4050
|
-
'<button class="btn
|
|
4297
|
+
html+='<div class="admin-pending-card">'+
|
|
4298
|
+
'<div class="apc-name">'+esc(pu.username||pu.id||'Unknown')+'</div>'+
|
|
4299
|
+
'<div class="apc-meta"><span>\u{1F4BB} '+esc(pu.deviceName||'unknown')+'</span>'+(pu.createdAt?'<span>\u{1F552} '+formatDateTimeSeconds(pu.createdAt)+'</span>':'')+'</div>'+
|
|
4300
|
+
'<div class="apc-actions">'+
|
|
4301
|
+
'<button class="btn-approve" onclick="adminApproveUser("'+escAttr(pu.id)+'","'+escAttr(pu.username||'')+'")">'+t('admin.approve')+'</button>'+
|
|
4302
|
+
'<button class="btn-reject" onclick="adminRejectUser("'+escAttr(pu.id)+'")">'+t('admin.reject')+'</button>'+
|
|
4051
4303
|
'</div></div>';
|
|
4052
4304
|
}
|
|
4053
4305
|
html+='</div>';
|
|
4054
4306
|
}
|
|
4055
|
-
|
|
4056
|
-
|
|
4307
|
+
|
|
4308
|
+
var onlineUsers=users.filter(function(u){return !!u.isOnline;});
|
|
4309
|
+
var offlineUsers=users.filter(function(u){return !u.isOnline;});
|
|
4310
|
+
offlineUsers.sort(function(a,b){return (b.lastActiveAt||0)-(a.lastActiveAt||0);});
|
|
4311
|
+
var sorted=onlineUsers.concat(offlineUsers);
|
|
4312
|
+
var adminCount=users.filter(function(x){return x.role==='admin';}).length;
|
|
4313
|
+
|
|
4314
|
+
if(sorted.length===0){
|
|
4057
4315
|
html+='<div class="admin-empty"><span class="ae-icon">\u{1F465}</span>'+t('admin.noActiveUsers')+'</div>';
|
|
4058
4316
|
}else{
|
|
4059
|
-
|
|
4060
|
-
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
|
|
4064
|
-
|
|
4065
|
-
|
|
4066
|
-
|
|
4067
|
-
|
|
4068
|
-
|
|
4069
|
-
|
|
4070
|
-
var titleDisplay='<span class="admin-card-title" id="au_name_'+uid+'">'+esc(u.username||u.id)+
|
|
4071
|
-
' <button onclick="adminStartEditName(this,"'+uid+'","'+uname+'")" style="background:none;border:none;cursor:pointer;color:var(--text-muted);padding:2px;font-size:13px;vertical-align:middle;opacity:.5;transition:opacity .15s" onmouseenter="this.style.opacity=1" onmouseleave="this.style.opacity=.5" title="'+t('admin.editName')+'">\u270E</button></span>';
|
|
4072
|
-
|
|
4073
|
-
var editRow='<div id="au_edit_'+uid+'" style="display:none;align-items:center;gap:6px">'+
|
|
4074
|
-
'<input id="au_input_'+uid+'" type="text" value="'+uname+'" style="flex:1;padding:5px 10px;border:1px solid var(--pri);border-radius:8px;font-size:13px;font-weight:600;background:var(--bg);color:var(--text);outline:none;min-width:0" onkeydown="if(event.key==="Enter")adminSaveEditName("'+uid+'");if(event.key==="Escape")adminCancelEditName("'+uid+'")">'+
|
|
4075
|
-
'<button onclick="adminSaveEditName("'+uid+'")" class="btn btn-sm btn-primary" style="padding:4px 12px;font-size:11px;white-space:nowrap">\u2713</button>'+
|
|
4076
|
-
'<button onclick="adminCancelEditName("'+uid+'")" class="btn btn-sm btn-ghost" style="padding:4px 8px;font-size:11px;color:var(--text-muted)">\u2717</button></div>';
|
|
4077
|
-
|
|
4078
|
-
var mc=u.memoryCount||0, tc=u.taskCount||0, sc=u.skillCount||0;
|
|
4079
|
-
var contribHtml='<div class="au-contrib">'+
|
|
4080
|
-
'<span class="au-contrib-item"><span class="au-contrib-num" style="color:var(--pri)">'+mc+'</span> '+t('admin.contrib.memories')+'</span>'+
|
|
4081
|
-
'<span class="au-contrib-item"><span class="au-contrib-num" style="color:var(--green)">'+tc+'</span> '+t('admin.contrib.tasks')+'</span>'+
|
|
4082
|
-
'<span class="au-contrib-item"><span class="au-contrib-num" style="color:var(--amber)">'+sc+'</span> '+t('admin.contrib.skills')+'</span>'+
|
|
4083
|
-
'</div>';
|
|
4084
|
-
|
|
4085
|
-
var infoRows=[];
|
|
4086
|
-
if(u.deviceName) infoRows.push('<span class="au-info-item">\u{1F4BB} '+t('admin.device')+esc(u.deviceName)+'</span>');
|
|
4087
|
-
if(u.lastIp) infoRows.push('<span class="au-info-item">\u{1F310} '+t('admin.ip')+esc(u.lastIp)+'</span>');
|
|
4088
|
-
if(u.createdAt) infoRows.push('<span class="au-info-item">\u{1F4C5} '+t('admin.joined')+formatDateTimeSeconds(u.createdAt)+'</span>');
|
|
4089
|
-
if(u.approvedAt) infoRows.push('<span class="au-info-item">\u2705 '+t('admin.approved')+formatDateTimeSeconds(u.approvedAt)+'</span>');
|
|
4090
|
-
infoRows.push('<span class="au-info-item">\u{1F552} '+t('admin.lastActive')+(u.lastActiveAt?formatDateTimeSeconds(u.lastActiveAt):t('admin.neverActive'))+'</span>');
|
|
4091
|
-
var infoHtml='<div class="au-info">'+infoRows.join('')+'</div>';
|
|
4092
|
-
|
|
4093
|
-
var actions='';
|
|
4094
|
-
if(u.role!=='admin'){
|
|
4095
|
-
actions+='<button class="btn btn-sm btn-ghost" onclick="adminToggleRole("'+uid+'","admin")" style="color:var(--accent)">'+t('admin.promoteAdmin')+'</button>';
|
|
4096
|
-
actions+='<button class="btn btn-sm btn-ghost" onclick="adminRemoveUser("'+uid+'","'+uname+'")" style="color:var(--rose)">'+t('admin.remove')+'</button>';
|
|
4097
|
-
}else if(adminCount>1){
|
|
4098
|
-
actions+='<button class="btn btn-sm btn-ghost" onclick="adminToggleRole("'+uid+'","member")">'+t('admin.demoteMember')+'</button>';
|
|
4099
|
-
actions+='<button class="btn btn-sm btn-ghost" onclick="adminRemoveUser("'+uid+'","'+uname+'")" style="color:var(--rose)">'+t('admin.remove')+'</button>';
|
|
4100
|
-
}else{
|
|
4101
|
-
actions+='<span style="font-size:11px;color:var(--text-muted);padding:4px 0">'+t('admin.lastAdminHint')+'</span>';
|
|
4102
|
-
}
|
|
4103
|
-
html+='<div class="admin-card au-card"><div class="admin-card-header"><div style="flex:1;min-width:0">'+titleDisplay+editRow+'</div>'+
|
|
4104
|
-
'<span class="admin-badge '+(u.role==='admin'?'admin':'member')+'">'+esc(u.role||'member')+'</span></div>'+
|
|
4105
|
-
contribHtml+infoHtml+
|
|
4106
|
-
(actions?'<div class="admin-card-actions" style="border-top:1px dashed var(--border);padding-top:10px;margin-top:4px">'+actions+'</div>':'')+
|
|
4107
|
-
'</div>';
|
|
4317
|
+
html+='<div class="au-group-header"><span class="au-group-dot online"></span>'+t('admin.onlineUsers')+' <span class="au-group-count">('+onlineUsers.length+')</span></div>';
|
|
4318
|
+
if(onlineUsers.length===0){
|
|
4319
|
+
html+='<div style="font-size:12px;color:var(--text-muted);padding:8px 0 12px">\u2014</div>';
|
|
4320
|
+
}else{
|
|
4321
|
+
for(var i=0;i<onlineUsers.length;i++) html+=renderAdminUserCard(onlineUsers[i],adminCount);
|
|
4322
|
+
}
|
|
4323
|
+
html+='<div class="au-group-header"><span class="au-group-dot offline"></span>'+t('admin.offlineUsers')+' <span class="au-group-count">('+offlineUsers.length+')</span></div>';
|
|
4324
|
+
if(offlineUsers.length===0){
|
|
4325
|
+
html+='<div style="font-size:12px;color:var(--text-muted);padding:8px 0 12px">\u2014</div>';
|
|
4326
|
+
}else{
|
|
4327
|
+
for(var j=0;j<offlineUsers.length;j++) html+=renderAdminUserCard(offlineUsers[j],adminCount);
|
|
4108
4328
|
}
|
|
4109
|
-
html+=adminPaginateHtml(totalUsers,adminPage.users,'adminUsers');
|
|
4110
4329
|
}
|
|
4111
4330
|
el.innerHTML=html;
|
|
4112
4331
|
}
|
|
4113
|
-
function adminUsersPage(p){
|
|
4332
|
+
function adminUsersPage(p){renderAdminUsers(adminDataCache.users,adminDataCache._pending||[]);}
|
|
4114
4333
|
|
|
4115
4334
|
async function adminApproveUser(userId,username){
|
|
4116
4335
|
try{
|
|
@@ -4133,7 +4352,9 @@ async function adminToggleRole(userId,newRole){
|
|
|
4133
4352
|
try{
|
|
4134
4353
|
var r=await fetch('/api/sharing/change-role',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:userId,role:newRole})});
|
|
4135
4354
|
var d=await r.json();
|
|
4136
|
-
if(d.ok){toast(t('toast.roleChanged'),'success');loadAdminData();}
|
|
4355
|
+
if(d.ok){toast(t('toast.roleChanged'),'success');loadAdminData();}
|
|
4356
|
+
else if(d.error==='cannot_demote_owner'){toast(t('admin.ownerHint'),'error');}
|
|
4357
|
+
else{toast(d.error||t('toast.roleChangeFail'),'error');}
|
|
4137
4358
|
}catch(e){toast(t('toast.roleChangeFail')+': '+e.message,'error');}
|
|
4138
4359
|
}
|
|
4139
4360
|
function adminStartEditName(btn,userId,currentName){
|
|
@@ -4172,7 +4393,9 @@ async function adminRemoveUser(userId,username){
|
|
|
4172
4393
|
try{
|
|
4173
4394
|
var r=await fetch('/api/sharing/remove-user',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:userId,cleanResources:clean})});
|
|
4174
4395
|
var d=await r.json();
|
|
4175
|
-
if(d.ok){toast(t('toast.userRemoved'),'success');loadAdminData();}
|
|
4396
|
+
if(d.ok){toast(t('toast.userRemoved'),'success');loadAdminData();}
|
|
4397
|
+
else if(d.error==='cannot_remove_owner'){toast(t('admin.ownerHint'),'error');}
|
|
4398
|
+
else{toast(d.error||t('toast.removeFail'),'error');}
|
|
4176
4399
|
}catch(e){toast(t('toast.removeFail')+': '+e.message,'error');}
|
|
4177
4400
|
}
|
|
4178
4401
|
|
|
@@ -4244,7 +4467,7 @@ function renderAdminTasks(tasks){
|
|
|
4244
4467
|
(tk.chunkCount!=null?'<span class="admin-card-tag tag-kind">\u{1F4DD} '+tk.chunkCount+' '+t('admin.chunks')+'</span>':'')+
|
|
4245
4468
|
'</div>'+
|
|
4246
4469
|
'<span class="admin-card-actions" onclick="event.stopPropagation()">'+
|
|
4247
|
-
'<button class="btn btn-sm btn-ghost" onclick="adminDeleteTask("'+escAttr(tk.id)+'","'+escAttr(tk.title||tk.id)+'")" style="color:var(--rose)">'+t('admin.remove')+'</button>'+
|
|
4470
|
+
(window._isHubAdmin?'<button class="btn btn-sm btn-ghost" onclick="adminDeleteTask("'+escAttr(tk.id)+'","'+escAttr(tk.title||tk.id)+'")" style="color:var(--rose)">'+t('admin.remove')+'</button>':'')+
|
|
4248
4471
|
'<button class="btn btn-sm btn-ghost admin-card-expand-btn" onclick="toggleAdminTaskCard("'+cardId+'",'+i+')">'+t('admin.expand')+'</button>'+
|
|
4249
4472
|
'<span class="admin-card-time">'+(timeRange||formatDateTimeSeconds(tk.updatedAt||tk.createdAt))+'</span>'+
|
|
4250
4473
|
'</span>'+
|
|
@@ -4307,7 +4530,7 @@ function renderAdminSkills(skills){
|
|
|
4307
4530
|
(qs!=null?'<span class="admin-card-tag tag-kind">\u2605 '+Number(qs).toFixed(1)+'</span>':'')+
|
|
4308
4531
|
'</div>'+
|
|
4309
4532
|
'<span class="admin-card-actions" onclick="event.stopPropagation()">'+
|
|
4310
|
-
'<button class="btn btn-sm btn-ghost" onclick="adminDeleteSkill("'+escAttr(s.id)+'","'+escAttr(s.name||s.id)+'")" style="color:var(--rose)">'+t('admin.remove')+'</button>'+
|
|
4533
|
+
(window._isHubAdmin?'<button class="btn btn-sm btn-ghost" onclick="adminDeleteSkill("'+escAttr(s.id)+'","'+escAttr(s.name||s.id)+'")" style="color:var(--rose)">'+t('admin.remove')+'</button>':'')+
|
|
4311
4534
|
'<button class="btn btn-sm btn-ghost admin-card-expand-btn" onclick="toggleAdminSkillCard("'+cardId+'",'+i+')">'+t('admin.expand')+'</button>'+
|
|
4312
4535
|
(s.sourceSkillId?'<button class="btn btn-sm btn-ghost" onclick="window.open("/api/skill/'+encodeURIComponent(s.sourceSkillId)+'/download","_blank")" style="color:var(--pri)">\u2B07</button>':'')+
|
|
4313
4536
|
'<span class="admin-card-time">'+formatDateTimeSeconds(s.updatedAt||s.createdAt)+'</span>'+
|
|
@@ -4371,7 +4594,7 @@ function renderAdminMemories(memories){
|
|
|
4371
4594
|
(m.kind?'<span class="admin-card-tag tag-kind">'+esc(m.kind)+'</span>':'')+
|
|
4372
4595
|
'</div>'+
|
|
4373
4596
|
'<span class="admin-card-actions">'+
|
|
4374
|
-
'<button class="btn btn-sm btn-ghost" onclick="event.stopPropagation();adminDeleteMemory("'+escAttr(m.id)+'","'+escAttr(m.summary||m.id)+'")" style="color:var(--rose)">'+t('admin.remove')+'</button>'+
|
|
4597
|
+
(window._isHubAdmin?'<button class="btn btn-sm btn-ghost" onclick="event.stopPropagation();adminDeleteMemory("'+escAttr(m.id)+'","'+escAttr(m.summary||m.id)+'")" style="color:var(--rose)">'+t('admin.remove')+'</button>':'')+
|
|
4375
4598
|
'<button class="btn btn-sm btn-ghost admin-card-expand-btn" onclick="event.stopPropagation();toggleAdminMemoryCard("'+cardId+'",'+i+')">'+t('admin.expand')+'</button>'+
|
|
4376
4599
|
'<span class="admin-card-time">'+formatDateTimeSeconds(m.updatedAt||m.createdAt)+'</span>'+
|
|
4377
4600
|
'</span>'+
|
|
@@ -4449,12 +4672,19 @@ async function toggleAdminTaskCard(cardId,idx){
|
|
|
4449
4672
|
var tk=(adminTasksCache||[])[idx];
|
|
4450
4673
|
if(!tk){detail.innerHTML='<div style="color:var(--text-muted);font-size:14px;padding:12px">'+t('admin.noContent')+'</div>';return;}
|
|
4451
4674
|
var localTaskId=tk.sourceTaskId||tk.id;
|
|
4675
|
+
var hubTaskId=tk.id;
|
|
4452
4676
|
detail.innerHTML='<div class="spinner"></div>';
|
|
4453
4677
|
var task=null;
|
|
4454
4678
|
try{
|
|
4455
4679
|
var r=await fetch('/api/task/'+encodeURIComponent(localTaskId));
|
|
4456
4680
|
if(r.ok) task=await r.json();
|
|
4457
4681
|
}catch(e){}
|
|
4682
|
+
if(!task){
|
|
4683
|
+
try{
|
|
4684
|
+
var r2=await fetch('/api/admin/shared-tasks/'+encodeURIComponent(hubTaskId)+'/detail');
|
|
4685
|
+
if(r2.ok) task=await r2.json();
|
|
4686
|
+
}catch(e2){}
|
|
4687
|
+
}
|
|
4458
4688
|
if(!task){detail.innerHTML='<div style="color:var(--text-muted);font-size:14px;padding:12px">'+t('admin.noContent')+'</div>';return;}
|
|
4459
4689
|
var metaHtml='<div class="admin-card-detail-meta admin-task-meta">'+
|
|
4460
4690
|
(tk.status?'<span class="meta-item"><span class="task-status-badge '+tk.status+'">'+esc(tk.status)+'</span></span>':'')+
|
|
@@ -4525,11 +4755,18 @@ async function toggleAdminSkillCard(cardId,idx){
|
|
|
4525
4755
|
if(!sk){detail.innerHTML='<div style="color:var(--text-muted);font-size:13px">'+t('admin.noContent')+'</div>';return;}
|
|
4526
4756
|
detail.innerHTML='<div class="spinner"></div>';
|
|
4527
4757
|
var localSkillId=sk.sourceSkillId||sk.id;
|
|
4758
|
+
var hubSkillId=sk.id;
|
|
4528
4759
|
var localData=null;
|
|
4529
4760
|
try{
|
|
4530
4761
|
var lr=await fetch('/api/skill/'+encodeURIComponent(localSkillId));
|
|
4531
4762
|
if(lr.ok) localData=await lr.json();
|
|
4532
4763
|
}catch(e){}
|
|
4764
|
+
if(!localData){
|
|
4765
|
+
try{
|
|
4766
|
+
var hr=await fetch('/api/admin/shared-skills/'+encodeURIComponent(hubSkillId)+'/detail');
|
|
4767
|
+
if(hr.ok) localData=await hr.json();
|
|
4768
|
+
}catch(e2){}
|
|
4769
|
+
}
|
|
4533
4770
|
var localSkill=localData&&localData.skill?localData.skill:sk;
|
|
4534
4771
|
var files=localData&&localData.files?localData.files:[];
|
|
4535
4772
|
var versions=localData&&localData.versions?localData.versions:[];
|
|
@@ -5356,22 +5593,33 @@ function setTaskStatusFilter(btn,status){
|
|
|
5356
5593
|
loadTasks();
|
|
5357
5594
|
}
|
|
5358
5595
|
|
|
5359
|
-
async function loadTasks(){
|
|
5596
|
+
async function loadTasks(silent){
|
|
5360
5597
|
const scope=document.getElementById('taskSearchScope')?document.getElementById('taskSearchScope').value:taskSearchScope;
|
|
5361
5598
|
taskSearchScope=scope||'local';
|
|
5362
|
-
if(taskSearchScope
|
|
5599
|
+
if(taskSearchScope==='hub'){ return loadHubTasks(); }
|
|
5363
5600
|
const list=document.getElementById('tasksList');
|
|
5364
|
-
list.innerHTML='<div class="spinner"></div>';
|
|
5601
|
+
if(!silent) list.innerHTML='<div class="spinner"></div>';
|
|
5365
5602
|
try{
|
|
5366
5603
|
const params=new URLSearchParams({limit:String(TASKS_PER_PAGE),offset:String(tasksPage*TASKS_PER_PAGE)});
|
|
5367
5604
|
if(tasksStatusFilter) params.set('status',tasksStatusFilter);
|
|
5605
|
+
if(taskSearchScope==='local') params.set('owner','agent:main');
|
|
5606
|
+
var baseP=new URLSearchParams();
|
|
5607
|
+
if(taskSearchScope==='local') baseP.set('owner','agent:main');
|
|
5368
5608
|
const [data,allD,activeD,compD,skipD]=await Promise.all([
|
|
5369
5609
|
fetch('/api/tasks?'+params).then(r=>r.json()),
|
|
5370
|
-
fetch('/api/tasks?limit=1&offset=0').then(r=>r.json()),
|
|
5371
|
-
fetch('/api/tasks?status=active&limit=1&offset=0').then(r=>r.json()),
|
|
5372
|
-
fetch('/api/tasks?status=completed&limit=1&offset=0').then(r=>r.json()),
|
|
5373
|
-
fetch('/api/tasks?status=skipped&limit=1&offset=0').then(r=>r.json())
|
|
5610
|
+
fetch('/api/tasks?limit=1&offset=0&'+baseP).then(r=>r.json()),
|
|
5611
|
+
fetch('/api/tasks?status=active&limit=1&offset=0&'+baseP).then(r=>r.json()),
|
|
5612
|
+
fetch('/api/tasks?status=completed&limit=1&offset=0&'+baseP).then(r=>r.json()),
|
|
5613
|
+
fetch('/api/tasks?status=skipped&limit=1&offset=0&'+baseP).then(r=>r.json())
|
|
5374
5614
|
]);
|
|
5615
|
+
if(silent){
|
|
5616
|
+
var fp=JSON.stringify((data.tasks||[]).map(function(tk){return tk.id+'|'+tk.status+'|'+(tk.updatedAt||tk.startedAt)}));
|
|
5617
|
+
fp+=':'+allD.total+':'+activeD.total+':'+compD.total+':'+skipD.total;
|
|
5618
|
+
if(fp===_lastTasksFingerprint) return;
|
|
5619
|
+
_lastTasksFingerprint=fp;
|
|
5620
|
+
}else{
|
|
5621
|
+
_lastTasksFingerprint='';
|
|
5622
|
+
}
|
|
5375
5623
|
document.getElementById('tasksTotalCount').textContent=formatNum(allD.total);
|
|
5376
5624
|
document.getElementById('tasksActiveCount').textContent=formatNum(activeD.total);
|
|
5377
5625
|
document.getElementById('tasksCompletedCount').textContent=formatNum(compD.total);
|
|
@@ -5657,17 +5905,17 @@ function updateSkillCardBadge(skillId,newScope){
|
|
|
5657
5905
|
}
|
|
5658
5906
|
}
|
|
5659
5907
|
|
|
5660
|
-
async function loadSkills(){
|
|
5908
|
+
async function loadSkills(silent){
|
|
5661
5909
|
const list=document.getElementById('skillsList');
|
|
5662
5910
|
const hubList=document.getElementById('hubSkillsList');
|
|
5663
|
-
list.innerHTML='<div class="spinner"></div>';
|
|
5911
|
+
if(!silent) list.innerHTML='<div class="spinner"></div>';
|
|
5664
5912
|
var hubSection=document.getElementById('hubSkillsSection');
|
|
5665
5913
|
if(hubList){
|
|
5666
|
-
if(skillSearchScope==='local'){
|
|
5914
|
+
if(skillSearchScope==='local'||skillSearchScope==='allLocal'){
|
|
5667
5915
|
if(hubSection) hubSection.style.display='none';
|
|
5668
5916
|
}else{
|
|
5669
5917
|
if(hubSection) hubSection.style.display='block';
|
|
5670
|
-
hubList.innerHTML='<div class="spinner"></div>';
|
|
5918
|
+
if(!silent) hubList.innerHTML='<div class="spinner"></div>';
|
|
5671
5919
|
}
|
|
5672
5920
|
}
|
|
5673
5921
|
|
|
@@ -5691,6 +5939,13 @@ async function loadSkills(){
|
|
|
5691
5939
|
return haystack.includes(q);
|
|
5692
5940
|
});
|
|
5693
5941
|
}
|
|
5942
|
+
if(silent){
|
|
5943
|
+
var fp=JSON.stringify(localSkills.map(function(s){return s.id+'|'+s.status+'|'+s.version+'|'+(s.visibility||'')}));
|
|
5944
|
+
if(fp===_lastSkillsFingerprint) return;
|
|
5945
|
+
_lastSkillsFingerprint=fp;
|
|
5946
|
+
}else{
|
|
5947
|
+
_lastSkillsFingerprint='';
|
|
5948
|
+
}
|
|
5694
5949
|
|
|
5695
5950
|
const renderLocalCards=function(skills){
|
|
5696
5951
|
if(!skills||skills.length===0){
|
|
@@ -5736,7 +5991,7 @@ async function loadSkills(){
|
|
|
5736
5991
|
|
|
5737
5992
|
list.innerHTML=renderLocalCards(localSkills);
|
|
5738
5993
|
|
|
5739
|
-
if(skillSearchScope==='local'){
|
|
5994
|
+
if(skillSearchScope==='local'||skillSearchScope==='allLocal'){
|
|
5740
5995
|
if(hubSection) hubSection.style.display='none';
|
|
5741
5996
|
document.getElementById('skillSearchMeta').textContent=query?(t('skills.search.local')+' '+localSkills.length):'';
|
|
5742
5997
|
document.getElementById('skillsTotalCount').textContent=formatNum(localSkills.length);
|
|
@@ -5749,7 +6004,8 @@ async function loadSkills(){
|
|
|
5749
6004
|
|
|
5750
6005
|
if(!query){
|
|
5751
6006
|
if(hubSection) hubSection.style.display='block';
|
|
5752
|
-
|
|
6007
|
+
var localIds=new Set(localSkills.map(function(s){return s.id;}));
|
|
6008
|
+
if(hubList){ loadHubSkills(hubList, localIds); }
|
|
5753
6009
|
document.getElementById('skillSearchMeta').textContent=t('skills.search.local')+' '+localSkills.length;
|
|
5754
6010
|
document.getElementById('skillsTotalCount').textContent=formatNum(localSkills.length);
|
|
5755
6011
|
document.getElementById('skillsActiveCount').textContent=formatNum(localSkills.filter(s=>s.status==='active').length);
|
|
@@ -5807,7 +6063,47 @@ async function loadSkills(){
|
|
|
5807
6063
|
}
|
|
5808
6064
|
}
|
|
5809
6065
|
|
|
5810
|
-
async function
|
|
6066
|
+
async function loadHubTasks(){
|
|
6067
|
+
var list=document.getElementById('tasksList');
|
|
6068
|
+
if(!list) return;
|
|
6069
|
+
list.innerHTML='<div class="spinner"></div>';
|
|
6070
|
+
try{
|
|
6071
|
+
var r=await fetch('/api/sharing/tasks/list?limit=40');
|
|
6072
|
+
var d=await r.json();
|
|
6073
|
+
var tasks=Array.isArray(d.tasks)?d.tasks:[];
|
|
6074
|
+
hubTasksCache=tasks;
|
|
6075
|
+
document.getElementById('tasksTotalCount').textContent=formatNum(tasks.length);
|
|
6076
|
+
document.getElementById('tasksActiveCount').textContent='-';
|
|
6077
|
+
document.getElementById('tasksCompletedCount').textContent='-';
|
|
6078
|
+
document.getElementById('tasksSkippedCount').textContent='-';
|
|
6079
|
+
if(!tasks.length){
|
|
6080
|
+
list.innerHTML='<div style="text-align:center;padding:48px;color:var(--text-muted);font-size:14px">'+t('tasks.empty')+'</div>';
|
|
6081
|
+
document.getElementById('tasksPagination').innerHTML='';
|
|
6082
|
+
return;
|
|
6083
|
+
}
|
|
6084
|
+
list.innerHTML=tasks.map(function(task,idx){
|
|
6085
|
+
var timeStr=task.updatedAt?formatTime(task.updatedAt):(task.createdAt?formatTime(task.createdAt):'');
|
|
6086
|
+
return '<div class="task-card" onclick="openHubTaskDetailFromCache(\\x27hub\\x27,'+idx+')" style="cursor:pointer">'+
|
|
6087
|
+
'<div class="task-card-top">'+
|
|
6088
|
+
'<div class="task-card-title">'+esc(task.title||'(no title)')+'</div>'+
|
|
6089
|
+
'<div class="task-card-badges"><span class="scope-badge team">\\u{1F310} '+t('scope.hub')+'</span></div>'+
|
|
6090
|
+
'</div>'+
|
|
6091
|
+
(task.summary?'<div class="task-card-summary">'+esc(task.summary)+'</div>':'')+
|
|
6092
|
+
'<div class="task-card-bottom">'+
|
|
6093
|
+
(timeStr?'<span class="tag"><span class="icon">\\u{1F4C5}</span> '+timeStr+'</span>':'')+
|
|
6094
|
+
'<span class="tag"><span class="icon">\\u{1F464}</span> '+esc(task.ownerName||'unknown')+'</span>'+
|
|
6095
|
+
(task.chunkCount!=null?'<span class="tag"><span class="icon">\\u{1F4DD}</span> '+task.chunkCount+' '+t('tasks.chunks.label')+'</span>':'')+
|
|
6096
|
+
'</div>'+
|
|
6097
|
+
'</div>';
|
|
6098
|
+
}).join('');
|
|
6099
|
+
document.getElementById('tasksPagination').innerHTML='';
|
|
6100
|
+
}catch(e){
|
|
6101
|
+
list.innerHTML='<div style="text-align:center;padding:48px;color:var(--text-muted);font-size:14px">'+t('tasks.empty')+'</div>';
|
|
6102
|
+
document.getElementById('tasksPagination').innerHTML='';
|
|
6103
|
+
}
|
|
6104
|
+
}
|
|
6105
|
+
|
|
6106
|
+
async function loadHubSkills(hubList, localIds){
|
|
5811
6107
|
if(!hubList) hubList=document.getElementById('hubSkillsList');
|
|
5812
6108
|
if(!hubList) return;
|
|
5813
6109
|
var hubSection=document.getElementById('hubSkillsSection');
|
|
@@ -5815,7 +6111,8 @@ async function loadHubSkills(hubList){
|
|
|
5815
6111
|
try{
|
|
5816
6112
|
const r=await fetch('/api/sharing/skills/list?limit=40');
|
|
5817
6113
|
const d=await r.json();
|
|
5818
|
-
|
|
6114
|
+
var allSkills=Array.isArray(d.skills)?d.skills:[];
|
|
6115
|
+
const skills=localIds?allSkills.filter(function(s){return !localIds.has(s.sourceSkillId);}):allSkills;
|
|
5819
6116
|
hubSkillsCache=skills;
|
|
5820
6117
|
if(!skills.length){
|
|
5821
6118
|
if(hubSection) hubSection.style.display='none';
|
|
@@ -6167,6 +6464,7 @@ async function loadConfig(){
|
|
|
6167
6464
|
document.getElementById('cfgHubTeamToken').value=hub.teamToken||'';
|
|
6168
6465
|
document.getElementById('cfgClientHubAddress').value=client.hubAddress||'';
|
|
6169
6466
|
document.getElementById('cfgClientTeamToken').value=client.teamToken||'';
|
|
6467
|
+
document.getElementById('cfgClientNickname').value=client.nickname||'';
|
|
6170
6468
|
document.getElementById('cfgClientUserToken').value=client.userToken||'';
|
|
6171
6469
|
onSharingToggle();
|
|
6172
6470
|
updateHubShareInfo();
|
|
@@ -6335,6 +6633,7 @@ async function saveHubConfig(){
|
|
|
6335
6633
|
var hubPort=document.getElementById('cfgHubPort').value.trim();
|
|
6336
6634
|
var hubTeamName=document.getElementById('cfgHubTeamName').value.trim();
|
|
6337
6635
|
var hubTeamToken=document.getElementById('cfgHubTeamToken').value.trim();
|
|
6636
|
+
var hubAdminName=document.getElementById('cfgHubAdminName').value.trim();
|
|
6338
6637
|
cfg.sharing.hub={port:hubPort?Number(hubPort):18800};
|
|
6339
6638
|
if(hubTeamName) cfg.sharing.hub.teamName=hubTeamName;
|
|
6340
6639
|
if(hubTeamToken) cfg.sharing.hub.teamToken=hubTeamToken;
|
|
@@ -6344,8 +6643,12 @@ async function saveHubConfig(){
|
|
|
6344
6643
|
var clientAddr=document.getElementById('cfgClientHubAddress').value.trim();
|
|
6345
6644
|
var clientTeamToken=document.getElementById('cfgClientTeamToken').value.trim();
|
|
6346
6645
|
var clientUserToken=document.getElementById('cfgClientUserToken').value.trim();
|
|
6646
|
+
var clientNickname=document.getElementById('cfgClientNickname').value.trim();
|
|
6647
|
+
if(!clientAddr){done();toast(t('settings.hub.test.noAddr'),'error');return;}
|
|
6648
|
+
if(!clientTeamToken){done();toast(t('settings.hub.teamToken.required'),'error');return;}
|
|
6347
6649
|
cfg.sharing.client={};
|
|
6348
6650
|
if(clientAddr) cfg.sharing.client.hubAddress=clientAddr;
|
|
6651
|
+
if(clientNickname) cfg.sharing.client.nickname=clientNickname;
|
|
6349
6652
|
if(clientTeamToken) cfg.sharing.client.teamToken=clientTeamToken;
|
|
6350
6653
|
if(clientUserToken) cfg.sharing.client.userToken=clientUserToken;
|
|
6351
6654
|
cfg.sharing.hub={port:18800,teamName:'',teamToken:''};
|
|
@@ -6358,6 +6661,18 @@ async function saveHubConfig(){
|
|
|
6358
6661
|
done();toast(t('sharing.cannotJoinSelf'),'error');return;
|
|
6359
6662
|
}
|
|
6360
6663
|
}catch(e){}
|
|
6664
|
+
try{
|
|
6665
|
+
var testUrl=clientAddr.indexOf('://')>-1?clientAddr:'http://'+clientAddr;
|
|
6666
|
+
testUrl=testUrl.replace(/\\/+$/,'');
|
|
6667
|
+
var tr=await fetch('/api/sharing/test-hub',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({hubUrl:testUrl})});
|
|
6668
|
+
var td=await tr.json();
|
|
6669
|
+
if(!td.ok){
|
|
6670
|
+
var errMsg=td.error==='cannot_join_self'?t('sharing.cannotJoinSelf'):(td.error||t('settings.hub.test.fail'));
|
|
6671
|
+
done();toast(errMsg,'error');return;
|
|
6672
|
+
}
|
|
6673
|
+
}catch(e){
|
|
6674
|
+
done();toast(t('settings.hub.test.fail')+': '+String(e),'error');return;
|
|
6675
|
+
}
|
|
6361
6676
|
}
|
|
6362
6677
|
}
|
|
6363
6678
|
|
|
@@ -6367,11 +6682,25 @@ async function saveHubConfig(){
|
|
|
6367
6682
|
var confirmMsg=prevRole==='hub'?t('sharing.disable.confirm.hub'):t('sharing.disable.confirm.client');
|
|
6368
6683
|
if(!(await confirmModal(confirmMsg,{danger:true}))){done();return;}
|
|
6369
6684
|
}
|
|
6685
|
+
if(prevSharingEnabled&&sharingEnabled&&prevRole&&prevRole!==_sharingRole){
|
|
6686
|
+
var switchMsg=prevRole==='hub'?t('sharing.switch.hubToClient'):t('sharing.switch.clientToHub');
|
|
6687
|
+
if(!(await confirmModal(switchMsg,{danger:true}))){done();return;}
|
|
6688
|
+
}
|
|
6370
6689
|
|
|
6371
6690
|
var ok=await doSaveConfig(cfg, saveBtn, 'hubSaved');
|
|
6372
6691
|
if(ok){
|
|
6692
|
+
if(sharingEnabled&&_sharingRole==='hub'){
|
|
6693
|
+
var adminNameEl=document.getElementById('cfgHubAdminName');
|
|
6694
|
+
if(adminNameEl&&adminNameEl.value.trim()){
|
|
6695
|
+
try{await fetch('/api/sharing/update-username',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({username:adminNameEl.value.trim()})});}catch(e){}
|
|
6696
|
+
}
|
|
6697
|
+
}
|
|
6698
|
+
_lastSidebarFingerprint='';
|
|
6699
|
+
_lastSettingsFingerprint='';
|
|
6373
6700
|
loadSharingStatus(false);
|
|
6374
|
-
var
|
|
6701
|
+
var enabledChanged=(!!prevSharingEnabled)!==(!!sharingEnabled);
|
|
6702
|
+
var roleChanged=prevRole!==_sharingRole;
|
|
6703
|
+
var needsRestart=enabledChanged||roleChanged;
|
|
6375
6704
|
if(sharingEnabled) updateHubShareInfo();
|
|
6376
6705
|
if(needsRestart){
|
|
6377
6706
|
setTimeout(function(){showRestartOverlay(t('settings.restart.waiting'));},300);
|
|
@@ -6791,23 +7120,89 @@ function renderToolAgg(data){
|
|
|
6791
7120
|
'</tbody></table>';
|
|
6792
7121
|
}
|
|
6793
7122
|
|
|
6794
|
-
/* ───
|
|
6795
|
-
var
|
|
6796
|
-
|
|
6797
|
-
|
|
6798
|
-
|
|
6799
|
-
|
|
6800
|
-
|
|
7123
|
+
/* ─── Unified live-data poller ─── */
|
|
7124
|
+
var _livePoller=null;
|
|
7125
|
+
var _LIVE_POLL_MS=15000;
|
|
7126
|
+
var _livePollBusy=false;
|
|
7127
|
+
|
|
7128
|
+
async function _livePollTick(){
|
|
7129
|
+
if(_livePollBusy||document.hidden) return;
|
|
7130
|
+
_livePollBusy=true;
|
|
7131
|
+
try{
|
|
7132
|
+
if(sharingStatusCache&&sharingStatusCache.enabled&&_lastSharingConnStatus!=='rejected') loadSharingStatus(false);
|
|
7133
|
+
if(!_notifSSEConnected) pollNotifCount();
|
|
7134
|
+
pollAdminPending();
|
|
7135
|
+
if(_activeView==='admin') loadAdminData();
|
|
7136
|
+
else if(_activeView==='memories'){
|
|
7137
|
+
var _searchVal=(document.getElementById('searchInput')||{}).value||'';
|
|
7138
|
+
if(!_searchVal.trim()){
|
|
7139
|
+
if(memorySearchScope==='hub') loadHubMemories(true);
|
|
7140
|
+
else{loadStats();loadMemories(null,true);}
|
|
7141
|
+
}
|
|
7142
|
+
}
|
|
7143
|
+
else if(_activeView==='tasks') loadTasks(true);
|
|
7144
|
+
else if(_activeView==='skills') loadSkills(true);
|
|
7145
|
+
else if(_activeView==='analytics') loadMetrics();
|
|
7146
|
+
}catch(e){}
|
|
7147
|
+
_livePollBusy=false;
|
|
6801
7148
|
}
|
|
6802
|
-
|
|
6803
|
-
|
|
7149
|
+
|
|
7150
|
+
function startLivePoller(){
|
|
7151
|
+
stopLivePoller();
|
|
7152
|
+
_livePoller=setInterval(_livePollTick,_LIVE_POLL_MS);
|
|
7153
|
+
}
|
|
7154
|
+
function stopLivePoller(){
|
|
7155
|
+
if(_livePoller){clearInterval(_livePoller);_livePoller=null;}
|
|
6804
7156
|
}
|
|
6805
7157
|
|
|
6806
|
-
|
|
7158
|
+
document.addEventListener('visibilitychange',function(){
|
|
7159
|
+
if(document.hidden){
|
|
7160
|
+
stopLivePoller();
|
|
7161
|
+
}else{
|
|
7162
|
+
_livePollTick();
|
|
7163
|
+
startLivePoller();
|
|
7164
|
+
if(!_notifSSE||!_notifSSEConnected) connectNotifSSE();
|
|
7165
|
+
}
|
|
7166
|
+
});
|
|
7167
|
+
|
|
7168
|
+
/* ─── Notifications (SSE push + fallback poll) ─── */
|
|
6807
7169
|
var _notifCache=[];
|
|
6808
7170
|
var _notifUnread=0;
|
|
6809
7171
|
var _notifPollTimer=null;
|
|
6810
7172
|
var _notifPanelOpen=false;
|
|
7173
|
+
var _notifSSE=null;
|
|
7174
|
+
var _notifSSEConnected=false;
|
|
7175
|
+
var _notifSSERetryMs=1000;
|
|
7176
|
+
|
|
7177
|
+
function connectNotifSSE(){
|
|
7178
|
+
if(_notifSSE) return;
|
|
7179
|
+
try{
|
|
7180
|
+
_notifSSE=new EventSource('/api/notifications/stream');
|
|
7181
|
+
_notifSSE.onmessage=function(ev){
|
|
7182
|
+
try{
|
|
7183
|
+
var d=JSON.parse(ev.data);
|
|
7184
|
+
if(d.type==='connected'){_notifSSEConnected=true;_notifSSERetryMs=1000;return;}
|
|
7185
|
+
if(d.type==='update'){
|
|
7186
|
+
var prev=_notifUnread;
|
|
7187
|
+
_notifUnread=d.unreadCount||0;
|
|
7188
|
+
renderNotifBadge();
|
|
7189
|
+
if(_notifUnread>prev&&_notifPanelOpen) loadNotifications();
|
|
7190
|
+
}
|
|
7191
|
+
if(d.type==='cleared'){
|
|
7192
|
+
_notifUnread=0;_notifCache=[];
|
|
7193
|
+
renderNotifBadge();renderNotifPanel();
|
|
7194
|
+
}
|
|
7195
|
+
}catch(e){}
|
|
7196
|
+
};
|
|
7197
|
+
_notifSSE.onerror=function(){
|
|
7198
|
+
_notifSSEConnected=false;
|
|
7199
|
+
if(_notifSSE){_notifSSE.close();_notifSSE=null;}
|
|
7200
|
+
setTimeout(connectNotifSSE,Math.min(_notifSSERetryMs,30000));
|
|
7201
|
+
_notifSSERetryMs=Math.min(_notifSSERetryMs*2,30000);
|
|
7202
|
+
};
|
|
7203
|
+
}catch(e){}
|
|
7204
|
+
}
|
|
7205
|
+
connectNotifSSE();
|
|
6811
7206
|
|
|
6812
7207
|
function toggleNotifPanel(e){
|
|
6813
7208
|
if(e)e.stopPropagation();
|
|
@@ -6838,7 +7233,10 @@ function notifTimeAgo(ts){
|
|
|
6838
7233
|
return t('notif.timeAgo.day').replace('{n}',Math.floor(diff/86400000));
|
|
6839
7234
|
}
|
|
6840
7235
|
|
|
6841
|
-
function notifIcon(resource){
|
|
7236
|
+
function notifIcon(resource,type){
|
|
7237
|
+
if(type==='user_online') return '\\u{1F7E2}';
|
|
7238
|
+
if(type==='user_offline') return '\\u{1F534}';
|
|
7239
|
+
if(type==='user_join_request') return '\\u{1F464}';
|
|
6842
7240
|
if(resource==='memory') return '\\u{1F4DD}';
|
|
6843
7241
|
if(resource==='task') return '\\u{1F4CB}';
|
|
6844
7242
|
if(resource==='skill') return '\\u{1F9E0}';
|
|
@@ -6849,6 +7247,21 @@ function notifTypeText(n){
|
|
|
6849
7247
|
if(n.type==='resource_removed'){
|
|
6850
7248
|
return t('notif.removed.'+n.resource)||t('notif.removed.memory');
|
|
6851
7249
|
}
|
|
7250
|
+
if(n.type==='resource_shared'){
|
|
7251
|
+
return t('notif.shared.'+n.resource)||t('notif.shared.memory');
|
|
7252
|
+
}
|
|
7253
|
+
if(n.type==='resource_unshared'){
|
|
7254
|
+
return t('notif.unshared.'+n.resource)||t('notif.unshared.memory');
|
|
7255
|
+
}
|
|
7256
|
+
if(n.type==='user_join_request'){
|
|
7257
|
+
return t('notif.userJoin');
|
|
7258
|
+
}
|
|
7259
|
+
if(n.type==='user_online'){
|
|
7260
|
+
return t('notif.userOnline');
|
|
7261
|
+
}
|
|
7262
|
+
if(n.type==='user_offline'){
|
|
7263
|
+
return t('notif.userOffline');
|
|
7264
|
+
}
|
|
6852
7265
|
return n.message||n.type;
|
|
6853
7266
|
}
|
|
6854
7267
|
|
|
@@ -6893,7 +7306,7 @@ function renderNotifPanel(){
|
|
|
6893
7306
|
body.innerHTML=_notifCache.map(function(n){
|
|
6894
7307
|
var cls='notif-item'+(n.read?'':' unread');
|
|
6895
7308
|
return '<div class="'+cls+'" onclick="markNotifRead("'+esc(n.id)+'")">'+
|
|
6896
|
-
'<div class="notif-item-icon">'+notifIcon(n.resource)+'</div>'+
|
|
7309
|
+
'<div class="notif-item-icon">'+notifIcon(n.resource,n.type)+'</div>'+
|
|
6897
7310
|
'<div class="notif-item-body">'+
|
|
6898
7311
|
'<div class="notif-item-title">'+esc(notifTypeText(n))+'</div>'+
|
|
6899
7312
|
'<div class="notif-item-name">'+esc(n.title)+'</div>'+
|
|
@@ -6934,24 +7347,20 @@ async function clearAllNotifs(){
|
|
|
6934
7347
|
}catch(e){}
|
|
6935
7348
|
}
|
|
6936
7349
|
|
|
6937
|
-
function startNotifPoll(){
|
|
6938
|
-
|
|
6939
|
-
pollNotifCount();
|
|
6940
|
-
_notifPollTimer=setInterval(pollNotifCount,15000);
|
|
6941
|
-
}
|
|
6942
|
-
|
|
6943
|
-
function stopNotifPoll(){
|
|
6944
|
-
if(_notifPollTimer){clearInterval(_notifPollTimer);_notifPollTimer=null;}
|
|
6945
|
-
}
|
|
7350
|
+
function startNotifPoll(){ startLivePoller(); }
|
|
7351
|
+
function stopNotifPoll(){ }
|
|
6946
7352
|
|
|
6947
7353
|
/* ─── Data loading ─── */
|
|
6948
7354
|
async function loadAll(){
|
|
6949
|
-
await
|
|
7355
|
+
await loadStats();
|
|
7356
|
+
var initOwner=memorySearchScope==='local'?_currentAgentOwner:undefined;
|
|
7357
|
+
if(initOwner) await loadStats(initOwner);
|
|
7358
|
+
await Promise.all([loadMemories(),loadSharingStatus(false)]);
|
|
6950
7359
|
checkMigrateStatus();
|
|
6951
7360
|
connectPPSSE();
|
|
6952
7361
|
checkForUpdate();
|
|
6953
|
-
|
|
6954
|
-
|
|
7362
|
+
pollNotifCount();
|
|
7363
|
+
startLivePoller();
|
|
6955
7364
|
}
|
|
6956
7365
|
|
|
6957
7366
|
async function loadStats(ownerFilter){
|
|
@@ -6963,6 +7372,7 @@ async function loadStats(ownerFilter){
|
|
|
6963
7372
|
d=await r.json();
|
|
6964
7373
|
}catch(e){ d={}; }
|
|
6965
7374
|
if(!d||typeof d!=='object') d={};
|
|
7375
|
+
if(d.currentAgentOwner) _currentAgentOwner=d.currentAgentOwner;
|
|
6966
7376
|
const tm=d.totalMemories||0;
|
|
6967
7377
|
const dedupB=d.dedupBreakdown||{};
|
|
6968
7378
|
const activeCount=dedupB.active||tm;
|
|
@@ -7029,11 +7439,14 @@ async function loadStats(ownerFilter){
|
|
|
7029
7439
|
const ownerSel=document.getElementById('filterOwner');
|
|
7030
7440
|
if(ownerSel && d.owners && d.owners.length>0){
|
|
7031
7441
|
const curVal=ownerSel.value;
|
|
7032
|
-
|
|
7033
|
-
|
|
7034
|
-
|
|
7442
|
+
var agents=d.owners.filter(function(o){return o && o.indexOf('agent:')===0;});
|
|
7443
|
+
ownerSel.innerHTML='<option value="">'+t('filter.allagents')+'</option>';
|
|
7444
|
+
agents.forEach(function(o){
|
|
7445
|
+
var label=o.replace('agent:','');
|
|
7446
|
+
ownerSel.innerHTML+='<option value="'+o+'"'+(o===curVal?' selected':'')+'>'+label+'</option>';
|
|
7035
7447
|
});
|
|
7036
|
-
ownerSel.
|
|
7448
|
+
if(agents.length<=1) ownerSel.style.display='none';
|
|
7449
|
+
else ownerSel.style.display='';
|
|
7037
7450
|
}
|
|
7038
7451
|
}
|
|
7039
7452
|
|
|
@@ -7073,59 +7486,92 @@ function getFilterParams(){
|
|
|
7073
7486
|
if(dt) p.set('dateTo',dt);
|
|
7074
7487
|
const sort=document.getElementById('filterSort').value;
|
|
7075
7488
|
if(sort==='oldest') p.set('sort','oldest');
|
|
7076
|
-
const
|
|
7077
|
-
if(
|
|
7489
|
+
const scope=memorySearchScope||'local';
|
|
7490
|
+
if(scope==='local'){
|
|
7491
|
+
p.set('owner',_currentAgentOwner);
|
|
7492
|
+
}else{
|
|
7493
|
+
const owner=document.getElementById('filterOwner').value;
|
|
7494
|
+
if(owner) p.set('owner',owner);
|
|
7495
|
+
}
|
|
7078
7496
|
return p;
|
|
7079
7497
|
}
|
|
7080
7498
|
|
|
7081
|
-
async function loadMemories(page){
|
|
7499
|
+
async function loadMemories(page,silent){
|
|
7082
7500
|
if(page) currentPage=page;
|
|
7083
7501
|
const list=document.getElementById('memoryList');
|
|
7084
|
-
list.innerHTML='<div class="spinner"></div>';
|
|
7502
|
+
if(!silent) list.innerHTML='<div class="spinner"></div>';
|
|
7085
7503
|
try{
|
|
7086
7504
|
const p=getFilterParams();
|
|
7087
7505
|
p.set('limit',PAGE_SIZE);
|
|
7088
7506
|
p.set('page',currentPage);
|
|
7089
7507
|
const r=await fetch('/api/memories?'+p.toString());
|
|
7090
7508
|
const d=await r.json();
|
|
7509
|
+
var items=d.memories||[];
|
|
7510
|
+
if(silent){
|
|
7511
|
+
var fp=JSON.stringify(items.map(function(m){return m.id+'|'+m.updated_at}));
|
|
7512
|
+
if(fp===_lastMemoriesFingerprint) return;
|
|
7513
|
+
_lastMemoriesFingerprint=fp;
|
|
7514
|
+
}else{
|
|
7515
|
+
_lastMemoriesFingerprint=JSON.stringify(items.map(function(m){return m.id+'|'+m.updated_at}));
|
|
7516
|
+
}
|
|
7091
7517
|
totalPages=d.totalPages||1;
|
|
7092
7518
|
totalCount=d.total||0;
|
|
7093
7519
|
document.getElementById('searchMeta').textContent=totalCount+t('search.meta.total');
|
|
7094
|
-
renderMemories(
|
|
7520
|
+
renderMemories(items);
|
|
7095
7521
|
renderPagination();
|
|
7096
7522
|
}catch(e){
|
|
7097
|
-
|
|
7098
|
-
|
|
7099
|
-
|
|
7100
|
-
|
|
7523
|
+
if(!silent){
|
|
7524
|
+
list.innerHTML='';
|
|
7525
|
+
totalPages=1;totalCount=0;
|
|
7526
|
+
_lastMemoriesFingerprint='';
|
|
7527
|
+
renderMemories([]);
|
|
7528
|
+
renderPagination();
|
|
7529
|
+
}
|
|
7101
7530
|
}
|
|
7102
7531
|
}
|
|
7103
7532
|
|
|
7104
|
-
async function loadHubMemories(){
|
|
7533
|
+
async function loadHubMemories(silent){
|
|
7105
7534
|
const list=document.getElementById('memoryList');
|
|
7106
|
-
list.innerHTML='<div class="spinner"></div>';
|
|
7535
|
+
if(!silent) list.innerHTML='<div class="spinner"></div>';
|
|
7107
7536
|
try{
|
|
7108
7537
|
const r=await fetch('/api/sharing/memories/list?limit='+PAGE_SIZE);
|
|
7109
7538
|
const d=await r.json();
|
|
7110
7539
|
const items=d.memories||[];
|
|
7540
|
+
if(silent){
|
|
7541
|
+
var fp=JSON.stringify(items.map(function(m){return m.id+'|'+(m.updated_at||m.created_at)}));
|
|
7542
|
+
if(fp===_lastMemoriesFingerprint) return;
|
|
7543
|
+
_lastMemoriesFingerprint=fp;
|
|
7544
|
+
}else{
|
|
7545
|
+
_lastMemoriesFingerprint=JSON.stringify(items.map(function(m){return m.id+'|'+(m.updated_at||m.created_at)}));
|
|
7546
|
+
}
|
|
7547
|
+
totalPages=1;totalCount=items.length;currentPage=1;
|
|
7111
7548
|
document.getElementById('searchMeta').textContent=items.length+t('search.meta.total');
|
|
7112
7549
|
document.getElementById('sharingSearchMeta').textContent='';
|
|
7113
7550
|
renderMemories(items);
|
|
7114
7551
|
document.getElementById('pagination').innerHTML='';
|
|
7115
7552
|
}catch(e){
|
|
7116
|
-
|
|
7117
|
-
|
|
7118
|
-
|
|
7553
|
+
if(!silent){
|
|
7554
|
+
_lastMemoriesFingerprint='';
|
|
7555
|
+
document.getElementById('searchMeta').textContent='0'+t('search.meta.results');
|
|
7556
|
+
renderMemories([]);
|
|
7557
|
+
document.getElementById('pagination').innerHTML='';
|
|
7558
|
+
}
|
|
7119
7559
|
}
|
|
7120
7560
|
}
|
|
7121
7561
|
|
|
7122
7562
|
async function doSearch(query){
|
|
7123
7563
|
query=(query||'').trim();
|
|
7124
|
-
if(!query){
|
|
7564
|
+
if(!query){
|
|
7565
|
+
currentPage=1;
|
|
7566
|
+
if(memorySearchScope==='hub') loadHubMemories();
|
|
7567
|
+
else loadMemories();
|
|
7568
|
+
return;
|
|
7569
|
+
}
|
|
7570
|
+
currentPage=1;
|
|
7125
7571
|
var scope=document.getElementById('memorySearchScope')?.value||memorySearchScope||'local';
|
|
7126
7572
|
var list=document.getElementById('memoryList');
|
|
7127
7573
|
list.innerHTML='<div class="spinner"></div>';
|
|
7128
|
-
if(scope
|
|
7574
|
+
if(scope==='hub'){
|
|
7129
7575
|
try{
|
|
7130
7576
|
var r=await fetch('/api/sharing/search/memories',{
|
|
7131
7577
|
method:'POST',
|
|
@@ -7133,6 +7579,7 @@ async function doSearch(query){
|
|
|
7133
7579
|
body:JSON.stringify({query:query,scope:scope,maxResults:20,role:activeRole||undefined})
|
|
7134
7580
|
});
|
|
7135
7581
|
var data=await r.json();
|
|
7582
|
+
totalPages=1;totalCount=(data.results||[]).length;
|
|
7136
7583
|
renderSharingMemorySearchResults(data,query);
|
|
7137
7584
|
}catch(e){
|
|
7138
7585
|
document.getElementById('searchMeta').textContent='0'+t('search.meta.results');
|
|
@@ -7147,6 +7594,7 @@ async function doSearch(query){
|
|
|
7147
7594
|
var r=await fetch('/api/search?'+p.toString());
|
|
7148
7595
|
var d=await r.json();
|
|
7149
7596
|
var total=d.total||0;
|
|
7597
|
+
totalPages=1;totalCount=total;
|
|
7150
7598
|
var meta=[];
|
|
7151
7599
|
if(d.vectorCount>0) meta.push(d.vectorCount+t('search.meta.semantic'));
|
|
7152
7600
|
if(d.ftsCount>0) meta.push(d.ftsCount+t('search.meta.text'));
|
|
@@ -7235,7 +7683,8 @@ function renderMemories(items){
|
|
|
7235
7683
|
const isPublicMem=ownerVal==='public';
|
|
7236
7684
|
const localManaged=!!m.localSharingManaged;
|
|
7237
7685
|
const memShared=m.sharingVisibility||null;
|
|
7238
|
-
const
|
|
7686
|
+
const isHubScope=memorySearchScope==='hub';
|
|
7687
|
+
const memScope=isHubScope?'team':memShared?'team':isPublicMem?'local':'private';
|
|
7239
7688
|
const memScopeBadge=renderScopeBadge(memScope);
|
|
7240
7689
|
let dedupInfo='';
|
|
7241
7690
|
if(ds==='duplicate'||ds==='merged'){
|
|
@@ -7340,7 +7789,8 @@ function renderPagination(){
|
|
|
7340
7789
|
function goPage(p){
|
|
7341
7790
|
if(p<1||p>totalPages||p===currentPage) return;
|
|
7342
7791
|
currentPage=p;
|
|
7343
|
-
|
|
7792
|
+
if(memorySearchScope==='hub') loadHubMemories();
|
|
7793
|
+
else loadMemories();
|
|
7344
7794
|
document.getElementById('memoryList').scrollIntoView({behavior:'smooth',block:'start'});
|
|
7345
7795
|
}
|
|
7346
7796
|
|
|
@@ -8223,7 +8673,7 @@ async function checkForUpdate(){
|
|
|
8223
8673
|
const pkgSpec=d.installCommand?d.installCommand.replace(/^(?:npx\s+)?openclaw\s+plugins\s+install\s+/,''):(d.packageName+'@'+d.latest);
|
|
8224
8674
|
var banner=document.createElement('div');
|
|
8225
8675
|
banner.id='updateBanner';
|
|
8226
|
-
banner.style.cssText='display:flex;align-items:center;gap:12px;padding:10px max
|
|
8676
|
+
banner.style.cssText='display:flex;align-items:center;gap:12px;padding:10px 32px;max-width:1400px;margin:0 auto;width:100%;font-size:13px;font-weight:500;box-sizing:border-box;animation:slideIn .3s ease;background:linear-gradient(135deg,rgba(99,102,241,.08),rgba(139,92,246,.06));color:var(--pri);border-bottom:1px solid rgba(99,102,241,.18);backdrop-filter:blur(8px)';
|
|
8227
8677
|
var textNode=document.createElement('div');
|
|
8228
8678
|
textNode.style.cssText='display:flex;align-items:center;gap:8px;flex-shrink:0;font-size:13px';
|
|
8229
8679
|
textNode.innerHTML='<span style="font-size:15px">\u2728</span> '+t('update.available')+' <span style="padding:2px 8px;border-radius:6px;background:rgba(99,102,241,.1);font-size:12px;font-weight:600">v'+esc(d.current)+'</span> <span style="opacity:.5">\u2192</span> <span style="padding:2px 8px;border-radius:6px;background:rgba(52,211,153,.12);color:var(--green);font-size:12px;font-weight:600">v'+esc(d.latest)+'</span>';
|
|
@@ -8256,7 +8706,7 @@ async function checkForUpdate(){
|
|
|
8256
8706
|
|
|
8257
8707
|
/* ─── Init ─── */
|
|
8258
8708
|
document.getElementById('modalOverlay').addEventListener('click',e=>{if(e.target.id==='modalOverlay')closeModal()});
|
|
8259
|
-
document.getElementById('searchInput').addEventListener('keydown',e=>{if(e.key==='Escape'){e.target.value='';loadMemories()}});
|
|
8709
|
+
document.getElementById('searchInput').addEventListener('keydown',e=>{if(e.key==='Escape'){e.target.value='';currentPage=1;if(memorySearchScope==='hub')loadHubMemories();else loadMemories();}});
|
|
8260
8710
|
applyI18n();
|
|
8261
8711
|
checkAuth();
|
|
8262
8712
|
</script>
|