@memtensor/memos-local-openclaw-plugin 1.0.4-beta.8 → 1.0.4
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/.env.example +7 -0
- package/README.md +94 -27
- package/dist/capture/index.js +3 -1
- package/dist/capture/index.js.map +1 -1
- package/dist/client/connector.d.ts +5 -0
- package/dist/client/connector.d.ts.map +1 -1
- package/dist/client/connector.js +132 -10
- package/dist/client/connector.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +2 -1
- package/dist/config.js.map +1 -1
- package/dist/hub/server.d.ts +2 -0
- package/dist/hub/server.d.ts.map +1 -1
- package/dist/hub/server.js +251 -38
- package/dist/hub/server.js.map +1 -1
- package/dist/hub/user-manager.d.ts +9 -0
- package/dist/hub/user-manager.d.ts.map +1 -1
- package/dist/hub/user-manager.js +26 -2
- package/dist/hub/user-manager.js.map +1 -1
- package/dist/ingest/chunker.d.ts +2 -1
- package/dist/ingest/chunker.d.ts.map +1 -1
- package/dist/ingest/chunker.js +14 -10
- package/dist/ingest/chunker.js.map +1 -1
- package/dist/ingest/providers/index.js +2 -2
- package/dist/ingest/providers/index.js.map +1 -1
- package/dist/recall/engine.d.ts.map +1 -1
- package/dist/recall/engine.js +96 -1
- package/dist/recall/engine.js.map +1 -1
- package/dist/shared/llm-call.d.ts.map +1 -1
- package/dist/shared/llm-call.js +2 -1
- package/dist/shared/llm-call.js.map +1 -1
- package/dist/sharing/types.d.ts +1 -1
- package/dist/sharing/types.d.ts.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 +56 -5
- package/dist/skill/evolver.js.map +1 -1
- package/dist/skill/generator.d.ts +2 -0
- package/dist/skill/generator.d.ts.map +1 -1
- package/dist/skill/generator.js +45 -3
- package/dist/skill/generator.js.map +1 -1
- package/dist/skill/installer.d.ts +26 -0
- package/dist/skill/installer.d.ts.map +1 -1
- package/dist/skill/installer.js +80 -4
- package/dist/skill/installer.js.map +1 -1
- package/dist/skill/upgrader.d.ts +2 -0
- package/dist/skill/upgrader.d.ts.map +1 -1
- package/dist/skill/upgrader.js +139 -1
- package/dist/skill/upgrader.js.map +1 -1
- package/dist/skill/validator.d.ts +3 -0
- package/dist/skill/validator.d.ts.map +1 -1
- package/dist/skill/validator.js +75 -0
- package/dist/skill/validator.js.map +1 -1
- package/dist/storage/sqlite.d.ts +58 -0
- package/dist/storage/sqlite.d.ts.map +1 -1
- package/dist/storage/sqlite.js +295 -35
- package/dist/storage/sqlite.js.map +1 -1
- package/dist/telemetry.d.ts.map +1 -1
- package/dist/telemetry.js +27 -8
- package/dist/telemetry.js.map +1 -1
- package/dist/types.d.ts +10 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js +4 -0
- package/dist/types.js.map +1 -1
- package/dist/viewer/html.d.ts.map +1 -1
- package/dist/viewer/html.js +796 -289
- package/dist/viewer/html.js.map +1 -1
- package/dist/viewer/server.d.ts +11 -0
- package/dist/viewer/server.d.ts.map +1 -1
- package/dist/viewer/server.js +456 -92
- package/dist/viewer/server.js.map +1 -1
- package/index.ts +411 -52
- package/openclaw.plugin.json +1 -1
- package/package.json +2 -1
- package/prebuilds/darwin-arm64/better_sqlite3.node +0 -0
- package/prebuilds/darwin-x64/better_sqlite3.node +0 -0
- package/prebuilds/linux-x64/better_sqlite3.node +0 -0
- package/prebuilds/win32-x64/better_sqlite3.node +0 -0
- package/src/capture/index.ts +4 -1
- package/src/client/connector.ts +136 -10
- package/src/config.ts +2 -1
- package/src/hub/server.ts +246 -38
- package/src/hub/user-manager.ts +42 -6
- package/src/ingest/chunker.ts +19 -13
- package/src/ingest/providers/index.ts +2 -2
- package/src/recall/engine.ts +89 -1
- package/src/shared/llm-call.ts +2 -1
- package/src/sharing/types.ts +1 -1
- package/src/skill/evolver.ts +58 -6
- package/src/skill/generator.ts +44 -5
- package/src/skill/installer.ts +107 -4
- package/src/skill/upgrader.ts +139 -1
- package/src/skill/validator.ts +79 -0
- package/src/storage/sqlite.ts +326 -40
- package/src/telemetry.ts +27 -9
- package/src/types.ts +11 -0
- package/src/viewer/html.ts +796 -289
- package/src/viewer/server.ts +430 -89
- package/telemetry.credentials.json +5 -0
package/dist/viewer/html.js
CHANGED
|
@@ -157,7 +157,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
157
157
|
.search-bar input::placeholder{color:var(--text-muted)}
|
|
158
158
|
.search-bar input:focus{border-color:var(--pri);box-shadow:0 0 0 3px var(--pri-glow)}
|
|
159
159
|
.search-bar .search-icon{position:absolute;left:14px;top:50%;transform:translateY(-50%);color:var(--text-muted);font-size:14px;pointer-events:none}
|
|
160
|
-
.search-meta{font-size:12px;color:var(--text-sec);
|
|
160
|
+
.search-meta{font-size:12px;color:var(--text-sec);padding:0 2px}.search-meta:not(:empty){margin-bottom:14px}
|
|
161
161
|
.scope-select{padding:10px 12px;border:1px solid var(--border);border-radius:10px;background:var(--bg-card);color:var(--text);font-size:13px;min-width:110px;outline:none}
|
|
162
162
|
.sharing-inline-meta{font-size:12px;color:var(--text-muted);margin:-8px 0 14px 2px}
|
|
163
163
|
.sharing-sidebar-card{margin:14px 0 18px;border:1px solid var(--border);background:var(--bg-card);border-radius:12px;padding:12px;box-shadow:var(--shadow-sm)}
|
|
@@ -197,65 +197,92 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
197
197
|
.pending-user-name{font-size:14px;font-weight:700;color:var(--text)}
|
|
198
198
|
.pending-user-meta{font-size:12px;color:var(--text-sec);margin-top:4px}
|
|
199
199
|
.pending-user-actions{display:flex;gap:8px;margin-top:10px}
|
|
200
|
-
/* ─── Admin Panel ─── */
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
.admin-
|
|
209
|
-
.admin-
|
|
210
|
-
.admin-
|
|
211
|
-
.admin-
|
|
212
|
-
.admin-
|
|
213
|
-
.admin-
|
|
214
|
-
.admin-
|
|
215
|
-
.admin-stat-
|
|
216
|
-
.admin-stat-box:
|
|
217
|
-
.admin-stat-box
|
|
218
|
-
.admin-stat-box
|
|
219
|
-
.admin-stat-box
|
|
220
|
-
.admin-
|
|
221
|
-
.admin-
|
|
222
|
-
.admin-
|
|
223
|
-
.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)}
|
|
224
233
|
.admin-tab .at-icon{font-size:14px;line-height:1}
|
|
225
|
-
.admin-tab .at-count{font-size:10px;font-weight:700;padding:
|
|
226
|
-
.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)}
|
|
227
236
|
.admin-panel{display:none}
|
|
228
|
-
.admin-panel.active{display:block}
|
|
229
|
-
.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}
|
|
230
239
|
.admin-card-clickable{cursor:pointer}
|
|
231
|
-
.admin-card::before{content:'';position:absolute;top:0;left:0;bottom:0;width:3px;border-radius:3px 0 0 3px;background:var(--pri);opacity:.
|
|
232
|
-
.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}
|
|
233
243
|
.admin-card-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:6px}
|
|
234
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}
|
|
235
245
|
.admin-card-meta{font-size:12px;color:var(--text-muted);line-height:1.5}
|
|
236
|
-
.au-contrib{display:flex;gap:
|
|
237
|
-
.au-contrib-item{font-size:12px;color:var(--text-sec);display:flex;align-items:center;gap:
|
|
238
|
-
.au-contrib-num{font-size:
|
|
239
|
-
.au-info{display:flex;flex-wrap:wrap;gap:6px
|
|
240
|
-
.au-info-item{color:var(--text-muted);white-space:nowrap}
|
|
241
|
-
.au-status-dot{display:inline-block;width:8px;height:8px;border-radius:50%;margin-right:
|
|
242
|
-
.au-status-dot.online{background:#22c55e;box-shadow:0 0
|
|
243
|
-
.au-status-dot.offline{background:#
|
|
244
|
-
.au-status-text{font-size:
|
|
245
|
-
.au-status-text.online{color:#22c55e}
|
|
246
|
-
.au-status-text.offline{color:#
|
|
247
|
-
.au-
|
|
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:10px;font-weight:600;letter-spacing:.04em;padding:3px 10px;border-radius:6px;white-space:nowrap}
|
|
255
|
+
.au-status-text.online{color:#22c55e;background:rgba(34,197,94,.08);border:1px solid rgba(34,197,94,.18);text-shadow:0 0 8px rgba(34,197,94,.2)}
|
|
256
|
+
.au-status-text.offline{color:#6b7280;background:rgba(107,114,128,.06);border:1px solid rgba(107,114,128,.1)}
|
|
257
|
+
[data-theme="light"] .au-status-text.online{background:rgba(34,197,94,.06);border-color:rgba(34,197,94,.15)}
|
|
258
|
+
[data-theme="light"] .au-status-text.offline{background:rgba(0,0,0,.03);border-color:rgba(0,0,0,.06)}
|
|
259
|
+
.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}
|
|
248
260
|
.au-group-header:first-child{margin-top:0}
|
|
249
261
|
.au-group-header .au-group-dot{display:inline-block;width:8px;height:8px;border-radius:50%}
|
|
250
|
-
.au-group-header .au-group-dot.online{background:#22c55e}
|
|
251
|
-
.au-group-header .au-group-dot.offline{background:#
|
|
262
|
+
.au-group-header .au-group-dot.online{background:#22c55e;box-shadow:0 0 6px rgba(34,197,94,.5)}
|
|
263
|
+
.au-group-header .au-group-dot.offline{background:#6b7280}
|
|
252
264
|
.au-group-header .au-group-count{font-size:12px;font-weight:400;color:var(--text-muted)}
|
|
253
|
-
.au-card.au-offline{opacity:.
|
|
254
|
-
.au-card.au-offline
|
|
255
|
-
.au-card.au-
|
|
265
|
+
.au-card.au-offline{opacity:.55}
|
|
266
|
+
.au-card.au-offline:hover{opacity:.8}
|
|
267
|
+
.au-card.au-offline::before{background:#6b7280}
|
|
268
|
+
.au-card.au-online::before{background:#22c55e;box-shadow:0 0 8px rgba(34,197,94,.3)}
|
|
269
|
+
.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}
|
|
270
|
+
.admin-pending-section::before{content:'';position:absolute;top:0;left:0;right:0;height:2px;background:linear-gradient(90deg,transparent,#fbbf24,#f59e0b,transparent)}
|
|
271
|
+
.admin-pending-section h3{font-size:14px;font-weight:700;color:#fbbf24;margin:0 0 14px;display:flex;align-items:center;gap:8px}
|
|
272
|
+
.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}
|
|
273
|
+
.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}
|
|
274
|
+
.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}
|
|
275
|
+
.admin-pending-card:hover{border-color:rgba(251,191,36,.35);box-shadow:0 4px 16px rgba(251,191,36,.08)}
|
|
276
|
+
.admin-pending-card .apc-name{font-size:14px;font-weight:700;color:var(--text)}
|
|
277
|
+
.admin-pending-card .apc-meta{font-size:11px;color:var(--text-muted);margin-top:4px;display:flex;align-items:center;gap:6px}
|
|
278
|
+
.admin-pending-card .apc-actions{display:flex;gap:8px;margin-top:12px}
|
|
279
|
+
.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)}
|
|
280
|
+
.admin-pending-card .apc-actions .btn-approve:hover{transform:translateY(-1px);box-shadow:0 4px 16px rgba(34,197,94,.35)}
|
|
281
|
+
.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}
|
|
282
|
+
.admin-pending-card .apc-actions .btn-reject:hover{background:rgba(244,63,94,.06);border-color:rgba(244,63,94,.4)}
|
|
256
283
|
.admin-card-tags{display:flex;gap:5px;margin:8px 0;align-items:center}
|
|
257
284
|
.admin-card-tags-left{display:flex;flex-wrap:wrap;gap:5px;align-items:center;flex:1;min-width:0}
|
|
258
|
-
.admin-card-tag{display:inline-flex;align-items:center;gap:3px;padding:
|
|
285
|
+
.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}
|
|
259
286
|
.admin-card-tag.tag-role{background:rgba(99,102,241,.1);color:var(--pri)}
|
|
260
287
|
.admin-card-tag.tag-kind{background:rgba(245,158,11,.1);color:#f59e0b}
|
|
261
288
|
.admin-card-tag.tag-owner{background:rgba(34,197,94,.1);color:#22c55e}
|
|
@@ -263,16 +290,16 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
263
290
|
.admin-card-tag.tag-version{background:rgba(139,92,246,.1);color:#8b5cf6}
|
|
264
291
|
.admin-card-tag.tag-visibility{background:rgba(99,102,241,.08);color:var(--pri)}
|
|
265
292
|
.admin-card-tag.tag-group{background:rgba(139,92,246,.08);color:#8b5cf6}
|
|
266
|
-
.admin-card-preview{font-size:12px;color:var(--text-sec);line-height:1.5;margin:8px 0;padding:
|
|
267
|
-
.admin-card-actions{display:inline-flex;gap:
|
|
293
|
+
.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:120px;overflow:hidden;white-space:pre-wrap;word-break:break-all;position:relative;-webkit-mask-image:linear-gradient(to bottom,#000 88%,transparent 100%);mask-image:linear-gradient(to bottom,#000 88%,transparent 100%)}
|
|
294
|
+
.admin-card-actions{display:inline-flex;gap:6px;margin-left:auto;align-items:center;flex-shrink:0}
|
|
268
295
|
.admin-card-time{font-size:11px;color:var(--text-muted)}
|
|
269
|
-
.admin-card-detail{display:none;margin-top:0;padding:20px 24px 24px;border-top:1px dashed
|
|
296
|
+
.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}
|
|
270
297
|
@keyframes adminDetailIn{from{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:translateY(0)}}
|
|
271
298
|
.admin-card.expanded .admin-card-detail{display:block}
|
|
272
|
-
.admin-card.expanded{border-color:rgba(99,102,241,.3);box-shadow:0 4px 24px rgba(99,102,241,.
|
|
299
|
+
.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)}
|
|
273
300
|
.admin-card-detail-meta{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:18px;font-size:12px;color:var(--text-muted)}
|
|
274
|
-
.admin-card-detail-meta .meta-item{display:inline-flex;align-items:center;gap:4px;padding:5px 12px;background:
|
|
275
|
-
.admin-card-detail-meta .meta-item:hover{border-color:rgba(99,102,241,.25);background:rgba(99,102,241,.
|
|
301
|
+
.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}
|
|
302
|
+
.admin-card-detail-meta .meta-item:hover{border-color:rgba(99,102,241,.25);background:rgba(99,102,241,.06)}
|
|
276
303
|
.admin-card-detail-section{margin-top:20px}
|
|
277
304
|
.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}
|
|
278
305
|
.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))}
|
|
@@ -298,7 +325,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
298
325
|
.adm-msg-side.assistant .adm-msg-role{color:var(--green)}
|
|
299
326
|
.adm-msg-time{font-size:9px;color:var(--text-muted)}
|
|
300
327
|
.adm-msg-body{flex:1;min-width:0;padding:12px 16px;font-size:13px;line-height:1.75;color:var(--text);white-space:pre-wrap;word-break:break-word}
|
|
301
|
-
.adm-msg-body.collapsed{max-height:120px;overflow:hidden;-webkit-mask-image:linear-gradient(180deg,#000
|
|
328
|
+
.adm-msg-body.collapsed{max-height:120px;overflow:hidden;-webkit-mask-image:linear-gradient(180deg,#000 88%,transparent);mask-image:linear-gradient(180deg,#000 88%,transparent)}
|
|
302
329
|
.adm-msg-toggle{display:none;padding:0 16px 8px;font-size:11px;color:var(--pri);cursor:pointer;transition:color .15s}
|
|
303
330
|
.adm-msg-toggle:hover{color:var(--pri-dark)}
|
|
304
331
|
.admin-card-expand-btn{font-size:12px;color:var(--pri);cursor:pointer;background:none;border:none;padding:2px 6px;font-family:inherit}
|
|
@@ -306,18 +333,24 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
306
333
|
.admin-toolbar{display:flex;align-items:center;gap:10px;margin-bottom:14px;flex-wrap:wrap}
|
|
307
334
|
.admin-toolbar h3{font-size:14px;font-weight:600;color:var(--text);white-space:nowrap;margin:0;margin-right:auto;line-height:32px}
|
|
308
335
|
.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}
|
|
309
|
-
.admin-badge{display:inline-flex;align-items:center;gap:4px;font-size:
|
|
310
|
-
.admin-badge.admin{background:rgba(
|
|
311
|
-
.admin-badge.
|
|
312
|
-
.admin-badge.
|
|
313
|
-
.admin-badge.
|
|
314
|
-
.admin-badge.
|
|
315
|
-
.admin-
|
|
316
|
-
.admin-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
[data-theme="light"] .admin-
|
|
336
|
+
.admin-badge{display:inline-flex;align-items:center;gap:4px;font-size:9px;font-weight:700;padding:3px 10px;border-radius:6px;letter-spacing:.06em;text-transform:uppercase;position:relative;backdrop-filter:blur(4px);transition:all .25s}
|
|
337
|
+
.admin-badge.admin{background:linear-gradient(135deg,rgba(34,197,94,.12),rgba(16,185,129,.06));color:#22c55e;border:1px solid rgba(34,197,94,.2);box-shadow:0 0 12px rgba(34,197,94,.08),inset 0 1px 0 rgba(255,255,255,.05)}
|
|
338
|
+
.admin-badge.admin:hover{box-shadow:0 0 20px rgba(34,197,94,.15),inset 0 1px 0 rgba(255,255,255,.08)}
|
|
339
|
+
.admin-badge.member{background:rgba(99,102,241,.06);color:var(--text-muted);border:1px solid rgba(99,102,241,.12)}
|
|
340
|
+
.admin-badge.pending{background:linear-gradient(135deg,rgba(251,191,36,.12),rgba(245,158,11,.06));color:#fbbf24;border:1px solid rgba(251,191,36,.2);box-shadow:0 0 12px rgba(251,191,36,.08)}
|
|
341
|
+
.admin-badge.public{background:rgba(99,102,241,.08);color:var(--pri);border:1px solid rgba(99,102,241,.15)}
|
|
342
|
+
.admin-badge.group{background:rgba(139,92,246,.08);color:#8b5cf6;border:1px solid rgba(139,92,246,.15)}
|
|
343
|
+
.admin-badge.owner{background:linear-gradient(135deg,rgba(251,191,36,.12),rgba(245,158,11,.08));color:#f59e0b;border:1px solid rgba(251,191,36,.25);box-shadow:0 0 12px rgba(251,191,36,.1),inset 0 1px 0 rgba(255,255,255,.06)}
|
|
344
|
+
.au-badges{display:flex;align-items:center;gap:6px;flex-shrink:0;flex-wrap:wrap;justify-content:flex-end}
|
|
345
|
+
.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)}
|
|
346
|
+
.admin-empty .ae-icon{font-size:32px;display:block;margin-bottom:10px;opacity:.4}
|
|
347
|
+
[data-theme="light"] .admin-badge.admin{background:rgba(5,150,105,.08);color:#059669;border-color:rgba(5,150,105,.18)}
|
|
348
|
+
[data-theme="light"] .admin-badge.member{background:rgba(0,0,0,.04);color:#6b7280;border-color:rgba(0,0,0,.08)}
|
|
349
|
+
[data-theme="light"] .admin-badge.pending{background:rgba(245,158,11,.08);color:#d97706;border-color:rgba(245,158,11,.18)}
|
|
350
|
+
[data-theme="light"] .admin-badge.owner{background:rgba(245,158,11,.08);color:#b45309;border-color:rgba(245,158,11,.2)}
|
|
351
|
+
[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%)}
|
|
352
|
+
[data-theme="light"] .admin-stat-box{background:rgba(255,255,255,.8)}
|
|
353
|
+
[data-theme="light"] .admin-pending-section{background:linear-gradient(135deg,rgba(251,191,36,.03),rgba(245,158,11,.015))}
|
|
321
354
|
.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}
|
|
322
355
|
.confirm-overlay.show{display:flex}
|
|
323
356
|
.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}
|
|
@@ -715,7 +748,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
715
748
|
[data-theme="light"] .nav-tabs{background:rgba(0,0,0,.05)}
|
|
716
749
|
[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)}
|
|
717
750
|
.analytics-view,.settings-view,.logs-view,.migrate-view,.admin-view{flex:1;min-width:0;flex-direction:column;gap:20px}
|
|
718
|
-
.feed-wrap,.tasks-view,.skills-view,.analytics-view,.
|
|
751
|
+
.feed-wrap,.tasks-view,.skills-view,.analytics-view,.logs-view,.migrate-view,.admin-view,.settings-view{max-width:960px}
|
|
719
752
|
|
|
720
753
|
/* ─── Logs ─── */
|
|
721
754
|
.logs-toolbar{display:flex;align-items:center;justify-content:space-between;padding:8px 0}
|
|
@@ -774,6 +807,10 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
774
807
|
.recall-score.high{background:rgba(34,197,94,.12);color:#22c55e}
|
|
775
808
|
.recall-score.mid{background:rgba(251,191,36,.12);color:#f59e0b}
|
|
776
809
|
.recall-score.low{background:rgba(248,113,113,.1);color:var(--text-muted)}
|
|
810
|
+
.recall-origin{flex-shrink:0;font-size:9px;font-weight:600;padding:1px 5px;border-radius:4px}
|
|
811
|
+
.recall-origin.local-shared{background:rgba(59,130,246,.12);color:#3b82f6}
|
|
812
|
+
.recall-origin.hub-memory{background:rgba(139,92,246,.12);color:#8b5cf6}
|
|
813
|
+
.recall-origin.hub-remote{background:rgba(139,92,246,.12);color:#8b5cf6}
|
|
777
814
|
.recall-summary-short{flex:1;color:var(--text-sec);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
778
815
|
.recall-expand-icon{flex-shrink:0;font-size:10px;color:var(--text-muted);transition:transform .15s}
|
|
779
816
|
.recall-item.expanded .recall-expand-icon{transform:rotate(90deg)}
|
|
@@ -942,8 +979,6 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
942
979
|
.team-guide-steps li::marker{color:var(--pri);font-weight:700;font-size:11px}
|
|
943
980
|
.team-guide-opt .btn-guide{font-size:11px;padding:5px 14px;border-radius:6px;font-weight:600;border:1px solid rgba(99,102,241,.25);background:rgba(99,102,241,.08);color:var(--pri);cursor:pointer;transition:background .15s,border-color .15s}
|
|
944
981
|
.team-guide-opt .btn-guide:hover{background:rgba(99,102,241,.14);border-color:var(--pri)}
|
|
945
|
-
.team-guide-dismiss{position:absolute;top:10px;right:12px;background:none;border:none;color:var(--text-muted);font-size:15px;cursor:pointer;padding:4px;line-height:1;opacity:.5;transition:opacity .15s}
|
|
946
|
-
.team-guide-dismiss:hover{opacity:1}
|
|
947
982
|
[data-theme="light"] .team-guide{background:linear-gradient(135deg,rgba(6,182,212,.03),rgba(79,70,229,.02));border-color:rgba(6,182,212,.15)}
|
|
948
983
|
[data-theme="light"] .team-guide-opt{box-shadow:0 1px 3px rgba(0,0,0,.03)}
|
|
949
984
|
[data-theme="light"] .team-guide-opt:hover{box-shadow:0 4px 16px rgba(0,0,0,.04)}
|
|
@@ -1186,7 +1221,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1186
1221
|
</div>
|
|
1187
1222
|
<button class="btn btn-ghost btn-sm" onclick="doLogout()" data-i18n="logout">Logout</button>
|
|
1188
1223
|
</div>
|
|
1189
|
-
|
|
1224
|
+
</div>
|
|
1190
1225
|
</div>
|
|
1191
1226
|
|
|
1192
1227
|
<div class="main-content">
|
|
@@ -1195,7 +1230,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1195
1230
|
<div class="stat-card pri"><div class="stat-value" id="statTotal">-</div><div class="stat-label" data-i18n="stat.memories">Memories</div></div>
|
|
1196
1231
|
<div class="stat-card green"><div class="stat-value" id="statSessions">-</div><div class="stat-label" data-i18n="stat.sessions">Sessions</div></div>
|
|
1197
1232
|
<div class="stat-card amber"><div class="stat-value" id="statEmbeddings">-</div><div class="stat-label" data-i18n="stat.embeddings">Embeddings</div></div>
|
|
1198
|
-
<div class="stat-card rose"><div class="stat-value" id="
|
|
1233
|
+
<div class="stat-card rose"><div class="stat-value" id="statAgents">-</div><div class="stat-label" data-i18n="stat.agents">Agents</div></div>
|
|
1199
1234
|
</div>
|
|
1200
1235
|
<div id="sidebarSharingSection" style="display:none">
|
|
1201
1236
|
<div class="sharing-sidebar-card">
|
|
@@ -1218,7 +1253,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1218
1253
|
<select id="filterOwner" class="filter-select" onchange="onOwnerFilterChange()">
|
|
1219
1254
|
<option value="" data-i18n="filter.allagents">All agents</option>
|
|
1220
1255
|
</select>
|
|
1221
|
-
<select id="memorySearchScope" class="filter-select" onchange="onMemoryScopeChange()">
|
|
1256
|
+
<select id="memorySearchScope" class="filter-select" onchange="onMemoryScopeChange()" style="display:none">
|
|
1222
1257
|
<option value="local" data-i18n="scope.thisAgent">This Agent</option>
|
|
1223
1258
|
<option value="allLocal" data-i18n="scope.thisDevice">This Device</option>
|
|
1224
1259
|
<option value="hub" data-i18n="scope.hub">Team</option>
|
|
@@ -1230,7 +1265,6 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1230
1265
|
<button class="filter-chip active" data-role="" onclick="setRoleFilter(this,'')" data-i18n="filter.all">All</button>
|
|
1231
1266
|
<button class="filter-chip" data-role="user" onclick="setRoleFilter(this,'user')">User</button>
|
|
1232
1267
|
<button class="filter-chip" data-role="assistant" onclick="setRoleFilter(this,'assistant')">Assistant</button>
|
|
1233
|
-
<button class="filter-chip" data-role="system" onclick="setRoleFilter(this,'system')">System</button>
|
|
1234
1268
|
<span class="filter-sep"></span>
|
|
1235
1269
|
<select id="filterSort" class="filter-select" onchange="applyFilters()">
|
|
1236
1270
|
<option value="newest" data-i18n="filter.newest">Newest first</option>
|
|
@@ -1263,7 +1297,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1263
1297
|
<button class="filter-chip" data-task-status="active" onclick="setTaskStatusFilter(this,'active')" data-i18n="tasks.status.active">Active</button>
|
|
1264
1298
|
<button class="filter-chip" data-task-status="completed" onclick="setTaskStatusFilter(this,'completed')" data-i18n="tasks.status.completed">Completed</button>
|
|
1265
1299
|
<button class="filter-chip" data-task-status="skipped" onclick="setTaskStatusFilter(this,'skipped')" data-i18n="tasks.status.skipped">Skipped</button>
|
|
1266
|
-
<select id="taskSearchScope" class="scope-select" onchange="onTaskScopeChange()">
|
|
1300
|
+
<select id="taskSearchScope" class="scope-select" onchange="onTaskScopeChange()" style="display:none">
|
|
1267
1301
|
<option value="local" data-i18n="scope.thisAgent">This Agent</option>
|
|
1268
1302
|
<option value="allLocal" data-i18n="scope.thisDevice">This Device</option>
|
|
1269
1303
|
<option value="hub" data-i18n="scope.hub">Team</option>
|
|
@@ -1305,13 +1339,13 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1305
1339
|
<div class="search-bar">
|
|
1306
1340
|
<span class="search-icon">🔍</span>
|
|
1307
1341
|
<input type="text" id="skillSearchInput" placeholder="Search skills..." data-i18n-ph="skills.search.placeholder" oninput="debounceSkillSearch()">
|
|
1308
|
-
<select id="skillSearchScope" class="scope-select" onchange="onSkillScopeChange()">
|
|
1342
|
+
<select id="skillSearchScope" class="scope-select" onchange="onSkillScopeChange()" style="display:none">
|
|
1309
1343
|
<option value="local" data-i18n="scope.thisAgent">This Agent</option>
|
|
1310
1344
|
<option value="allLocal" data-i18n="scope.thisDevice">This Device</option>
|
|
1311
1345
|
<option value="hub" data-i18n="scope.hub">Team</option>
|
|
1312
1346
|
</select>
|
|
1313
1347
|
</div>
|
|
1314
|
-
<div class="search-meta" id="skillSearchMeta"></div>
|
|
1348
|
+
<div class="search-meta" id="skillSearchMeta" style="display:none"></div>
|
|
1315
1349
|
<div class="tasks-header">
|
|
1316
1350
|
<div class="tasks-stats">
|
|
1317
1351
|
<div class="tasks-stat"><span class="tasks-stat-value" id="skillsTotalCount">-</span><span class="tasks-stat-label" data-i18n="skills.total">Total Skills</span></div>
|
|
@@ -1325,8 +1359,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1325
1359
|
<button class="filter-chip" data-skill-status="active" onclick="setSkillStatusFilter(this,'active')" data-i18n="skills.filter.active">Active</button>
|
|
1326
1360
|
<button class="filter-chip" data-skill-status="draft" onclick="setSkillStatusFilter(this,'draft')" data-i18n="skills.filter.draft">Draft</button>
|
|
1327
1361
|
<button class="filter-chip" data-skill-status="archived" onclick="setSkillStatusFilter(this,'archived')" data-i18n="skills.filter.archived">Archived</button>
|
|
1328
|
-
<
|
|
1329
|
-
<select id="skillVisibilityFilter" class="filter-select" onchange="loadSkills()">
|
|
1362
|
+
<select id="skillVisibilityFilter" class="filter-select" onchange="loadSkills()" style="display:none">
|
|
1330
1363
|
<option value="" data-i18n="filter.allvisibility">All visibility</option>
|
|
1331
1364
|
<option value="public" data-i18n="filter.public">Public</option>
|
|
1332
1365
|
<option value="private" data-i18n="filter.private">Private</option>
|
|
@@ -1413,7 +1446,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1413
1446
|
<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">
|
|
1414
1447
|
<option value="" data-i18n="logs.allTools">All Tools</option>
|
|
1415
1448
|
</select>
|
|
1416
|
-
|
|
1449
|
+
|
|
1417
1450
|
</div>
|
|
1418
1451
|
<div class="logs-toolbar-right">
|
|
1419
1452
|
<input type="checkbox" id="logAutoRefresh" style="display:none">
|
|
@@ -1609,9 +1642,8 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1609
1642
|
</div>
|
|
1610
1643
|
</div>
|
|
1611
1644
|
<div class="settings-card-body">
|
|
1612
|
-
<!-- team setup guide (inside Hub card) -->
|
|
1645
|
+
<!-- team setup guide (inside Hub card) — always visible when sharing is not configured -->
|
|
1613
1646
|
<div class="team-guide" id="teamSetupGuide">
|
|
1614
|
-
<button class="team-guide-dismiss" onclick="dismissTeamGuide()" title="Dismiss">×</button>
|
|
1615
1647
|
<div class="team-guide-title">\u{1F680} <span data-i18n="guide.title">Get Started with Team Collaboration</span></div>
|
|
1616
1648
|
<div class="team-guide-subtitle" data-i18n="guide.subtitle">MemOS supports team memory sharing. Choose one of the following options to enable collaboration, or continue using local-only mode.</div>
|
|
1617
1649
|
<div class="team-guide-options">
|
|
@@ -1625,7 +1657,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1625
1657
|
<li><span data-i18n="guide.join.s1">Ask your team admin for the Server Address and Team Token</span></li>
|
|
1626
1658
|
<li><span data-i18n="guide.join.s2">Enable sharing above, select "Client" mode</span></li>
|
|
1627
1659
|
<li><span data-i18n="guide.join.s3">Fill in Server Address and Team Token, click "Test Connection"</span></li>
|
|
1628
|
-
<li><span data-i18n="guide.join.s4">Save
|
|
1660
|
+
<li><span data-i18n="guide.join.s4">Click "Save & Apply" — the service restarts automatically (page refreshes)</span></li>
|
|
1629
1661
|
</ol>
|
|
1630
1662
|
<button class="btn-guide" onclick="guideGoToHub('client')" data-i18n="guide.join.btn">\u2192 Configure Client Mode</button>
|
|
1631
1663
|
</div>
|
|
@@ -1637,7 +1669,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1637
1669
|
<div class="team-guide-opt-desc" data-i18n="guide.hub.desc">Be the team server. Run it on this device so others can connect and share memories with you.</div>
|
|
1638
1670
|
<ol class="team-guide-steps">
|
|
1639
1671
|
<li><span data-i18n="guide.hub.s1">Enable sharing above, select "Server" mode</span></li>
|
|
1640
|
-
<li><span data-i18n="guide.hub.s2">Set a team name,
|
|
1672
|
+
<li><span data-i18n="guide.hub.s2">Set a team name, click "Save & Apply" — the service restarts automatically</span></li>
|
|
1641
1673
|
<li><span data-i18n="guide.hub.s3">Share the Server Address and Team Token with your team members</span></li>
|
|
1642
1674
|
<li><span data-i18n="guide.hub.s4">Approve join requests in the Admin Panel</span></li>
|
|
1643
1675
|
</ol>
|
|
@@ -1698,7 +1730,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1698
1730
|
<div style="font-weight:700;color:var(--text);margin-bottom:4px" data-i18n="settings.hub.clientSteps.title">Quick Setup (3 steps)</div>
|
|
1699
1731
|
<div><span style="color:var(--accent)">1.</span> <span data-i18n="settings.hub.clientSteps.s1">Ask your team admin for the Server Address and Team Token</span></div>
|
|
1700
1732
|
<div><span style="color:var(--accent)">2.</span> <span data-i18n="settings.hub.clientSteps.s2">Fill them in below, click "Test Connection" to verify</span></div>
|
|
1701
|
-
<div><span style="color:var(--accent)">3.</span> <span data-i18n="settings.hub.clientSteps.s3">Click "Save
|
|
1733
|
+
<div><span style="color:var(--accent)">3.</span> <span data-i18n="settings.hub.clientSteps.s3">Click "Save & Apply" — the service will restart and page refreshes automatically</span></div>
|
|
1702
1734
|
</div>
|
|
1703
1735
|
<div class="settings-grid">
|
|
1704
1736
|
<div class="settings-field full-width">
|
|
@@ -1789,8 +1821,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1789
1821
|
<div id="adminMainContent">
|
|
1790
1822
|
<div class="admin-header">
|
|
1791
1823
|
<div class="admin-header-top">
|
|
1792
|
-
<h2><span class="ah-icon">\u{
|
|
1793
|
-
<button class="btn btn-sm btn-ghost" onclick="loadAdminData()" style="backdrop-filter:blur(8px)" data-i18n="admin.refresh">\u21BB Refresh</button>
|
|
1824
|
+
<h2><span class="ah-icon">\u{26A1}</span> <span data-i18n="admin.title">Team Admin Panel</span></h2>
|
|
1794
1825
|
</div>
|
|
1795
1826
|
<div class="admin-header-sub" data-i18n="admin.subtitle">Manage team members and shared resources</div>
|
|
1796
1827
|
<div class="admin-stat-row" id="adminStats"></div>
|
|
@@ -2003,7 +2034,9 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
2003
2034
|
<script>
|
|
2004
2035
|
let activeSession=null,activeRole='',editingId=null,searchTimer=null,memoryCache={},currentPage=1,totalPages=1,totalCount=0,PAGE_SIZE=40,metricsDays=30;
|
|
2005
2036
|
let memorySearchScope='local',skillSearchScope='local',taskSearchScope='local';
|
|
2037
|
+
let _lastMemoriesFingerprint='',_lastTasksFingerprint='',_lastSkillsFingerprint='';
|
|
2006
2038
|
let _embeddingWarningShown=false;
|
|
2039
|
+
let _currentAgentOwner='agent:main';
|
|
2007
2040
|
|
|
2008
2041
|
/* ─── i18n ─── */
|
|
2009
2042
|
const I18N={
|
|
@@ -2054,8 +2087,8 @@ const I18N={
|
|
|
2054
2087
|
'skills.load.error':'Failed to load skills',
|
|
2055
2088
|
'skills.hub.title':'\u{1F310} Team Skills',
|
|
2056
2089
|
'scope.local':'Local',
|
|
2057
|
-
'scope.thisAgent':'This Agent',
|
|
2058
|
-
'scope.thisDevice':'
|
|
2090
|
+
'scope.thisAgent':'This Agent Only',
|
|
2091
|
+
'scope.thisDevice':'All Local Agents',
|
|
2059
2092
|
'scope.group':'Group',
|
|
2060
2093
|
'scope.all':'All',
|
|
2061
2094
|
'skills.visibility.public':'Shared Locally',
|
|
@@ -2093,6 +2126,13 @@ const I18N={
|
|
|
2093
2126
|
'notif.userJoin':'New user requests to join the team',
|
|
2094
2127
|
'notif.userOnline':'User came online',
|
|
2095
2128
|
'notif.userOffline':'User went offline',
|
|
2129
|
+
'notif.userLeft':'User has left the team',
|
|
2130
|
+
'notif.membershipApproved':'Your team join request has been approved',
|
|
2131
|
+
'notif.membershipRejected':'Your team join request has been declined',
|
|
2132
|
+
'notif.membershipRemoved':'You have been removed from the team by the admin',
|
|
2133
|
+
'notif.hubShutdown':'The team server has been shut down',
|
|
2134
|
+
'notif.rolePromoted':'You have been promoted to admin',
|
|
2135
|
+
'notif.roleDemoted':'You have been changed to member',
|
|
2096
2136
|
'notif.clearAll':'Clear all',
|
|
2097
2137
|
'notif.timeAgo.just':'just now',
|
|
2098
2138
|
'notif.timeAgo.min':'{n}m ago',
|
|
@@ -2101,7 +2141,7 @@ const I18N={
|
|
|
2101
2141
|
'stat.memories':'Memories',
|
|
2102
2142
|
'stat.sessions':'Sessions',
|
|
2103
2143
|
'stat.embeddings':'Embeddings',
|
|
2104
|
-
'stat.
|
|
2144
|
+
'stat.agents':'Agents',
|
|
2105
2145
|
'stat.active':'active',
|
|
2106
2146
|
'stat.deduped':'deduped',
|
|
2107
2147
|
'sidebar.sessions':'Sessions',
|
|
@@ -2200,6 +2240,9 @@ const I18N={
|
|
|
2200
2240
|
'logs.recall.noHits':'No matching memories',
|
|
2201
2241
|
'logs.recall.noneRelevant':'LLM filter: none relevant',
|
|
2202
2242
|
'logs.recall.more':'{n} more...',
|
|
2243
|
+
'recall.origin.localShared':'Local Shared',
|
|
2244
|
+
'recall.origin.hubMemory':'Team Cache',
|
|
2245
|
+
'recall.origin.hubRemote':'Team',
|
|
2203
2246
|
'tab.import':'\u{1F4E5} Import',
|
|
2204
2247
|
'tab.settings':'\u2699 Settings',
|
|
2205
2248
|
'settings.modelconfig':'Model Configuration',
|
|
@@ -2240,12 +2283,12 @@ const I18N={
|
|
|
2240
2283
|
'settings.test.ok':'Connected',
|
|
2241
2284
|
'settings.test.fail':'Failed',
|
|
2242
2285
|
'settings.session.expired':'Session expired, please refresh the page to log in again',
|
|
2243
|
-
'settings.save':'Save
|
|
2286
|
+
'settings.save':'Save & Apply',
|
|
2244
2287
|
'settings.reset':'Reset',
|
|
2245
2288
|
'settings.saved':'Saved',
|
|
2246
|
-
'settings.restart.hint':'
|
|
2247
|
-
'settings.restart.autoRefresh':'
|
|
2248
|
-
'settings.restart.waiting':'Configuration saved.
|
|
2289
|
+
'settings.restart.hint':'Changes will take effect after the service restarts automatically.',
|
|
2290
|
+
'settings.restart.autoRefresh':'Service restarting, page will refresh automatically...',
|
|
2291
|
+
'settings.restart.waiting':'Configuration saved. Service is restarting...',
|
|
2249
2292
|
'settings.save.fail':'Failed to save settings',
|
|
2250
2293
|
'settings.save.emb.required':'Embedding model is required. Please configure an embedding model before saving.',
|
|
2251
2294
|
'settings.save.emb.fail':'Embedding model test failed, cannot save',
|
|
@@ -2372,16 +2415,16 @@ const I18N={
|
|
|
2372
2415
|
'settings.hub.tokenCopied':'Team Token copied!',
|
|
2373
2416
|
'settings.hub.hubSteps.title':'Quick Setup (3 steps)',
|
|
2374
2417
|
'settings.hub.hubSteps.s1':'Fill in Team Name below (or keep default)',
|
|
2375
|
-
'settings.hub.hubSteps.s2':'Click "Save
|
|
2418
|
+
'settings.hub.hubSteps.s2':'Click "Save & Apply" — the service will restart automatically',
|
|
2376
2419
|
'settings.hub.hubSteps.s3':'Share the Server Address and Team Token below with your team members',
|
|
2377
2420
|
'settings.hub.clientSteps.title':'Quick Setup (3 steps)',
|
|
2378
2421
|
'settings.hub.clientSteps.s1':'Ask your team admin for the Server Address and Team Token',
|
|
2379
2422
|
'settings.hub.clientSteps.s2':'Fill them in below, click "Test Connection" to verify',
|
|
2380
|
-
'settings.hub.clientSteps.s3':'Click "Save
|
|
2423
|
+
'settings.hub.clientSteps.s3':'Click "Save & Apply" — the service will restart and page refreshes automatically',
|
|
2381
2424
|
'settings.hub.shareInfo.title':'Share this info with your team members:',
|
|
2382
2425
|
'settings.hub.shareInfo.yourIP':'your-IP',
|
|
2383
2426
|
'settings.hub.shareInfo.clickCopy':'Click to copy',
|
|
2384
|
-
'settings.hub.restartAlert':'Team sharing config saved!
|
|
2427
|
+
'settings.hub.restartAlert':'Team sharing config saved! The service will restart automatically to apply changes.',
|
|
2385
2428
|
'settings.hub.hubAddress':'Server Address',
|
|
2386
2429
|
'settings.hub.hubAddress.hint':'Team server address, e.g. 192.168.1.100:18800',
|
|
2387
2430
|
'settings.hub.teamTokenClient':'Team Token',
|
|
@@ -2392,6 +2435,7 @@ const I18N={
|
|
|
2392
2435
|
'settings.hub.userToken.hint':'Usually auto-obtained after joining. Only fill if given by admin.',
|
|
2393
2436
|
'settings.hub.testConnection':'Test Connection',
|
|
2394
2437
|
'settings.hub.test.noAddr':'Please enter server address first',
|
|
2438
|
+
'settings.hub.teamToken.required':'Please enter team token',
|
|
2395
2439
|
'settings.hub.test.testing':'Testing...',
|
|
2396
2440
|
'settings.hub.test.ok':'Connected successfully',
|
|
2397
2441
|
'settings.hub.test.fail':'Connection failed',
|
|
@@ -2401,6 +2445,10 @@ const I18N={
|
|
|
2401
2445
|
'sidebar.hub':'\u{1F310} Team Sharing',
|
|
2402
2446
|
'sharing.sidebar.connected':'Connected',
|
|
2403
2447
|
'sharing.sidebar.disconnected':'Disconnected',
|
|
2448
|
+
'sharing.sidebar.hubRunning':'Hub Running',
|
|
2449
|
+
'sharing.sidebar.teamName':'Team',
|
|
2450
|
+
'sharing.sidebar.members':'Members',
|
|
2451
|
+
'sharing.sidebar.online':'online',
|
|
2404
2452
|
'sharing.sidebar.pending':'Pending Approval',
|
|
2405
2453
|
'sharing.sidebar.rejected':'Rejected',
|
|
2406
2454
|
'sharing.sidebar.starting':'Starting...',
|
|
@@ -2410,11 +2458,21 @@ const I18N={
|
|
|
2410
2458
|
'sharing.sidebar.targetHub':'Team Server:',
|
|
2411
2459
|
'sharing.pendingApproval.hint':'Your join request has been submitted. Please wait for the team admin to approve.',
|
|
2412
2460
|
'sharing.rejected.hint':'Your join request was rejected by the team admin. Please contact the admin or retry.',
|
|
2461
|
+
'sharing.removed.hint':'You have been removed from the team by the admin. You can re-apply to join.',
|
|
2462
|
+
'sharing.joinTeam':'Join Team',
|
|
2463
|
+
'sharing.joinSent.pending':'Join request sent! Waiting for admin approval.',
|
|
2464
|
+
'sharing.joinSent.active':'Successfully joined the team!',
|
|
2413
2465
|
'sharing.retryJoin':'Retry Join',
|
|
2414
2466
|
'sharing.retryJoin.hint':'Clears local data and re-submits the join request',
|
|
2415
2467
|
'sharing.retryJoin.confirm':'This will clear your current connection and re-submit a join request. Continue?',
|
|
2468
|
+
'sharing.leaveTeam':'Leave Team',
|
|
2469
|
+
'sharing.leaveTeam.confirm':'You are about to leave team "{team}".\\n\\nWhat will happen:\\n\\u2022 You will disconnect from the team server\\n\\u2022 The team admin will be notified that you left\\n\\u2022 You will no longer receive shared memories, tasks, or skills\\n\\u2022 Your local data is preserved and not affected\\n\\u2022 You can rejoin later if the admin approves\\n\\nAre you sure?',
|
|
2470
|
+
'sharing.leaveTeam.success':'You have left the team. Sharing has been disabled.',
|
|
2471
|
+
'sharing.leaveTeam.fail':'Failed to leave team',
|
|
2472
|
+
'sharing.team.default':'the team',
|
|
2416
2473
|
'sharing.retryJoin.success':'Join request re-submitted. Waiting for admin approval.',
|
|
2417
2474
|
'sharing.retryJoin.fail':'Failed to retry join',
|
|
2475
|
+
'sharing.ownerRemoved':'(removed)',
|
|
2418
2476
|
'sharing.cannotJoinSelf':'Cannot join your own server. Please enter a remote server address.',
|
|
2419
2477
|
'scope.hub':'Team',
|
|
2420
2478
|
'memory.detail.title':'Memory Detail',
|
|
@@ -2465,6 +2523,7 @@ const I18N={
|
|
|
2465
2523
|
'admin.editName':'Edit Name',
|
|
2466
2524
|
'admin.lastAdminHint':'Last admin — cannot remove or demote',
|
|
2467
2525
|
'admin.ownerHint':'Hub owner — cannot be demoted or removed',
|
|
2526
|
+
'admin.selfHint':'This is you',
|
|
2468
2527
|
'admin.editNamePrompt':'Enter new username:',
|
|
2469
2528
|
'confirm.promoteAdmin':'Promote this user to admin? They will be able to manage all team members and resources.',
|
|
2470
2529
|
'confirm.demoteMember':'Demote this admin to member?',
|
|
@@ -2525,6 +2584,9 @@ const I18N={
|
|
|
2525
2584
|
'admin.groupsFailed':'Failed to load groups: ',
|
|
2526
2585
|
'toast.userApproved':'User approved',
|
|
2527
2586
|
'sharing.approved.toast':'Your join request has been approved!',
|
|
2587
|
+
'sharing.rejected.toast':'Your join request was rejected by the admin.',
|
|
2588
|
+
'sharing.hubOffline.toast':'Team server is offline. Will reconnect automatically when it comes back.',
|
|
2589
|
+
'sharing.hubReconnected.toast':'Team server is back online! Connection restored.',
|
|
2528
2590
|
'toast.userRejected':'User rejected',
|
|
2529
2591
|
'toast.approveFail':'Approve failed',
|
|
2530
2592
|
'toast.rejectFail':'Reject failed',
|
|
@@ -2617,9 +2679,9 @@ const I18N={
|
|
|
2617
2679
|
'share.status.agents':'Local',
|
|
2618
2680
|
'share.status.hub':'Team',
|
|
2619
2681
|
'share.scope.title':'Sharing Scope',
|
|
2620
|
-
'share.scope.private':'
|
|
2621
|
-
'share.scope.local':'
|
|
2622
|
-
'share.scope.team':'Team',
|
|
2682
|
+
'share.scope.private':'Private',
|
|
2683
|
+
'share.scope.local':'Local Shared',
|
|
2684
|
+
'share.scope.team':'Team Shared',
|
|
2623
2685
|
'share.scope.current':'Current',
|
|
2624
2686
|
'share.scope.teamDisabled':'Not connected to team server',
|
|
2625
2687
|
'share.scope.teamIncludes':'Includes visibility to all local agents',
|
|
@@ -2684,7 +2746,10 @@ const I18N={
|
|
|
2684
2746
|
'update.dismiss':'Dismiss',
|
|
2685
2747
|
'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?',
|
|
2686
2748
|
'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?',
|
|
2687
|
-
'sharing.disable.restartAlert':'Sharing has been disabled.
|
|
2749
|
+
'sharing.disable.restartAlert':'Sharing has been disabled. The service will restart automatically to apply the change.',
|
|
2750
|
+
'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 the service restarts\\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?',
|
|
2751
|
+
'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 the service restarts\\n\\u2022 Your local data is not affected\\n\\nAre you sure?',
|
|
2752
|
+
'sharing.switch.hubAddress':'You are about to leave the current team and join a different one.\\n\\nWhat will happen:\\n\\u2022 You will disconnect from the current team server\\n\\u2022 The current team admin will be notified that you left\\n\\u2022 You will join the new team server as a new member\\n\\u2022 Your local data is not affected\\n\\nAre you sure?',
|
|
2688
2753
|
'admin.notEnabled.title':'Team sharing is not enabled',
|
|
2689
2754
|
'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.',
|
|
2690
2755
|
'admin.notEnabled.setupHub':'Set Up as Team Server',
|
|
@@ -2702,12 +2767,12 @@ const I18N={
|
|
|
2702
2767
|
'guide.join.s1':'Ask your team admin for the Server Address and Team Token',
|
|
2703
2768
|
'guide.join.s2':'Go to Settings \u2192 Team Sharing, enable sharing, select "Client" mode',
|
|
2704
2769
|
'guide.join.s3':'Fill in Server Address and Team Token, click "Test Connection"',
|
|
2705
|
-
'guide.join.s4':'Save
|
|
2770
|
+
'guide.join.s4':'Click "Save & Apply" — the service restarts automatically (page refreshes)',
|
|
2706
2771
|
'guide.join.btn':'\u2192 Configure Client Mode',
|
|
2707
2772
|
'guide.hub.title':'Start Your Own Team Server',
|
|
2708
2773
|
'guide.hub.desc':'Be the team server. Run it on this device so others can connect and share memories with you.',
|
|
2709
2774
|
'guide.hub.s1':'Go to Settings \u2192 Team Sharing, enable sharing, select "Server" mode',
|
|
2710
|
-
'guide.hub.s2':'Set a team name,
|
|
2775
|
+
'guide.hub.s2':'Set a team name, click "Save & Apply" — the service restarts automatically',
|
|
2711
2776
|
'guide.hub.s3':'Share the Server Address and Team Token with your team members',
|
|
2712
2777
|
'guide.hub.s4':'Approve join requests in the Admin Panel',
|
|
2713
2778
|
'guide.hub.btn':'\u2192 Configure Server Mode'
|
|
@@ -2759,8 +2824,8 @@ const I18N={
|
|
|
2759
2824
|
'skills.load.error':'加载技能失败',
|
|
2760
2825
|
'skills.hub.title':'\u{1F310} 团队共享技能',
|
|
2761
2826
|
'scope.local':'本地',
|
|
2762
|
-
'scope.thisAgent':'
|
|
2763
|
-
'scope.thisDevice':'
|
|
2827
|
+
'scope.thisAgent':'仅本智能体',
|
|
2828
|
+
'scope.thisDevice':'本机所有智能体',
|
|
2764
2829
|
'scope.group':'团队',
|
|
2765
2830
|
'scope.all':'全部',
|
|
2766
2831
|
'skills.visibility.public':'本机共享',
|
|
@@ -2798,6 +2863,13 @@ const I18N={
|
|
|
2798
2863
|
'notif.userJoin':'有新用户申请加入团队',
|
|
2799
2864
|
'notif.userOnline':'用户上线了',
|
|
2800
2865
|
'notif.userOffline':'用户下线了',
|
|
2866
|
+
'notif.userLeft':'用户已退出团队',
|
|
2867
|
+
'notif.membershipApproved':'你的团队加入申请已通过',
|
|
2868
|
+
'notif.membershipRejected':'你的团队加入申请已被拒绝',
|
|
2869
|
+
'notif.membershipRemoved':'你已被管理员移出团队',
|
|
2870
|
+
'notif.hubShutdown':'团队服务已关闭',
|
|
2871
|
+
'notif.rolePromoted':'你已被提升为管理员',
|
|
2872
|
+
'notif.roleDemoted':'你已被设为普通成员',
|
|
2801
2873
|
'notif.clearAll':'清除全部',
|
|
2802
2874
|
'notif.timeAgo.just':'刚刚',
|
|
2803
2875
|
'notif.timeAgo.min':'{n}分钟前',
|
|
@@ -2806,7 +2878,7 @@ const I18N={
|
|
|
2806
2878
|
'stat.memories':'记忆',
|
|
2807
2879
|
'stat.sessions':'会话',
|
|
2808
2880
|
'stat.embeddings':'嵌入',
|
|
2809
|
-
'stat.
|
|
2881
|
+
'stat.agents':'智能体',
|
|
2810
2882
|
'stat.active':'活跃',
|
|
2811
2883
|
'stat.deduped':'已去重',
|
|
2812
2884
|
'sidebar.sessions':'会话列表',
|
|
@@ -2905,6 +2977,9 @@ const I18N={
|
|
|
2905
2977
|
'logs.recall.noHits':'未匹配到记忆',
|
|
2906
2978
|
'logs.recall.noneRelevant':'LLM 过滤:无相关记忆',
|
|
2907
2979
|
'logs.recall.more':'还有 {n} 条...',
|
|
2980
|
+
'recall.origin.localShared':'本机共享',
|
|
2981
|
+
'recall.origin.hubMemory':'团队缓存',
|
|
2982
|
+
'recall.origin.hubRemote':'团队',
|
|
2908
2983
|
'tab.import':'\u{1F4E5} 导入',
|
|
2909
2984
|
'tab.settings':'\u2699 设置',
|
|
2910
2985
|
'settings.modelconfig':'模型配置',
|
|
@@ -2945,12 +3020,12 @@ const I18N={
|
|
|
2945
3020
|
'settings.test.ok':'连接成功',
|
|
2946
3021
|
'settings.test.fail':'连接失败',
|
|
2947
3022
|
'settings.session.expired':'登录已过期,请刷新页面重新登录',
|
|
2948
|
-
'settings.save':'
|
|
3023
|
+
'settings.save':'保存并应用',
|
|
2949
3024
|
'settings.reset':'重置',
|
|
2950
3025
|
'settings.saved':'已保存',
|
|
2951
|
-
'settings.restart.hint':'
|
|
2952
|
-
'settings.restart.autoRefresh':'
|
|
2953
|
-
'settings.restart.waiting':'
|
|
3026
|
+
'settings.restart.hint':'修改将在服务自动重启后生效。',
|
|
3027
|
+
'settings.restart.autoRefresh':'服务重启中,页面将自动刷新...',
|
|
3028
|
+
'settings.restart.waiting':'配置已保存,服务正在重启...',
|
|
2954
3029
|
'settings.save.fail':'保存设置失败',
|
|
2955
3030
|
'settings.save.emb.required':'嵌入模型为必填项,请先配置嵌入模型再保存。',
|
|
2956
3031
|
'settings.save.emb.fail':'嵌入模型测试失败,无法保存',
|
|
@@ -3077,16 +3152,16 @@ const I18N={
|
|
|
3077
3152
|
'settings.hub.tokenCopied':'团队令牌已复制!',
|
|
3078
3153
|
'settings.hub.hubSteps.title':'快速配置(3 步)',
|
|
3079
3154
|
'settings.hub.hubSteps.s1':'填写下方团队名称(或保持默认)',
|
|
3080
|
-
'settings.hub.hubSteps.s2':'
|
|
3155
|
+
'settings.hub.hubSteps.s2':'点击「保存并应用」,服务将自动重启',
|
|
3081
3156
|
'settings.hub.hubSteps.s3':'将下方的服务器地址和团队令牌分享给团队成员',
|
|
3082
3157
|
'settings.hub.clientSteps.title':'快速配置(3 步)',
|
|
3083
3158
|
'settings.hub.clientSteps.s1':'向团队管理员获取服务器地址和团队令牌',
|
|
3084
3159
|
'settings.hub.clientSteps.s2':'填入下方,点击"测试连接"验证连通性',
|
|
3085
|
-
'settings.hub.clientSteps.s3':'
|
|
3160
|
+
'settings.hub.clientSteps.s3':'点击「保存并应用」,服务将自动重启(页面会自动刷新)',
|
|
3086
3161
|
'settings.hub.shareInfo.title':'请将以下信息分享给团队成员:',
|
|
3087
3162
|
'settings.hub.shareInfo.yourIP':'你的IP',
|
|
3088
3163
|
'settings.hub.shareInfo.clickCopy':'点击复制',
|
|
3089
|
-
'settings.hub.restartAlert':'
|
|
3164
|
+
'settings.hub.restartAlert':'团队共享配置已保存!服务将自动重启以应用更改。',
|
|
3090
3165
|
'settings.hub.hubAddress':'服务器地址',
|
|
3091
3166
|
'settings.hub.hubAddress.hint':'团队服务器地址,如 192.168.1.100:18800',
|
|
3092
3167
|
'settings.hub.teamTokenClient':'团队令牌',
|
|
@@ -3097,6 +3172,7 @@ const I18N={
|
|
|
3097
3172
|
'settings.hub.userToken.hint':'通常在加入团队后自动获取,无需手动填写。',
|
|
3098
3173
|
'settings.hub.testConnection':'测试连接',
|
|
3099
3174
|
'settings.hub.test.noAddr':'请先输入服务器地址',
|
|
3175
|
+
'settings.hub.teamToken.required':'请输入团队令牌',
|
|
3100
3176
|
'settings.hub.test.testing':'测试中...',
|
|
3101
3177
|
'settings.hub.test.ok':'连接成功',
|
|
3102
3178
|
'settings.hub.test.fail':'连接失败',
|
|
@@ -3106,6 +3182,10 @@ const I18N={
|
|
|
3106
3182
|
'sidebar.hub':'\u{1F310} 团队共享',
|
|
3107
3183
|
'sharing.sidebar.connected':'已连接',
|
|
3108
3184
|
'sharing.sidebar.disconnected':'已断开',
|
|
3185
|
+
'sharing.sidebar.hubRunning':'服务运行中',
|
|
3186
|
+
'sharing.sidebar.teamName':'团队',
|
|
3187
|
+
'sharing.sidebar.members':'成员',
|
|
3188
|
+
'sharing.sidebar.online':'在线',
|
|
3109
3189
|
'sharing.sidebar.pending':'等待审核',
|
|
3110
3190
|
'sharing.sidebar.rejected':'已拒绝',
|
|
3111
3191
|
'sharing.sidebar.starting':'启动中...',
|
|
@@ -3115,11 +3195,21 @@ const I18N={
|
|
|
3115
3195
|
'sharing.sidebar.targetHub':'团队服务器:',
|
|
3116
3196
|
'sharing.pendingApproval.hint':'加入申请已提交,请等待团队管理员审核通过。',
|
|
3117
3197
|
'sharing.rejected.hint':'您的加入申请已被团队管理员拒绝,请联系管理员或重新申请。',
|
|
3198
|
+
'sharing.removed.hint':'您已被管理员从团队中移除,可以重新申请加入。',
|
|
3199
|
+
'sharing.joinTeam':'加入团队',
|
|
3200
|
+
'sharing.joinSent.pending':'加入申请已发送,等待管理员审批。',
|
|
3201
|
+
'sharing.joinSent.active':'成功加入团队!',
|
|
3118
3202
|
'sharing.retryJoin':'重新申请',
|
|
3119
3203
|
'sharing.retryJoin.hint':'清除本地连接数据并重新提交加入申请',
|
|
3120
3204
|
'sharing.retryJoin.confirm':'这将清除当前连接数据并重新提交加入申请,是否继续?',
|
|
3205
|
+
'sharing.leaveTeam':'退出团队',
|
|
3206
|
+
'sharing.leaveTeam.confirm':'你即将退出团队「{team}」。\\n\\n退出后将会:\\n\\u2022 断开与团队服务器的连接\\n\\u2022 团队管理员会收到你退出的通知\\n\\u2022 你将无法再接收团队共享的记忆、任务和技能\\n\\u2022 你的本地数据不受影响,会完整保留\\n\\u2022 之后可以重新申请加入(需管理员审批)\\n\\n确定要退出吗?',
|
|
3207
|
+
'sharing.leaveTeam.success':'你已退出团队,团队共享已关闭。',
|
|
3208
|
+
'sharing.leaveTeam.fail':'退出团队失败',
|
|
3209
|
+
'sharing.team.default':'该团队',
|
|
3121
3210
|
'sharing.retryJoin.success':'加入申请已重新提交,请等待管理员审核。',
|
|
3122
3211
|
'sharing.retryJoin.fail':'重新申请失败',
|
|
3212
|
+
'sharing.ownerRemoved':'(已移除)',
|
|
3123
3213
|
'sharing.cannotJoinSelf':'不能加入自己的服务端,请输入远程服务器地址。',
|
|
3124
3214
|
'scope.hub':'团队',
|
|
3125
3215
|
'memory.detail.title':'记忆详情',
|
|
@@ -3170,6 +3260,7 @@ const I18N={
|
|
|
3170
3260
|
'admin.editName':'编辑名称',
|
|
3171
3261
|
'admin.lastAdminHint':'唯一管理员 — 无法删除或降级',
|
|
3172
3262
|
'admin.ownerHint':'Hub 创建者 — 不可降级或移除',
|
|
3263
|
+
'admin.selfHint':'这是你自己',
|
|
3173
3264
|
'admin.editNamePrompt':'请输入新用户名:',
|
|
3174
3265
|
'confirm.promoteAdmin':'确定要将此用户提升为管理员吗?管理员可以管理所有团队成员和资源。',
|
|
3175
3266
|
'confirm.demoteMember':'确定要将此管理员降为普通成员吗?',
|
|
@@ -3230,6 +3321,9 @@ const I18N={
|
|
|
3230
3321
|
'admin.groupsFailed':'加载分组失败:',
|
|
3231
3322
|
'toast.userApproved':'用户已批准',
|
|
3232
3323
|
'sharing.approved.toast':'您的加入申请已通过审核!',
|
|
3324
|
+
'sharing.rejected.toast':'您的加入申请已被管理员拒绝。',
|
|
3325
|
+
'sharing.hubOffline.toast':'团队服务已离线,恢复后将自动重新连接。',
|
|
3326
|
+
'sharing.hubReconnected.toast':'团队服务已恢复上线,连接已自动恢复!',
|
|
3233
3327
|
'toast.userRejected':'用户已拒绝',
|
|
3234
3328
|
'toast.approveFail':'批准失败',
|
|
3235
3329
|
'toast.rejectFail':'拒绝失败',
|
|
@@ -3322,9 +3416,9 @@ const I18N={
|
|
|
3322
3416
|
'share.status.agents':'本机',
|
|
3323
3417
|
'share.status.hub':'团队',
|
|
3324
3418
|
'share.scope.title':'共享范围',
|
|
3325
|
-
'share.scope.private':'
|
|
3326
|
-
'share.scope.local':'
|
|
3327
|
-
'share.scope.team':'
|
|
3419
|
+
'share.scope.private':'私有',
|
|
3420
|
+
'share.scope.local':'本机共享',
|
|
3421
|
+
'share.scope.team':'团队共享',
|
|
3328
3422
|
'share.scope.current':'当前',
|
|
3329
3423
|
'share.scope.teamDisabled':'未连接团队服务器',
|
|
3330
3424
|
'share.scope.teamIncludes':'包含本机所有智能体的可见性',
|
|
@@ -3389,7 +3483,10 @@ const I18N={
|
|
|
3389
3483
|
'update.dismiss':'关闭',
|
|
3390
3484
|
'sharing.disable.confirm.hub':'你即将关闭团队服务。\\n\\n关闭后将会:\\n\\u2022 所有已连接的团队成员将断开连接\\n\\u2022 他们将无法继续同步记忆、任务和技能\\n\\u2022 已共享的数据会保留,重新开启后仍可使用\\n\\n确定要关闭吗?',
|
|
3391
3485
|
'sharing.disable.confirm.client':'你即将断开与团队的连接。\\n\\n断开后将会:\\n\\u2022 你将无法再接收团队共享的记忆、任务和技能\\n\\u2022 你的本地数据不受影响,会完整保留\\n\\u2022 之后可以随时重新开启共享来恢复连接\\n\\n确定要断开吗?',
|
|
3392
|
-
'sharing.disable.restartAlert':'
|
|
3486
|
+
'sharing.disable.restartAlert':'共享已关闭,服务将自动重启以应用更改。',
|
|
3487
|
+
'sharing.switch.hubToClient':'你即将从服务端模式切换为客户端模式。\\n\\n切换后将会:\\n\\u2022 Hub 服务将在服务重启后关闭\\n\\u2022 所有已连接的团队成员将断开连接\\n\\u2022 Hub 上的共享数据会保留,以后可恢复使用\\n\\u2022 你将作为客户端加入指定的远程团队\\n\\n确定要切换吗?',
|
|
3488
|
+
'sharing.switch.clientToHub':'你即将从客户端模式切换为服务端模式。\\n\\n切换后将会:\\n\\u2022 你将断开与当前团队的连接\\n\\u2022 服务重启后将启动新的 Hub 服务\\n\\u2022 你的本地数据不受影响\\n\\n确定要切换吗?',
|
|
3489
|
+
'sharing.switch.hubAddress':'你即将离开当前团队并加入新的团队。\\n\\n操作后将会:\\n\\u2022 你将断开与当前团队服务器的连接\\n\\u2022 当前团队管理员会收到你离开的通知\\n\\u2022 你将作为新成员加入新的团队服务器\\n\\u2022 你的本地数据不受影响\\n\\n确定要切换吗?',
|
|
3393
3490
|
'admin.notEnabled.title':'团队共享尚未开启',
|
|
3394
3491
|
'admin.notEnabled.desc':'管理面板用于管理团队成员、共享的记忆、任务和技能。使用此功能前,需要先开启团队共享。',
|
|
3395
3492
|
'admin.notEnabled.setupHub':'配置为团队服务端',
|
|
@@ -3407,12 +3504,12 @@ const I18N={
|
|
|
3407
3504
|
'guide.join.s1':'向团队管理员索取服务器地址和团队令牌',
|
|
3408
3505
|
'guide.join.s2':'前往「设置 → 团队共享」,开启共享,选择「客户端」模式',
|
|
3409
3506
|
'guide.join.s3':'填写服务器地址和团队令牌,点击「测试连接」',
|
|
3410
|
-
'guide.join.s4':'
|
|
3507
|
+
'guide.join.s4':'点击「保存并应用」,服务将自动重启(页面会自动刷新)',
|
|
3411
3508
|
'guide.join.btn':'\u2192 配置客户端模式',
|
|
3412
3509
|
'guide.hub.title':'自建团队服务',
|
|
3413
3510
|
'guide.hub.desc':'将本机作为团队服务端,让其他成员连接过来共享记忆。',
|
|
3414
3511
|
'guide.hub.s1':'前往「设置 → 团队共享」,开启共享,选择「服务端」模式',
|
|
3415
|
-
'guide.hub.s2':'
|
|
3512
|
+
'guide.hub.s2':'设置团队名称,点击「保存并应用」,服务将自动重启',
|
|
3416
3513
|
'guide.hub.s3':'将服务器地址和团队令牌分享给团队成员',
|
|
3417
3514
|
'guide.hub.s4':'在管理面板中审批加入请求',
|
|
3418
3515
|
'guide.hub.btn':'\u2192 配置服务端模式'
|
|
@@ -3518,12 +3615,28 @@ async function doReset(){
|
|
|
3518
3615
|
}
|
|
3519
3616
|
|
|
3520
3617
|
var _sharingRole='client';
|
|
3618
|
+
var _loadedClientHubAddress='';
|
|
3521
3619
|
function _genToken(len){
|
|
3522
3620
|
var a=new Uint8Array(len||18);crypto.getRandomValues(a);
|
|
3523
3621
|
return btoa(String.fromCharCode.apply(null,a)).replace(/\\+/g,'-').replace(/\\//g,'_').replace(/=+$/,'');
|
|
3524
3622
|
}
|
|
3525
|
-
function onSharingToggle(){
|
|
3526
|
-
var
|
|
3623
|
+
async function onSharingToggle(){
|
|
3624
|
+
var chk=document.getElementById('cfgSharingEnabled');
|
|
3625
|
+
var on=chk.checked;
|
|
3626
|
+
if(!on && sharingStatusCache && sharingStatusCache.enabled){
|
|
3627
|
+
var prevRole=sharingStatusCache.role;
|
|
3628
|
+
var confirmMsg=prevRole==='hub'?t('sharing.disable.confirm.hub'):t('sharing.disable.confirm.client');
|
|
3629
|
+
if(!(await confirmModal(confirmMsg,{danger:true}))){
|
|
3630
|
+
chk.checked=true;
|
|
3631
|
+
return;
|
|
3632
|
+
}
|
|
3633
|
+
var cfg={sharing:{enabled:false,role:prevRole}};
|
|
3634
|
+
chk.disabled=true;
|
|
3635
|
+
var result=await doSaveConfig(cfg, null, 'hubSaved');
|
|
3636
|
+
chk.disabled=false;
|
|
3637
|
+
if(!result){chk.checked=true;return;}
|
|
3638
|
+
return;
|
|
3639
|
+
}
|
|
3527
3640
|
document.getElementById('sharingConfigPanel').style.display=on?'block':'none';
|
|
3528
3641
|
var pw=document.getElementById('sharingPanelsWrap');
|
|
3529
3642
|
if(pw) pw.style.display=on?'':'none';
|
|
@@ -3541,20 +3654,25 @@ function selectSharingRole(role){
|
|
|
3541
3654
|
var tp=document.getElementById('sharingTeamPanel');
|
|
3542
3655
|
var ap=document.getElementById('sharingAdminPanel');
|
|
3543
3656
|
if(role==='client'){
|
|
3544
|
-
if(sp) sp.style.display='none';
|
|
3657
|
+
if(sp) { sp.style.display='none'; sp.innerHTML=''; }
|
|
3545
3658
|
if(tp) tp.style.display='none';
|
|
3546
3659
|
if(ap) ap.style.display='none';
|
|
3547
3660
|
}else{
|
|
3548
|
-
if(sp) sp.style.display='';
|
|
3661
|
+
if(sp) { sp.style.display='none'; sp.innerHTML=''; }
|
|
3549
3662
|
if(tp) tp.style.display='';
|
|
3550
3663
|
if(ap) ap.style.display='';
|
|
3551
3664
|
}
|
|
3665
|
+
_lastSettingsFingerprint='';
|
|
3666
|
+
setTimeout(function(){ loadSharingStatus(true); },200);
|
|
3552
3667
|
if(role==='hub'){
|
|
3553
3668
|
var tk=document.getElementById('cfgHubTeamToken');
|
|
3554
3669
|
if(!tk.value.trim()) tk.value=_genToken(18);
|
|
3555
3670
|
var tn=document.getElementById('cfgHubTeamName');
|
|
3556
3671
|
if(!tn.value.trim()) tn.value='My Team';
|
|
3557
3672
|
}
|
|
3673
|
+
var card=document.getElementById('settingsSharingConfig');
|
|
3674
|
+
var saveBtn=card&&card.querySelector('.settings-actions .btn-primary');
|
|
3675
|
+
if(saveBtn&&typeof _hubSaveBtnLabel==='function') saveBtn.textContent=_hubSaveBtnLabel();
|
|
3558
3676
|
}
|
|
3559
3677
|
var _cachedLocalIP='';
|
|
3560
3678
|
function updateHubShareInfo(){
|
|
@@ -3589,13 +3707,6 @@ async function testHubConnection(){
|
|
|
3589
3707
|
if(!addr){result.innerHTML='<span style="color:var(--rose)">\u274C '+t('settings.hub.test.noAddr')+'</span>';return;}
|
|
3590
3708
|
btn.disabled=true;result.innerHTML=t('settings.hub.test.testing');
|
|
3591
3709
|
try{
|
|
3592
|
-
var ipsData=await fetch('/api/local-ips').then(function(r){return r.json();});
|
|
3593
|
-
var localAddrs=['127.0.0.1','localhost','0.0.0.0'].concat(ipsData.ips||[]);
|
|
3594
|
-
var parsed=new URL(addr.indexOf('://')>-1?addr:'http://'+addr);
|
|
3595
|
-
if(localAddrs.indexOf(parsed.hostname)>=0){
|
|
3596
|
-
result.innerHTML='<span style="color:var(--rose)">\u274C '+t('sharing.cannotJoinSelf')+'</span>';
|
|
3597
|
-
btn.disabled=false;return;
|
|
3598
|
-
}
|
|
3599
3710
|
}catch(e){}
|
|
3600
3711
|
try{
|
|
3601
3712
|
var url=addr.match(/^https?:\\/\\//)?addr:'http://'+addr;
|
|
@@ -3645,23 +3756,38 @@ function switchView(view){
|
|
|
3645
3756
|
else if(view==='skills') loadSkills();
|
|
3646
3757
|
else if(view==='analytics') loadMetrics();
|
|
3647
3758
|
else if(view==='logs') loadLogs();
|
|
3648
|
-
else if(view==='settings'){loadConfig()
|
|
3759
|
+
else if(view==='settings'){loadConfig().then(function(){
|
|
3760
|
+
var sharingOn=document.getElementById('cfgSharingEnabled');
|
|
3761
|
+
var sharingNotEnabled=!sharingOn||!sharingOn.checked;
|
|
3762
|
+
if(sharingNotEnabled){
|
|
3763
|
+
switchSettingsTab('hub',document.querySelector('.settings-tab-btn[data-tab="hub"]'));
|
|
3764
|
+
}
|
|
3765
|
+
});loadModelHealth();}
|
|
3649
3766
|
else if(view==='import'){if(!window._migrateRunning) migrateScan(false);}
|
|
3650
|
-
else if(view==='admin'){loadAdminData();}
|
|
3767
|
+
else if(view==='admin'){_lastAdminFingerprint='';loadAdminData();}
|
|
3651
3768
|
}
|
|
3652
3769
|
|
|
3653
3770
|
function onMemoryScopeChange(){
|
|
3654
3771
|
memorySearchScope=document.getElementById('memorySearchScope')?.value||'local';
|
|
3772
|
+
try{localStorage.setItem('memos_memorySearchScope',memorySearchScope);}catch(e){}
|
|
3773
|
+
currentPage=1;
|
|
3774
|
+
activeSession=null;activeRole='';
|
|
3775
|
+
_lastMemoriesFingerprint='';
|
|
3655
3776
|
var isHub=memorySearchScope==='hub';
|
|
3777
|
+
var isLocal=memorySearchScope==='local';
|
|
3656
3778
|
var ownerSel=document.getElementById('filterOwner');
|
|
3657
3779
|
var filterBar=document.getElementById('filterBar');
|
|
3658
3780
|
var dateFilter=document.querySelector('.date-filter');
|
|
3659
|
-
if(ownerSel)
|
|
3781
|
+
if(ownerSel){ownerSel.style.display=(isHub||isLocal)?'none':'';if(isHub||isLocal)ownerSel.value='';}
|
|
3660
3782
|
if(filterBar) filterBar.style.display=isHub?'none':'';
|
|
3661
3783
|
if(dateFilter) dateFilter.style.display=isHub?'none':'';
|
|
3662
3784
|
if(document.getElementById('searchInput').value.trim()) doSearch(document.getElementById('searchInput').value);
|
|
3663
3785
|
else if(isHub) { document.getElementById('sharingSearchMeta').textContent=''; loadHubMemories(); }
|
|
3664
|
-
else {
|
|
3786
|
+
else {
|
|
3787
|
+
document.getElementById('sharingSearchMeta').textContent='';
|
|
3788
|
+
var ownerArg=isLocal?_currentAgentOwner:undefined;
|
|
3789
|
+
loadStats(ownerArg); loadMemories();
|
|
3790
|
+
}
|
|
3665
3791
|
}
|
|
3666
3792
|
|
|
3667
3793
|
function onSkillScopeChange(){
|
|
@@ -3676,6 +3802,14 @@ function onTaskScopeChange(){
|
|
|
3676
3802
|
}
|
|
3677
3803
|
|
|
3678
3804
|
var _clientPendingPollTimer=null;
|
|
3805
|
+
var _lastSharingConnStatus='';
|
|
3806
|
+
function _updateScopeSelectorsVisibility(hubAvailable){
|
|
3807
|
+
var ids=['memorySearchScope','taskSearchScope','skillSearchScope'];
|
|
3808
|
+
for(var i=0;i<ids.length;i++){
|
|
3809
|
+
var el=document.getElementById(ids[i]);
|
|
3810
|
+
if(el) el.style.display=hubAvailable?'':'none';
|
|
3811
|
+
}
|
|
3812
|
+
}
|
|
3679
3813
|
async function loadSharingStatus(forcePending){
|
|
3680
3814
|
try{
|
|
3681
3815
|
const r=await fetch('/api/sharing/status');
|
|
@@ -3685,27 +3819,64 @@ async function loadSharingStatus(forcePending){
|
|
|
3685
3819
|
renderSharingSettings(d);
|
|
3686
3820
|
updateTeamGuide(d);
|
|
3687
3821
|
if(forcePending && d && d.admin && d.admin.canManageUsers) loadSharingPendingUsers();
|
|
3688
|
-
|
|
3689
|
-
|
|
3690
|
-
|
|
3691
|
-
|
|
3822
|
+
if(!d||!d.enabled){
|
|
3823
|
+
if(_clientPendingPollTimer){clearInterval(_clientPendingPollTimer);_clientPendingPollTimer=null;}
|
|
3824
|
+
_lastSharingConnStatus='';
|
|
3825
|
+
_updateScopeSelectorsVisibility(false);
|
|
3826
|
+
return;
|
|
3827
|
+
}
|
|
3828
|
+
var conn=d.connection||{};
|
|
3829
|
+
var curStatus=conn.rejected?'rejected':conn.pendingApproval?'pending':conn.connected?'connected':'none';
|
|
3830
|
+
var hubActive=d.role==='hub'||curStatus==='connected';
|
|
3831
|
+
_updateScopeSelectorsVisibility(hubActive);
|
|
3832
|
+
if(_lastSharingConnStatus==='pending'&&curStatus==='rejected'&&d.role==='client'){
|
|
3833
|
+
toast(t('sharing.rejected.toast'),'error');
|
|
3834
|
+
}
|
|
3835
|
+
if(_lastSharingConnStatus==='pending'&&curStatus==='connected'&&d.role==='client'){
|
|
3836
|
+
toast(t('sharing.approved.toast'),'success');
|
|
3837
|
+
loadMemories();loadTasks();loadSkills();
|
|
3838
|
+
if(_notifSSE){_notifSSE.close();_notifSSE=null;_notifSSEConnected=false;}
|
|
3839
|
+
connectNotifSSE();
|
|
3840
|
+
loadNotifications();
|
|
3841
|
+
}
|
|
3842
|
+
if(_lastSharingConnStatus==='connected'&&curStatus==='none'&&d.role==='client'){
|
|
3843
|
+
toast(t('sharing.hubOffline.toast'),'error');
|
|
3844
|
+
}
|
|
3845
|
+
if(_lastSharingConnStatus==='none'&&curStatus==='connected'&&d.role==='client'){
|
|
3846
|
+
toast(t('sharing.hubReconnected.toast'),'success');
|
|
3847
|
+
loadMemories();loadTasks();loadSkills();
|
|
3848
|
+
if(_notifSSE){_notifSSE.close();_notifSSE=null;_notifSSEConnected=false;}
|
|
3849
|
+
connectNotifSSE();
|
|
3850
|
+
loadNotifications();
|
|
3851
|
+
}
|
|
3852
|
+
_lastSharingConnStatus=curStatus;
|
|
3853
|
+
if(curStatus==='pending'&&!_clientPendingPollTimer){
|
|
3854
|
+
_clientPendingPollTimer=setInterval(function(){loadSharingStatus(false);},5000);
|
|
3855
|
+
}
|
|
3856
|
+
if(curStatus!=='pending'&&_clientPendingPollTimer){
|
|
3692
3857
|
clearInterval(_clientPendingPollTimer);
|
|
3693
3858
|
_clientPendingPollTimer=null;
|
|
3694
|
-
if(conn.connected) toast(t('sharing.approved.toast'),'success');
|
|
3695
3859
|
}
|
|
3696
3860
|
}catch(e){
|
|
3697
3861
|
renderSharingSidebar(null);
|
|
3698
3862
|
renderSharingSettings(null);
|
|
3699
3863
|
updateTeamGuide(null);
|
|
3864
|
+
_updateScopeSelectorsVisibility(false);
|
|
3700
3865
|
}
|
|
3701
3866
|
}
|
|
3702
3867
|
|
|
3868
|
+
var _lastSidebarFingerprint='';
|
|
3703
3869
|
function renderSharingSidebar(data){
|
|
3704
3870
|
var section=document.getElementById('sidebarSharingSection');
|
|
3705
3871
|
var statusEl=document.getElementById('sharingSidebarStatus');
|
|
3706
3872
|
var hintEl=document.getElementById('sharingSidebarHint');
|
|
3707
3873
|
var badgeEl=document.getElementById('sharingSidebarConnBadge');
|
|
3708
3874
|
if(!statusEl||!hintEl) return;
|
|
3875
|
+
var conn=data&&data.connection||{};
|
|
3876
|
+
var hs=data&&data.hubStats||{};
|
|
3877
|
+
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,tm:hs.totalMembers,om:hs.onlineMembers,pm:hs.pendingMembers});
|
|
3878
|
+
if(fp===_lastSidebarFingerprint) return;
|
|
3879
|
+
_lastSidebarFingerprint=fp;
|
|
3709
3880
|
if(!data||!data.enabled){
|
|
3710
3881
|
if(section) section.style.display='none';
|
|
3711
3882
|
window._isHubAdmin=false;
|
|
@@ -3718,8 +3889,16 @@ function renderSharingSidebar(data){
|
|
|
3718
3889
|
badgeEl.innerHTML='<span style="display:inline-flex;align-items:center;gap:4px;font-size:10px;font-weight:600;padding:2px 8px;border-radius:9999px;background:'+color+'15;color:'+color+'"><span style="display:inline-block;width:6px;height:6px;border-radius:50%;background:'+color+(glow?';box-shadow:0 0 4px '+color:'')+'"></span>'+esc(text)+'</span>';
|
|
3719
3890
|
}
|
|
3720
3891
|
if(data.role==='hub'){
|
|
3721
|
-
setBadge('#34d399',t('sharing.sidebar.
|
|
3722
|
-
|
|
3892
|
+
setBadge('#34d399',t('sharing.sidebar.hubRunning'),true);
|
|
3893
|
+
var hs=data.hubStats||{};
|
|
3894
|
+
var html='<div class="info-grid">';
|
|
3895
|
+
if(conn.teamName) html+='<span class="label">'+t('sharing.sidebar.teamName')+'</span><span class="value" style="font-weight:600">'+esc(conn.teamName)+'</span>';
|
|
3896
|
+
html+='<span class="label">'+t('sharing.sidebar.members')+'</span><span class="value">'+(hs.totalMembers||0)+' <span style="opacity:.5;font-size:10px">/ '+t('sharing.sidebar.online')+' '+(hs.onlineMembers||0)+'</span></span>';
|
|
3897
|
+
if(hs.pendingMembers>0){
|
|
3898
|
+
html+='<span class="label">'+t('sharing.sidebar.pending')+'</span><span class="value" style="color:var(--yellow,#fbbf24);font-weight:600">'+hs.pendingMembers+'</span>';
|
|
3899
|
+
}
|
|
3900
|
+
html+='</div>';
|
|
3901
|
+
statusEl.innerHTML=html;
|
|
3723
3902
|
hintEl.textContent='';
|
|
3724
3903
|
}else if(conn.pendingApproval&&conn.user){
|
|
3725
3904
|
setBadge('#fbbf24',t('sharing.sidebar.pending'),false);
|
|
@@ -3735,8 +3914,18 @@ function renderSharingSidebar(data){
|
|
|
3735
3914
|
html+='<span class="label">'+t('sharing.sidebar.identity')+'</span><span class="value">'+esc(conn.user.username||'-')+'</span>';
|
|
3736
3915
|
if(conn.teamName) html+='<span class="label">'+t('sharing.team')+'</span><span class="value">'+esc(conn.teamName)+'</span>';
|
|
3737
3916
|
html+='</div>';
|
|
3917
|
+
html+='<div style="margin-top:8px"><button class="btn btn-sm btn-primary" onclick="retryHubJoin()" style="font-size:11px">'+t('sharing.retryJoin')+'</button></div>';
|
|
3738
3918
|
statusEl.innerHTML=html;
|
|
3739
3919
|
hintEl.textContent=t('sharing.rejected.hint');
|
|
3920
|
+
}else if(conn.removed&&conn.user){
|
|
3921
|
+
setBadge('#ef4444',t('sharing.sidebar.disconnected'),false);
|
|
3922
|
+
var html='<div class="info-grid">';
|
|
3923
|
+
html+='<span class="label">'+t('sharing.sidebar.identity')+'</span><span class="value">'+esc(conn.user.username||'-')+'</span>';
|
|
3924
|
+
if(conn.teamName) html+='<span class="label">'+t('sharing.team')+'</span><span class="value">'+esc(conn.teamName)+'</span>';
|
|
3925
|
+
html+='</div>';
|
|
3926
|
+
html+='<div style="margin-top:8px"><button class="btn btn-sm btn-primary" onclick="retryHubJoin()" style="font-size:11px">'+t('sharing.retryJoin')+'</button></div>';
|
|
3927
|
+
statusEl.innerHTML=html;
|
|
3928
|
+
hintEl.textContent=t('sharing.removed.hint');
|
|
3740
3929
|
}else if(conn.connected&&conn.user){
|
|
3741
3930
|
var isAdmin=conn.user.role==='admin';
|
|
3742
3931
|
setBadge('#34d399',t('sharing.sidebar.connected'),true);
|
|
@@ -3757,25 +3946,43 @@ function renderSharingSidebar(data){
|
|
|
3757
3946
|
}
|
|
3758
3947
|
}
|
|
3759
3948
|
|
|
3949
|
+
var _lastSettingsFingerprint='';
|
|
3760
3950
|
function renderSharingSettings(data){
|
|
3761
3951
|
var statusEl=document.getElementById('sharingStatusPanel');
|
|
3762
3952
|
var teamEl=document.getElementById('sharingTeamPanel');
|
|
3763
3953
|
var adminEl=document.getElementById('sharingAdminPanel');
|
|
3764
3954
|
var panelsWrap=document.getElementById('sharingPanelsWrap');
|
|
3765
3955
|
if(!statusEl||!teamEl||!adminEl) return;
|
|
3956
|
+
var conn2=data&&data.connection||{};
|
|
3957
|
+
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});
|
|
3958
|
+
if(fp2===_lastSettingsFingerprint) return;
|
|
3959
|
+
_lastSettingsFingerprint=fp2;
|
|
3766
3960
|
if(!data||!data.enabled){
|
|
3767
3961
|
statusEl.innerHTML='';teamEl.innerHTML='';adminEl.innerHTML='';
|
|
3768
3962
|
if(panelsWrap) panelsWrap.style.display='none';
|
|
3963
|
+
var adminNavTab0=document.querySelector('.tab[data-view="admin"]');
|
|
3964
|
+
if(adminNavTab0) adminNavTab0.style.display='none';
|
|
3965
|
+
if(_activeView==='admin') switchView('memories');
|
|
3769
3966
|
return;
|
|
3770
3967
|
}
|
|
3771
3968
|
if(panelsWrap) panelsWrap.style.display='';
|
|
3772
3969
|
var conn=data.connection||{};
|
|
3773
3970
|
var user=conn.user||{};
|
|
3774
3971
|
var actualRole=data.role||_sharingRole||'client';
|
|
3775
|
-
|
|
3972
|
+
var prevIsAdmin=!!window._isHubAdmin;
|
|
3776
3973
|
var isAdmin=(data.admin&&data.admin.canManageUsers)||(conn.connected&&user.role==='admin')||(actualRole==='hub');
|
|
3777
3974
|
window._isHubAdmin=isAdmin;
|
|
3778
3975
|
if(isAdmin) startAdminPoll();
|
|
3976
|
+
var adminNavTab=document.querySelector('.tab[data-view="admin"]');
|
|
3977
|
+
if(adminNavTab){
|
|
3978
|
+
var showTab=(actualRole==='hub')||(conn.connected);
|
|
3979
|
+
adminNavTab.style.display=showTab?'':'none';
|
|
3980
|
+
if(!showTab&&_activeView==='admin') switchView('memories');
|
|
3981
|
+
}
|
|
3982
|
+
if(prevIsAdmin&&!isAdmin&&_activeView==='admin'){
|
|
3983
|
+
_lastAdminFingerprint='';
|
|
3984
|
+
loadAdminData();
|
|
3985
|
+
}
|
|
3779
3986
|
var hubAdminBtn=document.getElementById('hubAdminEntryBtn');
|
|
3780
3987
|
|
|
3781
3988
|
if(actualRole==='hub'){
|
|
@@ -3797,6 +4004,8 @@ function renderSharingSettings(data){
|
|
|
3797
4004
|
connBadge='<span class="hic-badge pending"><span class="hic-dot amber"></span>'+t('sharing.sidebar.pending')+'</span>';
|
|
3798
4005
|
}else if(conn.rejected){
|
|
3799
4006
|
connBadge='<span class="hic-badge disconnected"><span class="hic-dot red"></span>'+t('sharing.sidebar.rejected')+'</span>';
|
|
4007
|
+
}else if(conn.removed){
|
|
4008
|
+
connBadge='<span class="hic-badge disconnected"><span class="hic-dot red"></span>'+t('sharing.sidebar.disconnected')+'</span>';
|
|
3800
4009
|
}else if(conn.connected){
|
|
3801
4010
|
connBadge='<span class="hic-badge connected"><span class="hic-dot green"></span>'+t('sharing.sidebar.connected')+'</span>';
|
|
3802
4011
|
}else{
|
|
@@ -3812,13 +4021,21 @@ function renderSharingSettings(data){
|
|
|
3812
4021
|
sh+='</div><div class="hic-empty" style="color:#ef4444">'+t('sharing.rejected.hint')+'</div>'+
|
|
3813
4022
|
'<div style="margin-top:10px;padding:0 16px 14px"><button class="btn btn-sm btn-primary" onclick="retryHubJoin()">'+t('sharing.retryJoin')+'</button>'+
|
|
3814
4023
|
'<span style="font-size:11px;color:var(--text-muted);margin-left:8px">'+t('sharing.retryJoin.hint')+'</span></div></div>';
|
|
4024
|
+
}else if(conn.removed){
|
|
4025
|
+
if(user.username) sh+='<span class="hic-label">'+t('sharing.user')+'</span><span class="hic-value">'+esc(user.username)+'</span>';
|
|
4026
|
+
sh+='</div><div class="hic-empty" style="color:#ef4444">'+t('sharing.removed.hint')+'</div>'+
|
|
4027
|
+
'<div style="margin-top:10px;padding:0 16px 14px"><button class="btn btn-sm btn-primary" onclick="retryHubJoin()">'+t('sharing.retryJoin')+'</button>'+
|
|
4028
|
+
'<span style="font-size:11px;color:var(--text-muted);margin-left:8px">'+t('sharing.retryJoin.hint')+'</span></div></div>';
|
|
3815
4029
|
}else if(conn.connected&&user.username){
|
|
3816
4030
|
sh+='<span class="hic-label">'+t('sharing.user')+'</span><span class="hic-value" style="display:flex;align-items:center;gap:6px">'+
|
|
3817
4031
|
'<input type="text" id="hubUsernameInput" value="'+esc(user.username)+'" style="border:1px solid var(--border);border-radius:6px;padding:3px 8px;font-size:12px;background:var(--bg);color:var(--text);width:120px;font-family:inherit" />'+
|
|
3818
4032
|
'<button class="btn btn-sm" onclick="updateHubUsername()" style="padding:2px 10px;font-size:11px">'+t('sharing.saveUsername')+'</button>'+
|
|
3819
4033
|
'</span>';
|
|
3820
4034
|
sh+='<span class="hic-label">'+t('sharing.team')+'</span><span class="hic-value">'+esc(conn.teamName||'-')+'</span>';
|
|
3821
|
-
sh+='</div
|
|
4035
|
+
sh+='</div>'+
|
|
4036
|
+
'<div style="border-top:1px solid var(--border);margin-top:10px;padding:10px 16px 6px;display:flex;align-items:center;justify-content:flex-end">'+
|
|
4037
|
+
'<button class="btn btn-sm" onclick="leaveTeam()" style="color:#ef4444;border-color:rgba(239,68,68,.3);font-size:11px;padding:4px 12px">'+t('sharing.leaveTeam')+'</button>'+
|
|
4038
|
+
'</div></div>';
|
|
3822
4039
|
}else{
|
|
3823
4040
|
sh+='</div><div class="hic-empty" style="color:var(--text-muted)">'+t('sharing.disconnected.hint')+'</div>'+
|
|
3824
4041
|
'<div style="margin-top:10px;padding:0 16px 14px"><button class="btn btn-sm btn-primary" id="btnRetryConn" onclick="retryConnection()">'+t('sharing.retryConnection')+'</button>'+
|
|
@@ -3837,6 +4054,7 @@ async function retryConnection(){
|
|
|
3837
4054
|
var result=document.getElementById('retryConnResult');
|
|
3838
4055
|
if(btn){btn.disabled=true;btn.textContent=t('sharing.retryConnection.loading');}
|
|
3839
4056
|
if(result) result.innerHTML='<span style="color:var(--text-muted)">'+t('sharing.retryConnection.loading')+'</span>';
|
|
4057
|
+
toast(t('sharing.retryConnection.loading'),'info');
|
|
3840
4058
|
try{
|
|
3841
4059
|
await loadSharingStatus(false);
|
|
3842
4060
|
var d=sharingStatusCache;
|
|
@@ -3844,9 +4062,11 @@ async function retryConnection(){
|
|
|
3844
4062
|
toast(t('sharing.retryConnection.success'),'success');
|
|
3845
4063
|
if(result) result.innerHTML='<span style="color:#22c55e">\\u2705 '+t('sharing.retryConnection.success')+'</span>';
|
|
3846
4064
|
}else{
|
|
4065
|
+
toast(t('sharing.retryConnection.fail'),'error');
|
|
3847
4066
|
if(result) result.innerHTML='<span style="color:#ef4444">'+t('sharing.retryConnection.fail')+'</span>';
|
|
3848
4067
|
}
|
|
3849
4068
|
}catch(e){
|
|
4069
|
+
toast(t('sharing.retryConnection.fail'),'error');
|
|
3850
4070
|
if(result) result.innerHTML='<span style="color:#ef4444">'+t('sharing.retryConnection.fail')+'</span>';
|
|
3851
4071
|
}
|
|
3852
4072
|
if(btn){btn.disabled=false;btn.textContent=t('sharing.retryConnection');}
|
|
@@ -3859,19 +4079,36 @@ async function retryHubJoin(){
|
|
|
3859
4079
|
var d=await r.json();
|
|
3860
4080
|
if(d.ok){
|
|
3861
4081
|
toast(t('sharing.retryJoin.success'),'success');
|
|
3862
|
-
|
|
4082
|
+
_lastSidebarFingerprint='';_lastSettingsFingerprint='';_lastSharingConnStatus='';
|
|
4083
|
+
setTimeout(function(){loadSharingStatus(true);},800);
|
|
3863
4084
|
}else{
|
|
3864
4085
|
toast(d.error||t('sharing.retryJoin.fail'),'error');
|
|
3865
4086
|
}
|
|
3866
4087
|
}catch(e){toast(t('sharing.retryJoin.fail')+': '+e.message,'error');}
|
|
3867
4088
|
}
|
|
3868
4089
|
|
|
4090
|
+
async function leaveTeam(){
|
|
4091
|
+
var teamName=(sharingStatusCache&&sharingStatusCache.connection&&sharingStatusCache.connection.teamName)||'';
|
|
4092
|
+
var msg=t('sharing.leaveTeam.confirm').replace('{team}',teamName||t('sharing.team.default'));
|
|
4093
|
+
if(!(await confirmModal(msg,{danger:true}))) return;
|
|
4094
|
+
try{
|
|
4095
|
+
var r=await fetch('/api/sharing/leave',{method:'POST',headers:{'Content-Type':'application/json'},body:'{}'});
|
|
4096
|
+
var d=await r.json();
|
|
4097
|
+
if(d.ok){
|
|
4098
|
+
toast(t('sharing.leaveTeam.success'),'success');
|
|
4099
|
+
showRestartOverlay(t('settings.restart.waiting'));
|
|
4100
|
+
}else{
|
|
4101
|
+
toast(d.error||t('sharing.leaveTeam.fail'),'error');
|
|
4102
|
+
}
|
|
4103
|
+
}catch(e){toast(t('sharing.leaveTeam.fail')+': '+e.message,'error');}
|
|
4104
|
+
}
|
|
4105
|
+
|
|
3869
4106
|
async function updateHubUsername(){
|
|
3870
4107
|
var input=document.getElementById('hubUsernameInput');
|
|
3871
4108
|
if(!input) return;
|
|
3872
4109
|
var newName=input.value.trim();
|
|
3873
4110
|
if(!newName||newName.length<2||newName.length>32){
|
|
3874
|
-
|
|
4111
|
+
alertModal(t('sharing.username.invalid'));
|
|
3875
4112
|
return;
|
|
3876
4113
|
}
|
|
3877
4114
|
try{
|
|
@@ -3882,17 +4119,17 @@ async function updateHubUsername(){
|
|
|
3882
4119
|
});
|
|
3883
4120
|
var d=await r.json();
|
|
3884
4121
|
if(d.error==='username_taken'){
|
|
3885
|
-
|
|
4122
|
+
alertModal(t('sharing.username.taken'),{danger:true});
|
|
3886
4123
|
return;
|
|
3887
4124
|
}
|
|
3888
4125
|
if(d.error){
|
|
3889
|
-
|
|
4126
|
+
alertModal(d.error,{danger:true});
|
|
3890
4127
|
return;
|
|
3891
4128
|
}
|
|
3892
4129
|
toast(t('sharing.username.updated'),'success');
|
|
3893
4130
|
loadSharingStatus(false);
|
|
3894
4131
|
}catch(e){
|
|
3895
|
-
|
|
4132
|
+
alertModal(t('sharing.username.error'),{danger:true});
|
|
3896
4133
|
}
|
|
3897
4134
|
}
|
|
3898
4135
|
|
|
@@ -3938,7 +4175,7 @@ async function approveSharingUser(userId,username){
|
|
|
3938
4175
|
try{
|
|
3939
4176
|
const r=await fetch('/api/sharing/approve-user',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:userId,username:username})});
|
|
3940
4177
|
const d=await r.json();
|
|
3941
|
-
if(d.ok){toast(t('toast.userApproved'),'success');loadSharingPendingUsers();loadSharingStatus(true);} else {toast(d.error||t('toast.approveFail'),'error');}
|
|
4178
|
+
if(d.ok){toast(t('toast.userApproved'),'success');loadSharingPendingUsers();loadSharingStatus(true);_lastAdminFingerprint='';loadAdminData();} else {toast(d.error||t('toast.approveFail'),'error');}
|
|
3942
4179
|
}catch(e){toast(t('toast.approveFail')+': '+e.message,'error');}
|
|
3943
4180
|
}
|
|
3944
4181
|
|
|
@@ -3946,23 +4183,15 @@ async function rejectSharingUser(userId,username){
|
|
|
3946
4183
|
try{
|
|
3947
4184
|
const r=await fetch('/api/sharing/reject-user',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:userId,username:username})});
|
|
3948
4185
|
const d=await r.json();
|
|
3949
|
-
if(d.ok){toast(t('toast.userRejected'),'success');loadSharingPendingUsers();} else {toast(d.error||t('toast.rejectFail'),'error');}
|
|
4186
|
+
if(d.ok){toast(t('toast.userRejected'),'success');loadSharingPendingUsers();_lastAdminFingerprint='';loadAdminData();} else {toast(d.error||t('toast.rejectFail'),'error');}
|
|
3950
4187
|
}catch(e){toast(t('toast.rejectFail')+': '+e.message,'error');}
|
|
3951
4188
|
}
|
|
3952
4189
|
|
|
3953
4190
|
/* ─── Team Setup Guide ─── */
|
|
3954
|
-
var TEAM_GUIDE_DISMISSED_KEY='memos-team-guide-dismissed';
|
|
3955
4191
|
function updateTeamGuide(sharingData){
|
|
3956
4192
|
var el=document.getElementById('teamSetupGuide');
|
|
3957
4193
|
if(!el) return;
|
|
3958
|
-
|
|
3959
|
-
var isConfigured=sharingData&&sharingData.enabled;
|
|
3960
|
-
el.style.display=isConfigured?'none':'block';
|
|
3961
|
-
}
|
|
3962
|
-
function dismissTeamGuide(){
|
|
3963
|
-
localStorage.setItem(TEAM_GUIDE_DISMISSED_KEY,'1');
|
|
3964
|
-
var el=document.getElementById('teamSetupGuide');
|
|
3965
|
-
if(el) el.style.display='none';
|
|
4194
|
+
el.style.display='block';
|
|
3966
4195
|
}
|
|
3967
4196
|
function guideGoToHub(role){
|
|
3968
4197
|
switchSettingsTab('hub',document.querySelector('.settings-tab-btn[data-tab="hub"]'));
|
|
@@ -3976,6 +4205,7 @@ function guideGoToHub(role){
|
|
|
3976
4205
|
|
|
3977
4206
|
/* ─── Hub Admin Panel ─── */
|
|
3978
4207
|
var adminDataCache={users:[],groups:[],tasks:[],skills:[],memories:[]};
|
|
4208
|
+
var _lastAdminFingerprint='';
|
|
3979
4209
|
var hubTasksCache=[];
|
|
3980
4210
|
var hubSkillsCache=[];
|
|
3981
4211
|
var ADMIN_PAGE_SIZE=20;
|
|
@@ -3994,7 +4224,7 @@ function adminPaginateHtml(total,page,refilterFn){
|
|
|
3994
4224
|
if(end<pages) html+=(end<pages-1?'<span class="pg-info">...</span>':'')+'<button class="pg-btn" onclick="'+refilterFn+'Page('+(pages-1)+')">'+pages+'</button>';
|
|
3995
4225
|
html+='<button class="pg-btn'+(page>=pages-1?' disabled':'')+'" onclick="'+refilterFn+'Page('+(page+1)+')">\\u2192</button>';
|
|
3996
4226
|
html+='<span class="pg-info">'+total+' '+t('pagination.total')+'</span>';
|
|
3997
|
-
|
|
4227
|
+
html+='</div>';
|
|
3998
4228
|
return html;
|
|
3999
4229
|
}
|
|
4000
4230
|
|
|
@@ -4056,12 +4286,12 @@ async function loadAdminData(){
|
|
|
4056
4286
|
var fetches;
|
|
4057
4287
|
if(isAdmin){
|
|
4058
4288
|
fetches=await Promise.all([
|
|
4059
|
-
|
|
4060
|
-
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
|
|
4064
|
-
|
|
4289
|
+
fetch('/api/sharing/users').then(function(r){return r.json();}),
|
|
4290
|
+
fetch('/api/admin/shared-tasks').then(function(r){return r.json();}),
|
|
4291
|
+
fetch('/api/admin/shared-skills').then(function(r){return r.json();}),
|
|
4292
|
+
fetch('/api/sharing/pending-users').then(function(r){return r.json();}),
|
|
4293
|
+
fetch('/api/admin/shared-memories').then(function(r){return r.json();})
|
|
4294
|
+
]);
|
|
4065
4295
|
}else{
|
|
4066
4296
|
fetches=await Promise.all([
|
|
4067
4297
|
Promise.resolve({users:[]}),
|
|
@@ -4072,11 +4302,23 @@ async function loadAdminData(){
|
|
|
4072
4302
|
]);
|
|
4073
4303
|
}
|
|
4074
4304
|
var usersR=fetches[0],tasksR=fetches[1],skillsR=fetches[2],pendingR=fetches[3],memoriesR=fetches[4];
|
|
4075
|
-
|
|
4076
|
-
|
|
4077
|
-
|
|
4078
|
-
|
|
4305
|
+
var _newUsers=Array.isArray(usersR.users)?usersR.users:[];
|
|
4306
|
+
var _newTasks=Array.isArray(tasksR.tasks)?tasksR.tasks:[];
|
|
4307
|
+
var _newSkills=Array.isArray(skillsR.skills)?skillsR.skills:[];
|
|
4308
|
+
var _newMemories=Array.isArray(memoriesR.memories)?memoriesR.memories:[];
|
|
4079
4309
|
var pending=isAdmin?(Array.isArray(pendingR.users)?pendingR.users:[]):[];
|
|
4310
|
+
var _fp=_newUsers.length+':'+_newTasks.length+':'+_newSkills.length+':'+_newMemories.length+':'+pending.length
|
|
4311
|
+
+':'+_newUsers.map(function(u){return u.id+'|'+(u.isOnline?1:0)+'|'+(u.role||'')+'|'+(u.status||'')+'|'+(u.username||'')+'|'+(u.memoryCount||0)+'|'+(u.taskCount||0)+'|'+(u.skillCount||0)}).join(',')
|
|
4312
|
+
+':'+_newMemories.map(function(m){return m.id}).join(',')
|
|
4313
|
+
+':'+_newTasks.map(function(t){return t.id+'|'+(t.status||'')}).join(',')
|
|
4314
|
+
+':'+_newSkills.map(function(s){return s.id+'|'+(s.status||'')}).join(',')
|
|
4315
|
+
+':'+pending.map(function(p){return p.id}).join(',');
|
|
4316
|
+
if(_fp===_lastAdminFingerprint) return;
|
|
4317
|
+
_lastAdminFingerprint=_fp;
|
|
4318
|
+
adminDataCache.users=_newUsers;
|
|
4319
|
+
adminDataCache.tasks=_newTasks;
|
|
4320
|
+
adminDataCache.skills=_newSkills;
|
|
4321
|
+
adminDataCache.memories=_newMemories;
|
|
4080
4322
|
adminDataCache._pending=pending;
|
|
4081
4323
|
var badge=document.getElementById('adminPendingBadge');
|
|
4082
4324
|
if(badge){if(pending.length>0){badge.textContent=pending.length;badge.style.display='inline';}else{badge.style.display='none';}}
|
|
@@ -4119,11 +4361,15 @@ function updateAdminTabsVisibility(){
|
|
|
4119
4361
|
if(subEl) subEl.textContent=isAdmin?t('admin.subtitle'):t('admin.subtitle.member');
|
|
4120
4362
|
}
|
|
4121
4363
|
|
|
4364
|
+
var _lastAdminStatsFp='';
|
|
4122
4365
|
function renderAdminStats(pendingCount){
|
|
4123
4366
|
var el=document.getElementById('adminStats');
|
|
4124
4367
|
if(!el) return;
|
|
4125
4368
|
var isAdmin=!!window._isHubAdmin;
|
|
4126
4369
|
var onlineCount=adminDataCache.users.filter(function(u){return !!u.isOnline;}).length;
|
|
4370
|
+
var sfp=onlineCount+':'+adminDataCache.users.length+':'+pendingCount+':'+(adminDataCache.memories||[]).length+':'+adminDataCache.tasks.length+':'+adminDataCache.skills.length+':'+isAdmin;
|
|
4371
|
+
if(sfp===_lastAdminStatsFp) return;
|
|
4372
|
+
_lastAdminStatsFp=sfp;
|
|
4127
4373
|
el.innerHTML=
|
|
4128
4374
|
(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>'+
|
|
4129
4375
|
'<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>':'')+
|
|
@@ -4145,9 +4391,10 @@ function auRelativeTime(ts){
|
|
|
4145
4391
|
return t('notif.timeAgo.day').replace('{n}',Math.floor(diff/86400000));
|
|
4146
4392
|
}
|
|
4147
4393
|
|
|
4148
|
-
function renderAdminUserCard(u,adminCount){
|
|
4394
|
+
function renderAdminUserCard(u,adminCount,myUserId){
|
|
4149
4395
|
var uid=escAttr(u.id);
|
|
4150
4396
|
var uname=escAttr(u.username||'');
|
|
4397
|
+
var isSelf=!!(myUserId&&u.id===myUserId);
|
|
4151
4398
|
var online=!!u.isOnline;
|
|
4152
4399
|
var statusCls=online?'online':'offline';
|
|
4153
4400
|
|
|
@@ -4181,7 +4428,9 @@ function renderAdminUserCard(u,adminCount){
|
|
|
4181
4428
|
var infoHtml='<div class="au-info">'+infoRows.join('')+'</div>';
|
|
4182
4429
|
|
|
4183
4430
|
var actions='';
|
|
4184
|
-
if(
|
|
4431
|
+
if(isSelf){
|
|
4432
|
+
actions+='<span style="font-size:11px;color:var(--text-muted);padding:4px 0">'+t('admin.selfHint')+'</span>';
|
|
4433
|
+
}else if(u.isOwner){
|
|
4185
4434
|
actions+='<span style="font-size:11px;color:var(--text-muted);padding:4px 0">'+t('admin.ownerHint')+'</span>';
|
|
4186
4435
|
}else if(u.role!=='admin'){
|
|
4187
4436
|
actions+='<button class="btn btn-sm btn-ghost" onclick="adminToggleRole("'+uid+'","admin")" style="color:var(--accent)">'+t('admin.promoteAdmin')+'</button>';
|
|
@@ -4192,14 +4441,15 @@ function renderAdminUserCard(u,adminCount){
|
|
|
4192
4441
|
}else{
|
|
4193
4442
|
actions+='<span style="font-size:11px;color:var(--text-muted);padding:4px 0">'+t('admin.lastAdminHint')+'</span>';
|
|
4194
4443
|
}
|
|
4195
|
-
var
|
|
4444
|
+
var badgesHtml='<div class="au-badges">'+statusLabel+
|
|
4445
|
+
'<span class="admin-badge '+(u.role==='admin'?'admin':'member')+'">'+esc(u.role||'member').toUpperCase()+'</span>'+
|
|
4446
|
+
(u.isOwner?'<span class="admin-badge owner">OWNER</span>':'')+
|
|
4447
|
+
'</div>';
|
|
4196
4448
|
|
|
4197
|
-
return '<div class="admin-card au-card au-'+statusCls+'"><div class="admin-card-header"><div style="flex:1;min-width:0
|
|
4198
|
-
|
|
4199
|
-
'</div>'+
|
|
4200
|
-
'<span class="admin-badge '+(u.role==='admin'?'admin':'member')+'">'+esc(u.role||'member')+'</span>'+ownerBadge+'</div>'+
|
|
4449
|
+
return '<div class="admin-card au-card au-'+statusCls+'"><div class="admin-card-header"><div style="flex:1;min-width:0">'+titleDisplay+editRow+'</div>'+
|
|
4450
|
+
badgesHtml+'</div>'+
|
|
4201
4451
|
contribHtml+infoHtml+
|
|
4202
|
-
(actions?'<div class="admin-card-actions" style="border-top:1px
|
|
4452
|
+
(actions?'<div class="admin-card-actions" style="border-top:1px solid rgba(99,102,241,.08);padding-top:12px;margin-top:6px">'+actions+'</div>':'')+
|
|
4203
4453
|
'</div>';
|
|
4204
4454
|
}
|
|
4205
4455
|
|
|
@@ -4213,14 +4463,15 @@ function renderAdminUsers(users,pending){
|
|
|
4213
4463
|
}
|
|
4214
4464
|
var html='';
|
|
4215
4465
|
if(pending&&pending.length>0){
|
|
4216
|
-
html+='<div
|
|
4466
|
+
html+='<div class="admin-pending-section"><h3>'+t('admin.pendingApproval')+' <span class="pending-count">'+pending.length+'</span></h3>';
|
|
4217
4467
|
for(var p=0;p<pending.length;p++){
|
|
4218
4468
|
var pu=pending[p];
|
|
4219
|
-
html+='<div class="admin-
|
|
4220
|
-
'<div class="
|
|
4221
|
-
'<div class="
|
|
4222
|
-
|
|
4223
|
-
'<button class="btn
|
|
4469
|
+
html+='<div class="admin-pending-card">'+
|
|
4470
|
+
'<div class="apc-name">'+esc(pu.username||pu.id||'Unknown')+'</div>'+
|
|
4471
|
+
'<div class="apc-meta"><span>\u{1F4BB} '+esc(pu.deviceName||'unknown')+'</span>'+(pu.createdAt?'<span>\u{1F552} '+formatDateTimeSeconds(pu.createdAt)+'</span>':'')+'</div>'+
|
|
4472
|
+
'<div class="apc-actions">'+
|
|
4473
|
+
'<button class="btn-approve" onclick="adminApproveUser("'+escAttr(pu.id)+'","'+escAttr(pu.username||'')+'")">'+t('admin.approve')+'</button>'+
|
|
4474
|
+
'<button class="btn-reject" onclick="adminRejectUser("'+escAttr(pu.id)+'")">'+t('admin.reject')+'</button>'+
|
|
4224
4475
|
'</div></div>';
|
|
4225
4476
|
}
|
|
4226
4477
|
html+='</div>';
|
|
@@ -4231,6 +4482,7 @@ function renderAdminUsers(users,pending){
|
|
|
4231
4482
|
offlineUsers.sort(function(a,b){return (b.lastActiveAt||0)-(a.lastActiveAt||0);});
|
|
4232
4483
|
var sorted=onlineUsers.concat(offlineUsers);
|
|
4233
4484
|
var adminCount=users.filter(function(x){return x.role==='admin';}).length;
|
|
4485
|
+
var myUserId=sharingStatusCache&&sharingStatusCache.connection&&sharingStatusCache.connection.user?sharingStatusCache.connection.user.id:null;
|
|
4234
4486
|
|
|
4235
4487
|
if(sorted.length===0){
|
|
4236
4488
|
html+='<div class="admin-empty"><span class="ae-icon">\u{1F465}</span>'+t('admin.noActiveUsers')+'</div>';
|
|
@@ -4239,13 +4491,13 @@ function renderAdminUsers(users,pending){
|
|
|
4239
4491
|
if(onlineUsers.length===0){
|
|
4240
4492
|
html+='<div style="font-size:12px;color:var(--text-muted);padding:8px 0 12px">\u2014</div>';
|
|
4241
4493
|
}else{
|
|
4242
|
-
for(var i=0;i<onlineUsers.length;i++) html+=renderAdminUserCard(onlineUsers[i],adminCount);
|
|
4494
|
+
for(var i=0;i<onlineUsers.length;i++) html+=renderAdminUserCard(onlineUsers[i],adminCount,myUserId);
|
|
4243
4495
|
}
|
|
4244
4496
|
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>';
|
|
4245
4497
|
if(offlineUsers.length===0){
|
|
4246
4498
|
html+='<div style="font-size:12px;color:var(--text-muted);padding:8px 0 12px">\u2014</div>';
|
|
4247
4499
|
}else{
|
|
4248
|
-
for(var j=0;j<offlineUsers.length;j++) html+=renderAdminUserCard(offlineUsers[j],adminCount);
|
|
4500
|
+
for(var j=0;j<offlineUsers.length;j++) html+=renderAdminUserCard(offlineUsers[j],adminCount,myUserId);
|
|
4249
4501
|
}
|
|
4250
4502
|
}
|
|
4251
4503
|
el.innerHTML=html;
|
|
@@ -4256,7 +4508,7 @@ async function adminApproveUser(userId,username){
|
|
|
4256
4508
|
try{
|
|
4257
4509
|
var r=await fetch('/api/sharing/approve-user',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:userId,username:username})});
|
|
4258
4510
|
var d=await r.json();
|
|
4259
|
-
if(d.ok){toast(t('toast.userApproved'),'success');loadAdminData();}else{toast(d.error||t('toast.approveFail'),'error');}
|
|
4511
|
+
if(d.ok){toast(t('toast.userApproved'),'success');_lastAdminFingerprint='';loadAdminData();}else{toast(d.error||t('toast.approveFail'),'error');}
|
|
4260
4512
|
}catch(e){toast(t('toast.approveFail')+': '+e.message,'error');}
|
|
4261
4513
|
}
|
|
4262
4514
|
async function adminRejectUser(userId){
|
|
@@ -4264,7 +4516,7 @@ async function adminRejectUser(userId){
|
|
|
4264
4516
|
try{
|
|
4265
4517
|
var r=await fetch('/api/sharing/reject-user',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:userId})});
|
|
4266
4518
|
var d=await r.json();
|
|
4267
|
-
if(d.ok){toast(t('toast.userRejected'),'success');loadAdminData();}else{toast(d.error||t('toast.rejectFail'),'error');}
|
|
4519
|
+
if(d.ok){toast(t('toast.userRejected'),'success');_lastAdminFingerprint='';loadAdminData();}else{toast(d.error||t('toast.rejectFail'),'error');}
|
|
4268
4520
|
}catch(e){toast(t('toast.rejectFail')+': '+e.message,'error');}
|
|
4269
4521
|
}
|
|
4270
4522
|
async function adminToggleRole(userId,newRole){
|
|
@@ -4273,7 +4525,14 @@ async function adminToggleRole(userId,newRole){
|
|
|
4273
4525
|
try{
|
|
4274
4526
|
var r=await fetch('/api/sharing/change-role',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:userId,role:newRole})});
|
|
4275
4527
|
var d=await r.json();
|
|
4276
|
-
if(d.ok){
|
|
4528
|
+
if(d.ok){
|
|
4529
|
+
toast(t('toast.roleChanged'),'success');
|
|
4530
|
+
_lastAdminFingerprint='';
|
|
4531
|
+
_lastSettingsFingerprint='';
|
|
4532
|
+
_lastSidebarFingerprint='';
|
|
4533
|
+
await loadSharingStatus(false);
|
|
4534
|
+
loadAdminData();
|
|
4535
|
+
}
|
|
4277
4536
|
else if(d.error==='cannot_demote_owner'){toast(t('admin.ownerHint'),'error');}
|
|
4278
4537
|
else{toast(d.error||t('toast.roleChangeFail'),'error');}
|
|
4279
4538
|
}catch(e){toast(t('toast.roleChangeFail')+': '+e.message,'error');}
|
|
@@ -4299,13 +4558,24 @@ async function adminSaveEditName(userId){
|
|
|
4299
4558
|
var inputEl=document.getElementById('au_input_'+userId);
|
|
4300
4559
|
if(!inputEl) return;
|
|
4301
4560
|
var newName=inputEl.value.trim();
|
|
4302
|
-
if(!newName||newName.length<2||newName.length>32){
|
|
4561
|
+
if(!newName||newName.length<2||newName.length>32){
|
|
4562
|
+
alertModal(t('toast.invalidUsername'),{title:t('admin.editName')});
|
|
4563
|
+
return;
|
|
4564
|
+
}
|
|
4303
4565
|
inputEl.disabled=true;
|
|
4304
4566
|
try{
|
|
4305
4567
|
var r=await fetch('/api/sharing/rename-user',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:userId,username:newName})});
|
|
4306
4568
|
var d=await r.json();
|
|
4307
|
-
if(d.ok){toast(t('toast.usernameChanged'),'success');
|
|
4308
|
-
|
|
4569
|
+
if(d.ok){toast(t('toast.usernameChanged'),'success');adminCancelEditName(userId);loadAdminData();}
|
|
4570
|
+
else{
|
|
4571
|
+
inputEl.disabled=false;
|
|
4572
|
+
if(d.error==='username_taken'){
|
|
4573
|
+
alertModal(t('sharing.username.taken'),{title:t('admin.editName'),danger:true});
|
|
4574
|
+
}else{
|
|
4575
|
+
alertModal(d.error||t('toast.renameFail'),{title:t('admin.editName'),danger:true});
|
|
4576
|
+
}
|
|
4577
|
+
}
|
|
4578
|
+
}catch(e){inputEl.disabled=false;alertModal(t('toast.renameFail'),{title:t('admin.editName'),danger:true});}
|
|
4309
4579
|
}
|
|
4310
4580
|
|
|
4311
4581
|
async function adminRemoveUser(userId,username){
|
|
@@ -4314,7 +4584,7 @@ async function adminRemoveUser(userId,username){
|
|
|
4314
4584
|
try{
|
|
4315
4585
|
var r=await fetch('/api/sharing/remove-user',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:userId,cleanResources:clean})});
|
|
4316
4586
|
var d=await r.json();
|
|
4317
|
-
if(d.ok){toast(t('toast.userRemoved'),'success');loadAdminData();}
|
|
4587
|
+
if(d.ok){toast(t('toast.userRemoved'),'success');_lastAdminFingerprint='';loadAdminData();}
|
|
4318
4588
|
else if(d.error==='cannot_remove_owner'){toast(t('admin.ownerHint'),'error');}
|
|
4319
4589
|
else{toast(d.error||t('toast.removeFail'),'error');}
|
|
4320
4590
|
}catch(e){toast(t('toast.removeFail')+': '+e.message,'error');}
|
|
@@ -4383,7 +4653,7 @@ function renderAdminTasks(tasks){
|
|
|
4383
4653
|
'<div class="admin-card-header"><div class="admin-card-title">'+esc(tk.title||tk.id)+'</div></div>'+
|
|
4384
4654
|
'<div class="admin-card-tags">'+
|
|
4385
4655
|
'<div class="admin-card-tags-left">'+
|
|
4386
|
-
'<span class="admin-card-tag tag-owner">\u{1F464} '+
|
|
4656
|
+
'<span class="admin-card-tag tag-owner">\u{1F464} '+fmtOwner(tk)+'</span>'+
|
|
4387
4657
|
(tk.status?'<span class="admin-card-tag tag-status">'+esc(tk.status)+'</span>':'')+
|
|
4388
4658
|
(tk.chunkCount!=null?'<span class="admin-card-tag tag-kind">\u{1F4DD} '+tk.chunkCount+' '+t('admin.chunks')+'</span>':'')+
|
|
4389
4659
|
'</div>'+
|
|
@@ -4445,7 +4715,7 @@ function renderAdminSkills(skills){
|
|
|
4445
4715
|
'<div class="admin-card-header"><div class="admin-card-title">'+esc(s.name||s.id)+'</div></div>'+
|
|
4446
4716
|
'<div class="admin-card-tags">'+
|
|
4447
4717
|
'<div class="admin-card-tags-left">'+
|
|
4448
|
-
'<span class="admin-card-tag tag-owner">\u{1F464} '+
|
|
4718
|
+
'<span class="admin-card-tag tag-owner">\u{1F464} '+fmtOwner(s)+'</span>'+
|
|
4449
4719
|
(s.status?'<span class="admin-card-tag tag-status">'+esc(s.status)+'</span>':'')+
|
|
4450
4720
|
(s.version!=null?'<span class="admin-card-tag tag-version">v'+s.version+'</span>':'')+
|
|
4451
4721
|
(qs!=null?'<span class="admin-card-tag tag-kind">\u2605 '+Number(qs).toFixed(1)+'</span>':'')+
|
|
@@ -4510,7 +4780,7 @@ function renderAdminMemories(memories){
|
|
|
4510
4780
|
'<div class="admin-card-header"><div class="admin-card-title">'+esc(m.summary||m.content?.slice(0,80)||m.id)+'</div></div>'+
|
|
4511
4781
|
'<div class="admin-card-tags">'+
|
|
4512
4782
|
'<div class="admin-card-tags-left">'+
|
|
4513
|
-
'<span class="admin-card-tag tag-owner">\u{1F464} '+
|
|
4783
|
+
'<span class="admin-card-tag tag-owner">\u{1F464} '+fmtOwner(m)+'</span>'+
|
|
4514
4784
|
(m.role?'<span class="admin-card-tag tag-role">'+esc(m.role)+'</span>':'')+
|
|
4515
4785
|
(m.kind?'<span class="admin-card-tag tag-kind">'+esc(m.kind)+'</span>':'')+
|
|
4516
4786
|
'</div>'+
|
|
@@ -4554,7 +4824,7 @@ function toggleAdminMemoryCard(cardId,idx){
|
|
|
4554
4824
|
(m.kind?'<span class="meta-item">'+t('admin.kind')+esc(m.kind)+'</span>':'')+
|
|
4555
4825
|
(m.role?'<span class="meta-item">'+t('admin.role')+esc(m.role)+'</span>':'')+
|
|
4556
4826
|
(m.visibility?'<span class="meta-item">'+t('admin.visibility')+esc(m.visibility)+'</span>':'')+
|
|
4557
|
-
'<span class="meta-item">'+t('admin.owner')+
|
|
4827
|
+
'<span class="meta-item">'+t('admin.owner')+fmtOwner(m)+'</span>'+
|
|
4558
4828
|
(m.groupName?'<span class="meta-item">'+t('admin.group')+esc(m.groupName)+'</span>':'')+
|
|
4559
4829
|
'<span class="meta-item">'+new Date(m.updatedAt||m.createdAt||0).toLocaleString(dateLoc())+'</span>'+
|
|
4560
4830
|
'</div>';
|
|
@@ -4610,7 +4880,7 @@ async function toggleAdminTaskCard(cardId,idx){
|
|
|
4610
4880
|
var metaHtml='<div class="admin-card-detail-meta admin-task-meta">'+
|
|
4611
4881
|
(tk.status?'<span class="meta-item"><span class="task-status-badge '+tk.status+'">'+esc(tk.status)+'</span></span>':'')+
|
|
4612
4882
|
(tk.visibility?'<span class="meta-item">'+t('admin.visibility')+esc(tk.visibility)+'</span>':'')+
|
|
4613
|
-
'<span class="meta-item">'+t('admin.owner')+
|
|
4883
|
+
'<span class="meta-item">'+t('admin.owner')+fmtOwner(tk)+'</span>'+
|
|
4614
4884
|
(tk.groupName?'<span class="meta-item">'+t('admin.group')+esc(tk.groupName)+'</span>':'')+
|
|
4615
4885
|
(task.chunks&&task.chunks.length?'<span class="meta-item">\u{1F4AC} '+task.chunks.length+' '+t('tasks.chunks.label')+'</span>':'')+
|
|
4616
4886
|
(task.startedAt?'<span class="meta-item">\u{1F4C5} '+formatDateTimeSeconds(task.startedAt)+'</span>':'')+
|
|
@@ -4697,7 +4967,7 @@ async function toggleAdminSkillCard(cardId,idx){
|
|
|
4697
4967
|
(localSkill.status?'<span class="meta-item"><span class="skill-badge status-'+localSkill.status+'">'+esc(localSkill.status)+'</span></span>':'')+
|
|
4698
4968
|
(sk.visibility?'<span class="meta-item">'+t('admin.visibility')+esc(sk.visibility||'hub')+'</span>':'')+
|
|
4699
4969
|
(qs!=null?'<span class="meta-item"><span class="skill-badge quality '+(qs>=7?'high':qs>=5?'mid':'low')+'">\u2605 '+Number(qs).toFixed(1)+'/10</span></span>':'')+
|
|
4700
|
-
'<span class="meta-item">'+t('admin.owner')+
|
|
4970
|
+
'<span class="meta-item">'+t('admin.owner')+fmtOwner(sk)+'</span>'+
|
|
4701
4971
|
(sk.groupName?'<span class="meta-item">'+t('admin.group')+esc(sk.groupName)+'</span>':'')+
|
|
4702
4972
|
'<span class="meta-item">'+t('admin.updated')+new Date(sk.updatedAt||sk.createdAt||0).toLocaleString(dateLoc())+'</span>'+
|
|
4703
4973
|
'</div>';
|
|
@@ -4766,7 +5036,7 @@ function renderSharingMemorySearchResults(data,query){
|
|
|
4766
5036
|
'<div class="summary">'+(idx+1)+'. '+esc(hit.summary||'(no summary)')+'</div>'+
|
|
4767
5037
|
'<div class="excerpt">'+esc(hit.excerpt||'')+'</div>'+
|
|
4768
5038
|
'<div class="hub-hit-meta">'+
|
|
4769
|
-
'<span class="meta-chip">owner: '+
|
|
5039
|
+
'<span class="meta-chip">owner: '+fmtOwner(hit)+'</span>'+
|
|
4770
5040
|
(hit.groupName?'<span class="meta-chip">group: '+esc(hit.groupName)+'</span>':'')+
|
|
4771
5041
|
'<span class="meta-chip">visibility: '+esc(hit.visibility||'hub')+'</span>'+
|
|
4772
5042
|
'</div>'+
|
|
@@ -4851,7 +5121,7 @@ function openHubTaskDetailFromCache(cacheKey,idx){
|
|
|
4851
5121
|
var meta=[
|
|
4852
5122
|
'<span class="meta-item">\\u{1F310} '+t('scope.hub')+'</span>',
|
|
4853
5123
|
task.status?'<span class="meta-item"><span class="task-status-badge '+task.status+'">'+esc(task.status)+'</span></span>':'',
|
|
4854
|
-
'<span class="meta-item">'+t('admin.owner')+
|
|
5124
|
+
'<span class="meta-item">'+t('admin.owner')+fmtOwner(task)+'</span>',
|
|
4855
5125
|
task.groupName?'<span class="meta-item">'+t('admin.group')+esc(task.groupName)+'</span>':'',
|
|
4856
5126
|
task.visibility?'<span class="meta-item">'+t('admin.visibility')+esc(task.visibility)+'</span>':'',
|
|
4857
5127
|
task.chunkCount!=null?'<span class="meta-item">\\u{1F4DD} '+esc(String(task.chunkCount))+' '+t('tasks.chunks.label')+'</span>':'',
|
|
@@ -4882,14 +5152,14 @@ function openHubSkillDetailFromCache(cacheKey,idx){
|
|
|
4882
5152
|
skill.status?'<span class="meta-item"><span class="skill-badge status-'+skill.status+'">'+esc(skill.status)+'</span></span>':'',
|
|
4883
5153
|
'<span class="meta-item">visibility: '+esc(skill.visibility||'hub')+'</span>',
|
|
4884
5154
|
qsBadge,
|
|
4885
|
-
'<span class="meta-item">'+t('admin.owner')+
|
|
5155
|
+
'<span class="meta-item">'+t('admin.owner')+fmtOwner(skill)+'</span>',
|
|
4886
5156
|
skill.groupName?'<span class="meta-item">'+t('admin.group')+esc(skill.groupName)+'</span>':'',
|
|
4887
5157
|
(skill.updatedAt||skill.createdAt)?'<span class="meta-item">'+t('admin.updated')+new Date(skill.updatedAt||skill.createdAt).toLocaleString(dateLoc())+'</span>':'',
|
|
4888
5158
|
].filter(Boolean);
|
|
4889
5159
|
document.getElementById('skillDetailMeta').innerHTML=meta.join('');
|
|
4890
5160
|
document.getElementById('skillDetailDesc').textContent=skill.description||'';
|
|
4891
5161
|
document.getElementById('skillFilesList').innerHTML='';
|
|
4892
|
-
document.getElementById('skillDetailContent').innerHTML=skill.content?
|
|
5162
|
+
document.getElementById('skillDetailContent').innerHTML=skill.content?renderSkillMarkdown(skill.content):'';
|
|
4893
5163
|
document.getElementById('skillVersionsList').innerHTML='';
|
|
4894
5164
|
document.getElementById('skillRelatedTasks').innerHTML='';
|
|
4895
5165
|
var visBtn=document.getElementById('skillVisibilityBtn');
|
|
@@ -4932,6 +5202,7 @@ function openScopeSelectorModal(resourceType, resourceId, currentScope, onConfir
|
|
|
4932
5202
|
var existing=document.getElementById('scopeSelectorOverlay');
|
|
4933
5203
|
if(existing) existing.remove();
|
|
4934
5204
|
var teamEnabled=sharingStatusCache&&sharingStatusCache.enabled;
|
|
5205
|
+
var teamConnected=teamEnabled&&sharingStatusCache.connection&&sharingStatusCache.connection.connected;
|
|
4935
5206
|
var overlay=document.createElement('div');
|
|
4936
5207
|
overlay.id='scopeSelectorOverlay';
|
|
4937
5208
|
overlay.style.cssText='position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.5);backdrop-filter:blur(6px);z-index:10000;display:flex;align-items:center;justify-content:center;animation:fadeIn 0.12s ease';
|
|
@@ -4945,7 +5216,7 @@ function openScopeSelectorModal(resourceType, resourceId, currentScope, onConfir
|
|
|
4945
5216
|
for(var i=0;i<scopes.length;i++){
|
|
4946
5217
|
var sc=scopes[i];
|
|
4947
5218
|
var isCurrent=sc===currentScope;
|
|
4948
|
-
var isDisabled=sc==='team'
|
|
5219
|
+
var isDisabled=sc==='team'&&(!teamEnabled||!teamConnected);
|
|
4949
5220
|
var color=getScopeColor(sc);
|
|
4950
5221
|
var cursor=isDisabled?'not-allowed':'pointer';
|
|
4951
5222
|
var opacity=isDisabled?'0.4':'1';
|
|
@@ -5014,7 +5285,8 @@ async function confirmScopeSelection(){
|
|
|
5014
5285
|
if(st.onConfirm) st.onConfirm(newScope);
|
|
5015
5286
|
else loadAll();
|
|
5016
5287
|
}else{
|
|
5017
|
-
|
|
5288
|
+
var errMsg=d.error==='inactive_memory'?t('share.scope.inactiveDisabled'):(d.message||d.error||t('share.scope.changeFail'));
|
|
5289
|
+
toast(errMsg,'error');
|
|
5018
5290
|
}
|
|
5019
5291
|
}catch(e){toast(t('share.scope.changeFail')+': '+e.message,'error');}
|
|
5020
5292
|
}
|
|
@@ -5265,6 +5537,13 @@ function parseMemoryAddEntries(out){
|
|
|
5265
5537
|
return results;
|
|
5266
5538
|
}
|
|
5267
5539
|
|
|
5540
|
+
function recallOriginBadge(origin){
|
|
5541
|
+
if(origin==='local-shared') return '<span class="recall-origin local-shared">'+t('recall.origin.localShared')+'</span>';
|
|
5542
|
+
if(origin==='hub-memory') return '<span class="recall-origin hub-memory">'+t('recall.origin.hubMemory')+'</span>';
|
|
5543
|
+
if(origin==='hub-remote') return '<span class="recall-origin hub-remote">'+t('recall.origin.hubRemote')+'</span>';
|
|
5544
|
+
return '';
|
|
5545
|
+
}
|
|
5546
|
+
|
|
5268
5547
|
function buildLogSummary(lg){
|
|
5269
5548
|
let inputObj=null;
|
|
5270
5549
|
try{inputObj=JSON.parse(lg.input);}catch(_){}
|
|
@@ -5289,8 +5568,9 @@ function buildLogSummary(lg){
|
|
|
5289
5568
|
var scoreClass=c.score>=0.7?'high':c.score>=0.5?'mid':'low';
|
|
5290
5569
|
var shortText=escapeHtml(c.summary||c.content||c.original_excerpt||'');
|
|
5291
5570
|
var fullText=escapeHtml(c.content||c.original_excerpt||c.summary||'');
|
|
5571
|
+
var oBadge=recallOriginBadge(c.origin);
|
|
5292
5572
|
html+='<div class="recall-item" onclick="event.stopPropagation();this.classList.toggle(\\\'expanded\\\')">';
|
|
5293
|
-
html+='<div class="recall-item-head"><span class="recall-score '+scoreClass+'">'+c.score.toFixed(2)+'</span><span class="log-msg-role '+(c.role||'user')+'">'+(c.role||'user')+'</span
|
|
5573
|
+
html+='<div class="recall-item-head"><span class="recall-score '+scoreClass+'">'+c.score.toFixed(2)+'</span><span class="log-msg-role '+(c.role||'user')+'">'+(c.role||'user')+'</span>'+oBadge+'<span class="recall-summary-short">'+shortText+'</span><span class="recall-expand-icon">\u25B6</span></div>';
|
|
5294
5574
|
html+='<div class="recall-summary-full">'+fullText+'</div>';
|
|
5295
5575
|
html+='</div>';
|
|
5296
5576
|
});
|
|
@@ -5303,8 +5583,9 @@ function buildLogSummary(lg){
|
|
|
5303
5583
|
var scoreClass=f.score>=0.7?'high':f.score>=0.5?'mid':'low';
|
|
5304
5584
|
var shortText=escapeHtml(f.summary||f.content||f.original_excerpt||'');
|
|
5305
5585
|
var fullText=escapeHtml(f.content||f.original_excerpt||f.summary||'');
|
|
5586
|
+
var oBadge=recallOriginBadge(f.origin);
|
|
5306
5587
|
html+='<div class="recall-item" onclick="event.stopPropagation();this.classList.toggle(\\\'expanded\\\')">';
|
|
5307
|
-
html+='<div class="recall-item-head"><span class="recall-score '+scoreClass+'">'+f.score.toFixed(2)+'</span><span class="log-msg-role '+(f.role||'user')+'">'+(f.role||'user')+'</span
|
|
5588
|
+
html+='<div class="recall-item-head"><span class="recall-score '+scoreClass+'">'+f.score.toFixed(2)+'</span><span class="log-msg-role '+(f.role||'user')+'">'+(f.role||'user')+'</span>'+oBadge+'<span class="recall-summary-short">'+shortText+'</span><span class="recall-expand-icon">\u25B6</span></div>';
|
|
5308
5589
|
html+='<div class="recall-summary-full">'+fullText+'</div>';
|
|
5309
5590
|
html+='</div>';
|
|
5310
5591
|
});
|
|
@@ -5368,8 +5649,9 @@ function buildRecallDetailHtml(rd){
|
|
|
5368
5649
|
var scoreClass=c.score>=0.7?'high':c.score>=0.5?'mid':'low';
|
|
5369
5650
|
var shortText=escapeHtml(c.summary||c.content||c.original_excerpt||'');
|
|
5370
5651
|
var fullText=escapeHtml(c.content||c.original_excerpt||c.summary||'');
|
|
5652
|
+
var oBadge=recallOriginBadge(c.origin);
|
|
5371
5653
|
html+='<div class="recall-item" onclick="event.stopPropagation();this.classList.toggle(\\\'expanded\\\')">';
|
|
5372
|
-
html+='<div class="recall-item-head"><span class="recall-idx">'+(i+1)+'</span><span class="recall-score '+scoreClass+'">'+c.score.toFixed(3)+'</span><span class="log-msg-role '+(c.role||'user')+'">'+(c.role||'user')+'</span
|
|
5654
|
+
html+='<div class="recall-item-head"><span class="recall-idx">'+(i+1)+'</span><span class="recall-score '+scoreClass+'">'+c.score.toFixed(3)+'</span><span class="log-msg-role '+(c.role||'user')+'">'+(c.role||'user')+'</span>'+oBadge+'<span class="recall-summary-short">'+shortText+'</span><span class="recall-expand-icon">\u25B6</span></div>';
|
|
5373
5655
|
html+='<div class="recall-summary-full">'+fullText+'</div>';
|
|
5374
5656
|
html+='</div>';
|
|
5375
5657
|
});
|
|
@@ -5383,8 +5665,9 @@ function buildRecallDetailHtml(rd){
|
|
|
5383
5665
|
var scoreClass=f.score>=0.7?'high':f.score>=0.5?'mid':'low';
|
|
5384
5666
|
var shortText=escapeHtml(f.summary||f.content||f.original_excerpt||'');
|
|
5385
5667
|
var fullText=escapeHtml(f.content||f.original_excerpt||f.summary||'');
|
|
5668
|
+
var oBadge=recallOriginBadge(f.origin);
|
|
5386
5669
|
html+='<div class="recall-item" onclick="event.stopPropagation();this.classList.toggle(\\\'expanded\\\')">';
|
|
5387
|
-
html+='<div class="recall-item-head"><span class="recall-idx">'+(i+1)+'</span><span class="recall-score '+scoreClass+'">'+f.score.toFixed(3)+'</span><span class="log-msg-role '+(f.role||'user')+'">'+(f.role||'user')+'</span
|
|
5670
|
+
html+='<div class="recall-item-head"><span class="recall-idx">'+(i+1)+'</span><span class="recall-score '+scoreClass+'">'+f.score.toFixed(3)+'</span><span class="log-msg-role '+(f.role||'user')+'">'+(f.role||'user')+'</span>'+oBadge+'<span class="recall-summary-short">'+shortText+'</span><span class="recall-expand-icon">\u25B6</span></div>';
|
|
5388
5671
|
html+='<div class="recall-summary-full">'+fullText+'</div>';
|
|
5389
5672
|
html+='</div>';
|
|
5390
5673
|
});
|
|
@@ -5514,12 +5797,12 @@ function setTaskStatusFilter(btn,status){
|
|
|
5514
5797
|
loadTasks();
|
|
5515
5798
|
}
|
|
5516
5799
|
|
|
5517
|
-
async function loadTasks(){
|
|
5800
|
+
async function loadTasks(silent){
|
|
5518
5801
|
const scope=document.getElementById('taskSearchScope')?document.getElementById('taskSearchScope').value:taskSearchScope;
|
|
5519
5802
|
taskSearchScope=scope||'local';
|
|
5520
5803
|
if(taskSearchScope==='hub'){ return loadHubTasks(); }
|
|
5521
5804
|
const list=document.getElementById('tasksList');
|
|
5522
|
-
list.innerHTML='<div class="spinner"></div>';
|
|
5805
|
+
if(!silent) list.innerHTML='<div class="spinner"></div>';
|
|
5523
5806
|
try{
|
|
5524
5807
|
const params=new URLSearchParams({limit:String(TASKS_PER_PAGE),offset:String(tasksPage*TASKS_PER_PAGE)});
|
|
5525
5808
|
if(tasksStatusFilter) params.set('status',tasksStatusFilter);
|
|
@@ -5533,6 +5816,14 @@ async function loadTasks(){
|
|
|
5533
5816
|
fetch('/api/tasks?status=completed&limit=1&offset=0&'+baseP).then(r=>r.json()),
|
|
5534
5817
|
fetch('/api/tasks?status=skipped&limit=1&offset=0&'+baseP).then(r=>r.json())
|
|
5535
5818
|
]);
|
|
5819
|
+
if(silent){
|
|
5820
|
+
var fp=JSON.stringify((data.tasks||[]).map(function(tk){return tk.id+'|'+tk.status+'|'+(tk.updatedAt||tk.startedAt)}));
|
|
5821
|
+
fp+=':'+allD.total+':'+activeD.total+':'+compD.total+':'+skipD.total;
|
|
5822
|
+
if(fp===_lastTasksFingerprint) return;
|
|
5823
|
+
_lastTasksFingerprint=fp;
|
|
5824
|
+
}else{
|
|
5825
|
+
_lastTasksFingerprint='';
|
|
5826
|
+
}
|
|
5536
5827
|
document.getElementById('tasksTotalCount').textContent=formatNum(allD.total);
|
|
5537
5828
|
document.getElementById('tasksActiveCount').textContent=formatNum(activeD.total);
|
|
5538
5829
|
document.getElementById('tasksCompletedCount').textContent=formatNum(compD.total);
|
|
@@ -5818,17 +6109,17 @@ function updateSkillCardBadge(skillId,newScope){
|
|
|
5818
6109
|
}
|
|
5819
6110
|
}
|
|
5820
6111
|
|
|
5821
|
-
async function loadSkills(){
|
|
6112
|
+
async function loadSkills(silent){
|
|
5822
6113
|
const list=document.getElementById('skillsList');
|
|
5823
6114
|
const hubList=document.getElementById('hubSkillsList');
|
|
5824
|
-
list.innerHTML='<div class="spinner"></div>';
|
|
6115
|
+
if(!silent) list.innerHTML='<div class="spinner"></div>';
|
|
5825
6116
|
var hubSection=document.getElementById('hubSkillsSection');
|
|
5826
6117
|
if(hubList){
|
|
5827
6118
|
if(skillSearchScope==='local'||skillSearchScope==='allLocal'){
|
|
5828
6119
|
if(hubSection) hubSection.style.display='none';
|
|
5829
6120
|
}else{
|
|
5830
6121
|
if(hubSection) hubSection.style.display='block';
|
|
5831
|
-
hubList.innerHTML='<div class="spinner"></div>';
|
|
6122
|
+
if(!silent) hubList.innerHTML='<div class="spinner"></div>';
|
|
5832
6123
|
}
|
|
5833
6124
|
}
|
|
5834
6125
|
|
|
@@ -5852,6 +6143,13 @@ async function loadSkills(){
|
|
|
5852
6143
|
return haystack.includes(q);
|
|
5853
6144
|
});
|
|
5854
6145
|
}
|
|
6146
|
+
if(silent){
|
|
6147
|
+
var fp=JSON.stringify(localSkills.map(function(s){return s.id+'|'+s.status+'|'+s.version+'|'+(s.visibility||'')}));
|
|
6148
|
+
if(fp===_lastSkillsFingerprint) return;
|
|
6149
|
+
_lastSkillsFingerprint=fp;
|
|
6150
|
+
}else{
|
|
6151
|
+
_lastSkillsFingerprint='';
|
|
6152
|
+
}
|
|
5855
6153
|
|
|
5856
6154
|
const renderLocalCards=function(skills){
|
|
5857
6155
|
if(!skills||skills.length===0){
|
|
@@ -5910,7 +6208,8 @@ async function loadSkills(){
|
|
|
5910
6208
|
|
|
5911
6209
|
if(!query){
|
|
5912
6210
|
if(hubSection) hubSection.style.display='block';
|
|
5913
|
-
|
|
6211
|
+
var localIds=new Set(localSkills.map(function(s){return s.id;}));
|
|
6212
|
+
if(hubList){ loadHubSkills(hubList, localIds); }
|
|
5914
6213
|
document.getElementById('skillSearchMeta').textContent=t('skills.search.local')+' '+localSkills.length;
|
|
5915
6214
|
document.getElementById('skillsTotalCount').textContent=formatNum(localSkills.length);
|
|
5916
6215
|
document.getElementById('skillsActiveCount').textContent=formatNum(localSkills.filter(s=>s.status==='active').length);
|
|
@@ -5944,7 +6243,7 @@ async function loadSkills(){
|
|
|
5944
6243
|
'<div class="summary">'+esc(skill.name)+'</div>'+
|
|
5945
6244
|
'<div class="excerpt">'+esc(skill.description||'')+'</div>'+
|
|
5946
6245
|
'<div class="hub-skill-meta">'+
|
|
5947
|
-
'<span class="meta-chip">owner: '+
|
|
6246
|
+
'<span class="meta-chip">owner: '+fmtOwner(skill)+'</span>'+
|
|
5948
6247
|
(skill.groupName?'<span class="meta-chip">group: '+esc(skill.groupName)+'</span>':'')+
|
|
5949
6248
|
'<span class="meta-chip">visibility: '+esc(skill.visibility||'hub')+'</span>'+
|
|
5950
6249
|
(skill.version!=null?'<span class="meta-chip">v'+skill.version+'</span>':'')+
|
|
@@ -5991,12 +6290,12 @@ async function loadHubTasks(){
|
|
|
5991
6290
|
return '<div class="task-card" onclick="openHubTaskDetailFromCache(\\x27hub\\x27,'+idx+')" style="cursor:pointer">'+
|
|
5992
6291
|
'<div class="task-card-top">'+
|
|
5993
6292
|
'<div class="task-card-title">'+esc(task.title||'(no title)')+'</div>'+
|
|
5994
|
-
'<div class="task-card-badges"
|
|
6293
|
+
'<div class="task-card-badges">'+renderScopeBadge('team')+'</div>'+
|
|
5995
6294
|
'</div>'+
|
|
5996
6295
|
(task.summary?'<div class="task-card-summary">'+esc(task.summary)+'</div>':'')+
|
|
5997
6296
|
'<div class="task-card-bottom">'+
|
|
5998
6297
|
(timeStr?'<span class="tag"><span class="icon">\\u{1F4C5}</span> '+timeStr+'</span>':'')+
|
|
5999
|
-
'<span class="tag"><span class="icon">\\u{1F464}</span> '+
|
|
6298
|
+
'<span class="tag"><span class="icon">\\u{1F464}</span> '+fmtOwner(task)+'</span>'+
|
|
6000
6299
|
(task.chunkCount!=null?'<span class="tag"><span class="icon">\\u{1F4DD}</span> '+task.chunkCount+' '+t('tasks.chunks.label')+'</span>':'')+
|
|
6001
6300
|
'</div>'+
|
|
6002
6301
|
'</div>';
|
|
@@ -6008,7 +6307,7 @@ async function loadHubTasks(){
|
|
|
6008
6307
|
}
|
|
6009
6308
|
}
|
|
6010
6309
|
|
|
6011
|
-
async function loadHubSkills(hubList){
|
|
6310
|
+
async function loadHubSkills(hubList, localIds){
|
|
6012
6311
|
if(!hubList) hubList=document.getElementById('hubSkillsList');
|
|
6013
6312
|
if(!hubList) return;
|
|
6014
6313
|
var hubSection=document.getElementById('hubSkillsSection');
|
|
@@ -6016,7 +6315,8 @@ async function loadHubSkills(hubList){
|
|
|
6016
6315
|
try{
|
|
6017
6316
|
const r=await fetch('/api/sharing/skills/list?limit=40');
|
|
6018
6317
|
const d=await r.json();
|
|
6019
|
-
|
|
6318
|
+
var allSkills=Array.isArray(d.skills)?d.skills:[];
|
|
6319
|
+
const skills=localIds?allSkills.filter(function(s){return !localIds.has(s.sourceSkillId);}):allSkills;
|
|
6020
6320
|
hubSkillsCache=skills;
|
|
6021
6321
|
if(!skills.length){
|
|
6022
6322
|
if(hubSection) hubSection.style.display='none';
|
|
@@ -6028,12 +6328,12 @@ async function loadHubSkills(hubList){
|
|
|
6028
6328
|
'<div class="summary">'+esc(skill.name)+'</div>'+
|
|
6029
6329
|
'<div class="excerpt">'+esc(skill.description||'')+'</div>'+
|
|
6030
6330
|
'<div class="hub-skill-meta">'+
|
|
6031
|
-
'<span class="meta-chip">owner: '+
|
|
6331
|
+
'<span class="meta-chip">owner: '+fmtOwner(skill)+'</span>'+
|
|
6032
6332
|
(skill.groupName?'<span class="meta-chip">group: '+esc(skill.groupName)+'</span>':'')+
|
|
6033
6333
|
'<span class="meta-chip">visibility: '+esc(skill.visibility||'hub')+'</span>'+
|
|
6034
6334
|
(skill.version!=null?'<span class="meta-chip">v'+skill.version+'</span>':'')+
|
|
6035
6335
|
'</div>'+
|
|
6036
|
-
'<div class="hub-skill-actions"><button class="btn btn-sm" onclick="event.stopPropagation();pullHubSkill(\\''+escAttr(skill.
|
|
6336
|
+
'<div class="hub-skill-actions"><button class="btn btn-sm" onclick="event.stopPropagation();pullHubSkill(\\''+escAttr(skill.id)+'\\')">'+t('skill.pullToLocal')+'</button></div>'+
|
|
6037
6337
|
'</div>';
|
|
6038
6338
|
}).join('');
|
|
6039
6339
|
}catch(e){
|
|
@@ -6367,6 +6667,7 @@ async function loadConfig(){
|
|
|
6367
6667
|
document.getElementById('cfgHubTeamName').value=hub.teamName||'';
|
|
6368
6668
|
document.getElementById('cfgHubTeamToken').value=hub.teamToken||'';
|
|
6369
6669
|
document.getElementById('cfgClientHubAddress').value=client.hubAddress||'';
|
|
6670
|
+
_loadedClientHubAddress=client.hubAddress||'';
|
|
6370
6671
|
document.getElementById('cfgClientTeamToken').value=client.teamToken||'';
|
|
6371
6672
|
document.getElementById('cfgClientNickname').value=client.nickname||'';
|
|
6372
6673
|
document.getElementById('cfgClientUserToken').value=client.userToken||'';
|
|
@@ -6412,20 +6713,24 @@ function flashSaved(id){
|
|
|
6412
6713
|
}
|
|
6413
6714
|
|
|
6414
6715
|
async function doSaveConfig(cfg, btnEl, savedId){
|
|
6415
|
-
btnEl.disabled=true;btnEl.textContent=t('settings.test.loading');
|
|
6416
|
-
function done(){btnEl.disabled=false;btnEl.textContent=t('settings.save');}
|
|
6716
|
+
if(btnEl){btnEl.disabled=true;btnEl.textContent=t('settings.test.loading');}
|
|
6717
|
+
function done(){if(btnEl){btnEl.disabled=false;btnEl.textContent=t('settings.save');}}
|
|
6417
6718
|
try{
|
|
6418
6719
|
const r=await fetch('/api/config',{method:'PUT',headers:{'Content-Type':'application/json'},body:JSON.stringify(cfg)});
|
|
6419
|
-
if(r.status===401){done();toast(t('settings.session.expired'),'error');return
|
|
6720
|
+
if(r.status===401){done();toast(t('settings.session.expired'),'error');return null;}
|
|
6420
6721
|
if(!r.ok) throw new Error(await r.text());
|
|
6722
|
+
var data=await r.json().catch(function(){return {ok:true};});
|
|
6421
6723
|
flashSaved(savedId);
|
|
6422
|
-
|
|
6423
|
-
|
|
6424
|
-
|
|
6724
|
+
if(data&&data.restart){
|
|
6725
|
+
showRestartOverlay(t('settings.restart.waiting'));
|
|
6726
|
+
}else{
|
|
6727
|
+
done();
|
|
6728
|
+
}
|
|
6729
|
+
return data;
|
|
6425
6730
|
}catch(e){
|
|
6426
6731
|
toast(t('settings.save.fail')+': '+e.message,'error');
|
|
6427
6732
|
done();
|
|
6428
|
-
return
|
|
6733
|
+
return null;
|
|
6429
6734
|
}
|
|
6430
6735
|
}
|
|
6431
6736
|
|
|
@@ -6520,11 +6825,19 @@ async function saveModelsConfig(){
|
|
|
6520
6825
|
await doSaveConfig(cfg, saveBtn, 'modelsSaved');
|
|
6521
6826
|
}
|
|
6522
6827
|
|
|
6828
|
+
function _hubSaveBtnLabel(){
|
|
6829
|
+
var on=document.getElementById('cfgSharingEnabled');
|
|
6830
|
+
if(on&&on.checked&&_sharingRole==='client'){
|
|
6831
|
+
var prevClient=sharingStatusCache&&sharingStatusCache.enabled&&sharingStatusCache.role==='client';
|
|
6832
|
+
return prevClient?t('settings.save'):t('sharing.joinTeam');
|
|
6833
|
+
}
|
|
6834
|
+
return t('settings.save');
|
|
6835
|
+
}
|
|
6523
6836
|
async function saveHubConfig(){
|
|
6524
6837
|
var card=document.getElementById('settingsSharingConfig');
|
|
6525
6838
|
var saveBtn=card.querySelector('.settings-actions .btn-primary');
|
|
6526
6839
|
saveBtn.disabled=true;saveBtn.textContent=t('settings.test.loading');
|
|
6527
|
-
function done(){saveBtn.disabled=false;saveBtn.textContent=
|
|
6840
|
+
function done(){saveBtn.disabled=false;saveBtn.textContent=_hubSaveBtnLabel();}
|
|
6528
6841
|
|
|
6529
6842
|
const cfg={};
|
|
6530
6843
|
var sharingEnabled=document.getElementById('cfgSharingEnabled').checked;
|
|
@@ -6538,7 +6851,7 @@ async function saveHubConfig(){
|
|
|
6538
6851
|
var hubTeamName=document.getElementById('cfgHubTeamName').value.trim();
|
|
6539
6852
|
var hubTeamToken=document.getElementById('cfgHubTeamToken').value.trim();
|
|
6540
6853
|
var hubAdminName=document.getElementById('cfgHubAdminName').value.trim();
|
|
6541
|
-
cfg.sharing.hub={port:
|
|
6854
|
+
if(hubPort) cfg.sharing.hub={port:Number(hubPort)}; else cfg.sharing.hub={};
|
|
6542
6855
|
if(hubTeamName) cfg.sharing.hub.teamName=hubTeamName;
|
|
6543
6856
|
if(hubTeamToken) cfg.sharing.hub.teamToken=hubTeamToken;
|
|
6544
6857
|
cfg.sharing.client={hubAddress:'',userToken:'',teamToken:''};
|
|
@@ -6548,21 +6861,29 @@ async function saveHubConfig(){
|
|
|
6548
6861
|
var clientTeamToken=document.getElementById('cfgClientTeamToken').value.trim();
|
|
6549
6862
|
var clientUserToken=document.getElementById('cfgClientUserToken').value.trim();
|
|
6550
6863
|
var clientNickname=document.getElementById('cfgClientNickname').value.trim();
|
|
6864
|
+
if(!clientAddr){done();toast(t('settings.hub.test.noAddr'),'error');return;}
|
|
6865
|
+
if(!clientTeamToken){done();toast(t('settings.hub.teamToken.required'),'error');return;}
|
|
6551
6866
|
cfg.sharing.client={};
|
|
6552
6867
|
if(clientAddr) cfg.sharing.client.hubAddress=clientAddr;
|
|
6553
6868
|
if(clientNickname) cfg.sharing.client.nickname=clientNickname;
|
|
6554
6869
|
if(clientTeamToken) cfg.sharing.client.teamToken=clientTeamToken;
|
|
6555
6870
|
if(clientUserToken) cfg.sharing.client.userToken=clientUserToken;
|
|
6556
|
-
cfg.sharing.hub={
|
|
6871
|
+
cfg.sharing.hub={teamName:'',teamToken:''};
|
|
6557
6872
|
if(clientAddr){
|
|
6558
6873
|
try{
|
|
6559
|
-
var ips=await fetch('/api/local-ips').then(function(r){return r.json();});
|
|
6560
|
-
var localAddrs=['127.0.0.1','localhost','0.0.0.0'].concat(ips.ips||[]);
|
|
6561
|
-
var parsed=new URL(clientAddr.indexOf('://')>-1?clientAddr:'http://'+clientAddr);
|
|
6562
|
-
if(localAddrs.indexOf(parsed.hostname)>=0){
|
|
6563
|
-
done();toast(t('sharing.cannotJoinSelf'),'error');return;
|
|
6564
|
-
}
|
|
6565
6874
|
}catch(e){}
|
|
6875
|
+
try{
|
|
6876
|
+
var testUrl=clientAddr.indexOf('://')>-1?clientAddr:'http://'+clientAddr;
|
|
6877
|
+
testUrl=testUrl.replace(/\\/+$/,'');
|
|
6878
|
+
var tr=await fetch('/api/sharing/test-hub',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({hubUrl:testUrl})});
|
|
6879
|
+
var td=await tr.json();
|
|
6880
|
+
if(!td.ok){
|
|
6881
|
+
var errMsg=td.error==='cannot_join_self'?t('sharing.cannotJoinSelf'):(td.error||t('settings.hub.test.fail'));
|
|
6882
|
+
done();toast(errMsg,'error');return;
|
|
6883
|
+
}
|
|
6884
|
+
}catch(e){
|
|
6885
|
+
done();toast(t('settings.hub.test.fail')+': '+String(e),'error');return;
|
|
6886
|
+
}
|
|
6566
6887
|
}
|
|
6567
6888
|
}
|
|
6568
6889
|
|
|
@@ -6572,21 +6893,44 @@ async function saveHubConfig(){
|
|
|
6572
6893
|
var confirmMsg=prevRole==='hub'?t('sharing.disable.confirm.hub'):t('sharing.disable.confirm.client');
|
|
6573
6894
|
if(!(await confirmModal(confirmMsg,{danger:true}))){done();return;}
|
|
6574
6895
|
}
|
|
6896
|
+
if(prevSharingEnabled&&sharingEnabled&&prevRole&&prevRole!==_sharingRole){
|
|
6897
|
+
var switchMsg=prevRole==='hub'?t('sharing.switch.hubToClient'):t('sharing.switch.clientToHub');
|
|
6898
|
+
if(!(await confirmModal(switchMsg,{danger:true}))){done();return;}
|
|
6899
|
+
}
|
|
6900
|
+
if(prevSharingEnabled&&sharingEnabled&&prevRole==='client'&&_sharingRole==='client'){
|
|
6901
|
+
var newAddr=(document.getElementById('cfgClientHubAddress').value||'').trim();
|
|
6902
|
+
if(_loadedClientHubAddress&&newAddr&&newAddr!==_loadedClientHubAddress){
|
|
6903
|
+
if(!(await confirmModal(t('sharing.switch.hubAddress'),{danger:true}))){done();return;}
|
|
6904
|
+
}
|
|
6905
|
+
}
|
|
6575
6906
|
|
|
6576
|
-
var
|
|
6577
|
-
if(
|
|
6907
|
+
var result=await doSaveConfig(cfg, saveBtn, 'hubSaved');
|
|
6908
|
+
if(result){
|
|
6578
6909
|
if(sharingEnabled&&_sharingRole==='hub'){
|
|
6579
6910
|
var adminNameEl=document.getElementById('cfgHubAdminName');
|
|
6580
6911
|
if(adminNameEl&&adminNameEl.value.trim()){
|
|
6581
6912
|
try{await fetch('/api/sharing/update-username',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({username:adminNameEl.value.trim()})});}catch(e){}
|
|
6582
6913
|
}
|
|
6583
6914
|
}
|
|
6584
|
-
|
|
6585
|
-
|
|
6586
|
-
|
|
6587
|
-
|
|
6588
|
-
|
|
6915
|
+
if(sharingEnabled&&_sharingRole==='client'&&result.joinStatus){
|
|
6916
|
+
if(result.joinStatus==='pending'){
|
|
6917
|
+
toast(t('sharing.joinSent.pending'),'success');
|
|
6918
|
+
}else if(result.joinStatus==='active'){
|
|
6919
|
+
toast(t('sharing.joinSent.active'),'success');
|
|
6920
|
+
}else{
|
|
6921
|
+
toast(t('settings.saved'),'success');
|
|
6922
|
+
}
|
|
6923
|
+
}else{
|
|
6924
|
+
toast(t('settings.saved'),'success');
|
|
6589
6925
|
}
|
|
6926
|
+
_lastSidebarFingerprint='';
|
|
6927
|
+
_lastSettingsFingerprint='';
|
|
6928
|
+
_lastSharingConnStatus='';
|
|
6929
|
+
_lastAdminFingerprint='';
|
|
6930
|
+
_lastAdminStatsFp='';
|
|
6931
|
+
if(sharingEnabled) updateHubShareInfo();
|
|
6932
|
+
loadSharingStatus(true);
|
|
6933
|
+
if(_activeView==='admin') loadAdminData();
|
|
6590
6934
|
}
|
|
6591
6935
|
}
|
|
6592
6936
|
|
|
@@ -6676,6 +7020,8 @@ function renderSkillMarkdown(md){
|
|
|
6676
7020
|
function closeSkillDetail(event){
|
|
6677
7021
|
if(event && event.target!==document.getElementById('skillDetailOverlay')) return;
|
|
6678
7022
|
document.getElementById('skillDetailOverlay').classList.remove('show');
|
|
7023
|
+
currentSkillId='';
|
|
7024
|
+
currentSkillDetail=null;
|
|
6679
7025
|
}
|
|
6680
7026
|
|
|
6681
7027
|
async function deleteSkill(skillId){
|
|
@@ -7010,16 +7356,29 @@ var _livePollBusy=false;
|
|
|
7010
7356
|
async function _livePollTick(){
|
|
7011
7357
|
if(_livePollBusy||document.hidden) return;
|
|
7012
7358
|
_livePollBusy=true;
|
|
7359
|
+
var _savedScrollY=window.scrollY;
|
|
7360
|
+
var _scrollTargets=['memoryList','tasksList','skillsList','adminUsersPanel','adminMemoriesPanel','adminTasksPanel','adminSkillsPanel'];
|
|
7361
|
+
var _savedScrollMap={};
|
|
7362
|
+
_scrollTargets.forEach(function(id){var el=document.getElementById(id);if(el&&el.scrollTop)_savedScrollMap[id]=el.scrollTop;});
|
|
7013
7363
|
try{
|
|
7014
|
-
if(sharingStatusCache&&sharingStatusCache.enabled) loadSharingStatus(false);
|
|
7015
|
-
if(!_notifSSEConnected) pollNotifCount();
|
|
7016
|
-
pollAdminPending();
|
|
7017
|
-
if(_activeView==='admin') loadAdminData();
|
|
7018
|
-
else if(_activeView==='memories'){
|
|
7019
|
-
|
|
7020
|
-
|
|
7021
|
-
|
|
7364
|
+
if(sharingStatusCache&&sharingStatusCache.enabled&&_lastSharingConnStatus!=='rejected') await loadSharingStatus(false);
|
|
7365
|
+
if(!_notifSSEConnected) await pollNotifCount();
|
|
7366
|
+
await pollAdminPending();
|
|
7367
|
+
if(_activeView==='admin') await loadAdminData();
|
|
7368
|
+
else if(_activeView==='memories'){
|
|
7369
|
+
var _searchVal=(document.getElementById('searchInput')||{}).value||'';
|
|
7370
|
+
if(!_searchVal.trim()){
|
|
7371
|
+
if(memorySearchScope==='hub') await loadHubMemories(true);
|
|
7372
|
+
else{var _pollOwner=memorySearchScope==='local'?_currentAgentOwner:undefined;await loadStats(_pollOwner);await loadMemories(null,true);}
|
|
7373
|
+
}
|
|
7374
|
+
}
|
|
7375
|
+
else if(_activeView==='tasks') await loadTasks(true);
|
|
7376
|
+
else if(_activeView==='skills') await loadSkills(true);
|
|
7377
|
+
else if(_activeView==='analytics') await loadMetrics();
|
|
7022
7378
|
}catch(e){}
|
|
7379
|
+
await new Promise(function(r){requestAnimationFrame(r);});
|
|
7380
|
+
window.scrollTo(0,_savedScrollY);
|
|
7381
|
+
for(var _sid in _savedScrollMap){var _sel=document.getElementById(_sid);if(_sel)_sel.scrollTop=_savedScrollMap[_sid];}
|
|
7023
7382
|
_livePollBusy=false;
|
|
7024
7383
|
}
|
|
7025
7384
|
|
|
@@ -7063,6 +7422,9 @@ function connectNotifSSE(){
|
|
|
7063
7422
|
_notifUnread=d.unreadCount||0;
|
|
7064
7423
|
renderNotifBadge();
|
|
7065
7424
|
if(_notifUnread>prev&&_notifPanelOpen) loadNotifications();
|
|
7425
|
+
if(_notifUnread>prev&&_activeView==='memories'&&memorySearchScope!=='hub'){
|
|
7426
|
+
syncTeamShareRemovedFromNotifications().then(function(){ loadMemories(currentPage,true); });
|
|
7427
|
+
}
|
|
7066
7428
|
}
|
|
7067
7429
|
if(d.type==='cleared'){
|
|
7068
7430
|
_notifUnread=0;_notifCache=[];
|
|
@@ -7112,7 +7474,12 @@ function notifTimeAgo(ts){
|
|
|
7112
7474
|
function notifIcon(resource,type){
|
|
7113
7475
|
if(type==='user_online') return '\\u{1F7E2}';
|
|
7114
7476
|
if(type==='user_offline') return '\\u{1F534}';
|
|
7477
|
+
if(type==='user_left') return '\\u{1F6AA}';
|
|
7115
7478
|
if(type==='user_join_request') return '\\u{1F464}';
|
|
7479
|
+
if(type==='membership_removed') return '\\u{26D4}';
|
|
7480
|
+
if(type==='hub_shutdown') return '\\u{1F6D1}';
|
|
7481
|
+
if(type==='role_promoted') return '\\u{2B06}';
|
|
7482
|
+
if(type==='role_demoted') return '\\u{2B07}';
|
|
7116
7483
|
if(resource==='memory') return '\\u{1F4DD}';
|
|
7117
7484
|
if(resource==='task') return '\\u{1F4CB}';
|
|
7118
7485
|
if(resource==='skill') return '\\u{1F9E0}';
|
|
@@ -7138,6 +7505,27 @@ function notifTypeText(n){
|
|
|
7138
7505
|
if(n.type==='user_offline'){
|
|
7139
7506
|
return t('notif.userOffline');
|
|
7140
7507
|
}
|
|
7508
|
+
if(n.type==='user_left'){
|
|
7509
|
+
return t('notif.userLeft');
|
|
7510
|
+
}
|
|
7511
|
+
if(n.type==='membership_approved'){
|
|
7512
|
+
return t('notif.membershipApproved');
|
|
7513
|
+
}
|
|
7514
|
+
if(n.type==='membership_rejected'){
|
|
7515
|
+
return t('notif.membershipRejected');
|
|
7516
|
+
}
|
|
7517
|
+
if(n.type==='membership_removed'){
|
|
7518
|
+
return t('notif.membershipRemoved');
|
|
7519
|
+
}
|
|
7520
|
+
if(n.type==='hub_shutdown'){
|
|
7521
|
+
return t('notif.hubShutdown');
|
|
7522
|
+
}
|
|
7523
|
+
if(n.type==='role_promoted'){
|
|
7524
|
+
return t('notif.rolePromoted');
|
|
7525
|
+
}
|
|
7526
|
+
if(n.type==='role_demoted'){
|
|
7527
|
+
return t('notif.roleDemoted');
|
|
7528
|
+
}
|
|
7141
7529
|
return n.message||n.type;
|
|
7142
7530
|
}
|
|
7143
7531
|
|
|
@@ -7172,6 +7560,21 @@ function renderNotifBadge(){
|
|
|
7172
7560
|
}
|
|
7173
7561
|
}
|
|
7174
7562
|
|
|
7563
|
+
var _notifKnownTypes={membership_approved:1,membership_rejected:1,membership_removed:1,hub_shutdown:1,user_left:1,user_online:1,user_offline:1,user_join_request:1,role_promoted:1,role_demoted:1,resource_removed:1,resource_shared:1,resource_unshared:1};
|
|
7564
|
+
function notifDisplayTitle(n){
|
|
7565
|
+
if(_notifKnownTypes[n.type]) return notifTypeText(n);
|
|
7566
|
+
return n.title||notifTypeText(n);
|
|
7567
|
+
}
|
|
7568
|
+
function notifDisplayDetail(n){
|
|
7569
|
+
if(_notifKnownTypes[n.type]){
|
|
7570
|
+
if(n.type==='resource_removed'||n.type==='resource_shared'||n.type==='resource_unshared') return n.title||'';
|
|
7571
|
+
var m=n.title&&n.title.match(/["\u201C]([^"\u201D]+)["\u201D]/);
|
|
7572
|
+
if(m) return m[1];
|
|
7573
|
+
if(n.type==='user_left'||n.type==='user_online'||n.type==='user_offline'||n.type==='user_join_request') return n.title||'';
|
|
7574
|
+
return '';
|
|
7575
|
+
}
|
|
7576
|
+
return n.title||'';
|
|
7577
|
+
}
|
|
7175
7578
|
function renderNotifPanel(){
|
|
7176
7579
|
var body=document.getElementById('notifPanelBody');
|
|
7177
7580
|
if(!body) return;
|
|
@@ -7181,11 +7584,12 @@ function renderNotifPanel(){
|
|
|
7181
7584
|
}
|
|
7182
7585
|
body.innerHTML=_notifCache.map(function(n){
|
|
7183
7586
|
var cls='notif-item'+(n.read?'':' unread');
|
|
7587
|
+
var detail=notifDisplayDetail(n);
|
|
7184
7588
|
return '<div class="'+cls+'" onclick="markNotifRead("'+esc(n.id)+'")">'+
|
|
7185
7589
|
'<div class="notif-item-icon">'+notifIcon(n.resource,n.type)+'</div>'+
|
|
7186
7590
|
'<div class="notif-item-body">'+
|
|
7187
|
-
'<div class="notif-item-title">'+esc(
|
|
7188
|
-
'<div class="notif-item-name">'+esc(
|
|
7591
|
+
'<div class="notif-item-title">'+esc(notifDisplayTitle(n))+'</div>'+
|
|
7592
|
+
(detail?'<div class="notif-item-name">'+esc(detail)+'</div>':'')+
|
|
7189
7593
|
'<div class="notif-item-time">'+notifTimeAgo(n.createdAt)+'</div>'+
|
|
7190
7594
|
'</div>'+
|
|
7191
7595
|
'<div class="notif-item-dot"></div>'+
|
|
@@ -7228,7 +7632,10 @@ function stopNotifPoll(){ }
|
|
|
7228
7632
|
|
|
7229
7633
|
/* ─── Data loading ─── */
|
|
7230
7634
|
async function loadAll(){
|
|
7231
|
-
await
|
|
7635
|
+
await loadStats();
|
|
7636
|
+
var initOwner=memorySearchScope==='local'?_currentAgentOwner:undefined;
|
|
7637
|
+
if(initOwner) await loadStats(initOwner);
|
|
7638
|
+
await Promise.all([loadMemories(),loadSharingStatus(false)]);
|
|
7232
7639
|
checkMigrateStatus();
|
|
7233
7640
|
connectPPSSE();
|
|
7234
7641
|
checkForUpdate();
|
|
@@ -7236,6 +7643,7 @@ async function loadAll(){
|
|
|
7236
7643
|
startLivePoller();
|
|
7237
7644
|
}
|
|
7238
7645
|
|
|
7646
|
+
var _lastStatsFp='';
|
|
7239
7647
|
async function loadStats(ownerFilter){
|
|
7240
7648
|
let d;
|
|
7241
7649
|
try{
|
|
@@ -7245,28 +7653,22 @@ async function loadStats(ownerFilter){
|
|
|
7245
7653
|
d=await r.json();
|
|
7246
7654
|
}catch(e){ d={}; }
|
|
7247
7655
|
if(!d||typeof d!=='object') d={};
|
|
7656
|
+
if(d.currentAgentOwner) _currentAgentOwner=d.currentAgentOwner;
|
|
7248
7657
|
const tm=d.totalMemories||0;
|
|
7249
7658
|
const dedupB=d.dedupBreakdown||{};
|
|
7250
7659
|
const activeCount=dedupB.active||tm;
|
|
7251
7660
|
const inactiveCount=(dedupB.duplicate||0)+(dedupB.merged||0);
|
|
7661
|
+
var agentCount=(d.owners&&d.owners.length)?d.owners.length:1;
|
|
7662
|
+
var sfp=tm+':'+(d.totalSessions||0)+':'+(d.totalEmbeddings||0)+':'+agentCount+':'+(d.embeddingProvider||'none')+':'+(ownerFilter||'');
|
|
7663
|
+
if(sfp===_lastStatsFp) return;
|
|
7664
|
+
_lastStatsFp=sfp;
|
|
7252
7665
|
document.getElementById('statTotal').textContent=tm;
|
|
7253
7666
|
if(inactiveCount>0){
|
|
7254
7667
|
document.getElementById('statTotal').title=activeCount+' '+t('stat.active')+', '+inactiveCount+' '+t('stat.deduped');
|
|
7255
7668
|
}
|
|
7256
7669
|
document.getElementById('statSessions').textContent=d.totalSessions||0;
|
|
7257
7670
|
document.getElementById('statEmbeddings').textContent=d.totalEmbeddings||0;
|
|
7258
|
-
|
|
7259
|
-
if(d.timeRange&&d.timeRange.earliest!=null&&d.timeRange.latest!=null){
|
|
7260
|
-
let e=Number(d.timeRange.earliest), l=Number(d.timeRange.latest);
|
|
7261
|
-
if(Number.isFinite(e)&&Number.isFinite(l)){
|
|
7262
|
-
if(e<1e12) e*=1000;
|
|
7263
|
-
if(l<1e12) l*=1000;
|
|
7264
|
-
days=Math.round((l-e)/86400000);
|
|
7265
|
-
days=Math.max(0,Math.min(36500,days));
|
|
7266
|
-
if(days===0) days=1;
|
|
7267
|
-
}
|
|
7268
|
-
}
|
|
7269
|
-
document.getElementById('statTimeSpan').textContent=days;
|
|
7671
|
+
document.getElementById('statAgents').textContent=agentCount;
|
|
7270
7672
|
|
|
7271
7673
|
const provEl=document.getElementById('embeddingStatus');
|
|
7272
7674
|
if(d.embeddingProvider && d.embeddingProvider!=='none'){
|
|
@@ -7358,55 +7760,108 @@ function getFilterParams(){
|
|
|
7358
7760
|
if(dt) p.set('dateTo',dt);
|
|
7359
7761
|
const sort=document.getElementById('filterSort').value;
|
|
7360
7762
|
if(sort==='oldest') p.set('sort','oldest');
|
|
7763
|
+
const scope=memorySearchScope||'local';
|
|
7764
|
+
if(scope==='local'){
|
|
7765
|
+
p.set('owner',_currentAgentOwner);
|
|
7766
|
+
}else if(scope==='allLocal'){
|
|
7361
7767
|
const owner=document.getElementById('filterOwner').value;
|
|
7362
7768
|
if(owner) p.set('owner',owner);
|
|
7769
|
+
}
|
|
7363
7770
|
return p;
|
|
7364
7771
|
}
|
|
7365
7772
|
|
|
7366
|
-
|
|
7773
|
+
/** Hub admin removed a shared memory — badge-only: clear team_shared_chunks (never touches chunks/embeddings/hub_memories recall data). */
|
|
7774
|
+
async function syncTeamShareRemovedFromNotifications(){
|
|
7775
|
+
try{
|
|
7776
|
+
var r=await fetch('/api/sharing/notifications');
|
|
7777
|
+
var d=await r.json();
|
|
7778
|
+
var list=d.notifications||[];
|
|
7779
|
+
for(var i=0;i<list.length;i++){
|
|
7780
|
+
var n=list[i];
|
|
7781
|
+
if(n.type!=='resource_removed'||n.resource!=='memory'||!n.message) continue;
|
|
7782
|
+
try{
|
|
7783
|
+
var meta=JSON.parse(n.message);
|
|
7784
|
+
if(meta.sourceChunkId){
|
|
7785
|
+
await fetch('/api/sharing/sync-hub-removal',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({sourceChunkId:meta.sourceChunkId,memoryId:meta.memoryId||''})});
|
|
7786
|
+
}
|
|
7787
|
+
}catch(e){}
|
|
7788
|
+
}
|
|
7789
|
+
}catch(e){}
|
|
7790
|
+
}
|
|
7791
|
+
|
|
7792
|
+
async function loadMemories(page,silent){
|
|
7367
7793
|
if(page) currentPage=page;
|
|
7368
7794
|
const list=document.getElementById('memoryList');
|
|
7369
|
-
list.innerHTML='<div class="spinner"></div>';
|
|
7795
|
+
if(!silent) list.innerHTML='<div class="spinner"></div>';
|
|
7370
7796
|
try{
|
|
7797
|
+
if(!silent) await syncTeamShareRemovedFromNotifications();
|
|
7371
7798
|
const p=getFilterParams();
|
|
7372
7799
|
p.set('limit',PAGE_SIZE);
|
|
7373
7800
|
p.set('page',currentPage);
|
|
7374
7801
|
const r=await fetch('/api/memories?'+p.toString());
|
|
7375
7802
|
const d=await r.json();
|
|
7803
|
+
var items=d.memories||[];
|
|
7804
|
+
if(silent){
|
|
7805
|
+
var fp=JSON.stringify(items.map(function(m){return m.id+'|'+m.updated_at}));
|
|
7806
|
+
if(fp===_lastMemoriesFingerprint) return;
|
|
7807
|
+
_lastMemoriesFingerprint=fp;
|
|
7808
|
+
}else{
|
|
7809
|
+
_lastMemoriesFingerprint=JSON.stringify(items.map(function(m){return m.id+'|'+m.updated_at}));
|
|
7810
|
+
}
|
|
7376
7811
|
totalPages=d.totalPages||1;
|
|
7377
7812
|
totalCount=d.total||0;
|
|
7378
7813
|
document.getElementById('searchMeta').textContent=totalCount+t('search.meta.total');
|
|
7379
|
-
renderMemories(
|
|
7814
|
+
renderMemories(items);
|
|
7380
7815
|
renderPagination();
|
|
7381
7816
|
}catch(e){
|
|
7817
|
+
if(!silent){
|
|
7382
7818
|
list.innerHTML='';
|
|
7383
7819
|
totalPages=1;totalCount=0;
|
|
7820
|
+
_lastMemoriesFingerprint='';
|
|
7384
7821
|
renderMemories([]);
|
|
7385
7822
|
renderPagination();
|
|
7823
|
+
}
|
|
7386
7824
|
}
|
|
7387
7825
|
}
|
|
7388
7826
|
|
|
7389
|
-
async function loadHubMemories(){
|
|
7827
|
+
async function loadHubMemories(silent){
|
|
7390
7828
|
const list=document.getElementById('memoryList');
|
|
7391
|
-
list.innerHTML='<div class="spinner"></div>';
|
|
7829
|
+
if(!silent) list.innerHTML='<div class="spinner"></div>';
|
|
7392
7830
|
try{
|
|
7393
7831
|
const r=await fetch('/api/sharing/memories/list?limit='+PAGE_SIZE);
|
|
7394
7832
|
const d=await r.json();
|
|
7395
7833
|
const items=d.memories||[];
|
|
7834
|
+
if(silent){
|
|
7835
|
+
var fp=JSON.stringify(items.map(function(m){return m.id+'|'+(m.updated_at||m.created_at)}));
|
|
7836
|
+
if(fp===_lastMemoriesFingerprint) return;
|
|
7837
|
+
_lastMemoriesFingerprint=fp;
|
|
7838
|
+
}else{
|
|
7839
|
+
_lastMemoriesFingerprint=JSON.stringify(items.map(function(m){return m.id+'|'+(m.updated_at||m.created_at)}));
|
|
7840
|
+
}
|
|
7841
|
+
totalPages=1;totalCount=items.length;currentPage=1;
|
|
7396
7842
|
document.getElementById('searchMeta').textContent=items.length+t('search.meta.total');
|
|
7397
7843
|
document.getElementById('sharingSearchMeta').textContent='';
|
|
7398
7844
|
renderMemories(items);
|
|
7399
7845
|
document.getElementById('pagination').innerHTML='';
|
|
7400
7846
|
}catch(e){
|
|
7847
|
+
if(!silent){
|
|
7848
|
+
_lastMemoriesFingerprint='';
|
|
7401
7849
|
document.getElementById('searchMeta').textContent='0'+t('search.meta.results');
|
|
7402
7850
|
renderMemories([]);
|
|
7403
7851
|
document.getElementById('pagination').innerHTML='';
|
|
7852
|
+
}
|
|
7404
7853
|
}
|
|
7405
7854
|
}
|
|
7406
7855
|
|
|
7407
7856
|
async function doSearch(query){
|
|
7408
7857
|
query=(query||'').trim();
|
|
7409
|
-
if(!query){
|
|
7858
|
+
if(!query){
|
|
7859
|
+
currentPage=1;
|
|
7860
|
+
if(memorySearchScope==='hub') loadHubMemories();
|
|
7861
|
+
else loadMemories();
|
|
7862
|
+
return;
|
|
7863
|
+
}
|
|
7864
|
+
currentPage=1;
|
|
7410
7865
|
var scope=document.getElementById('memorySearchScope')?.value||memorySearchScope||'local';
|
|
7411
7866
|
var list=document.getElementById('memoryList');
|
|
7412
7867
|
list.innerHTML='<div class="spinner"></div>';
|
|
@@ -7418,6 +7873,7 @@ async function doSearch(query){
|
|
|
7418
7873
|
body:JSON.stringify({query:query,scope:scope,maxResults:20,role:activeRole||undefined})
|
|
7419
7874
|
});
|
|
7420
7875
|
var data=await r.json();
|
|
7876
|
+
totalPages=1;totalCount=(data.results||[]).length;
|
|
7421
7877
|
renderSharingMemorySearchResults(data,query);
|
|
7422
7878
|
}catch(e){
|
|
7423
7879
|
document.getElementById('searchMeta').textContent='0'+t('search.meta.results');
|
|
@@ -7432,6 +7888,7 @@ async function doSearch(query){
|
|
|
7432
7888
|
var r=await fetch('/api/search?'+p.toString());
|
|
7433
7889
|
var d=await r.json();
|
|
7434
7890
|
var total=d.total||0;
|
|
7891
|
+
totalPages=1;totalCount=total;
|
|
7435
7892
|
var meta=[];
|
|
7436
7893
|
if(d.vectorCount>0) meta.push(d.vectorCount+t('search.meta.semantic'));
|
|
7437
7894
|
if(d.ftsCount>0) meta.push(d.ftsCount+t('search.meta.text'));
|
|
@@ -7512,7 +7969,7 @@ function renderMemories(items){
|
|
|
7512
7969
|
const mergeBadge=mc>0?'<span class="merge-badge">\\u{1F504} '+t('card.evolved')+' '+mc+t('card.times')+'</span>':'';
|
|
7513
7970
|
const updatedAt=(m.updated_at&&m.updated_at>m.created_at)?'<span class="card-updated">'+t('card.updated')+' '+new Date(m.updated_at).toLocaleString(dateLoc())+'</span>':'';
|
|
7514
7971
|
const ds=m.dedup_status||'active';
|
|
7515
|
-
const isInactive=ds==='merged';
|
|
7972
|
+
const isInactive=ds==='merged'||ds==='duplicate';
|
|
7516
7973
|
const dedupBadge=ds==='duplicate'?'<span class="dedup-badge duplicate">'+t('card.dedupDuplicate')+'</span>':ds==='merged'?'<span class="dedup-badge merged">'+t('card.dedupMerged')+'</span>':'';
|
|
7517
7974
|
const isImported=sid.startsWith('openclaw-import-')||sid.startsWith('openclaw-session-');
|
|
7518
7975
|
const importBadge=isImported?'<span class="import-badge">\u{1F990} '+t('card.imported')+'</span>':'';
|
|
@@ -7520,8 +7977,9 @@ function renderMemories(items){
|
|
|
7520
7977
|
const isPublicMem=ownerVal==='public';
|
|
7521
7978
|
const localManaged=!!m.localSharingManaged;
|
|
7522
7979
|
const memShared=m.sharingVisibility||null;
|
|
7980
|
+
const isHubScope=memorySearchScope==='hub';
|
|
7523
7981
|
const memScope=memShared?'team':isPublicMem?'local':'private';
|
|
7524
|
-
const memScopeBadge=renderScopeBadge(memScope);
|
|
7982
|
+
const memScopeBadge=isHubScope?renderScopeBadge('team'):renderScopeBadge(memScope);
|
|
7525
7983
|
let dedupInfo='';
|
|
7526
7984
|
if(ds==='duplicate'||ds==='merged'){
|
|
7527
7985
|
const reason=m.dedup_reason?'<span style="font-size:11px;color:var(--text-muted)">'+t('card.dedupReason')+esc(m.dedup_reason)+'</span>':'';
|
|
@@ -7625,7 +8083,8 @@ function renderPagination(){
|
|
|
7625
8083
|
function goPage(p){
|
|
7626
8084
|
if(p<1||p>totalPages||p===currentPage) return;
|
|
7627
8085
|
currentPage=p;
|
|
7628
|
-
|
|
8086
|
+
if(memorySearchScope==='hub') loadHubMemories();
|
|
8087
|
+
else loadMemories();
|
|
7629
8088
|
document.getElementById('memoryList').scrollIntoView({behavior:'smooth',block:'start'});
|
|
7630
8089
|
}
|
|
7631
8090
|
|
|
@@ -7705,6 +8164,11 @@ function esc(s){
|
|
|
7705
8164
|
if(!s)return'';
|
|
7706
8165
|
return s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
|
|
7707
8166
|
}
|
|
8167
|
+
function fmtOwner(item){
|
|
8168
|
+
var name=item.ownerName||item.sourceUserId||'unknown';
|
|
8169
|
+
if(item.ownerStatus==='removed') return esc(name)+' <span style="color:#ef4444;font-size:0.9em">'+t('sharing.ownerRemoved')+'</span>';
|
|
8170
|
+
return esc(name);
|
|
8171
|
+
}
|
|
7708
8172
|
|
|
7709
8173
|
function renderSummaryHtml(raw){
|
|
7710
8174
|
if(!raw)return'';
|
|
@@ -8431,18 +8895,25 @@ function confirmModal(message,opts){
|
|
|
8431
8895
|
_confirmResolve=resolve;
|
|
8432
8896
|
var overlay=document.getElementById('confirmOverlay');
|
|
8433
8897
|
document.getElementById('confirmTitle').textContent=opts.title||t('confirm.title')||'\u786E\u8BA4';
|
|
8434
|
-
document.getElementById('confirmBody').
|
|
8898
|
+
document.getElementById('confirmBody').innerText=message||'';
|
|
8435
8899
|
var okBtn=document.getElementById('confirmOkBtn');
|
|
8436
8900
|
okBtn.textContent=opts.okText||t('confirm.ok')||'\u786E\u5B9A';
|
|
8437
8901
|
okBtn.className='btn-confirm-ok'+(opts.danger?' danger':'');
|
|
8438
|
-
document.getElementById('confirmCancelBtn')
|
|
8902
|
+
var cancelBtn=document.getElementById('confirmCancelBtn');
|
|
8903
|
+
cancelBtn.textContent=opts.cancelText||t('confirm.cancel')||'\u53D6\u6D88';
|
|
8904
|
+
cancelBtn.style.display=opts.hideCancel?'none':'';
|
|
8439
8905
|
overlay.classList.add('show');
|
|
8440
8906
|
});
|
|
8441
8907
|
}
|
|
8442
8908
|
function confirmModalClose(result){
|
|
8443
8909
|
document.getElementById('confirmOverlay').classList.remove('show');
|
|
8910
|
+
document.getElementById('confirmCancelBtn').style.display='';
|
|
8444
8911
|
if(_confirmResolve){var r=_confirmResolve;_confirmResolve=null;r(result);}
|
|
8445
8912
|
}
|
|
8913
|
+
function alertModal(message,opts){
|
|
8914
|
+
opts=opts||{};
|
|
8915
|
+
return confirmModal(message,Object.assign({},opts,{hideCancel:true,okText:opts.okText||t('confirm.ok')||'\u77E5\u9053\u4E86'}));
|
|
8916
|
+
}
|
|
8446
8917
|
|
|
8447
8918
|
/* ─── Theme ─── */
|
|
8448
8919
|
const VIEWER_THEME_KEY='memos-viewer-theme';
|
|
@@ -8465,14 +8936,35 @@ function showRestartOverlay(msg){
|
|
|
8465
8936
|
/* ─── Update check ─── */
|
|
8466
8937
|
function waitForGatewayAndReload(maxAttempts,attempt){
|
|
8467
8938
|
attempt=attempt||0;
|
|
8939
|
+
var phase=arguments.length>2?arguments[2]:'waitDown';
|
|
8940
|
+
var MAX_WAIT_DOWN=8;
|
|
8468
8941
|
function forceReload(){window.location.href=window.location.pathname+'?_t='+Date.now();}
|
|
8469
8942
|
if(attempt>=maxAttempts){forceReload();return;}
|
|
8943
|
+
var delay=phase==='waitDown'?1500:2500;
|
|
8470
8944
|
setTimeout(function(){
|
|
8471
8945
|
fetch('/api/auth/status').then(function(r){
|
|
8472
|
-
if(
|
|
8473
|
-
|
|
8474
|
-
|
|
8475
|
-
|
|
8946
|
+
if(phase==='waitDown'){
|
|
8947
|
+
if(r.ok||r.status===401||r.status===403){
|
|
8948
|
+
if(attempt>=MAX_WAIT_DOWN){
|
|
8949
|
+
forceReload();
|
|
8950
|
+
}else{
|
|
8951
|
+
waitForGatewayAndReload(maxAttempts,attempt+1,'waitDown');
|
|
8952
|
+
}
|
|
8953
|
+
}else{
|
|
8954
|
+
waitForGatewayAndReload(maxAttempts,0,'waitUp');
|
|
8955
|
+
}
|
|
8956
|
+
}else{
|
|
8957
|
+
if(r.ok||r.status===401||r.status===403) forceReload();
|
|
8958
|
+
else waitForGatewayAndReload(maxAttempts,attempt+1,'waitUp');
|
|
8959
|
+
}
|
|
8960
|
+
}).catch(function(){
|
|
8961
|
+
if(phase==='waitDown'){
|
|
8962
|
+
waitForGatewayAndReload(maxAttempts,0,'waitUp');
|
|
8963
|
+
}else{
|
|
8964
|
+
waitForGatewayAndReload(maxAttempts,attempt+1,'waitUp');
|
|
8965
|
+
}
|
|
8966
|
+
});
|
|
8967
|
+
},delay);
|
|
8476
8968
|
}
|
|
8477
8969
|
function doUpdateInstall(packageSpec,btnEl,statusEl){
|
|
8478
8970
|
btnEl.disabled=true;
|
|
@@ -8506,9 +8998,12 @@ async function checkForUpdate(){
|
|
|
8506
8998
|
const d=await r.json();
|
|
8507
8999
|
if(!d.updateAvailable)return;
|
|
8508
9000
|
const pkgSpec=d.installCommand?d.installCommand.replace(/^(?:npx\s+)?openclaw\s+plugins\s+install\s+/,''):(d.packageName+'@'+d.latest);
|
|
9001
|
+
var bannerWrap=document.createElement('div');
|
|
9002
|
+
bannerWrap.id='updateBannerWrap';
|
|
9003
|
+
bannerWrap.style.cssText='background:linear-gradient(135deg,rgba(99,102,241,.08),rgba(139,92,246,.06));border-bottom:1px solid rgba(99,102,241,.18);backdrop-filter:blur(8px);animation:slideIn .3s ease';
|
|
8509
9004
|
var banner=document.createElement('div');
|
|
8510
9005
|
banner.id='updateBanner';
|
|
8511
|
-
banner.style.cssText='display:flex;align-items:center;gap:12px;padding:10px 32px;max-width:1400px;margin:0 auto;
|
|
9006
|
+
banner.style.cssText='display:flex;align-items:center;gap:12px;padding:10px 32px;width:100%;max-width:1400px;margin:0 auto;font-size:13px;font-weight:500;box-sizing:border-box;color:var(--pri)';
|
|
8512
9007
|
var textNode=document.createElement('div');
|
|
8513
9008
|
textNode.style.cssText='display:flex;align-items:center;gap:8px;flex-shrink:0;font-size:13px';
|
|
8514
9009
|
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>';
|
|
@@ -8528,20 +9023,32 @@ async function checkForUpdate(){
|
|
|
8528
9023
|
btnClose.innerHTML='×';
|
|
8529
9024
|
btnClose.onmouseenter=function(){this.style.opacity='1'};
|
|
8530
9025
|
btnClose.onmouseleave=function(){this.style.opacity='.5'};
|
|
8531
|
-
btnClose.onclick=function(){
|
|
9026
|
+
btnClose.onclick=function(){bannerWrap.remove()};
|
|
9027
|
+
var spacerL=document.createElement('div');
|
|
9028
|
+
spacerL.style.cssText='flex:1';
|
|
9029
|
+
banner.appendChild(spacerL);
|
|
8532
9030
|
banner.appendChild(textNode);
|
|
8533
9031
|
banner.appendChild(statusDiv);
|
|
8534
9032
|
banner.appendChild(spacer);
|
|
8535
9033
|
banner.appendChild(btnClose);
|
|
9034
|
+
bannerWrap.appendChild(banner);
|
|
8536
9035
|
var tb=document.querySelector('.topbar');
|
|
8537
|
-
if(tb&&tb.parentNode){tb.parentNode.insertBefore(
|
|
8538
|
-
else{document.body.insertBefore(
|
|
9036
|
+
if(tb&&tb.parentNode){tb.parentNode.insertBefore(bannerWrap,tb);}
|
|
9037
|
+
else{document.body.insertBefore(bannerWrap,document.body.firstChild);}
|
|
8539
9038
|
}catch(e){}
|
|
8540
9039
|
}
|
|
8541
9040
|
|
|
8542
9041
|
/* ─── Init ─── */
|
|
9042
|
+
try{
|
|
9043
|
+
var savedScope=localStorage.getItem('memos_memorySearchScope');
|
|
9044
|
+
if(savedScope&&(savedScope==='local'||savedScope==='allLocal'||savedScope==='hub')){
|
|
9045
|
+
memorySearchScope=savedScope;
|
|
9046
|
+
var scopeEl=document.getElementById('memorySearchScope');
|
|
9047
|
+
if(scopeEl) scopeEl.value=savedScope;
|
|
9048
|
+
}
|
|
9049
|
+
}catch(e){}
|
|
8543
9050
|
document.getElementById('modalOverlay').addEventListener('click',e=>{if(e.target.id==='modalOverlay')closeModal()});
|
|
8544
|
-
document.getElementById('searchInput').addEventListener('keydown',e=>{if(e.key==='Escape'){e.target.value='';loadMemories()}});
|
|
9051
|
+
document.getElementById('searchInput').addEventListener('keydown',e=>{if(e.key==='Escape'){e.target.value='';currentPage=1;if(memorySearchScope==='hub')loadHubMemories();else loadMemories();}});
|
|
8545
9052
|
applyI18n();
|
|
8546
9053
|
checkAuth();
|
|
8547
9054
|
</script>
|