@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/dist/viewer/html.js
CHANGED
|
@@ -15,6 +15,7 @@ function viewerHTML(pluginVersion) {
|
|
|
15
15
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
16
16
|
<style>
|
|
17
17
|
*{margin:0;padding:0;box-sizing:border-box}
|
|
18
|
+
html{overflow-y:scroll}
|
|
18
19
|
:root{
|
|
19
20
|
--bg:#0b0d11;--bg-card:#12141a;--bg-card-hover:#1a1d25;
|
|
20
21
|
--border:rgba(255,255,255,.08);--border-glow:rgba(255,255,255,.14);
|
|
@@ -109,7 +110,8 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
109
110
|
|
|
110
111
|
/* ─── App Layout (dark dashboard, same as www) ─── */
|
|
111
112
|
.app{display:none;flex-direction:column;min-height:100vh}
|
|
112
|
-
.topbar{background:rgba(11,13,17,.88);border-bottom:1px solid var(--border);
|
|
113
|
+
.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)}
|
|
114
|
+
.topbar-inner{display:flex;align-items:center;width:100%;max-width:1400px;margin:0 auto;padding:0 32px}
|
|
113
115
|
.topbar .brand{display:flex;align-items:center;gap:8px;font-weight:700;font-size:15px;color:var(--text);letter-spacing:-.02em;flex-shrink:0}
|
|
114
116
|
.topbar .brand .icon{width:24px;height:24px;display:flex;align-items:center;justify-content:center;font-size:18px;background:none;border-radius:0}
|
|
115
117
|
.topbar .brand .brand-title{font-size:13px;font-weight:500;opacity:.7}
|
|
@@ -195,50 +197,90 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
195
197
|
.pending-user-name{font-size:14px;font-weight:700;color:var(--text)}
|
|
196
198
|
.pending-user-meta{font-size:12px;color:var(--text-sec);margin-top:4px}
|
|
197
199
|
.pending-user-actions{display:flex;gap:8px;margin-top:10px}
|
|
198
|
-
/* ─── Admin Panel ─── */
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
.admin-
|
|
207
|
-
.admin-
|
|
208
|
-
.admin-
|
|
209
|
-
.admin-
|
|
210
|
-
.admin-
|
|
211
|
-
.admin-
|
|
212
|
-
.admin-
|
|
213
|
-
.admin-stat-
|
|
214
|
-
.admin-stat-box:
|
|
215
|
-
.admin-stat-box
|
|
216
|
-
.admin-stat-box
|
|
217
|
-
.admin-stat-box
|
|
218
|
-
.admin-
|
|
219
|
-
.admin-
|
|
220
|
-
.admin-
|
|
221
|
-
.admin-
|
|
200
|
+
/* ─── Admin Panel (Cyber) ─── */
|
|
201
|
+
@keyframes adminGlow{0%,100%{opacity:.6}50%{opacity:1}}
|
|
202
|
+
@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)}}
|
|
203
|
+
@keyframes adminScanline{0%{background-position:0 0}100%{background-position:0 100%}}
|
|
204
|
+
@keyframes adminSlideIn{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}
|
|
205
|
+
@keyframes adminCountUp{from{opacity:0;transform:translateY(8px) scale(.8)}to{opacity:1;transform:translateY(0) scale(1)}}
|
|
206
|
+
@keyframes pendingPulse{0%,100%{border-color:rgba(251,191,36,.3)}50%{border-color:rgba(251,191,36,.7)}}
|
|
207
|
+
@keyframes dotBreathe{0%,100%{transform:scale(1);opacity:.8}50%{transform:scale(1.3);opacity:1}}
|
|
208
|
+
.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}
|
|
209
|
+
.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}
|
|
210
|
+
.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}
|
|
211
|
+
.admin-header-top{display:flex;justify-content:space-between;align-items:center;position:relative;z-index:1}
|
|
212
|
+
.admin-header h2{font-size:18px;font-weight:800;color:var(--text);display:flex;align-items:center;gap:12px;margin:0;letter-spacing:-.01em}
|
|
213
|
+
.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}
|
|
214
|
+
.admin-header-sub{font-size:11px;color:var(--text-muted);margin-top:6px;position:relative;z-index:1;letter-spacing:.02em}
|
|
215
|
+
.admin-stat-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:10px;margin-top:20px;position:relative;z-index:1}
|
|
216
|
+
.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)}
|
|
217
|
+
.admin-stat-box:hover{border-color:rgba(99,102,241,.35);transform:translateY(-2px);box-shadow:0 8px 24px rgba(99,102,241,.12)}
|
|
218
|
+
.admin-stat-box::before{content:'';position:absolute;top:0;left:0;right:0;height:2px;opacity:.8}
|
|
219
|
+
.admin-stat-box:nth-child(1)::before{background:linear-gradient(90deg,transparent,#22c55e,transparent)}
|
|
220
|
+
.admin-stat-box:nth-child(2)::before{background:linear-gradient(90deg,transparent,#fbbf24,transparent)}
|
|
221
|
+
.admin-stat-box:nth-child(3)::before{background:linear-gradient(90deg,transparent,#8b5cf6,transparent)}
|
|
222
|
+
.admin-stat-box:nth-child(4)::before{background:linear-gradient(90deg,transparent,#06b6d4,transparent)}
|
|
223
|
+
.admin-stat-box:nth-child(5)::before{background:linear-gradient(90deg,transparent,#6366f1,transparent)}
|
|
224
|
+
.admin-stat-box:nth-child(6)::before{background:linear-gradient(90deg,transparent,#f43f5e,transparent)}
|
|
225
|
+
.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}
|
|
226
|
+
.admin-stat-box .as-icon{font-size:18px;margin-bottom:6px;display:block;filter:drop-shadow(0 2px 4px rgba(0,0,0,.15))}
|
|
227
|
+
.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)}
|
|
228
|
+
.admin-stat-box .lbl{font-size:10px;color:var(--text-muted);margin-top:4px;letter-spacing:.05em;text-transform:uppercase}
|
|
229
|
+
.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)}
|
|
230
|
+
.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}
|
|
231
|
+
.admin-tab:hover{background:rgba(99,102,241,.08);color:var(--text)}
|
|
232
|
+
.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)}
|
|
222
233
|
.admin-tab .at-icon{font-size:14px;line-height:1}
|
|
223
|
-
.admin-tab .at-count{font-size:10px;font-weight:700;padding:
|
|
224
|
-
.admin-tab.active .at-count{background:rgba(99,102,241,.15)}
|
|
234
|
+
.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}
|
|
235
|
+
.admin-tab.active .at-count{background:rgba(99,102,241,.2);box-shadow:0 0 8px rgba(99,102,241,.15)}
|
|
225
236
|
.admin-panel{display:none}
|
|
226
|
-
.admin-panel.active{display:block}
|
|
227
|
-
.admin-card{border:1px solid var(--border);border-radius:
|
|
237
|
+
.admin-panel.active{display:block;animation:adminSlideIn .3s ease-out}
|
|
238
|
+
.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}
|
|
228
239
|
.admin-card-clickable{cursor:pointer}
|
|
229
|
-
.admin-card::before{content:'';position:absolute;top:0;left:0;bottom:0;width:3px;border-radius:3px 0 0 3px;background:var(--pri);opacity:.
|
|
230
|
-
.admin-card:hover{border-color:rgba(99,102,241,.25);box-shadow:0
|
|
240
|
+
.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}
|
|
241
|
+
.admin-card:hover{border-color:rgba(99,102,241,.25);box-shadow:0 4px 20px rgba(99,102,241,.06);transform:translateY(-1px)}
|
|
242
|
+
.admin-card:hover::before{opacity:.8}
|
|
231
243
|
.admin-card-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:6px}
|
|
232
244
|
.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}
|
|
233
245
|
.admin-card-meta{font-size:12px;color:var(--text-muted);line-height:1.5}
|
|
234
|
-
.au-contrib{display:flex;gap:
|
|
235
|
-
.au-contrib-item{font-size:12px;color:var(--text-sec);display:flex;align-items:center;gap:
|
|
236
|
-
.au-contrib-num{font-size:
|
|
237
|
-
.au-info{display:flex;flex-wrap:wrap;gap:6px
|
|
238
|
-
.au-info-item{color:var(--text-muted);white-space:nowrap}
|
|
246
|
+
.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)}
|
|
247
|
+
.au-contrib-item{font-size:12px;color:var(--text-sec);display:flex;align-items:center;gap:5px}
|
|
248
|
+
.au-contrib-num{font-size:20px;font-weight:800;line-height:1;font-variant-numeric:tabular-nums}
|
|
249
|
+
.au-info{display:flex;flex-wrap:wrap;gap:6px 16px;padding:8px 0;font-size:11px}
|
|
250
|
+
.au-info-item{color:var(--text-muted);white-space:nowrap;display:inline-flex;align-items:center;gap:3px}
|
|
251
|
+
.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}
|
|
252
|
+
.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}
|
|
253
|
+
.au-status-dot.offline{background:#6b7280;box-shadow:none}
|
|
254
|
+
.au-status-text{font-size:11px;font-weight:600;letter-spacing:.02em}
|
|
255
|
+
.au-status-text.online{color:#22c55e;text-shadow:0 0 8px rgba(34,197,94,.3)}
|
|
256
|
+
.au-status-text.offline{color:#6b7280}
|
|
257
|
+
.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}
|
|
258
|
+
.au-group-header:first-child{margin-top:0}
|
|
259
|
+
.au-group-header .au-group-dot{display:inline-block;width:8px;height:8px;border-radius:50%}
|
|
260
|
+
.au-group-header .au-group-dot.online{background:#22c55e;box-shadow:0 0 6px rgba(34,197,94,.5)}
|
|
261
|
+
.au-group-header .au-group-dot.offline{background:#6b7280}
|
|
262
|
+
.au-group-header .au-group-count{font-size:12px;font-weight:400;color:var(--text-muted)}
|
|
263
|
+
.au-card.au-offline{opacity:.55}
|
|
264
|
+
.au-card.au-offline:hover{opacity:.8}
|
|
265
|
+
.au-card.au-offline::before{background:#6b7280}
|
|
266
|
+
.au-card.au-online::before{background:#22c55e;box-shadow:0 0 8px rgba(34,197,94,.3)}
|
|
267
|
+
.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}
|
|
268
|
+
.admin-pending-section::before{content:'';position:absolute;top:0;left:0;right:0;height:2px;background:linear-gradient(90deg,transparent,#fbbf24,#f59e0b,transparent)}
|
|
269
|
+
.admin-pending-section h3{font-size:14px;font-weight:700;color:#fbbf24;margin:0 0 14px;display:flex;align-items:center;gap:8px}
|
|
270
|
+
.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}
|
|
271
|
+
.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}
|
|
272
|
+
.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}
|
|
273
|
+
.admin-pending-card:hover{border-color:rgba(251,191,36,.35);box-shadow:0 4px 16px rgba(251,191,36,.08)}
|
|
274
|
+
.admin-pending-card .apc-name{font-size:14px;font-weight:700;color:var(--text)}
|
|
275
|
+
.admin-pending-card .apc-meta{font-size:11px;color:var(--text-muted);margin-top:4px;display:flex;align-items:center;gap:6px}
|
|
276
|
+
.admin-pending-card .apc-actions{display:flex;gap:8px;margin-top:12px}
|
|
277
|
+
.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)}
|
|
278
|
+
.admin-pending-card .apc-actions .btn-approve:hover{transform:translateY(-1px);box-shadow:0 4px 16px rgba(34,197,94,.35)}
|
|
279
|
+
.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}
|
|
280
|
+
.admin-pending-card .apc-actions .btn-reject:hover{background:rgba(244,63,94,.06);border-color:rgba(244,63,94,.4)}
|
|
239
281
|
.admin-card-tags{display:flex;gap:5px;margin:8px 0;align-items:center}
|
|
240
282
|
.admin-card-tags-left{display:flex;flex-wrap:wrap;gap:5px;align-items:center;flex:1;min-width:0}
|
|
241
|
-
.admin-card-tag{display:inline-flex;align-items:center;gap:3px;padding:
|
|
283
|
+
.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}
|
|
242
284
|
.admin-card-tag.tag-role{background:rgba(99,102,241,.1);color:var(--pri)}
|
|
243
285
|
.admin-card-tag.tag-kind{background:rgba(245,158,11,.1);color:#f59e0b}
|
|
244
286
|
.admin-card-tag.tag-owner{background:rgba(34,197,94,.1);color:#22c55e}
|
|
@@ -246,16 +288,16 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
246
288
|
.admin-card-tag.tag-version{background:rgba(139,92,246,.1);color:#8b5cf6}
|
|
247
289
|
.admin-card-tag.tag-visibility{background:rgba(99,102,241,.08);color:var(--pri)}
|
|
248
290
|
.admin-card-tag.tag-group{background:rgba(139,92,246,.08);color:#8b5cf6}
|
|
249
|
-
.admin-card-preview{font-size:12px;color:var(--text-sec);line-height:1.5;margin:8px 0;padding:
|
|
250
|
-
.admin-card-actions{display:inline-flex;gap:
|
|
291
|
+
.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}
|
|
292
|
+
.admin-card-actions{display:inline-flex;gap:6px;margin-left:auto;align-items:center;flex-shrink:0}
|
|
251
293
|
.admin-card-time{font-size:11px;color:var(--text-muted)}
|
|
252
|
-
.admin-card-detail{display:none;margin-top:0;padding:20px 24px 24px;border-top:1px dashed
|
|
294
|
+
.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}
|
|
253
295
|
@keyframes adminDetailIn{from{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:translateY(0)}}
|
|
254
296
|
.admin-card.expanded .admin-card-detail{display:block}
|
|
255
|
-
.admin-card.expanded{border-color:rgba(99,102,241,.3);box-shadow:0 4px 24px rgba(99,102,241,.
|
|
297
|
+
.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)}
|
|
256
298
|
.admin-card-detail-meta{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:18px;font-size:12px;color:var(--text-muted)}
|
|
257
|
-
.admin-card-detail-meta .meta-item{display:inline-flex;align-items:center;gap:4px;padding:5px 12px;background:
|
|
258
|
-
.admin-card-detail-meta .meta-item:hover{border-color:rgba(99,102,241,.25);background:rgba(99,102,241,.
|
|
299
|
+
.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}
|
|
300
|
+
.admin-card-detail-meta .meta-item:hover{border-color:rgba(99,102,241,.25);background:rgba(99,102,241,.06)}
|
|
259
301
|
.admin-card-detail-section{margin-top:20px}
|
|
260
302
|
.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}
|
|
261
303
|
.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))}
|
|
@@ -289,18 +331,20 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
289
331
|
.admin-toolbar{display:flex;align-items:center;gap:10px;margin-bottom:14px;flex-wrap:wrap}
|
|
290
332
|
.admin-toolbar h3{font-size:14px;font-weight:600;color:var(--text);white-space:nowrap;margin:0;margin-right:auto;line-height:32px}
|
|
291
333
|
.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}
|
|
292
|
-
.admin-badge{display:inline-flex;align-items:center;gap:4px;font-size:10px;font-weight:700;padding:3px 10px;border-radius:999px;letter-spacing:.
|
|
293
|
-
.admin-badge.admin{background:rgba(
|
|
294
|
-
.admin-badge.member{background:rgba(
|
|
295
|
-
.admin-badge.pending{background:rgba(
|
|
334
|
+
.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}
|
|
335
|
+
.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)}
|
|
336
|
+
.admin-badge.member{background:rgba(99,102,241,.08);color:var(--text-muted)}
|
|
337
|
+
.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)}
|
|
296
338
|
.admin-badge.public{background:rgba(99,102,241,.1);color:var(--pri)}
|
|
297
339
|
.admin-badge.group{background:rgba(139,92,246,.1);color:var(--violet)}
|
|
298
|
-
.admin-empty{font-size:13px;color:var(--text-muted);padding:
|
|
299
|
-
.admin-empty .ae-icon{font-size:
|
|
340
|
+
.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)}
|
|
341
|
+
.admin-empty .ae-icon{font-size:32px;display:block;margin-bottom:10px;opacity:.4}
|
|
300
342
|
[data-theme="light"] .admin-badge.admin{background:rgba(5,150,105,.1);color:#059669}
|
|
301
343
|
[data-theme="light"] .admin-badge.member{background:rgba(0,0,0,.06);color:#6b7280}
|
|
302
344
|
[data-theme="light"] .admin-badge.pending{background:rgba(245,158,11,.1);color:#d97706}
|
|
303
|
-
[data-theme="light"] .admin-header{background:linear-gradient(135deg,rgba(99,102,241,.
|
|
345
|
+
[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%)}
|
|
346
|
+
[data-theme="light"] .admin-stat-box{background:rgba(255,255,255,.8)}
|
|
347
|
+
[data-theme="light"] .admin-pending-section{background:linear-gradient(135deg,rgba(251,191,36,.03),rgba(245,158,11,.015))}
|
|
304
348
|
.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}
|
|
305
349
|
.confirm-overlay.show{display:flex}
|
|
306
350
|
.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}
|
|
@@ -542,8 +586,10 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
542
586
|
.pagination .pg-info{font-size:12px;color:var(--text-sec);padding:0 12px}
|
|
543
587
|
|
|
544
588
|
/* ─── Tasks 视图 ─── */
|
|
545
|
-
.
|
|
546
|
-
.
|
|
589
|
+
.view-container{flex:1;min-width:0}
|
|
590
|
+
.view-container>.vp{display:none;flex-direction:column}
|
|
591
|
+
.view-container>.vp.show{display:flex}
|
|
592
|
+
.tasks-view{flex:1;min-width:0;flex-direction:column;gap:16px}
|
|
547
593
|
.tasks-header{display:flex;flex-direction:column;gap:14px}
|
|
548
594
|
.tasks-stats{display:flex;gap:16px}
|
|
549
595
|
.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}
|
|
@@ -621,8 +667,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
621
667
|
[data-theme="light"] .tasks-stat{background:#fff}
|
|
622
668
|
|
|
623
669
|
/* ─── Skills ─── */
|
|
624
|
-
.skills-view{
|
|
625
|
-
.skills-view.show{display:flex}
|
|
670
|
+
.skills-view{flex:1;min-width:0;flex-direction:column;gap:16px}
|
|
626
671
|
.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}
|
|
627
672
|
.skill-card:hover{border-color:var(--border-glow);background:var(--bg-card-hover);transform:translateY(-1px);box-shadow:var(--shadow)}
|
|
628
673
|
.skill-card::before{content:'';position:absolute;top:0;left:0;bottom:0;width:3px;border-radius:3px 0 0 3px;background:var(--violet)}
|
|
@@ -696,9 +741,8 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
696
741
|
.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)}
|
|
697
742
|
[data-theme="light"] .nav-tabs{background:rgba(0,0,0,.05)}
|
|
698
743
|
[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)}
|
|
699
|
-
.analytics-view,.settings-view,.logs-view,.migrate-view,.admin-view{
|
|
700
|
-
.analytics-view
|
|
701
|
-
.feed-wrap,.tasks-view,.skills-view,.analytics-view,.settings-view,.logs-view,.migrate-view,.admin-view{max-width:960px}
|
|
744
|
+
.analytics-view,.settings-view,.logs-view,.migrate-view,.admin-view{flex:1;min-width:0;flex-direction:column;gap:20px}
|
|
745
|
+
.feed-wrap,.tasks-view,.skills-view,.analytics-view,.settings-view,.logs-view,.migrate-view,.admin-view{max-width:960px;margin:0 auto}
|
|
702
746
|
|
|
703
747
|
/* ─── Logs ─── */
|
|
704
748
|
.logs-toolbar{display:flex;align-items:center;justify-content:space-between;padding:8px 0}
|
|
@@ -900,7 +944,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
900
944
|
.test-result.ok{color:#22c55e}
|
|
901
945
|
.test-result.fail{color:var(--rose)}
|
|
902
946
|
.test-result.loading{color:var(--text-muted)}
|
|
903
|
-
.settings-actions{display:flex;gap:12px;justify-content:flex-end;align-items:center;margin-top:20px;padding-top:16px;
|
|
947
|
+
.settings-actions{display:flex;gap:12px;justify-content:flex-end;align-items:center;margin-top:20px;padding-top:16px;flex-wrap:nowrap}
|
|
904
948
|
.settings-actions .btn{flex:0 0 auto;min-width:0;padding:8px 24px;font-size:13px}
|
|
905
949
|
.settings-actions .btn-primary{background:rgba(99,102,241,.08);color:var(--pri);border:1px solid rgba(99,102,241,.25);font-weight:600}
|
|
906
950
|
.settings-actions .btn-primary:hover{background:rgba(99,102,241,.14);border-color:var(--pri)}
|
|
@@ -971,8 +1015,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
971
1015
|
.migrate-log-item .log-meta .tag.error{background:rgba(239,68,68,.1);color:#ef4444}
|
|
972
1016
|
.migrate-log-item .log-meta .tag.duplicate{background:rgba(245,158,11,.1);color:#f59e0b}
|
|
973
1017
|
@keyframes migrateFadeIn{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}
|
|
974
|
-
.feed-wrap{flex:1;min-width:0;
|
|
975
|
-
.feed-wrap.hide{display:none}
|
|
1018
|
+
.feed-wrap{flex:1;min-width:0;flex-direction:column}
|
|
976
1019
|
.analytics-view{flex-direction:column;gap:20px}
|
|
977
1020
|
.analytics-cards{display:grid;grid-template-columns:repeat(4,1fr);gap:14px}
|
|
978
1021
|
.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)}
|
|
@@ -1056,7 +1099,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1056
1099
|
[data-theme="light"] .auth-theme-toggle .theme-icon-dark{display:none}
|
|
1057
1100
|
|
|
1058
1101
|
@media(max-width:1100px){.analytics-cards{grid-template-columns:repeat(3,1fr)}}
|
|
1059
|
-
@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}}
|
|
1102
|
+
@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}}
|
|
1060
1103
|
</style>
|
|
1061
1104
|
</head>
|
|
1062
1105
|
<body>
|
|
@@ -1141,6 +1184,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1141
1184
|
<!-- ─── Main App ─── -->
|
|
1142
1185
|
<div class="app" id="app">
|
|
1143
1186
|
<div class="topbar">
|
|
1187
|
+
<div class="topbar-inner">
|
|
1144
1188
|
<div class="brand">
|
|
1145
1189
|
<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>
|
|
1146
1190
|
<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}
|
|
@@ -1167,10 +1211,10 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1167
1211
|
<div class="notif-panel-body" id="notifPanelBody"><div class="notif-empty" data-i18n="notif.empty">No notifications</div></div>
|
|
1168
1212
|
</div>
|
|
1169
1213
|
</div>
|
|
1170
|
-
<button class="btn btn-ghost btn-sm" onclick="loadAll()" data-i18n="refresh">\u21BB Refresh</button>
|
|
1171
1214
|
<button class="btn btn-ghost btn-sm" onclick="doLogout()" data-i18n="logout">Logout</button>
|
|
1172
1215
|
</div>
|
|
1173
1216
|
</div>
|
|
1217
|
+
</div>
|
|
1174
1218
|
|
|
1175
1219
|
<div class="main-content">
|
|
1176
1220
|
<div class="sidebar" id="sidebar">
|
|
@@ -1192,18 +1236,19 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1192
1236
|
<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>
|
|
1193
1237
|
</div>
|
|
1194
1238
|
|
|
1195
|
-
<div class="
|
|
1239
|
+
<div class="view-container">
|
|
1240
|
+
<div class="feed-wrap vp show" id="feedWrap">
|
|
1196
1241
|
<div class="feed">
|
|
1197
1242
|
<div class="search-bar">
|
|
1198
1243
|
<span class="search-icon">\u{1F50D}</span>
|
|
1199
1244
|
<input type="text" id="searchInput" data-i18n-ph="search.placeholder" placeholder="Search memories (supports semantic search)..." oninput="debounceSearch()">
|
|
1200
1245
|
<select id="filterOwner" class="filter-select" onchange="onOwnerFilterChange()">
|
|
1201
|
-
<option value="" data-i18n="filter.
|
|
1202
|
-
<option value="public" data-i18n="filter.public">Public</option>
|
|
1246
|
+
<option value="" data-i18n="filter.allagents">All agents</option>
|
|
1203
1247
|
</select>
|
|
1204
1248
|
<select id="memorySearchScope" class="filter-select" onchange="onMemoryScopeChange()">
|
|
1205
|
-
<option value="local" data-i18n="scope.
|
|
1206
|
-
<option value="
|
|
1249
|
+
<option value="local" data-i18n="scope.thisAgent">This Agent</option>
|
|
1250
|
+
<option value="allLocal" data-i18n="scope.thisDevice">This Device</option>
|
|
1251
|
+
<option value="hub" data-i18n="scope.hub">Team</option>
|
|
1207
1252
|
</select>
|
|
1208
1253
|
</div>
|
|
1209
1254
|
<div class="search-meta" id="searchMeta"></div>
|
|
@@ -1232,7 +1277,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1232
1277
|
<div class="pagination" id="pagination"></div>
|
|
1233
1278
|
</div>
|
|
1234
1279
|
</div>
|
|
1235
|
-
<div class="tasks-view" id="tasksView">
|
|
1280
|
+
<div class="tasks-view vp" id="tasksView">
|
|
1236
1281
|
<div class="tasks-header">
|
|
1237
1282
|
<div class="tasks-stats">
|
|
1238
1283
|
<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>
|
|
@@ -1246,10 +1291,10 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1246
1291
|
<button class="filter-chip" data-task-status="completed" onclick="setTaskStatusFilter(this,'completed')" data-i18n="tasks.status.completed">Completed</button>
|
|
1247
1292
|
<button class="filter-chip" data-task-status="skipped" onclick="setTaskStatusFilter(this,'skipped')" data-i18n="tasks.status.skipped">Skipped</button>
|
|
1248
1293
|
<select id="taskSearchScope" class="scope-select" onchange="onTaskScopeChange()">
|
|
1249
|
-
<option value="local" data-i18n="scope.
|
|
1250
|
-
<option value="
|
|
1294
|
+
<option value="local" data-i18n="scope.thisAgent">This Agent</option>
|
|
1295
|
+
<option value="allLocal" data-i18n="scope.thisDevice">This Device</option>
|
|
1296
|
+
<option value="hub" data-i18n="scope.hub">Team</option>
|
|
1251
1297
|
</select>
|
|
1252
|
-
<button class="btn btn-sm btn-ghost" onclick="loadTasks()" style="margin-left:auto" data-i18n="refresh">\u21BB Refresh</button>
|
|
1253
1298
|
</div>
|
|
1254
1299
|
</div>
|
|
1255
1300
|
<div class="tasks-list" id="tasksList"><div class="spinner"></div></div>
|
|
@@ -1283,13 +1328,14 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1283
1328
|
<div class="content" id="sharedMemoryContent"></div>
|
|
1284
1329
|
</div>
|
|
1285
1330
|
</div>
|
|
1286
|
-
<div class="skills-view" id="skillsView">
|
|
1331
|
+
<div class="skills-view vp" id="skillsView">
|
|
1287
1332
|
<div class="search-bar">
|
|
1288
1333
|
<span class="search-icon">🔍</span>
|
|
1289
1334
|
<input type="text" id="skillSearchInput" placeholder="Search skills..." data-i18n-ph="skills.search.placeholder" oninput="debounceSkillSearch()">
|
|
1290
1335
|
<select id="skillSearchScope" class="scope-select" onchange="onSkillScopeChange()">
|
|
1291
|
-
<option value="local" data-i18n="scope.
|
|
1292
|
-
<option value="
|
|
1336
|
+
<option value="local" data-i18n="scope.thisAgent">This Agent</option>
|
|
1337
|
+
<option value="allLocal" data-i18n="scope.thisDevice">This Device</option>
|
|
1338
|
+
<option value="hub" data-i18n="scope.hub">Team</option>
|
|
1293
1339
|
</select>
|
|
1294
1340
|
</div>
|
|
1295
1341
|
<div class="search-meta" id="skillSearchMeta"></div>
|
|
@@ -1312,7 +1358,6 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1312
1358
|
<option value="public" data-i18n="filter.public">Public</option>
|
|
1313
1359
|
<option value="private" data-i18n="filter.private">Private</option>
|
|
1314
1360
|
</select>
|
|
1315
|
-
<button class="btn btn-sm btn-ghost" onclick="loadSkills()" style="margin-left:auto" data-i18n="refresh">\u21BB Refresh</button>
|
|
1316
1361
|
</div>
|
|
1317
1362
|
</div>
|
|
1318
1363
|
<div class="tasks-list" id="skillsList"><div class="spinner"></div></div>
|
|
@@ -1345,7 +1390,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1345
1390
|
<div id="skillDetailActions" style="display:flex;gap:8px;margin-top:16px;padding-top:12px;border-top:1px solid var(--border)"></div>
|
|
1346
1391
|
</div>
|
|
1347
1392
|
</div>
|
|
1348
|
-
<div class="analytics-view" id="analyticsView">
|
|
1393
|
+
<div class="analytics-view vp" id="analyticsView">
|
|
1349
1394
|
<div class="metrics-toolbar" style="margin-bottom:0">
|
|
1350
1395
|
<span style="font-size:12px;color:var(--text-sec);font-weight:600" data-i18n="range">Range</span>
|
|
1351
1396
|
<button class="range-btn" data-days="7" onclick="setMetricsDays(7)">7 <span data-i18n="range.days">days</span></button>
|
|
@@ -1389,7 +1434,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1389
1434
|
</div>
|
|
1390
1435
|
|
|
1391
1436
|
<!-- ─── Logs View ─── -->
|
|
1392
|
-
<div class="logs-view" id="logsView">
|
|
1437
|
+
<div class="logs-view vp" id="logsView">
|
|
1393
1438
|
<div class="logs-toolbar">
|
|
1394
1439
|
<div class="logs-toolbar-left">
|
|
1395
1440
|
<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">
|
|
@@ -1406,7 +1451,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1406
1451
|
</div>
|
|
1407
1452
|
|
|
1408
1453
|
<!-- ─── Settings View ─── -->
|
|
1409
|
-
<div class="settings-view" id="settingsView">
|
|
1454
|
+
<div class="settings-view vp" id="settingsView">
|
|
1410
1455
|
<div class="settings-tabs-bar">
|
|
1411
1456
|
<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>
|
|
1412
1457
|
<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>
|
|
@@ -1572,7 +1617,6 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1572
1617
|
</div>
|
|
1573
1618
|
</div>
|
|
1574
1619
|
|
|
1575
|
-
<div class="settings-card-divider"></div>
|
|
1576
1620
|
<div class="settings-actions">
|
|
1577
1621
|
<span class="settings-saved" id="modelsSaved">\u2713 <span data-i18n="settings.saved">Saved</span></span>
|
|
1578
1622
|
<button class="btn btn-ghost" onclick="loadConfig()" data-i18n="settings.reset">Reset</button>
|
|
@@ -1661,6 +1705,11 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1661
1705
|
<input type="text" id="cfgHubTeamName" placeholder="My Team">
|
|
1662
1706
|
<div class="field-hint" data-i18n="settings.hub.teamName.hint">Your team display name</div>
|
|
1663
1707
|
</div>
|
|
1708
|
+
<div class="settings-field">
|
|
1709
|
+
<label data-i18n="settings.hub.adminName">Admin Name</label>
|
|
1710
|
+
<input type="text" id="cfgHubAdminName" placeholder="" maxlength="32">
|
|
1711
|
+
<div class="field-hint" data-i18n="settings.hub.adminName.hint">Your display name as team admin</div>
|
|
1712
|
+
</div>
|
|
1664
1713
|
</div>
|
|
1665
1714
|
<div id="hubShareInfo" style="display:none;margin-top:14px;background:var(--bg);border:1px solid var(--border);border-radius:10px;padding:14px 18px">
|
|
1666
1715
|
<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>
|
|
@@ -1689,6 +1738,11 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1689
1738
|
<input type="text" id="cfgClientTeamToken" placeholder="">
|
|
1690
1739
|
<div class="field-hint" data-i18n="settings.hub.teamTokenClient.hint">Get this from your team admin to join</div>
|
|
1691
1740
|
</div>
|
|
1741
|
+
<div class="settings-field">
|
|
1742
|
+
<label data-i18n="settings.hub.nickname">Nickname</label>
|
|
1743
|
+
<input type="text" id="cfgClientNickname" placeholder="" maxlength="32">
|
|
1744
|
+
<div class="field-hint" data-i18n="settings.hub.nickname.hint">Your display name in the team. If empty, uses system username.</div>
|
|
1745
|
+
</div>
|
|
1692
1746
|
<input type="hidden" id="cfgClientUserToken" value="">
|
|
1693
1747
|
</div>
|
|
1694
1748
|
<div style="margin-top:12px">
|
|
@@ -1743,7 +1797,6 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1743
1797
|
</div>
|
|
1744
1798
|
<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>
|
|
1745
1799
|
|
|
1746
|
-
<div class="settings-card-divider"></div>
|
|
1747
1800
|
<div class="settings-actions">
|
|
1748
1801
|
<span class="settings-saved" id="generalSaved">\u2713 <span data-i18n="settings.saved">Saved</span></span>
|
|
1749
1802
|
<button class="btn btn-ghost" onclick="loadConfig()" data-i18n="settings.reset">Reset</button>
|
|
@@ -1758,13 +1811,12 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1758
1811
|
</div>
|
|
1759
1812
|
|
|
1760
1813
|
<!-- ─── Admin Page ─── -->
|
|
1761
|
-
<div class="admin-view" id="adminView">
|
|
1814
|
+
<div class="admin-view vp" id="adminView">
|
|
1762
1815
|
<div id="adminNotEnabled" style="display:none"></div>
|
|
1763
1816
|
<div id="adminMainContent">
|
|
1764
1817
|
<div class="admin-header">
|
|
1765
1818
|
<div class="admin-header-top">
|
|
1766
|
-
<h2><span class="ah-icon">\u{
|
|
1767
|
-
<button class="btn btn-sm btn-ghost" onclick="loadAdminData()" style="backdrop-filter:blur(8px)" data-i18n="admin.refresh">\u21BB Refresh</button>
|
|
1819
|
+
<h2><span class="ah-icon">\u{26A1}</span> <span data-i18n="admin.title">Team Admin Panel</span></h2>
|
|
1768
1820
|
</div>
|
|
1769
1821
|
<div class="admin-header-sub" data-i18n="admin.subtitle">Manage team members and shared resources</div>
|
|
1770
1822
|
<div class="admin-stat-row" id="adminStats"></div>
|
|
@@ -1783,7 +1835,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1783
1835
|
</div>
|
|
1784
1836
|
|
|
1785
1837
|
<!-- ─── Import Page ─── -->
|
|
1786
|
-
<div class="migrate-view" id="migrateView">
|
|
1838
|
+
<div class="migrate-view vp" id="migrateView">
|
|
1787
1839
|
<div class="settings-section" style="border:1px solid rgba(99,102,241,.15)">
|
|
1788
1840
|
<h3><span class="icon">\u{1F4E5}</span> <span data-i18n="migrate.title">Import OpenClaw Memory</span></h3>
|
|
1789
1841
|
<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>
|
|
@@ -1953,6 +2005,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1953
2005
|
|
|
1954
2006
|
</div>
|
|
1955
2007
|
|
|
2008
|
+
</div>
|
|
1956
2009
|
</div>
|
|
1957
2010
|
</div>
|
|
1958
2011
|
|
|
@@ -1976,7 +2029,9 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1976
2029
|
<script>
|
|
1977
2030
|
let activeSession=null,activeRole='',editingId=null,searchTimer=null,memoryCache={},currentPage=1,totalPages=1,totalCount=0,PAGE_SIZE=40,metricsDays=30;
|
|
1978
2031
|
let memorySearchScope='local',skillSearchScope='local',taskSearchScope='local';
|
|
2032
|
+
let _lastMemoriesFingerprint='',_lastTasksFingerprint='',_lastSkillsFingerprint='';
|
|
1979
2033
|
let _embeddingWarningShown=false;
|
|
2034
|
+
let _currentAgentOwner='agent:main';
|
|
1980
2035
|
|
|
1981
2036
|
/* ─── i18n ─── */
|
|
1982
2037
|
const I18N={
|
|
@@ -2027,6 +2082,8 @@ const I18N={
|
|
|
2027
2082
|
'skills.load.error':'Failed to load skills',
|
|
2028
2083
|
'skills.hub.title':'\u{1F310} Team Skills',
|
|
2029
2084
|
'scope.local':'Local',
|
|
2085
|
+
'scope.thisAgent':'This Agent',
|
|
2086
|
+
'scope.thisDevice':'This Device',
|
|
2030
2087
|
'scope.group':'Group',
|
|
2031
2088
|
'scope.all':'All',
|
|
2032
2089
|
'skills.visibility.public':'Shared Locally',
|
|
@@ -2055,6 +2112,15 @@ const I18N={
|
|
|
2055
2112
|
'notif.removed.memory':'Your shared memory was removed by admin',
|
|
2056
2113
|
'notif.removed.task':'Your shared task was removed by admin',
|
|
2057
2114
|
'notif.removed.skill':'Your shared skill was removed by admin',
|
|
2115
|
+
'notif.shared.memory':'A new memory was shared',
|
|
2116
|
+
'notif.shared.task':'A new task was shared',
|
|
2117
|
+
'notif.shared.skill':'A new skill was shared',
|
|
2118
|
+
'notif.unshared.memory':'A memory was unshared',
|
|
2119
|
+
'notif.unshared.task':'A task was unshared',
|
|
2120
|
+
'notif.unshared.skill':'A skill was unshared',
|
|
2121
|
+
'notif.userJoin':'New user requests to join the team',
|
|
2122
|
+
'notif.userOnline':'User came online',
|
|
2123
|
+
'notif.userOffline':'User went offline',
|
|
2058
2124
|
'notif.clearAll':'Clear all',
|
|
2059
2125
|
'notif.timeAgo.just':'just now',
|
|
2060
2126
|
'notif.timeAgo.min':'{n}m ago',
|
|
@@ -2078,6 +2144,7 @@ const I18N={
|
|
|
2078
2144
|
'filter.newest':'Newest first',
|
|
2079
2145
|
'filter.oldest':'Oldest first',
|
|
2080
2146
|
'filter.allowners':'All owners',
|
|
2147
|
+
'filter.allagents':'All agents',
|
|
2081
2148
|
'filter.allsessions':'All sessions',
|
|
2082
2149
|
'filter.public':'Public',
|
|
2083
2150
|
'filter.private':'Private',
|
|
@@ -2326,6 +2393,8 @@ const I18N={
|
|
|
2326
2393
|
'settings.hub.port.hint':'Port for team server. Default: 18800',
|
|
2327
2394
|
'settings.hub.teamName':'Team Name',
|
|
2328
2395
|
'settings.hub.teamName.hint':'Display name for your team',
|
|
2396
|
+
'settings.hub.adminName':'Admin Name',
|
|
2397
|
+
'settings.hub.adminName.hint':'Your display name as team admin',
|
|
2329
2398
|
'settings.hub.teamToken':'Team Token',
|
|
2330
2399
|
'settings.hub.teamToken.hint':'Auto-generated secret for clients to join. Click to copy. Share this with your team members.',
|
|
2331
2400
|
'settings.hub.tokenCopied':'Team Token copied!',
|
|
@@ -2345,10 +2414,13 @@ const I18N={
|
|
|
2345
2414
|
'settings.hub.hubAddress.hint':'Team server address, e.g. 192.168.1.100:18800',
|
|
2346
2415
|
'settings.hub.teamTokenClient':'Team Token',
|
|
2347
2416
|
'settings.hub.teamTokenClient.hint':'Get this from your team admin to join',
|
|
2417
|
+
'settings.hub.nickname':'Nickname',
|
|
2418
|
+
'settings.hub.nickname.hint':'Your display name in the team. If empty, uses system username.',
|
|
2348
2419
|
'settings.hub.userToken':'User Token',
|
|
2349
2420
|
'settings.hub.userToken.hint':'Usually auto-obtained after joining. Only fill if given by admin.',
|
|
2350
2421
|
'settings.hub.testConnection':'Test Connection',
|
|
2351
2422
|
'settings.hub.test.noAddr':'Please enter server address first',
|
|
2423
|
+
'settings.hub.teamToken.required':'Please enter team token',
|
|
2352
2424
|
'settings.hub.test.testing':'Testing...',
|
|
2353
2425
|
'settings.hub.test.ok':'Connected successfully',
|
|
2354
2426
|
'settings.hub.test.fail':'Connection failed',
|
|
@@ -2383,6 +2455,7 @@ const I18N={
|
|
|
2383
2455
|
'memory.detail.viewTarget':'View target: ',
|
|
2384
2456
|
'admin.title':'Team Admin Panel',
|
|
2385
2457
|
'admin.subtitle':'Manage team members and shared resources',
|
|
2458
|
+
'admin.subtitle.member':'Browse shared memories, tasks and skills from your team',
|
|
2386
2459
|
'admin.refresh':'\u21BB Refresh',
|
|
2387
2460
|
'admin.tab.users':'Users',
|
|
2388
2461
|
'admin.tab.tasks':'Shared Tasks',
|
|
@@ -2398,6 +2471,12 @@ const I18N={
|
|
|
2398
2471
|
'admin.pendingApproval':'Pending Approval',
|
|
2399
2472
|
'admin.activeUsers':'Active Users',
|
|
2400
2473
|
'admin.noActiveUsers':'No active users.',
|
|
2474
|
+
'admin.onlineUsers':'Online',
|
|
2475
|
+
'admin.offlineUsers':'Offline',
|
|
2476
|
+
'admin.online':'Online',
|
|
2477
|
+
'admin.offline':'Offline',
|
|
2478
|
+
'admin.offlineFor':'Offline for {time}',
|
|
2479
|
+
'admin.onlineNow':'Online now',
|
|
2401
2480
|
'admin.approve':'Approve',
|
|
2402
2481
|
'admin.reject':'Reject',
|
|
2403
2482
|
'admin.device':'Device: ',
|
|
@@ -2414,6 +2493,7 @@ const I18N={
|
|
|
2414
2493
|
'admin.demoteMember':'Demote to Member',
|
|
2415
2494
|
'admin.editName':'Edit Name',
|
|
2416
2495
|
'admin.lastAdminHint':'Last admin — cannot remove or demote',
|
|
2496
|
+
'admin.ownerHint':'Hub owner — cannot be demoted or removed',
|
|
2417
2497
|
'admin.editNamePrompt':'Enter new username:',
|
|
2418
2498
|
'confirm.promoteAdmin':'Promote this user to admin? They will be able to manage all team members and resources.',
|
|
2419
2499
|
'confirm.demoteMember':'Demote this admin to member?',
|
|
@@ -2474,6 +2554,7 @@ const I18N={
|
|
|
2474
2554
|
'admin.groupsFailed':'Failed to load groups: ',
|
|
2475
2555
|
'toast.userApproved':'User approved',
|
|
2476
2556
|
'sharing.approved.toast':'Your join request has been approved!',
|
|
2557
|
+
'sharing.rejected.toast':'Your join request was rejected by the admin.',
|
|
2477
2558
|
'toast.userRejected':'User rejected',
|
|
2478
2559
|
'toast.approveFail':'Approve failed',
|
|
2479
2560
|
'toast.rejectFail':'Reject failed',
|
|
@@ -2634,6 +2715,8 @@ const I18N={
|
|
|
2634
2715
|
'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?',
|
|
2635
2716
|
'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?',
|
|
2636
2717
|
'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',
|
|
2718
|
+
'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?',
|
|
2719
|
+
'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?',
|
|
2637
2720
|
'admin.notEnabled.title':'Team sharing is not enabled',
|
|
2638
2721
|
'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.',
|
|
2639
2722
|
'admin.notEnabled.setupHub':'Set Up as Team Server',
|
|
@@ -2708,6 +2791,8 @@ const I18N={
|
|
|
2708
2791
|
'skills.load.error':'加载技能失败',
|
|
2709
2792
|
'skills.hub.title':'\u{1F310} 团队共享技能',
|
|
2710
2793
|
'scope.local':'本地',
|
|
2794
|
+
'scope.thisAgent':'当前智能体',
|
|
2795
|
+
'scope.thisDevice':'本机全部',
|
|
2711
2796
|
'scope.group':'团队',
|
|
2712
2797
|
'scope.all':'全部',
|
|
2713
2798
|
'skills.visibility.public':'本机共享',
|
|
@@ -2736,6 +2821,15 @@ const I18N={
|
|
|
2736
2821
|
'notif.removed.memory':'你共享的记忆被管理员移除',
|
|
2737
2822
|
'notif.removed.task':'你共享的任务被管理员移除',
|
|
2738
2823
|
'notif.removed.skill':'你共享的技能被管理员移除',
|
|
2824
|
+
'notif.shared.memory':'有新的记忆被共享',
|
|
2825
|
+
'notif.shared.task':'有新的任务被共享',
|
|
2826
|
+
'notif.shared.skill':'有新的技能被共享',
|
|
2827
|
+
'notif.unshared.memory':'有记忆取消了共享',
|
|
2828
|
+
'notif.unshared.task':'有任务取消了共享',
|
|
2829
|
+
'notif.unshared.skill':'有技能取消了共享',
|
|
2830
|
+
'notif.userJoin':'有新用户申请加入团队',
|
|
2831
|
+
'notif.userOnline':'用户上线了',
|
|
2832
|
+
'notif.userOffline':'用户下线了',
|
|
2739
2833
|
'notif.clearAll':'清除全部',
|
|
2740
2834
|
'notif.timeAgo.just':'刚刚',
|
|
2741
2835
|
'notif.timeAgo.min':'{n}分钟前',
|
|
@@ -2759,6 +2853,7 @@ const I18N={
|
|
|
2759
2853
|
'filter.newest':'最新优先',
|
|
2760
2854
|
'filter.oldest':'最早优先',
|
|
2761
2855
|
'filter.allowners':'所有归属',
|
|
2856
|
+
'filter.allagents':'全部智能体',
|
|
2762
2857
|
'filter.allsessions':'全部会话',
|
|
2763
2858
|
'filter.public':'公开',
|
|
2764
2859
|
'filter.private':'私有',
|
|
@@ -3007,6 +3102,8 @@ const I18N={
|
|
|
3007
3102
|
'settings.hub.port.hint':'团队服务端口,默认 18800',
|
|
3008
3103
|
'settings.hub.teamName':'团队名称',
|
|
3009
3104
|
'settings.hub.teamName.hint':'你的团队显示名称',
|
|
3105
|
+
'settings.hub.adminName':'管理员名称',
|
|
3106
|
+
'settings.hub.adminName.hint':'你在团队中的显示名称',
|
|
3010
3107
|
'settings.hub.teamToken':'团队令牌',
|
|
3011
3108
|
'settings.hub.teamToken.hint':'自动生成的密钥,点击可复制。请将此令牌分享给团队成员。',
|
|
3012
3109
|
'settings.hub.tokenCopied':'团队令牌已复制!',
|
|
@@ -3026,10 +3123,13 @@ const I18N={
|
|
|
3026
3123
|
'settings.hub.hubAddress.hint':'团队服务器地址,如 192.168.1.100:18800',
|
|
3027
3124
|
'settings.hub.teamTokenClient':'团队令牌',
|
|
3028
3125
|
'settings.hub.teamTokenClient.hint':'向团队管理员获取此令牌以加入团队',
|
|
3126
|
+
'settings.hub.nickname':'昵称',
|
|
3127
|
+
'settings.hub.nickname.hint':'你在团队中的显示名称。留空则使用系统用户名。',
|
|
3029
3128
|
'settings.hub.userToken':'用户令牌',
|
|
3030
3129
|
'settings.hub.userToken.hint':'通常在加入团队后自动获取,无需手动填写。',
|
|
3031
3130
|
'settings.hub.testConnection':'测试连接',
|
|
3032
3131
|
'settings.hub.test.noAddr':'请先输入服务器地址',
|
|
3132
|
+
'settings.hub.teamToken.required':'请输入团队令牌',
|
|
3033
3133
|
'settings.hub.test.testing':'测试中...',
|
|
3034
3134
|
'settings.hub.test.ok':'连接成功',
|
|
3035
3135
|
'settings.hub.test.fail':'连接失败',
|
|
@@ -3064,6 +3164,7 @@ const I18N={
|
|
|
3064
3164
|
'memory.detail.viewTarget':'查看目标: ',
|
|
3065
3165
|
'admin.title':'团队管理面板',
|
|
3066
3166
|
'admin.subtitle':'管理团队成员和共享资源',
|
|
3167
|
+
'admin.subtitle.member':'浏览团队共享的记忆、任务和技能',
|
|
3067
3168
|
'admin.refresh':'\u21BB 刷新',
|
|
3068
3169
|
'admin.tab.users':'用户',
|
|
3069
3170
|
'admin.tab.tasks':'共享任务',
|
|
@@ -3079,6 +3180,12 @@ const I18N={
|
|
|
3079
3180
|
'admin.pendingApproval':'待审批',
|
|
3080
3181
|
'admin.activeUsers':'活跃用户',
|
|
3081
3182
|
'admin.noActiveUsers':'暂无活跃用户。',
|
|
3183
|
+
'admin.onlineUsers':'在线',
|
|
3184
|
+
'admin.offlineUsers':'离线',
|
|
3185
|
+
'admin.online':'在线',
|
|
3186
|
+
'admin.offline':'离线',
|
|
3187
|
+
'admin.offlineFor':'离线 {time}',
|
|
3188
|
+
'admin.onlineNow':'当前在线',
|
|
3082
3189
|
'admin.approve':'批准',
|
|
3083
3190
|
'admin.reject':'拒绝',
|
|
3084
3191
|
'admin.device':'设备:',
|
|
@@ -3095,6 +3202,7 @@ const I18N={
|
|
|
3095
3202
|
'admin.demoteMember':'降为成员',
|
|
3096
3203
|
'admin.editName':'编辑名称',
|
|
3097
3204
|
'admin.lastAdminHint':'唯一管理员 — 无法删除或降级',
|
|
3205
|
+
'admin.ownerHint':'Hub 创建者 — 不可降级或移除',
|
|
3098
3206
|
'admin.editNamePrompt':'请输入新用户名:',
|
|
3099
3207
|
'confirm.promoteAdmin':'确定要将此用户提升为管理员吗?管理员可以管理所有团队成员和资源。',
|
|
3100
3208
|
'confirm.demoteMember':'确定要将此管理员降为普通成员吗?',
|
|
@@ -3155,6 +3263,7 @@ const I18N={
|
|
|
3155
3263
|
'admin.groupsFailed':'加载分组失败:',
|
|
3156
3264
|
'toast.userApproved':'用户已批准',
|
|
3157
3265
|
'sharing.approved.toast':'您的加入申请已通过审核!',
|
|
3266
|
+
'sharing.rejected.toast':'您的加入申请已被管理员拒绝。',
|
|
3158
3267
|
'toast.userRejected':'用户已拒绝',
|
|
3159
3268
|
'toast.approveFail':'批准失败',
|
|
3160
3269
|
'toast.rejectFail':'拒绝失败',
|
|
@@ -3315,6 +3424,8 @@ const I18N={
|
|
|
3315
3424
|
'sharing.disable.confirm.hub':'你即将关闭团队服务。\\n\\n关闭后将会:\\n\\u2022 所有已连接的团队成员将断开连接\\n\\u2022 他们将无法继续同步记忆、任务和技能\\n\\u2022 已共享的数据会保留,重新开启后仍可使用\\n\\n确定要关闭吗?',
|
|
3316
3425
|
'sharing.disable.confirm.client':'你即将断开与团队的连接。\\n\\n断开后将会:\\n\\u2022 你将无法再接收团队共享的记忆、任务和技能\\n\\u2022 你的本地数据不受影响,会完整保留\\n\\u2022 之后可以随时重新开启共享来恢复连接\\n\\n确定要断开吗?',
|
|
3317
3426
|
'sharing.disable.restartAlert':'共享已关闭。请重启 OpenClaw 网关使更改生效。\\n\\n执行命令:openclaw gateway stop && openclaw gateway start',
|
|
3427
|
+
'sharing.switch.hubToClient':'你即将从服务端模式切换为客户端模式。\\n\\n切换后将会:\\n\\u2022 Hub 服务将在重启后关闭\\n\\u2022 所有已连接的团队成员将断开连接\\n\\u2022 Hub 上的共享数据会保留,以后可恢复使用\\n\\u2022 你将作为客户端加入指定的远程团队\\n\\n确定要切换吗?',
|
|
3428
|
+
'sharing.switch.clientToHub':'你即将从客户端模式切换为服务端模式。\\n\\n切换后将会:\\n\\u2022 你将断开与当前团队的连接\\n\\u2022 重启后将启动新的 Hub 服务\\n\\u2022 你的本地数据不受影响\\n\\n确定要切换吗?',
|
|
3318
3429
|
'admin.notEnabled.title':'团队共享尚未开启',
|
|
3319
3430
|
'admin.notEnabled.desc':'管理面板用于管理团队成员、共享的记忆、任务和技能。使用此功能前,需要先开启团队共享。',
|
|
3320
3431
|
'admin.notEnabled.setupHub':'配置为团队服务端',
|
|
@@ -3552,59 +3663,49 @@ function switchSettingsTab(tab,btn){
|
|
|
3552
3663
|
});
|
|
3553
3664
|
}
|
|
3554
3665
|
|
|
3666
|
+
var _activeView='memories';
|
|
3555
3667
|
function switchView(view){
|
|
3668
|
+
_activeView=view;
|
|
3556
3669
|
document.querySelectorAll('.nav-tabs .tab').forEach(t=>t.classList.toggle('active',t.dataset.view===view));
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
const settingsView=document.getElementById('settingsView');
|
|
3563
|
-
const migrateView=document.getElementById('migrateView');
|
|
3564
|
-
const adminView=document.getElementById('adminView');
|
|
3565
|
-
const sidebar=document.getElementById('sidebar');
|
|
3566
|
-
feedWrap.classList.add('hide');
|
|
3567
|
-
analyticsView.classList.remove('show');
|
|
3568
|
-
tasksView.classList.remove('show');
|
|
3569
|
-
skillsView.classList.remove('show');
|
|
3570
|
-
logsView.classList.remove('show');
|
|
3571
|
-
settingsView.classList.remove('show');
|
|
3572
|
-
migrateView.classList.remove('show');
|
|
3573
|
-
if(adminView) adminView.classList.remove('show');
|
|
3670
|
+
var viewMap={memories:'feedWrap',tasks:'tasksView',skills:'skillsView',analytics:'analyticsView',logs:'logsView',settings:'settingsView',import:'migrateView',admin:'adminView'};
|
|
3671
|
+
for(var k in viewMap){
|
|
3672
|
+
var el=document.getElementById(viewMap[k]);
|
|
3673
|
+
if(el) el.classList.toggle('show',k===view);
|
|
3674
|
+
}
|
|
3574
3675
|
var sessionSection=document.getElementById('sidebarSessionSection');
|
|
3575
|
-
if(
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
} else if(view==='tasks'||view==='skills'){
|
|
3579
|
-
if(sessionSection){sessionSection.style.visibility='hidden';sessionSection.style.pointerEvents='none';}
|
|
3580
|
-
if(view==='tasks'){tasksView.classList.add('show');loadTasks();}
|
|
3581
|
-
else{skillsView.classList.add('show');loadSkills();}
|
|
3582
|
-
} else {
|
|
3583
|
-
if(sessionSection){sessionSection.style.visibility='hidden';sessionSection.style.pointerEvents='none';}
|
|
3584
|
-
if(view==='analytics'){
|
|
3585
|
-
analyticsView.classList.add('show');
|
|
3586
|
-
loadMetrics();
|
|
3587
|
-
} else if(view==='logs'){
|
|
3588
|
-
logsView.classList.add('show');
|
|
3589
|
-
loadLogs();
|
|
3590
|
-
} else if(view==='settings'){
|
|
3591
|
-
settingsView.classList.add('show');
|
|
3592
|
-
loadConfig();
|
|
3593
|
-
loadModelHealth();
|
|
3594
|
-
} else if(view==='import'){
|
|
3595
|
-
migrateView.classList.add('show');
|
|
3596
|
-
if(!window._migrateRunning) migrateScan(false);
|
|
3597
|
-
} else if(view==='admin'){
|
|
3598
|
-
if(adminView){adminView.classList.add('show');loadAdminData();}
|
|
3599
|
-
}
|
|
3676
|
+
if(sessionSection){
|
|
3677
|
+
if(view==='memories'){sessionSection.style.visibility='';sessionSection.style.pointerEvents='';}
|
|
3678
|
+
else{sessionSection.style.visibility='hidden';sessionSection.style.pointerEvents='none';}
|
|
3600
3679
|
}
|
|
3680
|
+
if(view==='tasks') loadTasks();
|
|
3681
|
+
else if(view==='skills') loadSkills();
|
|
3682
|
+
else if(view==='analytics') loadMetrics();
|
|
3683
|
+
else if(view==='logs') loadLogs();
|
|
3684
|
+
else if(view==='settings'){loadConfig();loadModelHealth();}
|
|
3685
|
+
else if(view==='import'){if(!window._migrateRunning) migrateScan(false);}
|
|
3686
|
+
else if(view==='admin'){loadAdminData();}
|
|
3601
3687
|
}
|
|
3602
3688
|
|
|
3603
3689
|
function onMemoryScopeChange(){
|
|
3604
3690
|
memorySearchScope=document.getElementById('memorySearchScope')?.value||'local';
|
|
3691
|
+
currentPage=1;
|
|
3692
|
+
activeSession=null;activeRole='';
|
|
3693
|
+
_lastMemoriesFingerprint='';
|
|
3694
|
+
var isHub=memorySearchScope==='hub';
|
|
3695
|
+
var isLocal=memorySearchScope==='local';
|
|
3696
|
+
var ownerSel=document.getElementById('filterOwner');
|
|
3697
|
+
var filterBar=document.getElementById('filterBar');
|
|
3698
|
+
var dateFilter=document.querySelector('.date-filter');
|
|
3699
|
+
if(ownerSel) ownerSel.style.display=(isHub||isLocal)?'none':'';
|
|
3700
|
+
if(filterBar) filterBar.style.display=isHub?'none':'';
|
|
3701
|
+
if(dateFilter) dateFilter.style.display=isHub?'none':'';
|
|
3605
3702
|
if(document.getElementById('searchInput').value.trim()) doSearch(document.getElementById('searchInput').value);
|
|
3606
|
-
else if(
|
|
3607
|
-
else {
|
|
3703
|
+
else if(isHub) { document.getElementById('sharingSearchMeta').textContent=''; loadHubMemories(); }
|
|
3704
|
+
else {
|
|
3705
|
+
document.getElementById('sharingSearchMeta').textContent='';
|
|
3706
|
+
var ownerArg=isLocal?_currentAgentOwner:undefined;
|
|
3707
|
+
loadStats(ownerArg); loadMemories();
|
|
3708
|
+
}
|
|
3608
3709
|
}
|
|
3609
3710
|
|
|
3610
3711
|
function onSkillScopeChange(){
|
|
@@ -3619,6 +3720,7 @@ function onTaskScopeChange(){
|
|
|
3619
3720
|
}
|
|
3620
3721
|
|
|
3621
3722
|
var _clientPendingPollTimer=null;
|
|
3723
|
+
var _lastSharingConnStatus='';
|
|
3622
3724
|
async function loadSharingStatus(forcePending){
|
|
3623
3725
|
try{
|
|
3624
3726
|
const r=await fetch('/api/sharing/status');
|
|
@@ -3628,13 +3730,26 @@ async function loadSharingStatus(forcePending){
|
|
|
3628
3730
|
renderSharingSettings(d);
|
|
3629
3731
|
updateTeamGuide(d);
|
|
3630
3732
|
if(forcePending && d && d.admin && d.admin.canManageUsers) loadSharingPendingUsers();
|
|
3631
|
-
|
|
3632
|
-
|
|
3733
|
+
if(!d||!d.enabled){
|
|
3734
|
+
if(_clientPendingPollTimer){clearInterval(_clientPendingPollTimer);_clientPendingPollTimer=null;}
|
|
3735
|
+
_lastSharingConnStatus='';
|
|
3736
|
+
return;
|
|
3737
|
+
}
|
|
3738
|
+
var conn=d.connection||{};
|
|
3739
|
+
var curStatus=conn.rejected?'rejected':conn.pendingApproval?'pending':conn.connected?'connected':'none';
|
|
3740
|
+
if(_lastSharingConnStatus==='pending'&&curStatus==='rejected'){
|
|
3741
|
+
toast(t('sharing.rejected.toast'),'error');
|
|
3742
|
+
}
|
|
3743
|
+
if(_lastSharingConnStatus==='pending'&&curStatus==='connected'){
|
|
3744
|
+
toast(t('sharing.approved.toast'),'success');
|
|
3745
|
+
}
|
|
3746
|
+
_lastSharingConnStatus=curStatus;
|
|
3747
|
+
if(curStatus==='pending'&&!_clientPendingPollTimer){
|
|
3633
3748
|
_clientPendingPollTimer=setInterval(function(){loadSharingStatus(false);},10000);
|
|
3634
|
-
}
|
|
3749
|
+
}
|
|
3750
|
+
if(curStatus!=='pending'&&_clientPendingPollTimer){
|
|
3635
3751
|
clearInterval(_clientPendingPollTimer);
|
|
3636
3752
|
_clientPendingPollTimer=null;
|
|
3637
|
-
if(conn.connected) toast(t('sharing.approved.toast'),'success');
|
|
3638
3753
|
}
|
|
3639
3754
|
}catch(e){
|
|
3640
3755
|
renderSharingSidebar(null);
|
|
@@ -3643,12 +3758,17 @@ async function loadSharingStatus(forcePending){
|
|
|
3643
3758
|
}
|
|
3644
3759
|
}
|
|
3645
3760
|
|
|
3761
|
+
var _lastSidebarFingerprint='';
|
|
3646
3762
|
function renderSharingSidebar(data){
|
|
3647
3763
|
var section=document.getElementById('sidebarSharingSection');
|
|
3648
3764
|
var statusEl=document.getElementById('sharingSidebarStatus');
|
|
3649
3765
|
var hintEl=document.getElementById('sharingSidebarHint');
|
|
3650
3766
|
var badgeEl=document.getElementById('sharingSidebarConnBadge');
|
|
3651
3767
|
if(!statusEl||!hintEl) return;
|
|
3768
|
+
var conn=data&&data.connection||{};
|
|
3769
|
+
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});
|
|
3770
|
+
if(fp===_lastSidebarFingerprint) return;
|
|
3771
|
+
_lastSidebarFingerprint=fp;
|
|
3652
3772
|
if(!data||!data.enabled){
|
|
3653
3773
|
if(section) section.style.display='none';
|
|
3654
3774
|
window._isHubAdmin=false;
|
|
@@ -3700,12 +3820,17 @@ function renderSharingSidebar(data){
|
|
|
3700
3820
|
}
|
|
3701
3821
|
}
|
|
3702
3822
|
|
|
3823
|
+
var _lastSettingsFingerprint='';
|
|
3703
3824
|
function renderSharingSettings(data){
|
|
3704
3825
|
var statusEl=document.getElementById('sharingStatusPanel');
|
|
3705
3826
|
var teamEl=document.getElementById('sharingTeamPanel');
|
|
3706
3827
|
var adminEl=document.getElementById('sharingAdminPanel');
|
|
3707
3828
|
var panelsWrap=document.getElementById('sharingPanelsWrap');
|
|
3708
3829
|
if(!statusEl||!teamEl||!adminEl) return;
|
|
3830
|
+
var conn2=data&&data.connection||{};
|
|
3831
|
+
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});
|
|
3832
|
+
if(fp2===_lastSettingsFingerprint) return;
|
|
3833
|
+
_lastSettingsFingerprint=fp2;
|
|
3709
3834
|
if(!data||!data.enabled){
|
|
3710
3835
|
statusEl.innerHTML='';teamEl.innerHTML='';adminEl.innerHTML='';
|
|
3711
3836
|
if(panelsWrap) panelsWrap.style.display='none';
|
|
@@ -3722,8 +3847,12 @@ function renderSharingSettings(data){
|
|
|
3722
3847
|
var hubAdminBtn=document.getElementById('hubAdminEntryBtn');
|
|
3723
3848
|
|
|
3724
3849
|
if(actualRole==='hub'){
|
|
3725
|
-
|
|
3850
|
+
teamEl.innerHTML='';adminEl.innerHTML='';statusEl.innerHTML='';statusEl.style.display='none';
|
|
3726
3851
|
if(hubAdminBtn) hubAdminBtn.style.display=isAdmin?'':'none';
|
|
3852
|
+
var hubUser=conn.user||{};
|
|
3853
|
+
var hubName=hubUser.username||'admin';
|
|
3854
|
+
var adminNameInput=document.getElementById('cfgHubAdminName');
|
|
3855
|
+
if(adminNameInput) adminNameInput.value=hubName;
|
|
3727
3856
|
return;
|
|
3728
3857
|
}
|
|
3729
3858
|
|
|
@@ -3915,6 +4044,9 @@ function guideGoToHub(role){
|
|
|
3915
4044
|
|
|
3916
4045
|
/* ─── Hub Admin Panel ─── */
|
|
3917
4046
|
var adminDataCache={users:[],groups:[],tasks:[],skills:[],memories:[]};
|
|
4047
|
+
var _lastAdminFingerprint='';
|
|
4048
|
+
var hubTasksCache=[];
|
|
4049
|
+
var hubSkillsCache=[];
|
|
3918
4050
|
var ADMIN_PAGE_SIZE=20;
|
|
3919
4051
|
var adminPage={users:0,tasks:0,skills:0,memories:0};
|
|
3920
4052
|
|
|
@@ -3936,12 +4068,9 @@ function adminPaginateHtml(total,page,refilterFn){
|
|
|
3936
4068
|
}
|
|
3937
4069
|
|
|
3938
4070
|
var _adminPollTimer=null;
|
|
3939
|
-
function startAdminPoll(){
|
|
3940
|
-
if(_adminPollTimer) return;
|
|
3941
|
-
_adminPollTimer=setInterval(function(){pollAdminPending();},30000);
|
|
3942
|
-
pollAdminPending();
|
|
3943
|
-
}
|
|
4071
|
+
function startAdminPoll(){ startLivePoller(); }
|
|
3944
4072
|
async function pollAdminPending(){
|
|
4073
|
+
if(!window._isHubAdmin) return;
|
|
3945
4074
|
try{
|
|
3946
4075
|
var r=await fetch('/api/sharing/pending-users');
|
|
3947
4076
|
var d=await r.json();
|
|
@@ -3991,24 +4120,44 @@ async function loadAdminData(){
|
|
|
3991
4120
|
}
|
|
3992
4121
|
if(notEnabledEl) notEnabledEl.style.display='none';
|
|
3993
4122
|
if(mainEl) mainEl.style.display='';
|
|
3994
|
-
|
|
3995
|
-
var statsEl=document.getElementById('adminStats');
|
|
3996
|
-
if(statsEl) statsEl.innerHTML='<div class="admin-empty">'+t('admin.noPermission')+'</div>';
|
|
3997
|
-
return;
|
|
3998
|
-
}
|
|
4123
|
+
var isAdmin=!!window._isHubAdmin;
|
|
3999
4124
|
try{
|
|
4000
|
-
var
|
|
4001
|
-
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
|
|
4005
|
-
|
|
4006
|
-
|
|
4007
|
-
|
|
4008
|
-
|
|
4009
|
-
|
|
4010
|
-
|
|
4011
|
-
|
|
4125
|
+
var fetches;
|
|
4126
|
+
if(isAdmin){
|
|
4127
|
+
fetches=await Promise.all([
|
|
4128
|
+
fetch('/api/sharing/users').then(function(r){return r.json();}),
|
|
4129
|
+
fetch('/api/admin/shared-tasks').then(function(r){return r.json();}),
|
|
4130
|
+
fetch('/api/admin/shared-skills').then(function(r){return r.json();}),
|
|
4131
|
+
fetch('/api/sharing/pending-users').then(function(r){return r.json();}),
|
|
4132
|
+
fetch('/api/admin/shared-memories').then(function(r){return r.json();})
|
|
4133
|
+
]);
|
|
4134
|
+
}else{
|
|
4135
|
+
fetches=await Promise.all([
|
|
4136
|
+
Promise.resolve({users:[]}),
|
|
4137
|
+
fetch('/api/sharing/tasks/list?limit=500').then(function(r){return r.json();}),
|
|
4138
|
+
fetch('/api/sharing/skills/list?limit=500').then(function(r){return r.json();}),
|
|
4139
|
+
Promise.resolve({users:[]}),
|
|
4140
|
+
fetch('/api/sharing/memories/list?limit=500').then(function(r){return r.json();})
|
|
4141
|
+
]);
|
|
4142
|
+
}
|
|
4143
|
+
var usersR=fetches[0],tasksR=fetches[1],skillsR=fetches[2],pendingR=fetches[3],memoriesR=fetches[4];
|
|
4144
|
+
var _newUsers=Array.isArray(usersR.users)?usersR.users:[];
|
|
4145
|
+
var _newTasks=Array.isArray(tasksR.tasks)?tasksR.tasks:[];
|
|
4146
|
+
var _newSkills=Array.isArray(skillsR.skills)?skillsR.skills:[];
|
|
4147
|
+
var _newMemories=Array.isArray(memoriesR.memories)?memoriesR.memories:[];
|
|
4148
|
+
var pending=isAdmin?(Array.isArray(pendingR.users)?pendingR.users:[]):[];
|
|
4149
|
+
var _fp=_newUsers.length+':'+_newTasks.length+':'+_newSkills.length+':'+_newMemories.length+':'+pending.length
|
|
4150
|
+
+':'+_newUsers.map(function(u){return u.id+'|'+(u.isOnline?1:0)+'|'+(u.role||'')}).join(',')
|
|
4151
|
+
+':'+_newMemories.map(function(m){return m.id}).join(',')
|
|
4152
|
+
+':'+_newTasks.map(function(t){return t.id+'|'+(t.status||'')}).join(',')
|
|
4153
|
+
+':'+_newSkills.map(function(s){return s.id+'|'+(s.status||'')}).join(',')
|
|
4154
|
+
+':'+pending.map(function(p){return p.id}).join(',');
|
|
4155
|
+
if(_fp===_lastAdminFingerprint) return;
|
|
4156
|
+
_lastAdminFingerprint=_fp;
|
|
4157
|
+
adminDataCache.users=_newUsers;
|
|
4158
|
+
adminDataCache.tasks=_newTasks;
|
|
4159
|
+
adminDataCache.skills=_newSkills;
|
|
4160
|
+
adminDataCache.memories=_newMemories;
|
|
4012
4161
|
adminDataCache._pending=pending;
|
|
4013
4162
|
var badge=document.getElementById('adminPendingBadge');
|
|
4014
4163
|
if(badge){if(pending.length>0){badge.textContent=pending.length;badge.style.display='inline';}else{badge.style.display='none';}}
|
|
@@ -4017,18 +4166,48 @@ async function loadAdminData(){
|
|
|
4017
4166
|
renderAdminTasks(adminDataCache.tasks);
|
|
4018
4167
|
renderAdminSkills(adminDataCache.skills);
|
|
4019
4168
|
renderAdminMemories(adminDataCache.memories);
|
|
4169
|
+
updateAdminTabsVisibility();
|
|
4020
4170
|
}catch(e){
|
|
4021
4171
|
var statsEl=document.getElementById('adminStats');
|
|
4022
4172
|
if(statsEl) statsEl.innerHTML='<div class="admin-empty">'+t('admin.loadFailed')+esc(String(e))+'</div>';
|
|
4023
4173
|
}
|
|
4024
4174
|
}
|
|
4175
|
+
function updateAdminTabsVisibility(){
|
|
4176
|
+
var bar=document.getElementById('adminTabsBar');
|
|
4177
|
+
if(!bar) return;
|
|
4178
|
+
var tabs=bar.querySelectorAll('.admin-tab');
|
|
4179
|
+
var isAdmin=!!window._isHubAdmin;
|
|
4180
|
+
tabs.forEach(function(tab){
|
|
4181
|
+
var onclick=tab.getAttribute('onclick')||'';
|
|
4182
|
+
if(onclick.indexOf("'users'")!==-1){
|
|
4183
|
+
tab.style.display=isAdmin?'':'none';
|
|
4184
|
+
}
|
|
4185
|
+
});
|
|
4186
|
+
if(!isAdmin){
|
|
4187
|
+
var usersPanel=document.getElementById('adminUsersPanel');
|
|
4188
|
+
if(usersPanel&&usersPanel.classList.contains('active')){
|
|
4189
|
+
usersPanel.classList.remove('active');
|
|
4190
|
+
var memPanel=document.getElementById('adminMemoriesPanel');
|
|
4191
|
+
if(memPanel) memPanel.classList.add('active');
|
|
4192
|
+
tabs.forEach(function(tab){
|
|
4193
|
+
tab.classList.remove('active');
|
|
4194
|
+
var onclick=tab.getAttribute('onclick')||'';
|
|
4195
|
+
if(onclick.indexOf("'memories'")!==-1) tab.classList.add('active');
|
|
4196
|
+
});
|
|
4197
|
+
}
|
|
4198
|
+
}
|
|
4199
|
+
var subEl=document.querySelector('.admin-header-sub');
|
|
4200
|
+
if(subEl) subEl.textContent=isAdmin?t('admin.subtitle'):t('admin.subtitle.member');
|
|
4201
|
+
}
|
|
4025
4202
|
|
|
4026
4203
|
function renderAdminStats(pendingCount){
|
|
4027
4204
|
var el=document.getElementById('adminStats');
|
|
4028
4205
|
if(!el) return;
|
|
4206
|
+
var isAdmin=!!window._isHubAdmin;
|
|
4207
|
+
var onlineCount=adminDataCache.users.filter(function(u){return !!u.isOnline;}).length;
|
|
4029
4208
|
el.innerHTML=
|
|
4030
|
-
'<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>'+
|
|
4031
|
-
'<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>'+
|
|
4209
|
+
(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>'+
|
|
4210
|
+
'<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>':'')+
|
|
4032
4211
|
'<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>'+
|
|
4033
4212
|
'<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>'+
|
|
4034
4213
|
'<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>';
|
|
@@ -4038,82 +4217,122 @@ function renderAdminStats(pendingCount){
|
|
|
4038
4217
|
tc=document.getElementById('adminTabCountSkills');if(tc)tc.textContent=adminDataCache.skills.length;
|
|
4039
4218
|
}
|
|
4040
4219
|
|
|
4220
|
+
function auRelativeTime(ts){
|
|
4221
|
+
if(!ts) return t('admin.neverActive');
|
|
4222
|
+
var diff=Date.now()-ts;
|
|
4223
|
+
if(diff<60000) return t('notif.timeAgo.just');
|
|
4224
|
+
if(diff<3600000) return t('notif.timeAgo.min').replace('{n}',Math.floor(diff/60000));
|
|
4225
|
+
if(diff<86400000) return t('notif.timeAgo.hour').replace('{n}',Math.floor(diff/3600000));
|
|
4226
|
+
return t('notif.timeAgo.day').replace('{n}',Math.floor(diff/86400000));
|
|
4227
|
+
}
|
|
4228
|
+
|
|
4229
|
+
function renderAdminUserCard(u,adminCount){
|
|
4230
|
+
var uid=escAttr(u.id);
|
|
4231
|
+
var uname=escAttr(u.username||'');
|
|
4232
|
+
var online=!!u.isOnline;
|
|
4233
|
+
var statusCls=online?'online':'offline';
|
|
4234
|
+
|
|
4235
|
+
var statusIndicator='<span class="au-status-dot '+statusCls+'"></span>';
|
|
4236
|
+
var statusLabel=online
|
|
4237
|
+
?'<span class="au-status-text online">'+t('admin.onlineNow')+'</span>'
|
|
4238
|
+
:'<span class="au-status-text offline">'+auRelativeTime(u.lastActiveAt)+'</span>';
|
|
4239
|
+
|
|
4240
|
+
var titleDisplay='<span class="admin-card-title" id="au_name_'+uid+'">'+statusIndicator+esc(u.username||u.id)+
|
|
4241
|
+
' <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>';
|
|
4242
|
+
|
|
4243
|
+
var editRow='<div id="au_edit_'+uid+'" style="display:none;align-items:center;gap:6px">'+
|
|
4244
|
+
'<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+'")">'+
|
|
4245
|
+
'<button onclick="adminSaveEditName("'+uid+'")" class="btn btn-sm btn-primary" style="padding:4px 12px;font-size:11px;white-space:nowrap">\u2713</button>'+
|
|
4246
|
+
'<button onclick="adminCancelEditName("'+uid+'")" class="btn btn-sm btn-ghost" style="padding:4px 8px;font-size:11px;color:var(--text-muted)">\u2717</button></div>';
|
|
4247
|
+
|
|
4248
|
+
var mc=u.memoryCount||0, tc=u.taskCount||0, sc=u.skillCount||0;
|
|
4249
|
+
var contribHtml='<div class="au-contrib">'+
|
|
4250
|
+
'<span class="au-contrib-item"><span class="au-contrib-num" style="color:var(--pri)">'+mc+'</span> '+t('admin.contrib.memories')+'</span>'+
|
|
4251
|
+
'<span class="au-contrib-item"><span class="au-contrib-num" style="color:var(--green)">'+tc+'</span> '+t('admin.contrib.tasks')+'</span>'+
|
|
4252
|
+
'<span class="au-contrib-item"><span class="au-contrib-num" style="color:var(--amber)">'+sc+'</span> '+t('admin.contrib.skills')+'</span>'+
|
|
4253
|
+
'</div>';
|
|
4254
|
+
|
|
4255
|
+
var infoRows=[];
|
|
4256
|
+
if(u.deviceName) infoRows.push('<span class="au-info-item">\u{1F4BB} '+t('admin.device')+esc(u.deviceName)+'</span>');
|
|
4257
|
+
if(u.lastIp) infoRows.push('<span class="au-info-item">\u{1F310} '+t('admin.ip')+esc(u.lastIp)+'</span>');
|
|
4258
|
+
if(u.createdAt) infoRows.push('<span class="au-info-item">\u{1F4C5} '+t('admin.joined')+formatDateTimeSeconds(u.createdAt)+'</span>');
|
|
4259
|
+
if(u.approvedAt) infoRows.push('<span class="au-info-item">\u2705 '+t('admin.approved')+formatDateTimeSeconds(u.approvedAt)+'</span>');
|
|
4260
|
+
var lastAct=u.lastActiveAt||u.approvedAt||u.createdAt;
|
|
4261
|
+
infoRows.push('<span class="au-info-item">\u{1F552} '+t('admin.lastActive')+(lastAct?formatDateTimeSeconds(lastAct):t('admin.neverActive'))+'</span>');
|
|
4262
|
+
var infoHtml='<div class="au-info">'+infoRows.join('')+'</div>';
|
|
4263
|
+
|
|
4264
|
+
var actions='';
|
|
4265
|
+
if(u.isOwner){
|
|
4266
|
+
actions+='<span style="font-size:11px;color:var(--text-muted);padding:4px 0">'+t('admin.ownerHint')+'</span>';
|
|
4267
|
+
}else if(u.role!=='admin'){
|
|
4268
|
+
actions+='<button class="btn btn-sm btn-ghost" onclick="adminToggleRole("'+uid+'","admin")" style="color:var(--accent)">'+t('admin.promoteAdmin')+'</button>';
|
|
4269
|
+
actions+='<button class="btn btn-sm btn-ghost" onclick="adminRemoveUser("'+uid+'","'+uname+'")" style="color:var(--rose)">'+t('admin.remove')+'</button>';
|
|
4270
|
+
}else if(adminCount>1){
|
|
4271
|
+
actions+='<button class="btn btn-sm btn-ghost" onclick="adminToggleRole("'+uid+'","member")">'+t('admin.demoteMember')+'</button>';
|
|
4272
|
+
actions+='<button class="btn btn-sm btn-ghost" onclick="adminRemoveUser("'+uid+'","'+uname+'")" style="color:var(--rose)">'+t('admin.remove')+'</button>';
|
|
4273
|
+
}else{
|
|
4274
|
+
actions+='<span style="font-size:11px;color:var(--text-muted);padding:4px 0">'+t('admin.lastAdminHint')+'</span>';
|
|
4275
|
+
}
|
|
4276
|
+
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>':'';
|
|
4277
|
+
|
|
4278
|
+
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">'+
|
|
4279
|
+
'<div style="flex:1;min-width:0">'+titleDisplay+editRow+'</div>'+statusLabel+
|
|
4280
|
+
'</div>'+
|
|
4281
|
+
'<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>'+
|
|
4282
|
+
contribHtml+infoHtml+
|
|
4283
|
+
(actions?'<div class="admin-card-actions" style="border-top:1px solid rgba(99,102,241,.08);padding-top:12px;margin-top:6px">'+actions+'</div>':'')+
|
|
4284
|
+
'</div>';
|
|
4285
|
+
}
|
|
4286
|
+
|
|
4041
4287
|
function renderAdminUsers(users,pending){
|
|
4042
4288
|
var el=document.getElementById('adminUsersPanel');
|
|
4043
4289
|
if(!el) return;
|
|
4290
|
+
var isAdmin=!!window._isHubAdmin;
|
|
4291
|
+
if(!isAdmin){
|
|
4292
|
+
el.innerHTML='<div class="admin-empty" style="padding:32px;text-align:center;color:var(--text-sec)">'+t('admin.noPermission')+'</div>';
|
|
4293
|
+
return;
|
|
4294
|
+
}
|
|
4044
4295
|
var html='';
|
|
4045
4296
|
if(pending&&pending.length>0){
|
|
4046
|
-
html+='<div
|
|
4297
|
+
html+='<div class="admin-pending-section"><h3>'+t('admin.pendingApproval')+' <span class="pending-count">'+pending.length+'</span></h3>';
|
|
4047
4298
|
for(var p=0;p<pending.length;p++){
|
|
4048
4299
|
var pu=pending[p];
|
|
4049
|
-
html+='<div class="admin-
|
|
4050
|
-
'<div class="
|
|
4051
|
-
'<div class="
|
|
4052
|
-
|
|
4053
|
-
'<button class="btn
|
|
4300
|
+
html+='<div class="admin-pending-card">'+
|
|
4301
|
+
'<div class="apc-name">'+esc(pu.username||pu.id||'Unknown')+'</div>'+
|
|
4302
|
+
'<div class="apc-meta"><span>\u{1F4BB} '+esc(pu.deviceName||'unknown')+'</span>'+(pu.createdAt?'<span>\u{1F552} '+formatDateTimeSeconds(pu.createdAt)+'</span>':'')+'</div>'+
|
|
4303
|
+
'<div class="apc-actions">'+
|
|
4304
|
+
'<button class="btn-approve" onclick="adminApproveUser("'+escAttr(pu.id)+'","'+escAttr(pu.username||'')+'")">'+t('admin.approve')+'</button>'+
|
|
4305
|
+
'<button class="btn-reject" onclick="adminRejectUser("'+escAttr(pu.id)+'")">'+t('admin.reject')+'</button>'+
|
|
4054
4306
|
'</div></div>';
|
|
4055
4307
|
}
|
|
4056
4308
|
html+='</div>';
|
|
4057
4309
|
}
|
|
4058
|
-
|
|
4059
|
-
|
|
4310
|
+
|
|
4311
|
+
var onlineUsers=users.filter(function(u){return !!u.isOnline;});
|
|
4312
|
+
var offlineUsers=users.filter(function(u){return !u.isOnline;});
|
|
4313
|
+
offlineUsers.sort(function(a,b){return (b.lastActiveAt||0)-(a.lastActiveAt||0);});
|
|
4314
|
+
var sorted=onlineUsers.concat(offlineUsers);
|
|
4315
|
+
var adminCount=users.filter(function(x){return x.role==='admin';}).length;
|
|
4316
|
+
|
|
4317
|
+
if(sorted.length===0){
|
|
4060
4318
|
html+='<div class="admin-empty"><span class="ae-icon">\u{1F465}</span>'+t('admin.noActiveUsers')+'</div>';
|
|
4061
4319
|
}else{
|
|
4062
|
-
|
|
4063
|
-
|
|
4064
|
-
|
|
4065
|
-
|
|
4066
|
-
|
|
4067
|
-
|
|
4068
|
-
|
|
4069
|
-
|
|
4070
|
-
|
|
4071
|
-
|
|
4072
|
-
|
|
4073
|
-
var titleDisplay='<span class="admin-card-title" id="au_name_'+uid+'">'+esc(u.username||u.id)+
|
|
4074
|
-
' <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>';
|
|
4075
|
-
|
|
4076
|
-
var editRow='<div id="au_edit_'+uid+'" style="display:none;align-items:center;gap:6px">'+
|
|
4077
|
-
'<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+'")">'+
|
|
4078
|
-
'<button onclick="adminSaveEditName("'+uid+'")" class="btn btn-sm btn-primary" style="padding:4px 12px;font-size:11px;white-space:nowrap">\u2713</button>'+
|
|
4079
|
-
'<button onclick="adminCancelEditName("'+uid+'")" class="btn btn-sm btn-ghost" style="padding:4px 8px;font-size:11px;color:var(--text-muted)">\u2717</button></div>';
|
|
4080
|
-
|
|
4081
|
-
var mc=u.memoryCount||0, tc=u.taskCount||0, sc=u.skillCount||0;
|
|
4082
|
-
var contribHtml='<div class="au-contrib">'+
|
|
4083
|
-
'<span class="au-contrib-item"><span class="au-contrib-num" style="color:var(--pri)">'+mc+'</span> '+t('admin.contrib.memories')+'</span>'+
|
|
4084
|
-
'<span class="au-contrib-item"><span class="au-contrib-num" style="color:var(--green)">'+tc+'</span> '+t('admin.contrib.tasks')+'</span>'+
|
|
4085
|
-
'<span class="au-contrib-item"><span class="au-contrib-num" style="color:var(--amber)">'+sc+'</span> '+t('admin.contrib.skills')+'</span>'+
|
|
4086
|
-
'</div>';
|
|
4087
|
-
|
|
4088
|
-
var infoRows=[];
|
|
4089
|
-
if(u.deviceName) infoRows.push('<span class="au-info-item">\u{1F4BB} '+t('admin.device')+esc(u.deviceName)+'</span>');
|
|
4090
|
-
if(u.lastIp) infoRows.push('<span class="au-info-item">\u{1F310} '+t('admin.ip')+esc(u.lastIp)+'</span>');
|
|
4091
|
-
if(u.createdAt) infoRows.push('<span class="au-info-item">\u{1F4C5} '+t('admin.joined')+formatDateTimeSeconds(u.createdAt)+'</span>');
|
|
4092
|
-
if(u.approvedAt) infoRows.push('<span class="au-info-item">\u2705 '+t('admin.approved')+formatDateTimeSeconds(u.approvedAt)+'</span>');
|
|
4093
|
-
infoRows.push('<span class="au-info-item">\u{1F552} '+t('admin.lastActive')+(u.lastActiveAt?formatDateTimeSeconds(u.lastActiveAt):t('admin.neverActive'))+'</span>');
|
|
4094
|
-
var infoHtml='<div class="au-info">'+infoRows.join('')+'</div>';
|
|
4095
|
-
|
|
4096
|
-
var actions='';
|
|
4097
|
-
if(u.role!=='admin'){
|
|
4098
|
-
actions+='<button class="btn btn-sm btn-ghost" onclick="adminToggleRole("'+uid+'","admin")" style="color:var(--accent)">'+t('admin.promoteAdmin')+'</button>';
|
|
4099
|
-
actions+='<button class="btn btn-sm btn-ghost" onclick="adminRemoveUser("'+uid+'","'+uname+'")" style="color:var(--rose)">'+t('admin.remove')+'</button>';
|
|
4100
|
-
}else if(adminCount>1){
|
|
4101
|
-
actions+='<button class="btn btn-sm btn-ghost" onclick="adminToggleRole("'+uid+'","member")">'+t('admin.demoteMember')+'</button>';
|
|
4102
|
-
actions+='<button class="btn btn-sm btn-ghost" onclick="adminRemoveUser("'+uid+'","'+uname+'")" style="color:var(--rose)">'+t('admin.remove')+'</button>';
|
|
4103
|
-
}else{
|
|
4104
|
-
actions+='<span style="font-size:11px;color:var(--text-muted);padding:4px 0">'+t('admin.lastAdminHint')+'</span>';
|
|
4105
|
-
}
|
|
4106
|
-
html+='<div class="admin-card au-card"><div class="admin-card-header"><div style="flex:1;min-width:0">'+titleDisplay+editRow+'</div>'+
|
|
4107
|
-
'<span class="admin-badge '+(u.role==='admin'?'admin':'member')+'">'+esc(u.role||'member')+'</span></div>'+
|
|
4108
|
-
contribHtml+infoHtml+
|
|
4109
|
-
(actions?'<div class="admin-card-actions" style="border-top:1px dashed var(--border);padding-top:10px;margin-top:4px">'+actions+'</div>':'')+
|
|
4110
|
-
'</div>';
|
|
4320
|
+
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>';
|
|
4321
|
+
if(onlineUsers.length===0){
|
|
4322
|
+
html+='<div style="font-size:12px;color:var(--text-muted);padding:8px 0 12px">\u2014</div>';
|
|
4323
|
+
}else{
|
|
4324
|
+
for(var i=0;i<onlineUsers.length;i++) html+=renderAdminUserCard(onlineUsers[i],adminCount);
|
|
4325
|
+
}
|
|
4326
|
+
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>';
|
|
4327
|
+
if(offlineUsers.length===0){
|
|
4328
|
+
html+='<div style="font-size:12px;color:var(--text-muted);padding:8px 0 12px">\u2014</div>';
|
|
4329
|
+
}else{
|
|
4330
|
+
for(var j=0;j<offlineUsers.length;j++) html+=renderAdminUserCard(offlineUsers[j],adminCount);
|
|
4111
4331
|
}
|
|
4112
|
-
html+=adminPaginateHtml(totalUsers,adminPage.users,'adminUsers');
|
|
4113
4332
|
}
|
|
4114
4333
|
el.innerHTML=html;
|
|
4115
4334
|
}
|
|
4116
|
-
function adminUsersPage(p){
|
|
4335
|
+
function adminUsersPage(p){renderAdminUsers(adminDataCache.users,adminDataCache._pending||[]);}
|
|
4117
4336
|
|
|
4118
4337
|
async function adminApproveUser(userId,username){
|
|
4119
4338
|
try{
|
|
@@ -4136,7 +4355,9 @@ async function adminToggleRole(userId,newRole){
|
|
|
4136
4355
|
try{
|
|
4137
4356
|
var r=await fetch('/api/sharing/change-role',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:userId,role:newRole})});
|
|
4138
4357
|
var d=await r.json();
|
|
4139
|
-
if(d.ok){toast(t('toast.roleChanged'),'success');loadAdminData();}
|
|
4358
|
+
if(d.ok){toast(t('toast.roleChanged'),'success');loadAdminData();}
|
|
4359
|
+
else if(d.error==='cannot_demote_owner'){toast(t('admin.ownerHint'),'error');}
|
|
4360
|
+
else{toast(d.error||t('toast.roleChangeFail'),'error');}
|
|
4140
4361
|
}catch(e){toast(t('toast.roleChangeFail')+': '+e.message,'error');}
|
|
4141
4362
|
}
|
|
4142
4363
|
function adminStartEditName(btn,userId,currentName){
|
|
@@ -4175,7 +4396,9 @@ async function adminRemoveUser(userId,username){
|
|
|
4175
4396
|
try{
|
|
4176
4397
|
var r=await fetch('/api/sharing/remove-user',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:userId,cleanResources:clean})});
|
|
4177
4398
|
var d=await r.json();
|
|
4178
|
-
if(d.ok){toast(t('toast.userRemoved'),'success');loadAdminData();}
|
|
4399
|
+
if(d.ok){toast(t('toast.userRemoved'),'success');loadAdminData();}
|
|
4400
|
+
else if(d.error==='cannot_remove_owner'){toast(t('admin.ownerHint'),'error');}
|
|
4401
|
+
else{toast(d.error||t('toast.removeFail'),'error');}
|
|
4179
4402
|
}catch(e){toast(t('toast.removeFail')+': '+e.message,'error');}
|
|
4180
4403
|
}
|
|
4181
4404
|
|
|
@@ -4247,7 +4470,7 @@ function renderAdminTasks(tasks){
|
|
|
4247
4470
|
(tk.chunkCount!=null?'<span class="admin-card-tag tag-kind">\u{1F4DD} '+tk.chunkCount+' '+t('admin.chunks')+'</span>':'')+
|
|
4248
4471
|
'</div>'+
|
|
4249
4472
|
'<span class="admin-card-actions" onclick="event.stopPropagation()">'+
|
|
4250
|
-
'<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>'+
|
|
4473
|
+
(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>':'')+
|
|
4251
4474
|
'<button class="btn btn-sm btn-ghost admin-card-expand-btn" onclick="toggleAdminTaskCard("'+cardId+'",'+i+')">'+t('admin.expand')+'</button>'+
|
|
4252
4475
|
'<span class="admin-card-time">'+(timeRange||formatDateTimeSeconds(tk.updatedAt||tk.createdAt))+'</span>'+
|
|
4253
4476
|
'</span>'+
|
|
@@ -4310,7 +4533,7 @@ function renderAdminSkills(skills){
|
|
|
4310
4533
|
(qs!=null?'<span class="admin-card-tag tag-kind">\u2605 '+Number(qs).toFixed(1)+'</span>':'')+
|
|
4311
4534
|
'</div>'+
|
|
4312
4535
|
'<span class="admin-card-actions" onclick="event.stopPropagation()">'+
|
|
4313
|
-
'<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>'+
|
|
4536
|
+
(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>':'')+
|
|
4314
4537
|
'<button class="btn btn-sm btn-ghost admin-card-expand-btn" onclick="toggleAdminSkillCard("'+cardId+'",'+i+')">'+t('admin.expand')+'</button>'+
|
|
4315
4538
|
(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>':'')+
|
|
4316
4539
|
'<span class="admin-card-time">'+formatDateTimeSeconds(s.updatedAt||s.createdAt)+'</span>'+
|
|
@@ -4374,7 +4597,7 @@ function renderAdminMemories(memories){
|
|
|
4374
4597
|
(m.kind?'<span class="admin-card-tag tag-kind">'+esc(m.kind)+'</span>':'')+
|
|
4375
4598
|
'</div>'+
|
|
4376
4599
|
'<span class="admin-card-actions">'+
|
|
4377
|
-
'<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>'+
|
|
4600
|
+
(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>':'')+
|
|
4378
4601
|
'<button class="btn btn-sm btn-ghost admin-card-expand-btn" onclick="event.stopPropagation();toggleAdminMemoryCard("'+cardId+'",'+i+')">'+t('admin.expand')+'</button>'+
|
|
4379
4602
|
'<span class="admin-card-time">'+formatDateTimeSeconds(m.updatedAt||m.createdAt)+'</span>'+
|
|
4380
4603
|
'</span>'+
|
|
@@ -4452,12 +4675,19 @@ async function toggleAdminTaskCard(cardId,idx){
|
|
|
4452
4675
|
var tk=(adminTasksCache||[])[idx];
|
|
4453
4676
|
if(!tk){detail.innerHTML='<div style="color:var(--text-muted);font-size:14px;padding:12px">'+t('admin.noContent')+'</div>';return;}
|
|
4454
4677
|
var localTaskId=tk.sourceTaskId||tk.id;
|
|
4678
|
+
var hubTaskId=tk.id;
|
|
4455
4679
|
detail.innerHTML='<div class="spinner"></div>';
|
|
4456
4680
|
var task=null;
|
|
4457
4681
|
try{
|
|
4458
4682
|
var r=await fetch('/api/task/'+encodeURIComponent(localTaskId));
|
|
4459
4683
|
if(r.ok) task=await r.json();
|
|
4460
4684
|
}catch(e){}
|
|
4685
|
+
if(!task){
|
|
4686
|
+
try{
|
|
4687
|
+
var r2=await fetch('/api/admin/shared-tasks/'+encodeURIComponent(hubTaskId)+'/detail');
|
|
4688
|
+
if(r2.ok) task=await r2.json();
|
|
4689
|
+
}catch(e2){}
|
|
4690
|
+
}
|
|
4461
4691
|
if(!task){detail.innerHTML='<div style="color:var(--text-muted);font-size:14px;padding:12px">'+t('admin.noContent')+'</div>';return;}
|
|
4462
4692
|
var metaHtml='<div class="admin-card-detail-meta admin-task-meta">'+
|
|
4463
4693
|
(tk.status?'<span class="meta-item"><span class="task-status-badge '+tk.status+'">'+esc(tk.status)+'</span></span>':'')+
|
|
@@ -4528,11 +4758,18 @@ async function toggleAdminSkillCard(cardId,idx){
|
|
|
4528
4758
|
if(!sk){detail.innerHTML='<div style="color:var(--text-muted);font-size:13px">'+t('admin.noContent')+'</div>';return;}
|
|
4529
4759
|
detail.innerHTML='<div class="spinner"></div>';
|
|
4530
4760
|
var localSkillId=sk.sourceSkillId||sk.id;
|
|
4761
|
+
var hubSkillId=sk.id;
|
|
4531
4762
|
var localData=null;
|
|
4532
4763
|
try{
|
|
4533
4764
|
var lr=await fetch('/api/skill/'+encodeURIComponent(localSkillId));
|
|
4534
4765
|
if(lr.ok) localData=await lr.json();
|
|
4535
4766
|
}catch(e){}
|
|
4767
|
+
if(!localData){
|
|
4768
|
+
try{
|
|
4769
|
+
var hr=await fetch('/api/admin/shared-skills/'+encodeURIComponent(hubSkillId)+'/detail');
|
|
4770
|
+
if(hr.ok) localData=await hr.json();
|
|
4771
|
+
}catch(e2){}
|
|
4772
|
+
}
|
|
4536
4773
|
var localSkill=localData&&localData.skill?localData.skill:sk;
|
|
4537
4774
|
var files=localData&&localData.files?localData.files:[];
|
|
4538
4775
|
var versions=localData&&localData.versions?localData.versions:[];
|
|
@@ -5359,22 +5596,33 @@ function setTaskStatusFilter(btn,status){
|
|
|
5359
5596
|
loadTasks();
|
|
5360
5597
|
}
|
|
5361
5598
|
|
|
5362
|
-
async function loadTasks(){
|
|
5599
|
+
async function loadTasks(silent){
|
|
5363
5600
|
const scope=document.getElementById('taskSearchScope')?document.getElementById('taskSearchScope').value:taskSearchScope;
|
|
5364
5601
|
taskSearchScope=scope||'local';
|
|
5365
|
-
if(taskSearchScope
|
|
5602
|
+
if(taskSearchScope==='hub'){ return loadHubTasks(); }
|
|
5366
5603
|
const list=document.getElementById('tasksList');
|
|
5367
|
-
list.innerHTML='<div class="spinner"></div>';
|
|
5604
|
+
if(!silent) list.innerHTML='<div class="spinner"></div>';
|
|
5368
5605
|
try{
|
|
5369
5606
|
const params=new URLSearchParams({limit:String(TASKS_PER_PAGE),offset:String(tasksPage*TASKS_PER_PAGE)});
|
|
5370
5607
|
if(tasksStatusFilter) params.set('status',tasksStatusFilter);
|
|
5608
|
+
if(taskSearchScope==='local') params.set('owner','agent:main');
|
|
5609
|
+
var baseP=new URLSearchParams();
|
|
5610
|
+
if(taskSearchScope==='local') baseP.set('owner','agent:main');
|
|
5371
5611
|
const [data,allD,activeD,compD,skipD]=await Promise.all([
|
|
5372
5612
|
fetch('/api/tasks?'+params).then(r=>r.json()),
|
|
5373
|
-
fetch('/api/tasks?limit=1&offset=0').then(r=>r.json()),
|
|
5374
|
-
fetch('/api/tasks?status=active&limit=1&offset=0').then(r=>r.json()),
|
|
5375
|
-
fetch('/api/tasks?status=completed&limit=1&offset=0').then(r=>r.json()),
|
|
5376
|
-
fetch('/api/tasks?status=skipped&limit=1&offset=0').then(r=>r.json())
|
|
5613
|
+
fetch('/api/tasks?limit=1&offset=0&'+baseP).then(r=>r.json()),
|
|
5614
|
+
fetch('/api/tasks?status=active&limit=1&offset=0&'+baseP).then(r=>r.json()),
|
|
5615
|
+
fetch('/api/tasks?status=completed&limit=1&offset=0&'+baseP).then(r=>r.json()),
|
|
5616
|
+
fetch('/api/tasks?status=skipped&limit=1&offset=0&'+baseP).then(r=>r.json())
|
|
5377
5617
|
]);
|
|
5618
|
+
if(silent){
|
|
5619
|
+
var fp=JSON.stringify((data.tasks||[]).map(function(tk){return tk.id+'|'+tk.status+'|'+(tk.updatedAt||tk.startedAt)}));
|
|
5620
|
+
fp+=':'+allD.total+':'+activeD.total+':'+compD.total+':'+skipD.total;
|
|
5621
|
+
if(fp===_lastTasksFingerprint) return;
|
|
5622
|
+
_lastTasksFingerprint=fp;
|
|
5623
|
+
}else{
|
|
5624
|
+
_lastTasksFingerprint='';
|
|
5625
|
+
}
|
|
5378
5626
|
document.getElementById('tasksTotalCount').textContent=formatNum(allD.total);
|
|
5379
5627
|
document.getElementById('tasksActiveCount').textContent=formatNum(activeD.total);
|
|
5380
5628
|
document.getElementById('tasksCompletedCount').textContent=formatNum(compD.total);
|
|
@@ -5660,17 +5908,17 @@ function updateSkillCardBadge(skillId,newScope){
|
|
|
5660
5908
|
}
|
|
5661
5909
|
}
|
|
5662
5910
|
|
|
5663
|
-
async function loadSkills(){
|
|
5911
|
+
async function loadSkills(silent){
|
|
5664
5912
|
const list=document.getElementById('skillsList');
|
|
5665
5913
|
const hubList=document.getElementById('hubSkillsList');
|
|
5666
|
-
list.innerHTML='<div class="spinner"></div>';
|
|
5914
|
+
if(!silent) list.innerHTML='<div class="spinner"></div>';
|
|
5667
5915
|
var hubSection=document.getElementById('hubSkillsSection');
|
|
5668
5916
|
if(hubList){
|
|
5669
|
-
if(skillSearchScope==='local'){
|
|
5917
|
+
if(skillSearchScope==='local'||skillSearchScope==='allLocal'){
|
|
5670
5918
|
if(hubSection) hubSection.style.display='none';
|
|
5671
5919
|
}else{
|
|
5672
5920
|
if(hubSection) hubSection.style.display='block';
|
|
5673
|
-
hubList.innerHTML='<div class="spinner"></div>';
|
|
5921
|
+
if(!silent) hubList.innerHTML='<div class="spinner"></div>';
|
|
5674
5922
|
}
|
|
5675
5923
|
}
|
|
5676
5924
|
|
|
@@ -5694,6 +5942,13 @@ async function loadSkills(){
|
|
|
5694
5942
|
return haystack.includes(q);
|
|
5695
5943
|
});
|
|
5696
5944
|
}
|
|
5945
|
+
if(silent){
|
|
5946
|
+
var fp=JSON.stringify(localSkills.map(function(s){return s.id+'|'+s.status+'|'+s.version+'|'+(s.visibility||'')}));
|
|
5947
|
+
if(fp===_lastSkillsFingerprint) return;
|
|
5948
|
+
_lastSkillsFingerprint=fp;
|
|
5949
|
+
}else{
|
|
5950
|
+
_lastSkillsFingerprint='';
|
|
5951
|
+
}
|
|
5697
5952
|
|
|
5698
5953
|
const renderLocalCards=function(skills){
|
|
5699
5954
|
if(!skills||skills.length===0){
|
|
@@ -5739,7 +5994,7 @@ async function loadSkills(){
|
|
|
5739
5994
|
|
|
5740
5995
|
list.innerHTML=renderLocalCards(localSkills);
|
|
5741
5996
|
|
|
5742
|
-
if(skillSearchScope==='local'){
|
|
5997
|
+
if(skillSearchScope==='local'||skillSearchScope==='allLocal'){
|
|
5743
5998
|
if(hubSection) hubSection.style.display='none';
|
|
5744
5999
|
document.getElementById('skillSearchMeta').textContent=query?(t('skills.search.local')+' '+localSkills.length):'';
|
|
5745
6000
|
document.getElementById('skillsTotalCount').textContent=formatNum(localSkills.length);
|
|
@@ -5752,7 +6007,8 @@ async function loadSkills(){
|
|
|
5752
6007
|
|
|
5753
6008
|
if(!query){
|
|
5754
6009
|
if(hubSection) hubSection.style.display='block';
|
|
5755
|
-
|
|
6010
|
+
var localIds=new Set(localSkills.map(function(s){return s.id;}));
|
|
6011
|
+
if(hubList){ loadHubSkills(hubList, localIds); }
|
|
5756
6012
|
document.getElementById('skillSearchMeta').textContent=t('skills.search.local')+' '+localSkills.length;
|
|
5757
6013
|
document.getElementById('skillsTotalCount').textContent=formatNum(localSkills.length);
|
|
5758
6014
|
document.getElementById('skillsActiveCount').textContent=formatNum(localSkills.filter(s=>s.status==='active').length);
|
|
@@ -5810,7 +6066,47 @@ async function loadSkills(){
|
|
|
5810
6066
|
}
|
|
5811
6067
|
}
|
|
5812
6068
|
|
|
5813
|
-
async function
|
|
6069
|
+
async function loadHubTasks(){
|
|
6070
|
+
var list=document.getElementById('tasksList');
|
|
6071
|
+
if(!list) return;
|
|
6072
|
+
list.innerHTML='<div class="spinner"></div>';
|
|
6073
|
+
try{
|
|
6074
|
+
var r=await fetch('/api/sharing/tasks/list?limit=40');
|
|
6075
|
+
var d=await r.json();
|
|
6076
|
+
var tasks=Array.isArray(d.tasks)?d.tasks:[];
|
|
6077
|
+
hubTasksCache=tasks;
|
|
6078
|
+
document.getElementById('tasksTotalCount').textContent=formatNum(tasks.length);
|
|
6079
|
+
document.getElementById('tasksActiveCount').textContent='-';
|
|
6080
|
+
document.getElementById('tasksCompletedCount').textContent='-';
|
|
6081
|
+
document.getElementById('tasksSkippedCount').textContent='-';
|
|
6082
|
+
if(!tasks.length){
|
|
6083
|
+
list.innerHTML='<div style="text-align:center;padding:48px;color:var(--text-muted);font-size:14px">'+t('tasks.empty')+'</div>';
|
|
6084
|
+
document.getElementById('tasksPagination').innerHTML='';
|
|
6085
|
+
return;
|
|
6086
|
+
}
|
|
6087
|
+
list.innerHTML=tasks.map(function(task,idx){
|
|
6088
|
+
var timeStr=task.updatedAt?formatTime(task.updatedAt):(task.createdAt?formatTime(task.createdAt):'');
|
|
6089
|
+
return '<div class="task-card" onclick="openHubTaskDetailFromCache(\\x27hub\\x27,'+idx+')" style="cursor:pointer">'+
|
|
6090
|
+
'<div class="task-card-top">'+
|
|
6091
|
+
'<div class="task-card-title">'+esc(task.title||'(no title)')+'</div>'+
|
|
6092
|
+
'<div class="task-card-badges"><span class="scope-badge team">\\u{1F310} '+t('scope.hub')+'</span></div>'+
|
|
6093
|
+
'</div>'+
|
|
6094
|
+
(task.summary?'<div class="task-card-summary">'+esc(task.summary)+'</div>':'')+
|
|
6095
|
+
'<div class="task-card-bottom">'+
|
|
6096
|
+
(timeStr?'<span class="tag"><span class="icon">\\u{1F4C5}</span> '+timeStr+'</span>':'')+
|
|
6097
|
+
'<span class="tag"><span class="icon">\\u{1F464}</span> '+esc(task.ownerName||'unknown')+'</span>'+
|
|
6098
|
+
(task.chunkCount!=null?'<span class="tag"><span class="icon">\\u{1F4DD}</span> '+task.chunkCount+' '+t('tasks.chunks.label')+'</span>':'')+
|
|
6099
|
+
'</div>'+
|
|
6100
|
+
'</div>';
|
|
6101
|
+
}).join('');
|
|
6102
|
+
document.getElementById('tasksPagination').innerHTML='';
|
|
6103
|
+
}catch(e){
|
|
6104
|
+
list.innerHTML='<div style="text-align:center;padding:48px;color:var(--text-muted);font-size:14px">'+t('tasks.empty')+'</div>';
|
|
6105
|
+
document.getElementById('tasksPagination').innerHTML='';
|
|
6106
|
+
}
|
|
6107
|
+
}
|
|
6108
|
+
|
|
6109
|
+
async function loadHubSkills(hubList, localIds){
|
|
5814
6110
|
if(!hubList) hubList=document.getElementById('hubSkillsList');
|
|
5815
6111
|
if(!hubList) return;
|
|
5816
6112
|
var hubSection=document.getElementById('hubSkillsSection');
|
|
@@ -5818,7 +6114,8 @@ async function loadHubSkills(hubList){
|
|
|
5818
6114
|
try{
|
|
5819
6115
|
const r=await fetch('/api/sharing/skills/list?limit=40');
|
|
5820
6116
|
const d=await r.json();
|
|
5821
|
-
|
|
6117
|
+
var allSkills=Array.isArray(d.skills)?d.skills:[];
|
|
6118
|
+
const skills=localIds?allSkills.filter(function(s){return !localIds.has(s.sourceSkillId);}):allSkills;
|
|
5822
6119
|
hubSkillsCache=skills;
|
|
5823
6120
|
if(!skills.length){
|
|
5824
6121
|
if(hubSection) hubSection.style.display='none';
|
|
@@ -6170,6 +6467,7 @@ async function loadConfig(){
|
|
|
6170
6467
|
document.getElementById('cfgHubTeamToken').value=hub.teamToken||'';
|
|
6171
6468
|
document.getElementById('cfgClientHubAddress').value=client.hubAddress||'';
|
|
6172
6469
|
document.getElementById('cfgClientTeamToken').value=client.teamToken||'';
|
|
6470
|
+
document.getElementById('cfgClientNickname').value=client.nickname||'';
|
|
6173
6471
|
document.getElementById('cfgClientUserToken').value=client.userToken||'';
|
|
6174
6472
|
onSharingToggle();
|
|
6175
6473
|
updateHubShareInfo();
|
|
@@ -6338,6 +6636,7 @@ async function saveHubConfig(){
|
|
|
6338
6636
|
var hubPort=document.getElementById('cfgHubPort').value.trim();
|
|
6339
6637
|
var hubTeamName=document.getElementById('cfgHubTeamName').value.trim();
|
|
6340
6638
|
var hubTeamToken=document.getElementById('cfgHubTeamToken').value.trim();
|
|
6639
|
+
var hubAdminName=document.getElementById('cfgHubAdminName').value.trim();
|
|
6341
6640
|
cfg.sharing.hub={port:hubPort?Number(hubPort):18800};
|
|
6342
6641
|
if(hubTeamName) cfg.sharing.hub.teamName=hubTeamName;
|
|
6343
6642
|
if(hubTeamToken) cfg.sharing.hub.teamToken=hubTeamToken;
|
|
@@ -6347,8 +6646,12 @@ async function saveHubConfig(){
|
|
|
6347
6646
|
var clientAddr=document.getElementById('cfgClientHubAddress').value.trim();
|
|
6348
6647
|
var clientTeamToken=document.getElementById('cfgClientTeamToken').value.trim();
|
|
6349
6648
|
var clientUserToken=document.getElementById('cfgClientUserToken').value.trim();
|
|
6649
|
+
var clientNickname=document.getElementById('cfgClientNickname').value.trim();
|
|
6650
|
+
if(!clientAddr){done();toast(t('settings.hub.test.noAddr'),'error');return;}
|
|
6651
|
+
if(!clientTeamToken){done();toast(t('settings.hub.teamToken.required'),'error');return;}
|
|
6350
6652
|
cfg.sharing.client={};
|
|
6351
6653
|
if(clientAddr) cfg.sharing.client.hubAddress=clientAddr;
|
|
6654
|
+
if(clientNickname) cfg.sharing.client.nickname=clientNickname;
|
|
6352
6655
|
if(clientTeamToken) cfg.sharing.client.teamToken=clientTeamToken;
|
|
6353
6656
|
if(clientUserToken) cfg.sharing.client.userToken=clientUserToken;
|
|
6354
6657
|
cfg.sharing.hub={port:18800,teamName:'',teamToken:''};
|
|
@@ -6361,6 +6664,18 @@ async function saveHubConfig(){
|
|
|
6361
6664
|
done();toast(t('sharing.cannotJoinSelf'),'error');return;
|
|
6362
6665
|
}
|
|
6363
6666
|
}catch(e){}
|
|
6667
|
+
try{
|
|
6668
|
+
var testUrl=clientAddr.indexOf('://')>-1?clientAddr:'http://'+clientAddr;
|
|
6669
|
+
testUrl=testUrl.replace(/\\/+$/,'');
|
|
6670
|
+
var tr=await fetch('/api/sharing/test-hub',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({hubUrl:testUrl})});
|
|
6671
|
+
var td=await tr.json();
|
|
6672
|
+
if(!td.ok){
|
|
6673
|
+
var errMsg=td.error==='cannot_join_self'?t('sharing.cannotJoinSelf'):(td.error||t('settings.hub.test.fail'));
|
|
6674
|
+
done();toast(errMsg,'error');return;
|
|
6675
|
+
}
|
|
6676
|
+
}catch(e){
|
|
6677
|
+
done();toast(t('settings.hub.test.fail')+': '+String(e),'error');return;
|
|
6678
|
+
}
|
|
6364
6679
|
}
|
|
6365
6680
|
}
|
|
6366
6681
|
|
|
@@ -6370,11 +6685,25 @@ async function saveHubConfig(){
|
|
|
6370
6685
|
var confirmMsg=prevRole==='hub'?t('sharing.disable.confirm.hub'):t('sharing.disable.confirm.client');
|
|
6371
6686
|
if(!(await confirmModal(confirmMsg,{danger:true}))){done();return;}
|
|
6372
6687
|
}
|
|
6688
|
+
if(prevSharingEnabled&&sharingEnabled&&prevRole&&prevRole!==_sharingRole){
|
|
6689
|
+
var switchMsg=prevRole==='hub'?t('sharing.switch.hubToClient'):t('sharing.switch.clientToHub');
|
|
6690
|
+
if(!(await confirmModal(switchMsg,{danger:true}))){done();return;}
|
|
6691
|
+
}
|
|
6373
6692
|
|
|
6374
6693
|
var ok=await doSaveConfig(cfg, saveBtn, 'hubSaved');
|
|
6375
6694
|
if(ok){
|
|
6695
|
+
if(sharingEnabled&&_sharingRole==='hub'){
|
|
6696
|
+
var adminNameEl=document.getElementById('cfgHubAdminName');
|
|
6697
|
+
if(adminNameEl&&adminNameEl.value.trim()){
|
|
6698
|
+
try{await fetch('/api/sharing/update-username',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({username:adminNameEl.value.trim()})});}catch(e){}
|
|
6699
|
+
}
|
|
6700
|
+
}
|
|
6701
|
+
_lastSidebarFingerprint='';
|
|
6702
|
+
_lastSettingsFingerprint='';
|
|
6376
6703
|
loadSharingStatus(false);
|
|
6377
|
-
var
|
|
6704
|
+
var enabledChanged=(!!prevSharingEnabled)!==(!!sharingEnabled);
|
|
6705
|
+
var roleChanged=prevRole!==_sharingRole;
|
|
6706
|
+
var needsRestart=enabledChanged||roleChanged;
|
|
6378
6707
|
if(sharingEnabled) updateHubShareInfo();
|
|
6379
6708
|
if(needsRestart){
|
|
6380
6709
|
setTimeout(function(){showRestartOverlay(t('settings.restart.waiting'));},300);
|
|
@@ -6794,23 +7123,89 @@ function renderToolAgg(data){
|
|
|
6794
7123
|
'</tbody></table>';
|
|
6795
7124
|
}
|
|
6796
7125
|
|
|
6797
|
-
/* ───
|
|
6798
|
-
var
|
|
6799
|
-
|
|
6800
|
-
|
|
6801
|
-
|
|
6802
|
-
|
|
6803
|
-
|
|
7126
|
+
/* ─── Unified live-data poller ─── */
|
|
7127
|
+
var _livePoller=null;
|
|
7128
|
+
var _LIVE_POLL_MS=15000;
|
|
7129
|
+
var _livePollBusy=false;
|
|
7130
|
+
|
|
7131
|
+
async function _livePollTick(){
|
|
7132
|
+
if(_livePollBusy||document.hidden) return;
|
|
7133
|
+
_livePollBusy=true;
|
|
7134
|
+
try{
|
|
7135
|
+
if(sharingStatusCache&&sharingStatusCache.enabled&&_lastSharingConnStatus!=='rejected') loadSharingStatus(false);
|
|
7136
|
+
if(!_notifSSEConnected) pollNotifCount();
|
|
7137
|
+
pollAdminPending();
|
|
7138
|
+
if(_activeView==='admin') loadAdminData();
|
|
7139
|
+
else if(_activeView==='memories'){
|
|
7140
|
+
var _searchVal=(document.getElementById('searchInput')||{}).value||'';
|
|
7141
|
+
if(!_searchVal.trim()){
|
|
7142
|
+
if(memorySearchScope==='hub') loadHubMemories(true);
|
|
7143
|
+
else{loadStats();loadMemories(null,true);}
|
|
7144
|
+
}
|
|
7145
|
+
}
|
|
7146
|
+
else if(_activeView==='tasks') loadTasks(true);
|
|
7147
|
+
else if(_activeView==='skills') loadSkills(true);
|
|
7148
|
+
else if(_activeView==='analytics') loadMetrics();
|
|
7149
|
+
}catch(e){}
|
|
7150
|
+
_livePollBusy=false;
|
|
6804
7151
|
}
|
|
6805
|
-
|
|
6806
|
-
|
|
7152
|
+
|
|
7153
|
+
function startLivePoller(){
|
|
7154
|
+
stopLivePoller();
|
|
7155
|
+
_livePoller=setInterval(_livePollTick,_LIVE_POLL_MS);
|
|
7156
|
+
}
|
|
7157
|
+
function stopLivePoller(){
|
|
7158
|
+
if(_livePoller){clearInterval(_livePoller);_livePoller=null;}
|
|
6807
7159
|
}
|
|
6808
7160
|
|
|
6809
|
-
|
|
7161
|
+
document.addEventListener('visibilitychange',function(){
|
|
7162
|
+
if(document.hidden){
|
|
7163
|
+
stopLivePoller();
|
|
7164
|
+
}else{
|
|
7165
|
+
_livePollTick();
|
|
7166
|
+
startLivePoller();
|
|
7167
|
+
if(!_notifSSE||!_notifSSEConnected) connectNotifSSE();
|
|
7168
|
+
}
|
|
7169
|
+
});
|
|
7170
|
+
|
|
7171
|
+
/* ─── Notifications (SSE push + fallback poll) ─── */
|
|
6810
7172
|
var _notifCache=[];
|
|
6811
7173
|
var _notifUnread=0;
|
|
6812
7174
|
var _notifPollTimer=null;
|
|
6813
7175
|
var _notifPanelOpen=false;
|
|
7176
|
+
var _notifSSE=null;
|
|
7177
|
+
var _notifSSEConnected=false;
|
|
7178
|
+
var _notifSSERetryMs=1000;
|
|
7179
|
+
|
|
7180
|
+
function connectNotifSSE(){
|
|
7181
|
+
if(_notifSSE) return;
|
|
7182
|
+
try{
|
|
7183
|
+
_notifSSE=new EventSource('/api/notifications/stream');
|
|
7184
|
+
_notifSSE.onmessage=function(ev){
|
|
7185
|
+
try{
|
|
7186
|
+
var d=JSON.parse(ev.data);
|
|
7187
|
+
if(d.type==='connected'){_notifSSEConnected=true;_notifSSERetryMs=1000;return;}
|
|
7188
|
+
if(d.type==='update'){
|
|
7189
|
+
var prev=_notifUnread;
|
|
7190
|
+
_notifUnread=d.unreadCount||0;
|
|
7191
|
+
renderNotifBadge();
|
|
7192
|
+
if(_notifUnread>prev&&_notifPanelOpen) loadNotifications();
|
|
7193
|
+
}
|
|
7194
|
+
if(d.type==='cleared'){
|
|
7195
|
+
_notifUnread=0;_notifCache=[];
|
|
7196
|
+
renderNotifBadge();renderNotifPanel();
|
|
7197
|
+
}
|
|
7198
|
+
}catch(e){}
|
|
7199
|
+
};
|
|
7200
|
+
_notifSSE.onerror=function(){
|
|
7201
|
+
_notifSSEConnected=false;
|
|
7202
|
+
if(_notifSSE){_notifSSE.close();_notifSSE=null;}
|
|
7203
|
+
setTimeout(connectNotifSSE,Math.min(_notifSSERetryMs,30000));
|
|
7204
|
+
_notifSSERetryMs=Math.min(_notifSSERetryMs*2,30000);
|
|
7205
|
+
};
|
|
7206
|
+
}catch(e){}
|
|
7207
|
+
}
|
|
7208
|
+
connectNotifSSE();
|
|
6814
7209
|
|
|
6815
7210
|
function toggleNotifPanel(e){
|
|
6816
7211
|
if(e)e.stopPropagation();
|
|
@@ -6841,7 +7236,10 @@ function notifTimeAgo(ts){
|
|
|
6841
7236
|
return t('notif.timeAgo.day').replace('{n}',Math.floor(diff/86400000));
|
|
6842
7237
|
}
|
|
6843
7238
|
|
|
6844
|
-
function notifIcon(resource){
|
|
7239
|
+
function notifIcon(resource,type){
|
|
7240
|
+
if(type==='user_online') return '\\u{1F7E2}';
|
|
7241
|
+
if(type==='user_offline') return '\\u{1F534}';
|
|
7242
|
+
if(type==='user_join_request') return '\\u{1F464}';
|
|
6845
7243
|
if(resource==='memory') return '\\u{1F4DD}';
|
|
6846
7244
|
if(resource==='task') return '\\u{1F4CB}';
|
|
6847
7245
|
if(resource==='skill') return '\\u{1F9E0}';
|
|
@@ -6852,6 +7250,21 @@ function notifTypeText(n){
|
|
|
6852
7250
|
if(n.type==='resource_removed'){
|
|
6853
7251
|
return t('notif.removed.'+n.resource)||t('notif.removed.memory');
|
|
6854
7252
|
}
|
|
7253
|
+
if(n.type==='resource_shared'){
|
|
7254
|
+
return t('notif.shared.'+n.resource)||t('notif.shared.memory');
|
|
7255
|
+
}
|
|
7256
|
+
if(n.type==='resource_unshared'){
|
|
7257
|
+
return t('notif.unshared.'+n.resource)||t('notif.unshared.memory');
|
|
7258
|
+
}
|
|
7259
|
+
if(n.type==='user_join_request'){
|
|
7260
|
+
return t('notif.userJoin');
|
|
7261
|
+
}
|
|
7262
|
+
if(n.type==='user_online'){
|
|
7263
|
+
return t('notif.userOnline');
|
|
7264
|
+
}
|
|
7265
|
+
if(n.type==='user_offline'){
|
|
7266
|
+
return t('notif.userOffline');
|
|
7267
|
+
}
|
|
6855
7268
|
return n.message||n.type;
|
|
6856
7269
|
}
|
|
6857
7270
|
|
|
@@ -6896,7 +7309,7 @@ function renderNotifPanel(){
|
|
|
6896
7309
|
body.innerHTML=_notifCache.map(function(n){
|
|
6897
7310
|
var cls='notif-item'+(n.read?'':' unread');
|
|
6898
7311
|
return '<div class="'+cls+'" onclick="markNotifRead("'+esc(n.id)+'")">'+
|
|
6899
|
-
'<div class="notif-item-icon">'+notifIcon(n.resource)+'</div>'+
|
|
7312
|
+
'<div class="notif-item-icon">'+notifIcon(n.resource,n.type)+'</div>'+
|
|
6900
7313
|
'<div class="notif-item-body">'+
|
|
6901
7314
|
'<div class="notif-item-title">'+esc(notifTypeText(n))+'</div>'+
|
|
6902
7315
|
'<div class="notif-item-name">'+esc(n.title)+'</div>'+
|
|
@@ -6937,24 +7350,20 @@ async function clearAllNotifs(){
|
|
|
6937
7350
|
}catch(e){}
|
|
6938
7351
|
}
|
|
6939
7352
|
|
|
6940
|
-
function startNotifPoll(){
|
|
6941
|
-
|
|
6942
|
-
pollNotifCount();
|
|
6943
|
-
_notifPollTimer=setInterval(pollNotifCount,15000);
|
|
6944
|
-
}
|
|
6945
|
-
|
|
6946
|
-
function stopNotifPoll(){
|
|
6947
|
-
if(_notifPollTimer){clearInterval(_notifPollTimer);_notifPollTimer=null;}
|
|
6948
|
-
}
|
|
7353
|
+
function startNotifPoll(){ startLivePoller(); }
|
|
7354
|
+
function stopNotifPoll(){ }
|
|
6949
7355
|
|
|
6950
7356
|
/* ─── Data loading ─── */
|
|
6951
7357
|
async function loadAll(){
|
|
6952
|
-
await
|
|
7358
|
+
await loadStats();
|
|
7359
|
+
var initOwner=memorySearchScope==='local'?_currentAgentOwner:undefined;
|
|
7360
|
+
if(initOwner) await loadStats(initOwner);
|
|
7361
|
+
await Promise.all([loadMemories(),loadSharingStatus(false)]);
|
|
6953
7362
|
checkMigrateStatus();
|
|
6954
7363
|
connectPPSSE();
|
|
6955
7364
|
checkForUpdate();
|
|
6956
|
-
|
|
6957
|
-
|
|
7365
|
+
pollNotifCount();
|
|
7366
|
+
startLivePoller();
|
|
6958
7367
|
}
|
|
6959
7368
|
|
|
6960
7369
|
async function loadStats(ownerFilter){
|
|
@@ -6966,6 +7375,7 @@ async function loadStats(ownerFilter){
|
|
|
6966
7375
|
d=await r.json();
|
|
6967
7376
|
}catch(e){ d={}; }
|
|
6968
7377
|
if(!d||typeof d!=='object') d={};
|
|
7378
|
+
if(d.currentAgentOwner) _currentAgentOwner=d.currentAgentOwner;
|
|
6969
7379
|
const tm=d.totalMemories||0;
|
|
6970
7380
|
const dedupB=d.dedupBreakdown||{};
|
|
6971
7381
|
const activeCount=dedupB.active||tm;
|
|
@@ -7032,11 +7442,14 @@ async function loadStats(ownerFilter){
|
|
|
7032
7442
|
const ownerSel=document.getElementById('filterOwner');
|
|
7033
7443
|
if(ownerSel && d.owners && d.owners.length>0){
|
|
7034
7444
|
const curVal=ownerSel.value;
|
|
7035
|
-
|
|
7036
|
-
|
|
7037
|
-
|
|
7445
|
+
var agents=d.owners.filter(function(o){return o && o.indexOf('agent:')===0;});
|
|
7446
|
+
ownerSel.innerHTML='<option value="">'+t('filter.allagents')+'</option>';
|
|
7447
|
+
agents.forEach(function(o){
|
|
7448
|
+
var label=o.replace('agent:','');
|
|
7449
|
+
ownerSel.innerHTML+='<option value="'+o+'"'+(o===curVal?' selected':'')+'>'+label+'</option>';
|
|
7038
7450
|
});
|
|
7039
|
-
ownerSel.
|
|
7451
|
+
if(agents.length<=1) ownerSel.style.display='none';
|
|
7452
|
+
else ownerSel.style.display='';
|
|
7040
7453
|
}
|
|
7041
7454
|
}
|
|
7042
7455
|
|
|
@@ -7076,59 +7489,92 @@ function getFilterParams(){
|
|
|
7076
7489
|
if(dt) p.set('dateTo',dt);
|
|
7077
7490
|
const sort=document.getElementById('filterSort').value;
|
|
7078
7491
|
if(sort==='oldest') p.set('sort','oldest');
|
|
7079
|
-
const
|
|
7080
|
-
if(
|
|
7492
|
+
const scope=memorySearchScope||'local';
|
|
7493
|
+
if(scope==='local'){
|
|
7494
|
+
p.set('owner',_currentAgentOwner);
|
|
7495
|
+
}else{
|
|
7496
|
+
const owner=document.getElementById('filterOwner').value;
|
|
7497
|
+
if(owner) p.set('owner',owner);
|
|
7498
|
+
}
|
|
7081
7499
|
return p;
|
|
7082
7500
|
}
|
|
7083
7501
|
|
|
7084
|
-
async function loadMemories(page){
|
|
7502
|
+
async function loadMemories(page,silent){
|
|
7085
7503
|
if(page) currentPage=page;
|
|
7086
7504
|
const list=document.getElementById('memoryList');
|
|
7087
|
-
list.innerHTML='<div class="spinner"></div>';
|
|
7505
|
+
if(!silent) list.innerHTML='<div class="spinner"></div>';
|
|
7088
7506
|
try{
|
|
7089
7507
|
const p=getFilterParams();
|
|
7090
7508
|
p.set('limit',PAGE_SIZE);
|
|
7091
7509
|
p.set('page',currentPage);
|
|
7092
7510
|
const r=await fetch('/api/memories?'+p.toString());
|
|
7093
7511
|
const d=await r.json();
|
|
7512
|
+
var items=d.memories||[];
|
|
7513
|
+
if(silent){
|
|
7514
|
+
var fp=JSON.stringify(items.map(function(m){return m.id+'|'+m.updated_at}));
|
|
7515
|
+
if(fp===_lastMemoriesFingerprint) return;
|
|
7516
|
+
_lastMemoriesFingerprint=fp;
|
|
7517
|
+
}else{
|
|
7518
|
+
_lastMemoriesFingerprint=JSON.stringify(items.map(function(m){return m.id+'|'+m.updated_at}));
|
|
7519
|
+
}
|
|
7094
7520
|
totalPages=d.totalPages||1;
|
|
7095
7521
|
totalCount=d.total||0;
|
|
7096
7522
|
document.getElementById('searchMeta').textContent=totalCount+t('search.meta.total');
|
|
7097
|
-
renderMemories(
|
|
7523
|
+
renderMemories(items);
|
|
7098
7524
|
renderPagination();
|
|
7099
7525
|
}catch(e){
|
|
7100
|
-
|
|
7101
|
-
|
|
7102
|
-
|
|
7103
|
-
|
|
7526
|
+
if(!silent){
|
|
7527
|
+
list.innerHTML='';
|
|
7528
|
+
totalPages=1;totalCount=0;
|
|
7529
|
+
_lastMemoriesFingerprint='';
|
|
7530
|
+
renderMemories([]);
|
|
7531
|
+
renderPagination();
|
|
7532
|
+
}
|
|
7104
7533
|
}
|
|
7105
7534
|
}
|
|
7106
7535
|
|
|
7107
|
-
async function loadHubMemories(){
|
|
7536
|
+
async function loadHubMemories(silent){
|
|
7108
7537
|
const list=document.getElementById('memoryList');
|
|
7109
|
-
list.innerHTML='<div class="spinner"></div>';
|
|
7538
|
+
if(!silent) list.innerHTML='<div class="spinner"></div>';
|
|
7110
7539
|
try{
|
|
7111
7540
|
const r=await fetch('/api/sharing/memories/list?limit='+PAGE_SIZE);
|
|
7112
7541
|
const d=await r.json();
|
|
7113
7542
|
const items=d.memories||[];
|
|
7543
|
+
if(silent){
|
|
7544
|
+
var fp=JSON.stringify(items.map(function(m){return m.id+'|'+(m.updated_at||m.created_at)}));
|
|
7545
|
+
if(fp===_lastMemoriesFingerprint) return;
|
|
7546
|
+
_lastMemoriesFingerprint=fp;
|
|
7547
|
+
}else{
|
|
7548
|
+
_lastMemoriesFingerprint=JSON.stringify(items.map(function(m){return m.id+'|'+(m.updated_at||m.created_at)}));
|
|
7549
|
+
}
|
|
7550
|
+
totalPages=1;totalCount=items.length;currentPage=1;
|
|
7114
7551
|
document.getElementById('searchMeta').textContent=items.length+t('search.meta.total');
|
|
7115
7552
|
document.getElementById('sharingSearchMeta').textContent='';
|
|
7116
7553
|
renderMemories(items);
|
|
7117
7554
|
document.getElementById('pagination').innerHTML='';
|
|
7118
7555
|
}catch(e){
|
|
7119
|
-
|
|
7120
|
-
|
|
7121
|
-
|
|
7556
|
+
if(!silent){
|
|
7557
|
+
_lastMemoriesFingerprint='';
|
|
7558
|
+
document.getElementById('searchMeta').textContent='0'+t('search.meta.results');
|
|
7559
|
+
renderMemories([]);
|
|
7560
|
+
document.getElementById('pagination').innerHTML='';
|
|
7561
|
+
}
|
|
7122
7562
|
}
|
|
7123
7563
|
}
|
|
7124
7564
|
|
|
7125
7565
|
async function doSearch(query){
|
|
7126
7566
|
query=(query||'').trim();
|
|
7127
|
-
if(!query){
|
|
7567
|
+
if(!query){
|
|
7568
|
+
currentPage=1;
|
|
7569
|
+
if(memorySearchScope==='hub') loadHubMemories();
|
|
7570
|
+
else loadMemories();
|
|
7571
|
+
return;
|
|
7572
|
+
}
|
|
7573
|
+
currentPage=1;
|
|
7128
7574
|
var scope=document.getElementById('memorySearchScope')?.value||memorySearchScope||'local';
|
|
7129
7575
|
var list=document.getElementById('memoryList');
|
|
7130
7576
|
list.innerHTML='<div class="spinner"></div>';
|
|
7131
|
-
if(scope
|
|
7577
|
+
if(scope==='hub'){
|
|
7132
7578
|
try{
|
|
7133
7579
|
var r=await fetch('/api/sharing/search/memories',{
|
|
7134
7580
|
method:'POST',
|
|
@@ -7136,6 +7582,7 @@ async function doSearch(query){
|
|
|
7136
7582
|
body:JSON.stringify({query:query,scope:scope,maxResults:20,role:activeRole||undefined})
|
|
7137
7583
|
});
|
|
7138
7584
|
var data=await r.json();
|
|
7585
|
+
totalPages=1;totalCount=(data.results||[]).length;
|
|
7139
7586
|
renderSharingMemorySearchResults(data,query);
|
|
7140
7587
|
}catch(e){
|
|
7141
7588
|
document.getElementById('searchMeta').textContent='0'+t('search.meta.results');
|
|
@@ -7150,6 +7597,7 @@ async function doSearch(query){
|
|
|
7150
7597
|
var r=await fetch('/api/search?'+p.toString());
|
|
7151
7598
|
var d=await r.json();
|
|
7152
7599
|
var total=d.total||0;
|
|
7600
|
+
totalPages=1;totalCount=total;
|
|
7153
7601
|
var meta=[];
|
|
7154
7602
|
if(d.vectorCount>0) meta.push(d.vectorCount+t('search.meta.semantic'));
|
|
7155
7603
|
if(d.ftsCount>0) meta.push(d.ftsCount+t('search.meta.text'));
|
|
@@ -7238,7 +7686,8 @@ function renderMemories(items){
|
|
|
7238
7686
|
const isPublicMem=ownerVal==='public';
|
|
7239
7687
|
const localManaged=!!m.localSharingManaged;
|
|
7240
7688
|
const memShared=m.sharingVisibility||null;
|
|
7241
|
-
const
|
|
7689
|
+
const isHubScope=memorySearchScope==='hub';
|
|
7690
|
+
const memScope=isHubScope?'team':memShared?'team':isPublicMem?'local':'private';
|
|
7242
7691
|
const memScopeBadge=renderScopeBadge(memScope);
|
|
7243
7692
|
let dedupInfo='';
|
|
7244
7693
|
if(ds==='duplicate'||ds==='merged'){
|
|
@@ -7343,7 +7792,8 @@ function renderPagination(){
|
|
|
7343
7792
|
function goPage(p){
|
|
7344
7793
|
if(p<1||p>totalPages||p===currentPage) return;
|
|
7345
7794
|
currentPage=p;
|
|
7346
|
-
|
|
7795
|
+
if(memorySearchScope==='hub') loadHubMemories();
|
|
7796
|
+
else loadMemories();
|
|
7347
7797
|
document.getElementById('memoryList').scrollIntoView({behavior:'smooth',block:'start'});
|
|
7348
7798
|
}
|
|
7349
7799
|
|
|
@@ -8226,7 +8676,7 @@ async function checkForUpdate(){
|
|
|
8226
8676
|
const pkgSpec=d.installCommand?d.installCommand.replace(/^(?:npx\s+)?openclaw\s+plugins\s+install\s+/,''):(d.packageName+'@'+d.latest);
|
|
8227
8677
|
var banner=document.createElement('div');
|
|
8228
8678
|
banner.id='updateBanner';
|
|
8229
|
-
banner.style.cssText='display:flex;align-items:center;gap:12px;padding:10px max
|
|
8679
|
+
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)';
|
|
8230
8680
|
var textNode=document.createElement('div');
|
|
8231
8681
|
textNode.style.cssText='display:flex;align-items:center;gap:8px;flex-shrink:0;font-size:13px';
|
|
8232
8682
|
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>';
|
|
@@ -8259,7 +8709,7 @@ async function checkForUpdate(){
|
|
|
8259
8709
|
|
|
8260
8710
|
/* ─── Init ─── */
|
|
8261
8711
|
document.getElementById('modalOverlay').addEventListener('click',e=>{if(e.target.id==='modalOverlay')closeModal()});
|
|
8262
|
-
document.getElementById('searchInput').addEventListener('keydown',e=>{if(e.key==='Escape'){e.target.value='';loadMemories()}});
|
|
8712
|
+
document.getElementById('searchInput').addEventListener('keydown',e=>{if(e.key==='Escape'){e.target.value='';currentPage=1;if(memorySearchScope==='hub')loadHubMemories();else loadMemories();}});
|
|
8263
8713
|
applyI18n();
|
|
8264
8714
|
checkAuth();
|
|
8265
8715
|
</script>
|