@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/src/viewer/html.ts
CHANGED
|
@@ -154,7 +154,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
154
154
|
.search-bar input::placeholder{color:var(--text-muted)}
|
|
155
155
|
.search-bar input:focus{border-color:var(--pri);box-shadow:0 0 0 3px var(--pri-glow)}
|
|
156
156
|
.search-bar .search-icon{position:absolute;left:14px;top:50%;transform:translateY(-50%);color:var(--text-muted);font-size:14px;pointer-events:none}
|
|
157
|
-
.search-meta{font-size:12px;color:var(--text-sec);
|
|
157
|
+
.search-meta{font-size:12px;color:var(--text-sec);padding:0 2px}.search-meta:not(:empty){margin-bottom:14px}
|
|
158
158
|
.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}
|
|
159
159
|
.sharing-inline-meta{font-size:12px;color:var(--text-muted);margin:-8px 0 14px 2px}
|
|
160
160
|
.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)}
|
|
@@ -194,65 +194,92 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
194
194
|
.pending-user-name{font-size:14px;font-weight:700;color:var(--text)}
|
|
195
195
|
.pending-user-meta{font-size:12px;color:var(--text-sec);margin-top:4px}
|
|
196
196
|
.pending-user-actions{display:flex;gap:8px;margin-top:10px}
|
|
197
|
-
/* ─── Admin Panel ─── */
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
.admin-
|
|
206
|
-
.admin-
|
|
207
|
-
.admin-
|
|
208
|
-
.admin-
|
|
209
|
-
.admin-
|
|
210
|
-
.admin-
|
|
211
|
-
.admin-
|
|
212
|
-
.admin-stat-
|
|
213
|
-
.admin-stat-box:
|
|
214
|
-
.admin-stat-box
|
|
215
|
-
.admin-stat-box
|
|
216
|
-
.admin-stat-box
|
|
217
|
-
.admin-
|
|
218
|
-
.admin-
|
|
219
|
-
.admin-
|
|
220
|
-
.admin-
|
|
197
|
+
/* ─── Admin Panel (Cyber) ─── */
|
|
198
|
+
@keyframes adminGlow{0%,100%{opacity:.6}50%{opacity:1}}
|
|
199
|
+
@keyframes adminPulse{0%{box-shadow:0 0 0 0 rgba(99,102,241,.4)}70%{box-shadow:0 0 0 8px rgba(99,102,241,0)}100%{box-shadow:0 0 0 0 rgba(99,102,241,0)}}
|
|
200
|
+
@keyframes adminScanline{0%{background-position:0 0}100%{background-position:0 100%}}
|
|
201
|
+
@keyframes adminSlideIn{from{opacity:0;transform:translateY(10px)}to{opacity:1;transform:translateY(0)}}
|
|
202
|
+
@keyframes adminCountUp{from{opacity:0;transform:translateY(8px) scale(.8)}to{opacity:1;transform:translateY(0) scale(1)}}
|
|
203
|
+
@keyframes pendingPulse{0%,100%{border-color:rgba(251,191,36,.3)}50%{border-color:rgba(251,191,36,.7)}}
|
|
204
|
+
@keyframes dotBreathe{0%,100%{transform:scale(1);opacity:.8}50%{transform:scale(1.3);opacity:1}}
|
|
205
|
+
.admin-header{position:relative;padding:32px 32px 24px;background:linear-gradient(135deg,rgba(99,102,241,.06) 0%,rgba(6,182,212,.04) 50%,rgba(139,92,246,.06) 100%);border:1px solid rgba(99,102,241,.15);border-radius:20px;margin-bottom:24px;overflow:hidden}
|
|
206
|
+
.admin-header::before{content:'';position:absolute;top:0;left:0;right:0;height:2px;background:linear-gradient(90deg,transparent,var(--pri),var(--cyan),var(--violet),transparent);animation:adminGlow 3s ease-in-out infinite}
|
|
207
|
+
.admin-header::after{content:'';position:absolute;inset:0;background:repeating-linear-gradient(0deg,transparent,transparent 2px,rgba(99,102,241,.015) 2px,rgba(99,102,241,.015) 4px);background-size:100% 8px;animation:adminScanline 8s linear infinite;pointer-events:none}
|
|
208
|
+
.admin-header-top{display:flex;justify-content:space-between;align-items:center;position:relative;z-index:1}
|
|
209
|
+
.admin-header h2{font-size:18px;font-weight:800;color:var(--text);display:flex;align-items:center;gap:12px;margin:0;letter-spacing:-.01em}
|
|
210
|
+
.admin-header h2 .ah-icon{width:40px;height:40px;border-radius:12px;background:linear-gradient(135deg,var(--pri),var(--violet));display:flex;align-items:center;justify-content:center;font-size:20px;box-shadow:0 4px 20px rgba(99,102,241,.3),inset 0 1px 0 rgba(255,255,255,.15);animation:adminPulse 2.5s infinite}
|
|
211
|
+
.admin-header-sub{font-size:11px;color:var(--text-muted);margin-top:6px;position:relative;z-index:1;letter-spacing:.02em}
|
|
212
|
+
.admin-stat-row{display:grid;grid-template-columns:repeat(auto-fit,minmax(120px,1fr));gap:10px;margin-top:20px;position:relative;z-index:1}
|
|
213
|
+
.admin-stat-box{position:relative;text-align:center;padding:18px 10px 16px;background:rgba(var(--bg-card-rgb,30,30,40),.6);backdrop-filter:blur(12px);border:1px solid rgba(99,102,241,.12);border-radius:14px;overflow:hidden;transition:all .25s cubic-bezier(.4,0,.2,1)}
|
|
214
|
+
.admin-stat-box:hover{border-color:rgba(99,102,241,.35);transform:translateY(-2px);box-shadow:0 8px 24px rgba(99,102,241,.12)}
|
|
215
|
+
.admin-stat-box::before{content:'';position:absolute;top:0;left:0;right:0;height:2px;opacity:.8}
|
|
216
|
+
.admin-stat-box:nth-child(1)::before{background:linear-gradient(90deg,transparent,#22c55e,transparent)}
|
|
217
|
+
.admin-stat-box:nth-child(2)::before{background:linear-gradient(90deg,transparent,#fbbf24,transparent)}
|
|
218
|
+
.admin-stat-box:nth-child(3)::before{background:linear-gradient(90deg,transparent,#8b5cf6,transparent)}
|
|
219
|
+
.admin-stat-box:nth-child(4)::before{background:linear-gradient(90deg,transparent,#06b6d4,transparent)}
|
|
220
|
+
.admin-stat-box:nth-child(5)::before{background:linear-gradient(90deg,transparent,#6366f1,transparent)}
|
|
221
|
+
.admin-stat-box:nth-child(6)::before{background:linear-gradient(90deg,transparent,#f43f5e,transparent)}
|
|
222
|
+
.admin-stat-box::after{content:'';position:absolute;inset:0;background:radial-gradient(circle at 50% 0%,rgba(99,102,241,.06),transparent 70%);pointer-events:none}
|
|
223
|
+
.admin-stat-box .as-icon{font-size:18px;margin-bottom:6px;display:block;filter:drop-shadow(0 2px 4px rgba(0,0,0,.15))}
|
|
224
|
+
.admin-stat-box .val{font-size:26px;font-weight:800;color:var(--text);font-variant-numeric:tabular-nums;animation:adminCountUp .4s ease-out;text-shadow:0 0 20px rgba(99,102,241,.15)}
|
|
225
|
+
.admin-stat-box .lbl{font-size:10px;color:var(--text-muted);margin-top:4px;letter-spacing:.05em;text-transform:uppercase}
|
|
226
|
+
.admin-tabs{display:flex;gap:3px;padding:3px;background:rgba(99,102,241,.03);border:1px solid rgba(99,102,241,.1);border-radius:14px;overflow-x:auto;-webkit-overflow-scrolling:touch;margin-bottom:24px;backdrop-filter:blur(8px)}
|
|
227
|
+
.admin-tab{position:relative;display:flex;align-items:center;gap:6px;padding:10px 18px;border:none;background:transparent;color:var(--text-muted);font-size:13px;font-weight:500;cursor:pointer;border-radius:11px;transition:all .25s cubic-bezier(.4,0,.2,1);white-space:nowrap;font-family:inherit}
|
|
228
|
+
.admin-tab:hover{background:rgba(99,102,241,.08);color:var(--text)}
|
|
229
|
+
.admin-tab.active{background:linear-gradient(135deg,rgba(99,102,241,.12),rgba(139,92,246,.08));color:var(--text);font-weight:600;box-shadow:0 2px 12px rgba(99,102,241,.1),inset 0 1px 0 rgba(255,255,255,.05);border:1px solid rgba(99,102,241,.15)}
|
|
221
230
|
.admin-tab .at-icon{font-size:14px;line-height:1}
|
|
222
|
-
.admin-tab .at-count{font-size:10px;font-weight:700;padding:
|
|
223
|
-
.admin-tab.active .at-count{background:rgba(99,102,241,.15)}
|
|
231
|
+
.admin-tab .at-count{font-size:10px;font-weight:700;padding:2px 7px;border-radius:8px;background:rgba(99,102,241,.12);color:var(--pri);min-width:18px;text-align:center;transition:all .2s}
|
|
232
|
+
.admin-tab.active .at-count{background:rgba(99,102,241,.2);box-shadow:0 0 8px rgba(99,102,241,.15)}
|
|
224
233
|
.admin-panel{display:none}
|
|
225
|
-
.admin-panel.active{display:block}
|
|
226
|
-
.admin-card{border:1px solid var(--border);border-radius:
|
|
234
|
+
.admin-panel.active{display:block;animation:adminSlideIn .3s ease-out}
|
|
235
|
+
.admin-card{border:1px solid var(--border);border-radius:14px;padding:18px 20px;background:var(--bg-card);margin-bottom:12px;transition:all .25s cubic-bezier(.4,0,.2,1);position:relative;overflow:hidden}
|
|
227
236
|
.admin-card-clickable{cursor:pointer}
|
|
228
|
-
.admin-card::before{content:'';position:absolute;top:0;left:0;bottom:0;width:3px;border-radius:3px 0 0 3px;background:var(--pri);opacity:.
|
|
229
|
-
.admin-card:hover{border-color:rgba(99,102,241,.25);box-shadow:0
|
|
237
|
+
.admin-card::before{content:'';position:absolute;top:0;left:0;bottom:0;width:3px;border-radius:3px 0 0 3px;background:var(--pri);opacity:.4;transition:opacity .2s}
|
|
238
|
+
.admin-card:hover{border-color:rgba(99,102,241,.25);box-shadow:0 4px 20px rgba(99,102,241,.06);transform:translateY(-1px)}
|
|
239
|
+
.admin-card:hover::before{opacity:.8}
|
|
230
240
|
.admin-card-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:6px}
|
|
231
241
|
.admin-card-title{font-size:14px;font-weight:700;color:var(--text);flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
232
242
|
.admin-card-meta{font-size:12px;color:var(--text-muted);line-height:1.5}
|
|
233
|
-
.au-contrib{display:flex;gap:
|
|
234
|
-
.au-contrib-item{font-size:12px;color:var(--text-sec);display:flex;align-items:center;gap:
|
|
235
|
-
.au-contrib-num{font-size:
|
|
236
|
-
.au-info{display:flex;flex-wrap:wrap;gap:6px
|
|
237
|
-
.au-info-item{color:var(--text-muted);white-space:nowrap}
|
|
238
|
-
.au-status-dot{display:inline-block;width:8px;height:8px;border-radius:50%;margin-right:
|
|
239
|
-
.au-status-dot.online{background:#22c55e;box-shadow:0 0
|
|
240
|
-
.au-status-dot.offline{background:#
|
|
241
|
-
.au-status-text{font-size:
|
|
242
|
-
.au-status-text.online{color:#22c55e}
|
|
243
|
-
.au-status-text.offline{color:#
|
|
244
|
-
.au-
|
|
243
|
+
.au-contrib{display:flex;gap:20px;padding:12px 0;margin:8px 0;border-top:1px solid rgba(99,102,241,.08);border-bottom:1px solid rgba(99,102,241,.08)}
|
|
244
|
+
.au-contrib-item{font-size:12px;color:var(--text-sec);display:flex;align-items:center;gap:5px}
|
|
245
|
+
.au-contrib-num{font-size:20px;font-weight:800;line-height:1;font-variant-numeric:tabular-nums}
|
|
246
|
+
.au-info{display:flex;flex-wrap:wrap;gap:6px 16px;padding:8px 0;font-size:11px}
|
|
247
|
+
.au-info-item{color:var(--text-muted);white-space:nowrap;display:inline-flex;align-items:center;gap:3px}
|
|
248
|
+
.au-status-dot{display:inline-block;width:8px;height:8px;border-radius:50%;margin-right:5px;vertical-align:middle;flex-shrink:0;transition:all .3s}
|
|
249
|
+
.au-status-dot.online{background:#22c55e;box-shadow:0 0 8px rgba(34,197,94,.6),0 0 16px rgba(34,197,94,.2);animation:dotBreathe 2s ease-in-out infinite}
|
|
250
|
+
.au-status-dot.offline{background:#6b7280;box-shadow:none}
|
|
251
|
+
.au-status-text{font-size:10px;font-weight:600;letter-spacing:.04em;padding:3px 10px;border-radius:6px;white-space:nowrap}
|
|
252
|
+
.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)}
|
|
253
|
+
.au-status-text.offline{color:#6b7280;background:rgba(107,114,128,.06);border:1px solid rgba(107,114,128,.1)}
|
|
254
|
+
[data-theme="light"] .au-status-text.online{background:rgba(34,197,94,.06);border-color:rgba(34,197,94,.15)}
|
|
255
|
+
[data-theme="light"] .au-status-text.offline{background:rgba(0,0,0,.03);border-color:rgba(0,0,0,.06)}
|
|
256
|
+
.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}
|
|
245
257
|
.au-group-header:first-child{margin-top:0}
|
|
246
258
|
.au-group-header .au-group-dot{display:inline-block;width:8px;height:8px;border-radius:50%}
|
|
247
|
-
.au-group-header .au-group-dot.online{background:#22c55e}
|
|
248
|
-
.au-group-header .au-group-dot.offline{background:#
|
|
259
|
+
.au-group-header .au-group-dot.online{background:#22c55e;box-shadow:0 0 6px rgba(34,197,94,.5)}
|
|
260
|
+
.au-group-header .au-group-dot.offline{background:#6b7280}
|
|
249
261
|
.au-group-header .au-group-count{font-size:12px;font-weight:400;color:var(--text-muted)}
|
|
250
|
-
.au-card.au-offline{opacity:.
|
|
251
|
-
.au-card.au-offline
|
|
252
|
-
.au-card.au-
|
|
262
|
+
.au-card.au-offline{opacity:.55}
|
|
263
|
+
.au-card.au-offline:hover{opacity:.8}
|
|
264
|
+
.au-card.au-offline::before{background:#6b7280}
|
|
265
|
+
.au-card.au-online::before{background:#22c55e;box-shadow:0 0 8px rgba(34,197,94,.3)}
|
|
266
|
+
.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}
|
|
267
|
+
.admin-pending-section::before{content:'';position:absolute;top:0;left:0;right:0;height:2px;background:linear-gradient(90deg,transparent,#fbbf24,#f59e0b,transparent)}
|
|
268
|
+
.admin-pending-section h3{font-size:14px;font-weight:700;color:#fbbf24;margin:0 0 14px;display:flex;align-items:center;gap:8px}
|
|
269
|
+
.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}
|
|
270
|
+
.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}
|
|
271
|
+
.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}
|
|
272
|
+
.admin-pending-card:hover{border-color:rgba(251,191,36,.35);box-shadow:0 4px 16px rgba(251,191,36,.08)}
|
|
273
|
+
.admin-pending-card .apc-name{font-size:14px;font-weight:700;color:var(--text)}
|
|
274
|
+
.admin-pending-card .apc-meta{font-size:11px;color:var(--text-muted);margin-top:4px;display:flex;align-items:center;gap:6px}
|
|
275
|
+
.admin-pending-card .apc-actions{display:flex;gap:8px;margin-top:12px}
|
|
276
|
+
.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)}
|
|
277
|
+
.admin-pending-card .apc-actions .btn-approve:hover{transform:translateY(-1px);box-shadow:0 4px 16px rgba(34,197,94,.35)}
|
|
278
|
+
.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}
|
|
279
|
+
.admin-pending-card .apc-actions .btn-reject:hover{background:rgba(244,63,94,.06);border-color:rgba(244,63,94,.4)}
|
|
253
280
|
.admin-card-tags{display:flex;gap:5px;margin:8px 0;align-items:center}
|
|
254
281
|
.admin-card-tags-left{display:flex;flex-wrap:wrap;gap:5px;align-items:center;flex:1;min-width:0}
|
|
255
|
-
.admin-card-tag{display:inline-flex;align-items:center;gap:3px;padding:
|
|
282
|
+
.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}
|
|
256
283
|
.admin-card-tag.tag-role{background:rgba(99,102,241,.1);color:var(--pri)}
|
|
257
284
|
.admin-card-tag.tag-kind{background:rgba(245,158,11,.1);color:#f59e0b}
|
|
258
285
|
.admin-card-tag.tag-owner{background:rgba(34,197,94,.1);color:#22c55e}
|
|
@@ -260,16 +287,16 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
260
287
|
.admin-card-tag.tag-version{background:rgba(139,92,246,.1);color:#8b5cf6}
|
|
261
288
|
.admin-card-tag.tag-visibility{background:rgba(99,102,241,.08);color:var(--pri)}
|
|
262
289
|
.admin-card-tag.tag-group{background:rgba(139,92,246,.08);color:#8b5cf6}
|
|
263
|
-
.admin-card-preview{font-size:12px;color:var(--text-sec);line-height:1.5;margin:8px 0;padding:
|
|
264
|
-
.admin-card-actions{display:inline-flex;gap:
|
|
290
|
+
.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%)}
|
|
291
|
+
.admin-card-actions{display:inline-flex;gap:6px;margin-left:auto;align-items:center;flex-shrink:0}
|
|
265
292
|
.admin-card-time{font-size:11px;color:var(--text-muted)}
|
|
266
|
-
.admin-card-detail{display:none;margin-top:0;padding:20px 24px 24px;border-top:1px dashed
|
|
293
|
+
.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}
|
|
267
294
|
@keyframes adminDetailIn{from{opacity:0;transform:translateY(-6px)}to{opacity:1;transform:translateY(0)}}
|
|
268
295
|
.admin-card.expanded .admin-card-detail{display:block}
|
|
269
|
-
.admin-card.expanded{border-color:rgba(99,102,241,.3);box-shadow:0 4px 24px rgba(99,102,241,.
|
|
296
|
+
.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)}
|
|
270
297
|
.admin-card-detail-meta{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:18px;font-size:12px;color:var(--text-muted)}
|
|
271
|
-
.admin-card-detail-meta .meta-item{display:inline-flex;align-items:center;gap:4px;padding:5px 12px;background:
|
|
272
|
-
.admin-card-detail-meta .meta-item:hover{border-color:rgba(99,102,241,.25);background:rgba(99,102,241,.
|
|
298
|
+
.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}
|
|
299
|
+
.admin-card-detail-meta .meta-item:hover{border-color:rgba(99,102,241,.25);background:rgba(99,102,241,.06)}
|
|
273
300
|
.admin-card-detail-section{margin-top:20px}
|
|
274
301
|
.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}
|
|
275
302
|
.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))}
|
|
@@ -295,7 +322,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
295
322
|
.adm-msg-side.assistant .adm-msg-role{color:var(--green)}
|
|
296
323
|
.adm-msg-time{font-size:9px;color:var(--text-muted)}
|
|
297
324
|
.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}
|
|
298
|
-
.adm-msg-body.collapsed{max-height:120px;overflow:hidden;-webkit-mask-image:linear-gradient(180deg,#000
|
|
325
|
+
.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)}
|
|
299
326
|
.adm-msg-toggle{display:none;padding:0 16px 8px;font-size:11px;color:var(--pri);cursor:pointer;transition:color .15s}
|
|
300
327
|
.adm-msg-toggle:hover{color:var(--pri-dark)}
|
|
301
328
|
.admin-card-expand-btn{font-size:12px;color:var(--pri);cursor:pointer;background:none;border:none;padding:2px 6px;font-family:inherit}
|
|
@@ -303,18 +330,24 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
303
330
|
.admin-toolbar{display:flex;align-items:center;gap:10px;margin-bottom:14px;flex-wrap:wrap}
|
|
304
331
|
.admin-toolbar h3{font-size:14px;font-weight:600;color:var(--text);white-space:nowrap;margin:0;margin-right:auto;line-height:32px}
|
|
305
332
|
.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}
|
|
306
|
-
.admin-badge{display:inline-flex;align-items:center;gap:4px;font-size:
|
|
307
|
-
.admin-badge.admin{background:rgba(
|
|
308
|
-
.admin-badge.
|
|
309
|
-
.admin-badge.
|
|
310
|
-
.admin-badge.
|
|
311
|
-
.admin-badge.
|
|
312
|
-
.admin-
|
|
313
|
-
.admin-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
[data-theme="light"] .admin-
|
|
333
|
+
.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}
|
|
334
|
+
.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)}
|
|
335
|
+
.admin-badge.admin:hover{box-shadow:0 0 20px rgba(34,197,94,.15),inset 0 1px 0 rgba(255,255,255,.08)}
|
|
336
|
+
.admin-badge.member{background:rgba(99,102,241,.06);color:var(--text-muted);border:1px solid rgba(99,102,241,.12)}
|
|
337
|
+
.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)}
|
|
338
|
+
.admin-badge.public{background:rgba(99,102,241,.08);color:var(--pri);border:1px solid rgba(99,102,241,.15)}
|
|
339
|
+
.admin-badge.group{background:rgba(139,92,246,.08);color:#8b5cf6;border:1px solid rgba(139,92,246,.15)}
|
|
340
|
+
.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)}
|
|
341
|
+
.au-badges{display:flex;align-items:center;gap:6px;flex-shrink:0;flex-wrap:wrap;justify-content:flex-end}
|
|
342
|
+
.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)}
|
|
343
|
+
.admin-empty .ae-icon{font-size:32px;display:block;margin-bottom:10px;opacity:.4}
|
|
344
|
+
[data-theme="light"] .admin-badge.admin{background:rgba(5,150,105,.08);color:#059669;border-color:rgba(5,150,105,.18)}
|
|
345
|
+
[data-theme="light"] .admin-badge.member{background:rgba(0,0,0,.04);color:#6b7280;border-color:rgba(0,0,0,.08)}
|
|
346
|
+
[data-theme="light"] .admin-badge.pending{background:rgba(245,158,11,.08);color:#d97706;border-color:rgba(245,158,11,.18)}
|
|
347
|
+
[data-theme="light"] .admin-badge.owner{background:rgba(245,158,11,.08);color:#b45309;border-color:rgba(245,158,11,.2)}
|
|
348
|
+
[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%)}
|
|
349
|
+
[data-theme="light"] .admin-stat-box{background:rgba(255,255,255,.8)}
|
|
350
|
+
[data-theme="light"] .admin-pending-section{background:linear-gradient(135deg,rgba(251,191,36,.03),rgba(245,158,11,.015))}
|
|
318
351
|
.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}
|
|
319
352
|
.confirm-overlay.show{display:flex}
|
|
320
353
|
.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}
|
|
@@ -712,7 +745,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
712
745
|
[data-theme="light"] .nav-tabs{background:rgba(0,0,0,.05)}
|
|
713
746
|
[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)}
|
|
714
747
|
.analytics-view,.settings-view,.logs-view,.migrate-view,.admin-view{flex:1;min-width:0;flex-direction:column;gap:20px}
|
|
715
|
-
.feed-wrap,.tasks-view,.skills-view,.analytics-view,.
|
|
748
|
+
.feed-wrap,.tasks-view,.skills-view,.analytics-view,.logs-view,.migrate-view,.admin-view,.settings-view{max-width:960px}
|
|
716
749
|
|
|
717
750
|
/* ─── Logs ─── */
|
|
718
751
|
.logs-toolbar{display:flex;align-items:center;justify-content:space-between;padding:8px 0}
|
|
@@ -771,6 +804,10 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
771
804
|
.recall-score.high{background:rgba(34,197,94,.12);color:#22c55e}
|
|
772
805
|
.recall-score.mid{background:rgba(251,191,36,.12);color:#f59e0b}
|
|
773
806
|
.recall-score.low{background:rgba(248,113,113,.1);color:var(--text-muted)}
|
|
807
|
+
.recall-origin{flex-shrink:0;font-size:9px;font-weight:600;padding:1px 5px;border-radius:4px}
|
|
808
|
+
.recall-origin.local-shared{background:rgba(59,130,246,.12);color:#3b82f6}
|
|
809
|
+
.recall-origin.hub-memory{background:rgba(139,92,246,.12);color:#8b5cf6}
|
|
810
|
+
.recall-origin.hub-remote{background:rgba(139,92,246,.12);color:#8b5cf6}
|
|
774
811
|
.recall-summary-short{flex:1;color:var(--text-sec);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
775
812
|
.recall-expand-icon{flex-shrink:0;font-size:10px;color:var(--text-muted);transition:transform .15s}
|
|
776
813
|
.recall-item.expanded .recall-expand-icon{transform:rotate(90deg)}
|
|
@@ -939,8 +976,6 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
939
976
|
.team-guide-steps li::marker{color:var(--pri);font-weight:700;font-size:11px}
|
|
940
977
|
.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}
|
|
941
978
|
.team-guide-opt .btn-guide:hover{background:rgba(99,102,241,.14);border-color:var(--pri)}
|
|
942
|
-
.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}
|
|
943
|
-
.team-guide-dismiss:hover{opacity:1}
|
|
944
979
|
[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)}
|
|
945
980
|
[data-theme="light"] .team-guide-opt{box-shadow:0 1px 3px rgba(0,0,0,.03)}
|
|
946
981
|
[data-theme="light"] .team-guide-opt:hover{box-shadow:0 4px 16px rgba(0,0,0,.04)}
|
|
@@ -1183,7 +1218,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1183
1218
|
</div>
|
|
1184
1219
|
<button class="btn btn-ghost btn-sm" onclick="doLogout()" data-i18n="logout">Logout</button>
|
|
1185
1220
|
</div>
|
|
1186
|
-
|
|
1221
|
+
</div>
|
|
1187
1222
|
</div>
|
|
1188
1223
|
|
|
1189
1224
|
<div class="main-content">
|
|
@@ -1192,7 +1227,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1192
1227
|
<div class="stat-card pri"><div class="stat-value" id="statTotal">-</div><div class="stat-label" data-i18n="stat.memories">Memories</div></div>
|
|
1193
1228
|
<div class="stat-card green"><div class="stat-value" id="statSessions">-</div><div class="stat-label" data-i18n="stat.sessions">Sessions</div></div>
|
|
1194
1229
|
<div class="stat-card amber"><div class="stat-value" id="statEmbeddings">-</div><div class="stat-label" data-i18n="stat.embeddings">Embeddings</div></div>
|
|
1195
|
-
<div class="stat-card rose"><div class="stat-value" id="
|
|
1230
|
+
<div class="stat-card rose"><div class="stat-value" id="statAgents">-</div><div class="stat-label" data-i18n="stat.agents">Agents</div></div>
|
|
1196
1231
|
</div>
|
|
1197
1232
|
<div id="sidebarSharingSection" style="display:none">
|
|
1198
1233
|
<div class="sharing-sidebar-card">
|
|
@@ -1215,7 +1250,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1215
1250
|
<select id="filterOwner" class="filter-select" onchange="onOwnerFilterChange()">
|
|
1216
1251
|
<option value="" data-i18n="filter.allagents">All agents</option>
|
|
1217
1252
|
</select>
|
|
1218
|
-
<select id="memorySearchScope" class="filter-select" onchange="onMemoryScopeChange()">
|
|
1253
|
+
<select id="memorySearchScope" class="filter-select" onchange="onMemoryScopeChange()" style="display:none">
|
|
1219
1254
|
<option value="local" data-i18n="scope.thisAgent">This Agent</option>
|
|
1220
1255
|
<option value="allLocal" data-i18n="scope.thisDevice">This Device</option>
|
|
1221
1256
|
<option value="hub" data-i18n="scope.hub">Team</option>
|
|
@@ -1227,7 +1262,6 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1227
1262
|
<button class="filter-chip active" data-role="" onclick="setRoleFilter(this,'')" data-i18n="filter.all">All</button>
|
|
1228
1263
|
<button class="filter-chip" data-role="user" onclick="setRoleFilter(this,'user')">User</button>
|
|
1229
1264
|
<button class="filter-chip" data-role="assistant" onclick="setRoleFilter(this,'assistant')">Assistant</button>
|
|
1230
|
-
<button class="filter-chip" data-role="system" onclick="setRoleFilter(this,'system')">System</button>
|
|
1231
1265
|
<span class="filter-sep"></span>
|
|
1232
1266
|
<select id="filterSort" class="filter-select" onchange="applyFilters()">
|
|
1233
1267
|
<option value="newest" data-i18n="filter.newest">Newest first</option>
|
|
@@ -1260,7 +1294,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1260
1294
|
<button class="filter-chip" data-task-status="active" onclick="setTaskStatusFilter(this,'active')" data-i18n="tasks.status.active">Active</button>
|
|
1261
1295
|
<button class="filter-chip" data-task-status="completed" onclick="setTaskStatusFilter(this,'completed')" data-i18n="tasks.status.completed">Completed</button>
|
|
1262
1296
|
<button class="filter-chip" data-task-status="skipped" onclick="setTaskStatusFilter(this,'skipped')" data-i18n="tasks.status.skipped">Skipped</button>
|
|
1263
|
-
<select id="taskSearchScope" class="scope-select" onchange="onTaskScopeChange()">
|
|
1297
|
+
<select id="taskSearchScope" class="scope-select" onchange="onTaskScopeChange()" style="display:none">
|
|
1264
1298
|
<option value="local" data-i18n="scope.thisAgent">This Agent</option>
|
|
1265
1299
|
<option value="allLocal" data-i18n="scope.thisDevice">This Device</option>
|
|
1266
1300
|
<option value="hub" data-i18n="scope.hub">Team</option>
|
|
@@ -1302,13 +1336,13 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1302
1336
|
<div class="search-bar">
|
|
1303
1337
|
<span class="search-icon">🔍</span>
|
|
1304
1338
|
<input type="text" id="skillSearchInput" placeholder="Search skills..." data-i18n-ph="skills.search.placeholder" oninput="debounceSkillSearch()">
|
|
1305
|
-
<select id="skillSearchScope" class="scope-select" onchange="onSkillScopeChange()">
|
|
1339
|
+
<select id="skillSearchScope" class="scope-select" onchange="onSkillScopeChange()" style="display:none">
|
|
1306
1340
|
<option value="local" data-i18n="scope.thisAgent">This Agent</option>
|
|
1307
1341
|
<option value="allLocal" data-i18n="scope.thisDevice">This Device</option>
|
|
1308
1342
|
<option value="hub" data-i18n="scope.hub">Team</option>
|
|
1309
1343
|
</select>
|
|
1310
1344
|
</div>
|
|
1311
|
-
<div class="search-meta" id="skillSearchMeta"></div>
|
|
1345
|
+
<div class="search-meta" id="skillSearchMeta" style="display:none"></div>
|
|
1312
1346
|
<div class="tasks-header">
|
|
1313
1347
|
<div class="tasks-stats">
|
|
1314
1348
|
<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>
|
|
@@ -1322,8 +1356,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1322
1356
|
<button class="filter-chip" data-skill-status="active" onclick="setSkillStatusFilter(this,'active')" data-i18n="skills.filter.active">Active</button>
|
|
1323
1357
|
<button class="filter-chip" data-skill-status="draft" onclick="setSkillStatusFilter(this,'draft')" data-i18n="skills.filter.draft">Draft</button>
|
|
1324
1358
|
<button class="filter-chip" data-skill-status="archived" onclick="setSkillStatusFilter(this,'archived')" data-i18n="skills.filter.archived">Archived</button>
|
|
1325
|
-
<
|
|
1326
|
-
<select id="skillVisibilityFilter" class="filter-select" onchange="loadSkills()">
|
|
1359
|
+
<select id="skillVisibilityFilter" class="filter-select" onchange="loadSkills()" style="display:none">
|
|
1327
1360
|
<option value="" data-i18n="filter.allvisibility">All visibility</option>
|
|
1328
1361
|
<option value="public" data-i18n="filter.public">Public</option>
|
|
1329
1362
|
<option value="private" data-i18n="filter.private">Private</option>
|
|
@@ -1410,7 +1443,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1410
1443
|
<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">
|
|
1411
1444
|
<option value="" data-i18n="logs.allTools">All Tools</option>
|
|
1412
1445
|
</select>
|
|
1413
|
-
|
|
1446
|
+
|
|
1414
1447
|
</div>
|
|
1415
1448
|
<div class="logs-toolbar-right">
|
|
1416
1449
|
<input type="checkbox" id="logAutoRefresh" style="display:none">
|
|
@@ -1606,9 +1639,8 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1606
1639
|
</div>
|
|
1607
1640
|
</div>
|
|
1608
1641
|
<div class="settings-card-body">
|
|
1609
|
-
<!-- team setup guide (inside Hub card) -->
|
|
1642
|
+
<!-- team setup guide (inside Hub card) — always visible when sharing is not configured -->
|
|
1610
1643
|
<div class="team-guide" id="teamSetupGuide">
|
|
1611
|
-
<button class="team-guide-dismiss" onclick="dismissTeamGuide()" title="Dismiss">×</button>
|
|
1612
1644
|
<div class="team-guide-title">\u{1F680} <span data-i18n="guide.title">Get Started with Team Collaboration</span></div>
|
|
1613
1645
|
<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>
|
|
1614
1646
|
<div class="team-guide-options">
|
|
@@ -1622,7 +1654,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1622
1654
|
<li><span data-i18n="guide.join.s1">Ask your team admin for the Server Address and Team Token</span></li>
|
|
1623
1655
|
<li><span data-i18n="guide.join.s2">Enable sharing above, select "Client" mode</span></li>
|
|
1624
1656
|
<li><span data-i18n="guide.join.s3">Fill in Server Address and Team Token, click "Test Connection"</span></li>
|
|
1625
|
-
<li><span data-i18n="guide.join.s4">Save
|
|
1657
|
+
<li><span data-i18n="guide.join.s4">Click "Save & Apply" — the service restarts automatically (page refreshes)</span></li>
|
|
1626
1658
|
</ol>
|
|
1627
1659
|
<button class="btn-guide" onclick="guideGoToHub('client')" data-i18n="guide.join.btn">\u2192 Configure Client Mode</button>
|
|
1628
1660
|
</div>
|
|
@@ -1634,7 +1666,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1634
1666
|
<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>
|
|
1635
1667
|
<ol class="team-guide-steps">
|
|
1636
1668
|
<li><span data-i18n="guide.hub.s1">Enable sharing above, select "Server" mode</span></li>
|
|
1637
|
-
<li><span data-i18n="guide.hub.s2">Set a team name,
|
|
1669
|
+
<li><span data-i18n="guide.hub.s2">Set a team name, click "Save & Apply" — the service restarts automatically</span></li>
|
|
1638
1670
|
<li><span data-i18n="guide.hub.s3">Share the Server Address and Team Token with your team members</span></li>
|
|
1639
1671
|
<li><span data-i18n="guide.hub.s4">Approve join requests in the Admin Panel</span></li>
|
|
1640
1672
|
</ol>
|
|
@@ -1695,7 +1727,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1695
1727
|
<div style="font-weight:700;color:var(--text);margin-bottom:4px" data-i18n="settings.hub.clientSteps.title">Quick Setup (3 steps)</div>
|
|
1696
1728
|
<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>
|
|
1697
1729
|
<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>
|
|
1698
|
-
<div><span style="color:var(--accent)">3.</span> <span data-i18n="settings.hub.clientSteps.s3">Click "Save
|
|
1730
|
+
<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>
|
|
1699
1731
|
</div>
|
|
1700
1732
|
<div class="settings-grid">
|
|
1701
1733
|
<div class="settings-field full-width">
|
|
@@ -1786,8 +1818,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1786
1818
|
<div id="adminMainContent">
|
|
1787
1819
|
<div class="admin-header">
|
|
1788
1820
|
<div class="admin-header-top">
|
|
1789
|
-
<h2><span class="ah-icon">\u{
|
|
1790
|
-
<button class="btn btn-sm btn-ghost" onclick="loadAdminData()" style="backdrop-filter:blur(8px)" data-i18n="admin.refresh">\u21BB Refresh</button>
|
|
1821
|
+
<h2><span class="ah-icon">\u{26A1}</span> <span data-i18n="admin.title">Team Admin Panel</span></h2>
|
|
1791
1822
|
</div>
|
|
1792
1823
|
<div class="admin-header-sub" data-i18n="admin.subtitle">Manage team members and shared resources</div>
|
|
1793
1824
|
<div class="admin-stat-row" id="adminStats"></div>
|
|
@@ -2000,7 +2031,9 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
2000
2031
|
<script>
|
|
2001
2032
|
let activeSession=null,activeRole='',editingId=null,searchTimer=null,memoryCache={},currentPage=1,totalPages=1,totalCount=0,PAGE_SIZE=40,metricsDays=30;
|
|
2002
2033
|
let memorySearchScope='local',skillSearchScope='local',taskSearchScope='local';
|
|
2034
|
+
let _lastMemoriesFingerprint='',_lastTasksFingerprint='',_lastSkillsFingerprint='';
|
|
2003
2035
|
let _embeddingWarningShown=false;
|
|
2036
|
+
let _currentAgentOwner='agent:main';
|
|
2004
2037
|
|
|
2005
2038
|
/* ─── i18n ─── */
|
|
2006
2039
|
const I18N={
|
|
@@ -2051,8 +2084,8 @@ const I18N={
|
|
|
2051
2084
|
'skills.load.error':'Failed to load skills',
|
|
2052
2085
|
'skills.hub.title':'\u{1F310} Team Skills',
|
|
2053
2086
|
'scope.local':'Local',
|
|
2054
|
-
'scope.thisAgent':'This Agent',
|
|
2055
|
-
'scope.thisDevice':'
|
|
2087
|
+
'scope.thisAgent':'This Agent Only',
|
|
2088
|
+
'scope.thisDevice':'All Local Agents',
|
|
2056
2089
|
'scope.group':'Group',
|
|
2057
2090
|
'scope.all':'All',
|
|
2058
2091
|
'skills.visibility.public':'Shared Locally',
|
|
@@ -2090,6 +2123,13 @@ const I18N={
|
|
|
2090
2123
|
'notif.userJoin':'New user requests to join the team',
|
|
2091
2124
|
'notif.userOnline':'User came online',
|
|
2092
2125
|
'notif.userOffline':'User went offline',
|
|
2126
|
+
'notif.userLeft':'User has left the team',
|
|
2127
|
+
'notif.membershipApproved':'Your team join request has been approved',
|
|
2128
|
+
'notif.membershipRejected':'Your team join request has been declined',
|
|
2129
|
+
'notif.membershipRemoved':'You have been removed from the team by the admin',
|
|
2130
|
+
'notif.hubShutdown':'The team server has been shut down',
|
|
2131
|
+
'notif.rolePromoted':'You have been promoted to admin',
|
|
2132
|
+
'notif.roleDemoted':'You have been changed to member',
|
|
2093
2133
|
'notif.clearAll':'Clear all',
|
|
2094
2134
|
'notif.timeAgo.just':'just now',
|
|
2095
2135
|
'notif.timeAgo.min':'{n}m ago',
|
|
@@ -2098,7 +2138,7 @@ const I18N={
|
|
|
2098
2138
|
'stat.memories':'Memories',
|
|
2099
2139
|
'stat.sessions':'Sessions',
|
|
2100
2140
|
'stat.embeddings':'Embeddings',
|
|
2101
|
-
'stat.
|
|
2141
|
+
'stat.agents':'Agents',
|
|
2102
2142
|
'stat.active':'active',
|
|
2103
2143
|
'stat.deduped':'deduped',
|
|
2104
2144
|
'sidebar.sessions':'Sessions',
|
|
@@ -2197,6 +2237,9 @@ const I18N={
|
|
|
2197
2237
|
'logs.recall.noHits':'No matching memories',
|
|
2198
2238
|
'logs.recall.noneRelevant':'LLM filter: none relevant',
|
|
2199
2239
|
'logs.recall.more':'{n} more...',
|
|
2240
|
+
'recall.origin.localShared':'Local Shared',
|
|
2241
|
+
'recall.origin.hubMemory':'Team Cache',
|
|
2242
|
+
'recall.origin.hubRemote':'Team',
|
|
2200
2243
|
'tab.import':'\u{1F4E5} Import',
|
|
2201
2244
|
'tab.settings':'\u2699 Settings',
|
|
2202
2245
|
'settings.modelconfig':'Model Configuration',
|
|
@@ -2237,12 +2280,12 @@ const I18N={
|
|
|
2237
2280
|
'settings.test.ok':'Connected',
|
|
2238
2281
|
'settings.test.fail':'Failed',
|
|
2239
2282
|
'settings.session.expired':'Session expired, please refresh the page to log in again',
|
|
2240
|
-
'settings.save':'Save
|
|
2283
|
+
'settings.save':'Save & Apply',
|
|
2241
2284
|
'settings.reset':'Reset',
|
|
2242
2285
|
'settings.saved':'Saved',
|
|
2243
|
-
'settings.restart.hint':'
|
|
2244
|
-
'settings.restart.autoRefresh':'
|
|
2245
|
-
'settings.restart.waiting':'Configuration saved.
|
|
2286
|
+
'settings.restart.hint':'Changes will take effect after the service restarts automatically.',
|
|
2287
|
+
'settings.restart.autoRefresh':'Service restarting, page will refresh automatically...',
|
|
2288
|
+
'settings.restart.waiting':'Configuration saved. Service is restarting...',
|
|
2246
2289
|
'settings.save.fail':'Failed to save settings',
|
|
2247
2290
|
'settings.save.emb.required':'Embedding model is required. Please configure an embedding model before saving.',
|
|
2248
2291
|
'settings.save.emb.fail':'Embedding model test failed, cannot save',
|
|
@@ -2369,16 +2412,16 @@ const I18N={
|
|
|
2369
2412
|
'settings.hub.tokenCopied':'Team Token copied!',
|
|
2370
2413
|
'settings.hub.hubSteps.title':'Quick Setup (3 steps)',
|
|
2371
2414
|
'settings.hub.hubSteps.s1':'Fill in Team Name below (or keep default)',
|
|
2372
|
-
'settings.hub.hubSteps.s2':'Click "Save
|
|
2415
|
+
'settings.hub.hubSteps.s2':'Click "Save & Apply" — the service will restart automatically',
|
|
2373
2416
|
'settings.hub.hubSteps.s3':'Share the Server Address and Team Token below with your team members',
|
|
2374
2417
|
'settings.hub.clientSteps.title':'Quick Setup (3 steps)',
|
|
2375
2418
|
'settings.hub.clientSteps.s1':'Ask your team admin for the Server Address and Team Token',
|
|
2376
2419
|
'settings.hub.clientSteps.s2':'Fill them in below, click "Test Connection" to verify',
|
|
2377
|
-
'settings.hub.clientSteps.s3':'Click "Save
|
|
2420
|
+
'settings.hub.clientSteps.s3':'Click "Save & Apply" — the service will restart and page refreshes automatically',
|
|
2378
2421
|
'settings.hub.shareInfo.title':'Share this info with your team members:',
|
|
2379
2422
|
'settings.hub.shareInfo.yourIP':'your-IP',
|
|
2380
2423
|
'settings.hub.shareInfo.clickCopy':'Click to copy',
|
|
2381
|
-
'settings.hub.restartAlert':'Team sharing config saved!
|
|
2424
|
+
'settings.hub.restartAlert':'Team sharing config saved! The service will restart automatically to apply changes.',
|
|
2382
2425
|
'settings.hub.hubAddress':'Server Address',
|
|
2383
2426
|
'settings.hub.hubAddress.hint':'Team server address, e.g. 192.168.1.100:18800',
|
|
2384
2427
|
'settings.hub.teamTokenClient':'Team Token',
|
|
@@ -2389,6 +2432,7 @@ const I18N={
|
|
|
2389
2432
|
'settings.hub.userToken.hint':'Usually auto-obtained after joining. Only fill if given by admin.',
|
|
2390
2433
|
'settings.hub.testConnection':'Test Connection',
|
|
2391
2434
|
'settings.hub.test.noAddr':'Please enter server address first',
|
|
2435
|
+
'settings.hub.teamToken.required':'Please enter team token',
|
|
2392
2436
|
'settings.hub.test.testing':'Testing...',
|
|
2393
2437
|
'settings.hub.test.ok':'Connected successfully',
|
|
2394
2438
|
'settings.hub.test.fail':'Connection failed',
|
|
@@ -2398,6 +2442,10 @@ const I18N={
|
|
|
2398
2442
|
'sidebar.hub':'\u{1F310} Team Sharing',
|
|
2399
2443
|
'sharing.sidebar.connected':'Connected',
|
|
2400
2444
|
'sharing.sidebar.disconnected':'Disconnected',
|
|
2445
|
+
'sharing.sidebar.hubRunning':'Hub Running',
|
|
2446
|
+
'sharing.sidebar.teamName':'Team',
|
|
2447
|
+
'sharing.sidebar.members':'Members',
|
|
2448
|
+
'sharing.sidebar.online':'online',
|
|
2401
2449
|
'sharing.sidebar.pending':'Pending Approval',
|
|
2402
2450
|
'sharing.sidebar.rejected':'Rejected',
|
|
2403
2451
|
'sharing.sidebar.starting':'Starting...',
|
|
@@ -2407,11 +2455,21 @@ const I18N={
|
|
|
2407
2455
|
'sharing.sidebar.targetHub':'Team Server:',
|
|
2408
2456
|
'sharing.pendingApproval.hint':'Your join request has been submitted. Please wait for the team admin to approve.',
|
|
2409
2457
|
'sharing.rejected.hint':'Your join request was rejected by the team admin. Please contact the admin or retry.',
|
|
2458
|
+
'sharing.removed.hint':'You have been removed from the team by the admin. You can re-apply to join.',
|
|
2459
|
+
'sharing.joinTeam':'Join Team',
|
|
2460
|
+
'sharing.joinSent.pending':'Join request sent! Waiting for admin approval.',
|
|
2461
|
+
'sharing.joinSent.active':'Successfully joined the team!',
|
|
2410
2462
|
'sharing.retryJoin':'Retry Join',
|
|
2411
2463
|
'sharing.retryJoin.hint':'Clears local data and re-submits the join request',
|
|
2412
2464
|
'sharing.retryJoin.confirm':'This will clear your current connection and re-submit a join request. Continue?',
|
|
2465
|
+
'sharing.leaveTeam':'Leave Team',
|
|
2466
|
+
'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?',
|
|
2467
|
+
'sharing.leaveTeam.success':'You have left the team. Sharing has been disabled.',
|
|
2468
|
+
'sharing.leaveTeam.fail':'Failed to leave team',
|
|
2469
|
+
'sharing.team.default':'the team',
|
|
2413
2470
|
'sharing.retryJoin.success':'Join request re-submitted. Waiting for admin approval.',
|
|
2414
2471
|
'sharing.retryJoin.fail':'Failed to retry join',
|
|
2472
|
+
'sharing.ownerRemoved':'(removed)',
|
|
2415
2473
|
'sharing.cannotJoinSelf':'Cannot join your own server. Please enter a remote server address.',
|
|
2416
2474
|
'scope.hub':'Team',
|
|
2417
2475
|
'memory.detail.title':'Memory Detail',
|
|
@@ -2462,6 +2520,7 @@ const I18N={
|
|
|
2462
2520
|
'admin.editName':'Edit Name',
|
|
2463
2521
|
'admin.lastAdminHint':'Last admin — cannot remove or demote',
|
|
2464
2522
|
'admin.ownerHint':'Hub owner — cannot be demoted or removed',
|
|
2523
|
+
'admin.selfHint':'This is you',
|
|
2465
2524
|
'admin.editNamePrompt':'Enter new username:',
|
|
2466
2525
|
'confirm.promoteAdmin':'Promote this user to admin? They will be able to manage all team members and resources.',
|
|
2467
2526
|
'confirm.demoteMember':'Demote this admin to member?',
|
|
@@ -2522,6 +2581,9 @@ const I18N={
|
|
|
2522
2581
|
'admin.groupsFailed':'Failed to load groups: ',
|
|
2523
2582
|
'toast.userApproved':'User approved',
|
|
2524
2583
|
'sharing.approved.toast':'Your join request has been approved!',
|
|
2584
|
+
'sharing.rejected.toast':'Your join request was rejected by the admin.',
|
|
2585
|
+
'sharing.hubOffline.toast':'Team server is offline. Will reconnect automatically when it comes back.',
|
|
2586
|
+
'sharing.hubReconnected.toast':'Team server is back online! Connection restored.',
|
|
2525
2587
|
'toast.userRejected':'User rejected',
|
|
2526
2588
|
'toast.approveFail':'Approve failed',
|
|
2527
2589
|
'toast.rejectFail':'Reject failed',
|
|
@@ -2614,9 +2676,9 @@ const I18N={
|
|
|
2614
2676
|
'share.status.agents':'Local',
|
|
2615
2677
|
'share.status.hub':'Team',
|
|
2616
2678
|
'share.scope.title':'Sharing Scope',
|
|
2617
|
-
'share.scope.private':'
|
|
2618
|
-
'share.scope.local':'
|
|
2619
|
-
'share.scope.team':'Team',
|
|
2679
|
+
'share.scope.private':'Private',
|
|
2680
|
+
'share.scope.local':'Local Shared',
|
|
2681
|
+
'share.scope.team':'Team Shared',
|
|
2620
2682
|
'share.scope.current':'Current',
|
|
2621
2683
|
'share.scope.teamDisabled':'Not connected to team server',
|
|
2622
2684
|
'share.scope.teamIncludes':'Includes visibility to all local agents',
|
|
@@ -2681,7 +2743,10 @@ const I18N={
|
|
|
2681
2743
|
'update.dismiss':'Dismiss',
|
|
2682
2744
|
'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?',
|
|
2683
2745
|
'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?',
|
|
2684
|
-
'sharing.disable.restartAlert':'Sharing has been disabled.
|
|
2746
|
+
'sharing.disable.restartAlert':'Sharing has been disabled. The service will restart automatically to apply the change.',
|
|
2747
|
+
'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?',
|
|
2748
|
+
'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?',
|
|
2749
|
+
'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?',
|
|
2685
2750
|
'admin.notEnabled.title':'Team sharing is not enabled',
|
|
2686
2751
|
'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.',
|
|
2687
2752
|
'admin.notEnabled.setupHub':'Set Up as Team Server',
|
|
@@ -2699,12 +2764,12 @@ const I18N={
|
|
|
2699
2764
|
'guide.join.s1':'Ask your team admin for the Server Address and Team Token',
|
|
2700
2765
|
'guide.join.s2':'Go to Settings \u2192 Team Sharing, enable sharing, select "Client" mode',
|
|
2701
2766
|
'guide.join.s3':'Fill in Server Address and Team Token, click "Test Connection"',
|
|
2702
|
-
'guide.join.s4':'Save
|
|
2767
|
+
'guide.join.s4':'Click "Save & Apply" — the service restarts automatically (page refreshes)',
|
|
2703
2768
|
'guide.join.btn':'\u2192 Configure Client Mode',
|
|
2704
2769
|
'guide.hub.title':'Start Your Own Team Server',
|
|
2705
2770
|
'guide.hub.desc':'Be the team server. Run it on this device so others can connect and share memories with you.',
|
|
2706
2771
|
'guide.hub.s1':'Go to Settings \u2192 Team Sharing, enable sharing, select "Server" mode',
|
|
2707
|
-
'guide.hub.s2':'Set a team name,
|
|
2772
|
+
'guide.hub.s2':'Set a team name, click "Save & Apply" — the service restarts automatically',
|
|
2708
2773
|
'guide.hub.s3':'Share the Server Address and Team Token with your team members',
|
|
2709
2774
|
'guide.hub.s4':'Approve join requests in the Admin Panel',
|
|
2710
2775
|
'guide.hub.btn':'\u2192 Configure Server Mode'
|
|
@@ -2756,8 +2821,8 @@ const I18N={
|
|
|
2756
2821
|
'skills.load.error':'加载技能失败',
|
|
2757
2822
|
'skills.hub.title':'\u{1F310} 团队共享技能',
|
|
2758
2823
|
'scope.local':'本地',
|
|
2759
|
-
'scope.thisAgent':'
|
|
2760
|
-
'scope.thisDevice':'
|
|
2824
|
+
'scope.thisAgent':'仅本智能体',
|
|
2825
|
+
'scope.thisDevice':'本机所有智能体',
|
|
2761
2826
|
'scope.group':'团队',
|
|
2762
2827
|
'scope.all':'全部',
|
|
2763
2828
|
'skills.visibility.public':'本机共享',
|
|
@@ -2795,6 +2860,13 @@ const I18N={
|
|
|
2795
2860
|
'notif.userJoin':'有新用户申请加入团队',
|
|
2796
2861
|
'notif.userOnline':'用户上线了',
|
|
2797
2862
|
'notif.userOffline':'用户下线了',
|
|
2863
|
+
'notif.userLeft':'用户已退出团队',
|
|
2864
|
+
'notif.membershipApproved':'你的团队加入申请已通过',
|
|
2865
|
+
'notif.membershipRejected':'你的团队加入申请已被拒绝',
|
|
2866
|
+
'notif.membershipRemoved':'你已被管理员移出团队',
|
|
2867
|
+
'notif.hubShutdown':'团队服务已关闭',
|
|
2868
|
+
'notif.rolePromoted':'你已被提升为管理员',
|
|
2869
|
+
'notif.roleDemoted':'你已被设为普通成员',
|
|
2798
2870
|
'notif.clearAll':'清除全部',
|
|
2799
2871
|
'notif.timeAgo.just':'刚刚',
|
|
2800
2872
|
'notif.timeAgo.min':'{n}分钟前',
|
|
@@ -2803,7 +2875,7 @@ const I18N={
|
|
|
2803
2875
|
'stat.memories':'记忆',
|
|
2804
2876
|
'stat.sessions':'会话',
|
|
2805
2877
|
'stat.embeddings':'嵌入',
|
|
2806
|
-
'stat.
|
|
2878
|
+
'stat.agents':'智能体',
|
|
2807
2879
|
'stat.active':'活跃',
|
|
2808
2880
|
'stat.deduped':'已去重',
|
|
2809
2881
|
'sidebar.sessions':'会话列表',
|
|
@@ -2902,6 +2974,9 @@ const I18N={
|
|
|
2902
2974
|
'logs.recall.noHits':'未匹配到记忆',
|
|
2903
2975
|
'logs.recall.noneRelevant':'LLM 过滤:无相关记忆',
|
|
2904
2976
|
'logs.recall.more':'还有 {n} 条...',
|
|
2977
|
+
'recall.origin.localShared':'本机共享',
|
|
2978
|
+
'recall.origin.hubMemory':'团队缓存',
|
|
2979
|
+
'recall.origin.hubRemote':'团队',
|
|
2905
2980
|
'tab.import':'\u{1F4E5} 导入',
|
|
2906
2981
|
'tab.settings':'\u2699 设置',
|
|
2907
2982
|
'settings.modelconfig':'模型配置',
|
|
@@ -2942,12 +3017,12 @@ const I18N={
|
|
|
2942
3017
|
'settings.test.ok':'连接成功',
|
|
2943
3018
|
'settings.test.fail':'连接失败',
|
|
2944
3019
|
'settings.session.expired':'登录已过期,请刷新页面重新登录',
|
|
2945
|
-
'settings.save':'
|
|
3020
|
+
'settings.save':'保存并应用',
|
|
2946
3021
|
'settings.reset':'重置',
|
|
2947
3022
|
'settings.saved':'已保存',
|
|
2948
|
-
'settings.restart.hint':'
|
|
2949
|
-
'settings.restart.autoRefresh':'
|
|
2950
|
-
'settings.restart.waiting':'
|
|
3023
|
+
'settings.restart.hint':'修改将在服务自动重启后生效。',
|
|
3024
|
+
'settings.restart.autoRefresh':'服务重启中,页面将自动刷新...',
|
|
3025
|
+
'settings.restart.waiting':'配置已保存,服务正在重启...',
|
|
2951
3026
|
'settings.save.fail':'保存设置失败',
|
|
2952
3027
|
'settings.save.emb.required':'嵌入模型为必填项,请先配置嵌入模型再保存。',
|
|
2953
3028
|
'settings.save.emb.fail':'嵌入模型测试失败,无法保存',
|
|
@@ -3074,16 +3149,16 @@ const I18N={
|
|
|
3074
3149
|
'settings.hub.tokenCopied':'团队令牌已复制!',
|
|
3075
3150
|
'settings.hub.hubSteps.title':'快速配置(3 步)',
|
|
3076
3151
|
'settings.hub.hubSteps.s1':'填写下方团队名称(或保持默认)',
|
|
3077
|
-
'settings.hub.hubSteps.s2':'
|
|
3152
|
+
'settings.hub.hubSteps.s2':'点击「保存并应用」,服务将自动重启',
|
|
3078
3153
|
'settings.hub.hubSteps.s3':'将下方的服务器地址和团队令牌分享给团队成员',
|
|
3079
3154
|
'settings.hub.clientSteps.title':'快速配置(3 步)',
|
|
3080
3155
|
'settings.hub.clientSteps.s1':'向团队管理员获取服务器地址和团队令牌',
|
|
3081
3156
|
'settings.hub.clientSteps.s2':'填入下方,点击"测试连接"验证连通性',
|
|
3082
|
-
'settings.hub.clientSteps.s3':'
|
|
3157
|
+
'settings.hub.clientSteps.s3':'点击「保存并应用」,服务将自动重启(页面会自动刷新)',
|
|
3083
3158
|
'settings.hub.shareInfo.title':'请将以下信息分享给团队成员:',
|
|
3084
3159
|
'settings.hub.shareInfo.yourIP':'你的IP',
|
|
3085
3160
|
'settings.hub.shareInfo.clickCopy':'点击复制',
|
|
3086
|
-
'settings.hub.restartAlert':'
|
|
3161
|
+
'settings.hub.restartAlert':'团队共享配置已保存!服务将自动重启以应用更改。',
|
|
3087
3162
|
'settings.hub.hubAddress':'服务器地址',
|
|
3088
3163
|
'settings.hub.hubAddress.hint':'团队服务器地址,如 192.168.1.100:18800',
|
|
3089
3164
|
'settings.hub.teamTokenClient':'团队令牌',
|
|
@@ -3094,6 +3169,7 @@ const I18N={
|
|
|
3094
3169
|
'settings.hub.userToken.hint':'通常在加入团队后自动获取,无需手动填写。',
|
|
3095
3170
|
'settings.hub.testConnection':'测试连接',
|
|
3096
3171
|
'settings.hub.test.noAddr':'请先输入服务器地址',
|
|
3172
|
+
'settings.hub.teamToken.required':'请输入团队令牌',
|
|
3097
3173
|
'settings.hub.test.testing':'测试中...',
|
|
3098
3174
|
'settings.hub.test.ok':'连接成功',
|
|
3099
3175
|
'settings.hub.test.fail':'连接失败',
|
|
@@ -3103,6 +3179,10 @@ const I18N={
|
|
|
3103
3179
|
'sidebar.hub':'\u{1F310} 团队共享',
|
|
3104
3180
|
'sharing.sidebar.connected':'已连接',
|
|
3105
3181
|
'sharing.sidebar.disconnected':'已断开',
|
|
3182
|
+
'sharing.sidebar.hubRunning':'服务运行中',
|
|
3183
|
+
'sharing.sidebar.teamName':'团队',
|
|
3184
|
+
'sharing.sidebar.members':'成员',
|
|
3185
|
+
'sharing.sidebar.online':'在线',
|
|
3106
3186
|
'sharing.sidebar.pending':'等待审核',
|
|
3107
3187
|
'sharing.sidebar.rejected':'已拒绝',
|
|
3108
3188
|
'sharing.sidebar.starting':'启动中...',
|
|
@@ -3112,11 +3192,21 @@ const I18N={
|
|
|
3112
3192
|
'sharing.sidebar.targetHub':'团队服务器:',
|
|
3113
3193
|
'sharing.pendingApproval.hint':'加入申请已提交,请等待团队管理员审核通过。',
|
|
3114
3194
|
'sharing.rejected.hint':'您的加入申请已被团队管理员拒绝,请联系管理员或重新申请。',
|
|
3195
|
+
'sharing.removed.hint':'您已被管理员从团队中移除,可以重新申请加入。',
|
|
3196
|
+
'sharing.joinTeam':'加入团队',
|
|
3197
|
+
'sharing.joinSent.pending':'加入申请已发送,等待管理员审批。',
|
|
3198
|
+
'sharing.joinSent.active':'成功加入团队!',
|
|
3115
3199
|
'sharing.retryJoin':'重新申请',
|
|
3116
3200
|
'sharing.retryJoin.hint':'清除本地连接数据并重新提交加入申请',
|
|
3117
3201
|
'sharing.retryJoin.confirm':'这将清除当前连接数据并重新提交加入申请,是否继续?',
|
|
3202
|
+
'sharing.leaveTeam':'退出团队',
|
|
3203
|
+
'sharing.leaveTeam.confirm':'你即将退出团队「{team}」。\\n\\n退出后将会:\\n\\u2022 断开与团队服务器的连接\\n\\u2022 团队管理员会收到你退出的通知\\n\\u2022 你将无法再接收团队共享的记忆、任务和技能\\n\\u2022 你的本地数据不受影响,会完整保留\\n\\u2022 之后可以重新申请加入(需管理员审批)\\n\\n确定要退出吗?',
|
|
3204
|
+
'sharing.leaveTeam.success':'你已退出团队,团队共享已关闭。',
|
|
3205
|
+
'sharing.leaveTeam.fail':'退出团队失败',
|
|
3206
|
+
'sharing.team.default':'该团队',
|
|
3118
3207
|
'sharing.retryJoin.success':'加入申请已重新提交,请等待管理员审核。',
|
|
3119
3208
|
'sharing.retryJoin.fail':'重新申请失败',
|
|
3209
|
+
'sharing.ownerRemoved':'(已移除)',
|
|
3120
3210
|
'sharing.cannotJoinSelf':'不能加入自己的服务端,请输入远程服务器地址。',
|
|
3121
3211
|
'scope.hub':'团队',
|
|
3122
3212
|
'memory.detail.title':'记忆详情',
|
|
@@ -3167,6 +3257,7 @@ const I18N={
|
|
|
3167
3257
|
'admin.editName':'编辑名称',
|
|
3168
3258
|
'admin.lastAdminHint':'唯一管理员 — 无法删除或降级',
|
|
3169
3259
|
'admin.ownerHint':'Hub 创建者 — 不可降级或移除',
|
|
3260
|
+
'admin.selfHint':'这是你自己',
|
|
3170
3261
|
'admin.editNamePrompt':'请输入新用户名:',
|
|
3171
3262
|
'confirm.promoteAdmin':'确定要将此用户提升为管理员吗?管理员可以管理所有团队成员和资源。',
|
|
3172
3263
|
'confirm.demoteMember':'确定要将此管理员降为普通成员吗?',
|
|
@@ -3227,6 +3318,9 @@ const I18N={
|
|
|
3227
3318
|
'admin.groupsFailed':'加载分组失败:',
|
|
3228
3319
|
'toast.userApproved':'用户已批准',
|
|
3229
3320
|
'sharing.approved.toast':'您的加入申请已通过审核!',
|
|
3321
|
+
'sharing.rejected.toast':'您的加入申请已被管理员拒绝。',
|
|
3322
|
+
'sharing.hubOffline.toast':'团队服务已离线,恢复后将自动重新连接。',
|
|
3323
|
+
'sharing.hubReconnected.toast':'团队服务已恢复上线,连接已自动恢复!',
|
|
3230
3324
|
'toast.userRejected':'用户已拒绝',
|
|
3231
3325
|
'toast.approveFail':'批准失败',
|
|
3232
3326
|
'toast.rejectFail':'拒绝失败',
|
|
@@ -3319,9 +3413,9 @@ const I18N={
|
|
|
3319
3413
|
'share.status.agents':'本机',
|
|
3320
3414
|
'share.status.hub':'团队',
|
|
3321
3415
|
'share.scope.title':'共享范围',
|
|
3322
|
-
'share.scope.private':'
|
|
3323
|
-
'share.scope.local':'
|
|
3324
|
-
'share.scope.team':'
|
|
3416
|
+
'share.scope.private':'私有',
|
|
3417
|
+
'share.scope.local':'本机共享',
|
|
3418
|
+
'share.scope.team':'团队共享',
|
|
3325
3419
|
'share.scope.current':'当前',
|
|
3326
3420
|
'share.scope.teamDisabled':'未连接团队服务器',
|
|
3327
3421
|
'share.scope.teamIncludes':'包含本机所有智能体的可见性',
|
|
@@ -3386,7 +3480,10 @@ const I18N={
|
|
|
3386
3480
|
'update.dismiss':'关闭',
|
|
3387
3481
|
'sharing.disable.confirm.hub':'你即将关闭团队服务。\\n\\n关闭后将会:\\n\\u2022 所有已连接的团队成员将断开连接\\n\\u2022 他们将无法继续同步记忆、任务和技能\\n\\u2022 已共享的数据会保留,重新开启后仍可使用\\n\\n确定要关闭吗?',
|
|
3388
3482
|
'sharing.disable.confirm.client':'你即将断开与团队的连接。\\n\\n断开后将会:\\n\\u2022 你将无法再接收团队共享的记忆、任务和技能\\n\\u2022 你的本地数据不受影响,会完整保留\\n\\u2022 之后可以随时重新开启共享来恢复连接\\n\\n确定要断开吗?',
|
|
3389
|
-
'sharing.disable.restartAlert':'
|
|
3483
|
+
'sharing.disable.restartAlert':'共享已关闭,服务将自动重启以应用更改。',
|
|
3484
|
+
'sharing.switch.hubToClient':'你即将从服务端模式切换为客户端模式。\\n\\n切换后将会:\\n\\u2022 Hub 服务将在服务重启后关闭\\n\\u2022 所有已连接的团队成员将断开连接\\n\\u2022 Hub 上的共享数据会保留,以后可恢复使用\\n\\u2022 你将作为客户端加入指定的远程团队\\n\\n确定要切换吗?',
|
|
3485
|
+
'sharing.switch.clientToHub':'你即将从客户端模式切换为服务端模式。\\n\\n切换后将会:\\n\\u2022 你将断开与当前团队的连接\\n\\u2022 服务重启后将启动新的 Hub 服务\\n\\u2022 你的本地数据不受影响\\n\\n确定要切换吗?',
|
|
3486
|
+
'sharing.switch.hubAddress':'你即将离开当前团队并加入新的团队。\\n\\n操作后将会:\\n\\u2022 你将断开与当前团队服务器的连接\\n\\u2022 当前团队管理员会收到你离开的通知\\n\\u2022 你将作为新成员加入新的团队服务器\\n\\u2022 你的本地数据不受影响\\n\\n确定要切换吗?',
|
|
3390
3487
|
'admin.notEnabled.title':'团队共享尚未开启',
|
|
3391
3488
|
'admin.notEnabled.desc':'管理面板用于管理团队成员、共享的记忆、任务和技能。使用此功能前,需要先开启团队共享。',
|
|
3392
3489
|
'admin.notEnabled.setupHub':'配置为团队服务端',
|
|
@@ -3404,12 +3501,12 @@ const I18N={
|
|
|
3404
3501
|
'guide.join.s1':'向团队管理员索取服务器地址和团队令牌',
|
|
3405
3502
|
'guide.join.s2':'前往「设置 → 团队共享」,开启共享,选择「客户端」模式',
|
|
3406
3503
|
'guide.join.s3':'填写服务器地址和团队令牌,点击「测试连接」',
|
|
3407
|
-
'guide.join.s4':'
|
|
3504
|
+
'guide.join.s4':'点击「保存并应用」,服务将自动重启(页面会自动刷新)',
|
|
3408
3505
|
'guide.join.btn':'\u2192 配置客户端模式',
|
|
3409
3506
|
'guide.hub.title':'自建团队服务',
|
|
3410
3507
|
'guide.hub.desc':'将本机作为团队服务端,让其他成员连接过来共享记忆。',
|
|
3411
3508
|
'guide.hub.s1':'前往「设置 → 团队共享」,开启共享,选择「服务端」模式',
|
|
3412
|
-
'guide.hub.s2':'
|
|
3509
|
+
'guide.hub.s2':'设置团队名称,点击「保存并应用」,服务将自动重启',
|
|
3413
3510
|
'guide.hub.s3':'将服务器地址和团队令牌分享给团队成员',
|
|
3414
3511
|
'guide.hub.s4':'在管理面板中审批加入请求',
|
|
3415
3512
|
'guide.hub.btn':'\u2192 配置服务端模式'
|
|
@@ -3515,12 +3612,28 @@ async function doReset(){
|
|
|
3515
3612
|
}
|
|
3516
3613
|
|
|
3517
3614
|
var _sharingRole='client';
|
|
3615
|
+
var _loadedClientHubAddress='';
|
|
3518
3616
|
function _genToken(len){
|
|
3519
3617
|
var a=new Uint8Array(len||18);crypto.getRandomValues(a);
|
|
3520
3618
|
return btoa(String.fromCharCode.apply(null,a)).replace(/\\+/g,'-').replace(/\\//g,'_').replace(/=+$/,'');
|
|
3521
3619
|
}
|
|
3522
|
-
function onSharingToggle(){
|
|
3523
|
-
var
|
|
3620
|
+
async function onSharingToggle(){
|
|
3621
|
+
var chk=document.getElementById('cfgSharingEnabled');
|
|
3622
|
+
var on=chk.checked;
|
|
3623
|
+
if(!on && sharingStatusCache && sharingStatusCache.enabled){
|
|
3624
|
+
var prevRole=sharingStatusCache.role;
|
|
3625
|
+
var confirmMsg=prevRole==='hub'?t('sharing.disable.confirm.hub'):t('sharing.disable.confirm.client');
|
|
3626
|
+
if(!(await confirmModal(confirmMsg,{danger:true}))){
|
|
3627
|
+
chk.checked=true;
|
|
3628
|
+
return;
|
|
3629
|
+
}
|
|
3630
|
+
var cfg={sharing:{enabled:false,role:prevRole}};
|
|
3631
|
+
chk.disabled=true;
|
|
3632
|
+
var result=await doSaveConfig(cfg, null, 'hubSaved');
|
|
3633
|
+
chk.disabled=false;
|
|
3634
|
+
if(!result){chk.checked=true;return;}
|
|
3635
|
+
return;
|
|
3636
|
+
}
|
|
3524
3637
|
document.getElementById('sharingConfigPanel').style.display=on?'block':'none';
|
|
3525
3638
|
var pw=document.getElementById('sharingPanelsWrap');
|
|
3526
3639
|
if(pw) pw.style.display=on?'':'none';
|
|
@@ -3538,20 +3651,25 @@ function selectSharingRole(role){
|
|
|
3538
3651
|
var tp=document.getElementById('sharingTeamPanel');
|
|
3539
3652
|
var ap=document.getElementById('sharingAdminPanel');
|
|
3540
3653
|
if(role==='client'){
|
|
3541
|
-
if(sp) sp.style.display='none';
|
|
3654
|
+
if(sp) { sp.style.display='none'; sp.innerHTML=''; }
|
|
3542
3655
|
if(tp) tp.style.display='none';
|
|
3543
3656
|
if(ap) ap.style.display='none';
|
|
3544
3657
|
}else{
|
|
3545
|
-
if(sp) sp.style.display='';
|
|
3658
|
+
if(sp) { sp.style.display='none'; sp.innerHTML=''; }
|
|
3546
3659
|
if(tp) tp.style.display='';
|
|
3547
3660
|
if(ap) ap.style.display='';
|
|
3548
3661
|
}
|
|
3662
|
+
_lastSettingsFingerprint='';
|
|
3663
|
+
setTimeout(function(){ loadSharingStatus(true); },200);
|
|
3549
3664
|
if(role==='hub'){
|
|
3550
3665
|
var tk=document.getElementById('cfgHubTeamToken');
|
|
3551
3666
|
if(!tk.value.trim()) tk.value=_genToken(18);
|
|
3552
3667
|
var tn=document.getElementById('cfgHubTeamName');
|
|
3553
3668
|
if(!tn.value.trim()) tn.value='My Team';
|
|
3554
3669
|
}
|
|
3670
|
+
var card=document.getElementById('settingsSharingConfig');
|
|
3671
|
+
var saveBtn=card&&card.querySelector('.settings-actions .btn-primary');
|
|
3672
|
+
if(saveBtn&&typeof _hubSaveBtnLabel==='function') saveBtn.textContent=_hubSaveBtnLabel();
|
|
3555
3673
|
}
|
|
3556
3674
|
var _cachedLocalIP='';
|
|
3557
3675
|
function updateHubShareInfo(){
|
|
@@ -3586,13 +3704,6 @@ async function testHubConnection(){
|
|
|
3586
3704
|
if(!addr){result.innerHTML='<span style="color:var(--rose)">\u274C '+t('settings.hub.test.noAddr')+'</span>';return;}
|
|
3587
3705
|
btn.disabled=true;result.innerHTML=t('settings.hub.test.testing');
|
|
3588
3706
|
try{
|
|
3589
|
-
var ipsData=await fetch('/api/local-ips').then(function(r){return r.json();});
|
|
3590
|
-
var localAddrs=['127.0.0.1','localhost','0.0.0.0'].concat(ipsData.ips||[]);
|
|
3591
|
-
var parsed=new URL(addr.indexOf('://')>-1?addr:'http://'+addr);
|
|
3592
|
-
if(localAddrs.indexOf(parsed.hostname)>=0){
|
|
3593
|
-
result.innerHTML='<span style="color:var(--rose)">\u274C '+t('sharing.cannotJoinSelf')+'</span>';
|
|
3594
|
-
btn.disabled=false;return;
|
|
3595
|
-
}
|
|
3596
3707
|
}catch(e){}
|
|
3597
3708
|
try{
|
|
3598
3709
|
var url=addr.match(/^https?:\\/\\//)?addr:'http://'+addr;
|
|
@@ -3642,23 +3753,38 @@ function switchView(view){
|
|
|
3642
3753
|
else if(view==='skills') loadSkills();
|
|
3643
3754
|
else if(view==='analytics') loadMetrics();
|
|
3644
3755
|
else if(view==='logs') loadLogs();
|
|
3645
|
-
else if(view==='settings'){loadConfig()
|
|
3756
|
+
else if(view==='settings'){loadConfig().then(function(){
|
|
3757
|
+
var sharingOn=document.getElementById('cfgSharingEnabled');
|
|
3758
|
+
var sharingNotEnabled=!sharingOn||!sharingOn.checked;
|
|
3759
|
+
if(sharingNotEnabled){
|
|
3760
|
+
switchSettingsTab('hub',document.querySelector('.settings-tab-btn[data-tab="hub"]'));
|
|
3761
|
+
}
|
|
3762
|
+
});loadModelHealth();}
|
|
3646
3763
|
else if(view==='import'){if(!window._migrateRunning) migrateScan(false);}
|
|
3647
|
-
else if(view==='admin'){loadAdminData();}
|
|
3764
|
+
else if(view==='admin'){_lastAdminFingerprint='';loadAdminData();}
|
|
3648
3765
|
}
|
|
3649
3766
|
|
|
3650
3767
|
function onMemoryScopeChange(){
|
|
3651
3768
|
memorySearchScope=document.getElementById('memorySearchScope')?.value||'local';
|
|
3769
|
+
try{localStorage.setItem('memos_memorySearchScope',memorySearchScope);}catch(e){}
|
|
3770
|
+
currentPage=1;
|
|
3771
|
+
activeSession=null;activeRole='';
|
|
3772
|
+
_lastMemoriesFingerprint='';
|
|
3652
3773
|
var isHub=memorySearchScope==='hub';
|
|
3774
|
+
var isLocal=memorySearchScope==='local';
|
|
3653
3775
|
var ownerSel=document.getElementById('filterOwner');
|
|
3654
3776
|
var filterBar=document.getElementById('filterBar');
|
|
3655
3777
|
var dateFilter=document.querySelector('.date-filter');
|
|
3656
|
-
if(ownerSel)
|
|
3778
|
+
if(ownerSel){ownerSel.style.display=(isHub||isLocal)?'none':'';if(isHub||isLocal)ownerSel.value='';}
|
|
3657
3779
|
if(filterBar) filterBar.style.display=isHub?'none':'';
|
|
3658
3780
|
if(dateFilter) dateFilter.style.display=isHub?'none':'';
|
|
3659
3781
|
if(document.getElementById('searchInput').value.trim()) doSearch(document.getElementById('searchInput').value);
|
|
3660
3782
|
else if(isHub) { document.getElementById('sharingSearchMeta').textContent=''; loadHubMemories(); }
|
|
3661
|
-
else {
|
|
3783
|
+
else {
|
|
3784
|
+
document.getElementById('sharingSearchMeta').textContent='';
|
|
3785
|
+
var ownerArg=isLocal?_currentAgentOwner:undefined;
|
|
3786
|
+
loadStats(ownerArg); loadMemories();
|
|
3787
|
+
}
|
|
3662
3788
|
}
|
|
3663
3789
|
|
|
3664
3790
|
function onSkillScopeChange(){
|
|
@@ -3673,6 +3799,14 @@ function onTaskScopeChange(){
|
|
|
3673
3799
|
}
|
|
3674
3800
|
|
|
3675
3801
|
var _clientPendingPollTimer=null;
|
|
3802
|
+
var _lastSharingConnStatus='';
|
|
3803
|
+
function _updateScopeSelectorsVisibility(hubAvailable){
|
|
3804
|
+
var ids=['memorySearchScope','taskSearchScope','skillSearchScope'];
|
|
3805
|
+
for(var i=0;i<ids.length;i++){
|
|
3806
|
+
var el=document.getElementById(ids[i]);
|
|
3807
|
+
if(el) el.style.display=hubAvailable?'':'none';
|
|
3808
|
+
}
|
|
3809
|
+
}
|
|
3676
3810
|
async function loadSharingStatus(forcePending){
|
|
3677
3811
|
try{
|
|
3678
3812
|
const r=await fetch('/api/sharing/status');
|
|
@@ -3682,27 +3816,64 @@ async function loadSharingStatus(forcePending){
|
|
|
3682
3816
|
renderSharingSettings(d);
|
|
3683
3817
|
updateTeamGuide(d);
|
|
3684
3818
|
if(forcePending && d && d.admin && d.admin.canManageUsers) loadSharingPendingUsers();
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
3688
|
-
|
|
3819
|
+
if(!d||!d.enabled){
|
|
3820
|
+
if(_clientPendingPollTimer){clearInterval(_clientPendingPollTimer);_clientPendingPollTimer=null;}
|
|
3821
|
+
_lastSharingConnStatus='';
|
|
3822
|
+
_updateScopeSelectorsVisibility(false);
|
|
3823
|
+
return;
|
|
3824
|
+
}
|
|
3825
|
+
var conn=d.connection||{};
|
|
3826
|
+
var curStatus=conn.rejected?'rejected':conn.pendingApproval?'pending':conn.connected?'connected':'none';
|
|
3827
|
+
var hubActive=d.role==='hub'||curStatus==='connected';
|
|
3828
|
+
_updateScopeSelectorsVisibility(hubActive);
|
|
3829
|
+
if(_lastSharingConnStatus==='pending'&&curStatus==='rejected'&&d.role==='client'){
|
|
3830
|
+
toast(t('sharing.rejected.toast'),'error');
|
|
3831
|
+
}
|
|
3832
|
+
if(_lastSharingConnStatus==='pending'&&curStatus==='connected'&&d.role==='client'){
|
|
3833
|
+
toast(t('sharing.approved.toast'),'success');
|
|
3834
|
+
loadMemories();loadTasks();loadSkills();
|
|
3835
|
+
if(_notifSSE){_notifSSE.close();_notifSSE=null;_notifSSEConnected=false;}
|
|
3836
|
+
connectNotifSSE();
|
|
3837
|
+
loadNotifications();
|
|
3838
|
+
}
|
|
3839
|
+
if(_lastSharingConnStatus==='connected'&&curStatus==='none'&&d.role==='client'){
|
|
3840
|
+
toast(t('sharing.hubOffline.toast'),'error');
|
|
3841
|
+
}
|
|
3842
|
+
if(_lastSharingConnStatus==='none'&&curStatus==='connected'&&d.role==='client'){
|
|
3843
|
+
toast(t('sharing.hubReconnected.toast'),'success');
|
|
3844
|
+
loadMemories();loadTasks();loadSkills();
|
|
3845
|
+
if(_notifSSE){_notifSSE.close();_notifSSE=null;_notifSSEConnected=false;}
|
|
3846
|
+
connectNotifSSE();
|
|
3847
|
+
loadNotifications();
|
|
3848
|
+
}
|
|
3849
|
+
_lastSharingConnStatus=curStatus;
|
|
3850
|
+
if(curStatus==='pending'&&!_clientPendingPollTimer){
|
|
3851
|
+
_clientPendingPollTimer=setInterval(function(){loadSharingStatus(false);},5000);
|
|
3852
|
+
}
|
|
3853
|
+
if(curStatus!=='pending'&&_clientPendingPollTimer){
|
|
3689
3854
|
clearInterval(_clientPendingPollTimer);
|
|
3690
3855
|
_clientPendingPollTimer=null;
|
|
3691
|
-
if(conn.connected) toast(t('sharing.approved.toast'),'success');
|
|
3692
3856
|
}
|
|
3693
3857
|
}catch(e){
|
|
3694
3858
|
renderSharingSidebar(null);
|
|
3695
3859
|
renderSharingSettings(null);
|
|
3696
3860
|
updateTeamGuide(null);
|
|
3861
|
+
_updateScopeSelectorsVisibility(false);
|
|
3697
3862
|
}
|
|
3698
3863
|
}
|
|
3699
3864
|
|
|
3865
|
+
var _lastSidebarFingerprint='';
|
|
3700
3866
|
function renderSharingSidebar(data){
|
|
3701
3867
|
var section=document.getElementById('sidebarSharingSection');
|
|
3702
3868
|
var statusEl=document.getElementById('sharingSidebarStatus');
|
|
3703
3869
|
var hintEl=document.getElementById('sharingSidebarHint');
|
|
3704
3870
|
var badgeEl=document.getElementById('sharingSidebarConnBadge');
|
|
3705
3871
|
if(!statusEl||!hintEl) return;
|
|
3872
|
+
var conn=data&&data.connection||{};
|
|
3873
|
+
var hs=data&&data.hubStats||{};
|
|
3874
|
+
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});
|
|
3875
|
+
if(fp===_lastSidebarFingerprint) return;
|
|
3876
|
+
_lastSidebarFingerprint=fp;
|
|
3706
3877
|
if(!data||!data.enabled){
|
|
3707
3878
|
if(section) section.style.display='none';
|
|
3708
3879
|
window._isHubAdmin=false;
|
|
@@ -3715,8 +3886,16 @@ function renderSharingSidebar(data){
|
|
|
3715
3886
|
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>';
|
|
3716
3887
|
}
|
|
3717
3888
|
if(data.role==='hub'){
|
|
3718
|
-
setBadge('#34d399',t('sharing.sidebar.
|
|
3719
|
-
|
|
3889
|
+
setBadge('#34d399',t('sharing.sidebar.hubRunning'),true);
|
|
3890
|
+
var hs=data.hubStats||{};
|
|
3891
|
+
var html='<div class="info-grid">';
|
|
3892
|
+
if(conn.teamName) html+='<span class="label">'+t('sharing.sidebar.teamName')+'</span><span class="value" style="font-weight:600">'+esc(conn.teamName)+'</span>';
|
|
3893
|
+
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>';
|
|
3894
|
+
if(hs.pendingMembers>0){
|
|
3895
|
+
html+='<span class="label">'+t('sharing.sidebar.pending')+'</span><span class="value" style="color:var(--yellow,#fbbf24);font-weight:600">'+hs.pendingMembers+'</span>';
|
|
3896
|
+
}
|
|
3897
|
+
html+='</div>';
|
|
3898
|
+
statusEl.innerHTML=html;
|
|
3720
3899
|
hintEl.textContent='';
|
|
3721
3900
|
}else if(conn.pendingApproval&&conn.user){
|
|
3722
3901
|
setBadge('#fbbf24',t('sharing.sidebar.pending'),false);
|
|
@@ -3732,8 +3911,18 @@ function renderSharingSidebar(data){
|
|
|
3732
3911
|
html+='<span class="label">'+t('sharing.sidebar.identity')+'</span><span class="value">'+esc(conn.user.username||'-')+'</span>';
|
|
3733
3912
|
if(conn.teamName) html+='<span class="label">'+t('sharing.team')+'</span><span class="value">'+esc(conn.teamName)+'</span>';
|
|
3734
3913
|
html+='</div>';
|
|
3914
|
+
html+='<div style="margin-top:8px"><button class="btn btn-sm btn-primary" onclick="retryHubJoin()" style="font-size:11px">'+t('sharing.retryJoin')+'</button></div>';
|
|
3735
3915
|
statusEl.innerHTML=html;
|
|
3736
3916
|
hintEl.textContent=t('sharing.rejected.hint');
|
|
3917
|
+
}else if(conn.removed&&conn.user){
|
|
3918
|
+
setBadge('#ef4444',t('sharing.sidebar.disconnected'),false);
|
|
3919
|
+
var html='<div class="info-grid">';
|
|
3920
|
+
html+='<span class="label">'+t('sharing.sidebar.identity')+'</span><span class="value">'+esc(conn.user.username||'-')+'</span>';
|
|
3921
|
+
if(conn.teamName) html+='<span class="label">'+t('sharing.team')+'</span><span class="value">'+esc(conn.teamName)+'</span>';
|
|
3922
|
+
html+='</div>';
|
|
3923
|
+
html+='<div style="margin-top:8px"><button class="btn btn-sm btn-primary" onclick="retryHubJoin()" style="font-size:11px">'+t('sharing.retryJoin')+'</button></div>';
|
|
3924
|
+
statusEl.innerHTML=html;
|
|
3925
|
+
hintEl.textContent=t('sharing.removed.hint');
|
|
3737
3926
|
}else if(conn.connected&&conn.user){
|
|
3738
3927
|
var isAdmin=conn.user.role==='admin';
|
|
3739
3928
|
setBadge('#34d399',t('sharing.sidebar.connected'),true);
|
|
@@ -3754,25 +3943,43 @@ function renderSharingSidebar(data){
|
|
|
3754
3943
|
}
|
|
3755
3944
|
}
|
|
3756
3945
|
|
|
3946
|
+
var _lastSettingsFingerprint='';
|
|
3757
3947
|
function renderSharingSettings(data){
|
|
3758
3948
|
var statusEl=document.getElementById('sharingStatusPanel');
|
|
3759
3949
|
var teamEl=document.getElementById('sharingTeamPanel');
|
|
3760
3950
|
var adminEl=document.getElementById('sharingAdminPanel');
|
|
3761
3951
|
var panelsWrap=document.getElementById('sharingPanelsWrap');
|
|
3762
3952
|
if(!statusEl||!teamEl||!adminEl) return;
|
|
3953
|
+
var conn2=data&&data.connection||{};
|
|
3954
|
+
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});
|
|
3955
|
+
if(fp2===_lastSettingsFingerprint) return;
|
|
3956
|
+
_lastSettingsFingerprint=fp2;
|
|
3763
3957
|
if(!data||!data.enabled){
|
|
3764
3958
|
statusEl.innerHTML='';teamEl.innerHTML='';adminEl.innerHTML='';
|
|
3765
3959
|
if(panelsWrap) panelsWrap.style.display='none';
|
|
3960
|
+
var adminNavTab0=document.querySelector('.tab[data-view="admin"]');
|
|
3961
|
+
if(adminNavTab0) adminNavTab0.style.display='none';
|
|
3962
|
+
if(_activeView==='admin') switchView('memories');
|
|
3766
3963
|
return;
|
|
3767
3964
|
}
|
|
3768
3965
|
if(panelsWrap) panelsWrap.style.display='';
|
|
3769
3966
|
var conn=data.connection||{};
|
|
3770
3967
|
var user=conn.user||{};
|
|
3771
3968
|
var actualRole=data.role||_sharingRole||'client';
|
|
3772
|
-
|
|
3969
|
+
var prevIsAdmin=!!window._isHubAdmin;
|
|
3773
3970
|
var isAdmin=(data.admin&&data.admin.canManageUsers)||(conn.connected&&user.role==='admin')||(actualRole==='hub');
|
|
3774
3971
|
window._isHubAdmin=isAdmin;
|
|
3775
3972
|
if(isAdmin) startAdminPoll();
|
|
3973
|
+
var adminNavTab=document.querySelector('.tab[data-view="admin"]');
|
|
3974
|
+
if(adminNavTab){
|
|
3975
|
+
var showTab=(actualRole==='hub')||(conn.connected);
|
|
3976
|
+
adminNavTab.style.display=showTab?'':'none';
|
|
3977
|
+
if(!showTab&&_activeView==='admin') switchView('memories');
|
|
3978
|
+
}
|
|
3979
|
+
if(prevIsAdmin&&!isAdmin&&_activeView==='admin'){
|
|
3980
|
+
_lastAdminFingerprint='';
|
|
3981
|
+
loadAdminData();
|
|
3982
|
+
}
|
|
3776
3983
|
var hubAdminBtn=document.getElementById('hubAdminEntryBtn');
|
|
3777
3984
|
|
|
3778
3985
|
if(actualRole==='hub'){
|
|
@@ -3794,6 +4001,8 @@ function renderSharingSettings(data){
|
|
|
3794
4001
|
connBadge='<span class="hic-badge pending"><span class="hic-dot amber"></span>'+t('sharing.sidebar.pending')+'</span>';
|
|
3795
4002
|
}else if(conn.rejected){
|
|
3796
4003
|
connBadge='<span class="hic-badge disconnected"><span class="hic-dot red"></span>'+t('sharing.sidebar.rejected')+'</span>';
|
|
4004
|
+
}else if(conn.removed){
|
|
4005
|
+
connBadge='<span class="hic-badge disconnected"><span class="hic-dot red"></span>'+t('sharing.sidebar.disconnected')+'</span>';
|
|
3797
4006
|
}else if(conn.connected){
|
|
3798
4007
|
connBadge='<span class="hic-badge connected"><span class="hic-dot green"></span>'+t('sharing.sidebar.connected')+'</span>';
|
|
3799
4008
|
}else{
|
|
@@ -3809,13 +4018,21 @@ function renderSharingSettings(data){
|
|
|
3809
4018
|
sh+='</div><div class="hic-empty" style="color:#ef4444">'+t('sharing.rejected.hint')+'</div>'+
|
|
3810
4019
|
'<div style="margin-top:10px;padding:0 16px 14px"><button class="btn btn-sm btn-primary" onclick="retryHubJoin()">'+t('sharing.retryJoin')+'</button>'+
|
|
3811
4020
|
'<span style="font-size:11px;color:var(--text-muted);margin-left:8px">'+t('sharing.retryJoin.hint')+'</span></div></div>';
|
|
4021
|
+
}else if(conn.removed){
|
|
4022
|
+
if(user.username) sh+='<span class="hic-label">'+t('sharing.user')+'</span><span class="hic-value">'+esc(user.username)+'</span>';
|
|
4023
|
+
sh+='</div><div class="hic-empty" style="color:#ef4444">'+t('sharing.removed.hint')+'</div>'+
|
|
4024
|
+
'<div style="margin-top:10px;padding:0 16px 14px"><button class="btn btn-sm btn-primary" onclick="retryHubJoin()">'+t('sharing.retryJoin')+'</button>'+
|
|
4025
|
+
'<span style="font-size:11px;color:var(--text-muted);margin-left:8px">'+t('sharing.retryJoin.hint')+'</span></div></div>';
|
|
3812
4026
|
}else if(conn.connected&&user.username){
|
|
3813
4027
|
sh+='<span class="hic-label">'+t('sharing.user')+'</span><span class="hic-value" style="display:flex;align-items:center;gap:6px">'+
|
|
3814
4028
|
'<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" />'+
|
|
3815
4029
|
'<button class="btn btn-sm" onclick="updateHubUsername()" style="padding:2px 10px;font-size:11px">'+t('sharing.saveUsername')+'</button>'+
|
|
3816
4030
|
'</span>';
|
|
3817
4031
|
sh+='<span class="hic-label">'+t('sharing.team')+'</span><span class="hic-value">'+esc(conn.teamName||'-')+'</span>';
|
|
3818
|
-
sh+='</div
|
|
4032
|
+
sh+='</div>'+
|
|
4033
|
+
'<div style="border-top:1px solid var(--border);margin-top:10px;padding:10px 16px 6px;display:flex;align-items:center;justify-content:flex-end">'+
|
|
4034
|
+
'<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>'+
|
|
4035
|
+
'</div></div>';
|
|
3819
4036
|
}else{
|
|
3820
4037
|
sh+='</div><div class="hic-empty" style="color:var(--text-muted)">'+t('sharing.disconnected.hint')+'</div>'+
|
|
3821
4038
|
'<div style="margin-top:10px;padding:0 16px 14px"><button class="btn btn-sm btn-primary" id="btnRetryConn" onclick="retryConnection()">'+t('sharing.retryConnection')+'</button>'+
|
|
@@ -3834,6 +4051,7 @@ async function retryConnection(){
|
|
|
3834
4051
|
var result=document.getElementById('retryConnResult');
|
|
3835
4052
|
if(btn){btn.disabled=true;btn.textContent=t('sharing.retryConnection.loading');}
|
|
3836
4053
|
if(result) result.innerHTML='<span style="color:var(--text-muted)">'+t('sharing.retryConnection.loading')+'</span>';
|
|
4054
|
+
toast(t('sharing.retryConnection.loading'),'info');
|
|
3837
4055
|
try{
|
|
3838
4056
|
await loadSharingStatus(false);
|
|
3839
4057
|
var d=sharingStatusCache;
|
|
@@ -3841,9 +4059,11 @@ async function retryConnection(){
|
|
|
3841
4059
|
toast(t('sharing.retryConnection.success'),'success');
|
|
3842
4060
|
if(result) result.innerHTML='<span style="color:#22c55e">\\u2705 '+t('sharing.retryConnection.success')+'</span>';
|
|
3843
4061
|
}else{
|
|
4062
|
+
toast(t('sharing.retryConnection.fail'),'error');
|
|
3844
4063
|
if(result) result.innerHTML='<span style="color:#ef4444">'+t('sharing.retryConnection.fail')+'</span>';
|
|
3845
4064
|
}
|
|
3846
4065
|
}catch(e){
|
|
4066
|
+
toast(t('sharing.retryConnection.fail'),'error');
|
|
3847
4067
|
if(result) result.innerHTML='<span style="color:#ef4444">'+t('sharing.retryConnection.fail')+'</span>';
|
|
3848
4068
|
}
|
|
3849
4069
|
if(btn){btn.disabled=false;btn.textContent=t('sharing.retryConnection');}
|
|
@@ -3856,19 +4076,36 @@ async function retryHubJoin(){
|
|
|
3856
4076
|
var d=await r.json();
|
|
3857
4077
|
if(d.ok){
|
|
3858
4078
|
toast(t('sharing.retryJoin.success'),'success');
|
|
3859
|
-
|
|
4079
|
+
_lastSidebarFingerprint='';_lastSettingsFingerprint='';_lastSharingConnStatus='';
|
|
4080
|
+
setTimeout(function(){loadSharingStatus(true);},800);
|
|
3860
4081
|
}else{
|
|
3861
4082
|
toast(d.error||t('sharing.retryJoin.fail'),'error');
|
|
3862
4083
|
}
|
|
3863
4084
|
}catch(e){toast(t('sharing.retryJoin.fail')+': '+e.message,'error');}
|
|
3864
4085
|
}
|
|
3865
4086
|
|
|
4087
|
+
async function leaveTeam(){
|
|
4088
|
+
var teamName=(sharingStatusCache&&sharingStatusCache.connection&&sharingStatusCache.connection.teamName)||'';
|
|
4089
|
+
var msg=t('sharing.leaveTeam.confirm').replace('{team}',teamName||t('sharing.team.default'));
|
|
4090
|
+
if(!(await confirmModal(msg,{danger:true}))) return;
|
|
4091
|
+
try{
|
|
4092
|
+
var r=await fetch('/api/sharing/leave',{method:'POST',headers:{'Content-Type':'application/json'},body:'{}'});
|
|
4093
|
+
var d=await r.json();
|
|
4094
|
+
if(d.ok){
|
|
4095
|
+
toast(t('sharing.leaveTeam.success'),'success');
|
|
4096
|
+
showRestartOverlay(t('settings.restart.waiting'));
|
|
4097
|
+
}else{
|
|
4098
|
+
toast(d.error||t('sharing.leaveTeam.fail'),'error');
|
|
4099
|
+
}
|
|
4100
|
+
}catch(e){toast(t('sharing.leaveTeam.fail')+': '+e.message,'error');}
|
|
4101
|
+
}
|
|
4102
|
+
|
|
3866
4103
|
async function updateHubUsername(){
|
|
3867
4104
|
var input=document.getElementById('hubUsernameInput');
|
|
3868
4105
|
if(!input) return;
|
|
3869
4106
|
var newName=input.value.trim();
|
|
3870
4107
|
if(!newName||newName.length<2||newName.length>32){
|
|
3871
|
-
|
|
4108
|
+
alertModal(t('sharing.username.invalid'));
|
|
3872
4109
|
return;
|
|
3873
4110
|
}
|
|
3874
4111
|
try{
|
|
@@ -3879,17 +4116,17 @@ async function updateHubUsername(){
|
|
|
3879
4116
|
});
|
|
3880
4117
|
var d=await r.json();
|
|
3881
4118
|
if(d.error==='username_taken'){
|
|
3882
|
-
|
|
4119
|
+
alertModal(t('sharing.username.taken'),{danger:true});
|
|
3883
4120
|
return;
|
|
3884
4121
|
}
|
|
3885
4122
|
if(d.error){
|
|
3886
|
-
|
|
4123
|
+
alertModal(d.error,{danger:true});
|
|
3887
4124
|
return;
|
|
3888
4125
|
}
|
|
3889
4126
|
toast(t('sharing.username.updated'),'success');
|
|
3890
4127
|
loadSharingStatus(false);
|
|
3891
4128
|
}catch(e){
|
|
3892
|
-
|
|
4129
|
+
alertModal(t('sharing.username.error'),{danger:true});
|
|
3893
4130
|
}
|
|
3894
4131
|
}
|
|
3895
4132
|
|
|
@@ -3935,7 +4172,7 @@ async function approveSharingUser(userId,username){
|
|
|
3935
4172
|
try{
|
|
3936
4173
|
const r=await fetch('/api/sharing/approve-user',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:userId,username:username})});
|
|
3937
4174
|
const d=await r.json();
|
|
3938
|
-
if(d.ok){toast(t('toast.userApproved'),'success');loadSharingPendingUsers();loadSharingStatus(true);} else {toast(d.error||t('toast.approveFail'),'error');}
|
|
4175
|
+
if(d.ok){toast(t('toast.userApproved'),'success');loadSharingPendingUsers();loadSharingStatus(true);_lastAdminFingerprint='';loadAdminData();} else {toast(d.error||t('toast.approveFail'),'error');}
|
|
3939
4176
|
}catch(e){toast(t('toast.approveFail')+': '+e.message,'error');}
|
|
3940
4177
|
}
|
|
3941
4178
|
|
|
@@ -3943,23 +4180,15 @@ async function rejectSharingUser(userId,username){
|
|
|
3943
4180
|
try{
|
|
3944
4181
|
const r=await fetch('/api/sharing/reject-user',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:userId,username:username})});
|
|
3945
4182
|
const d=await r.json();
|
|
3946
|
-
if(d.ok){toast(t('toast.userRejected'),'success');loadSharingPendingUsers();} else {toast(d.error||t('toast.rejectFail'),'error');}
|
|
4183
|
+
if(d.ok){toast(t('toast.userRejected'),'success');loadSharingPendingUsers();_lastAdminFingerprint='';loadAdminData();} else {toast(d.error||t('toast.rejectFail'),'error');}
|
|
3947
4184
|
}catch(e){toast(t('toast.rejectFail')+': '+e.message,'error');}
|
|
3948
4185
|
}
|
|
3949
4186
|
|
|
3950
4187
|
/* ─── Team Setup Guide ─── */
|
|
3951
|
-
var TEAM_GUIDE_DISMISSED_KEY='memos-team-guide-dismissed';
|
|
3952
4188
|
function updateTeamGuide(sharingData){
|
|
3953
4189
|
var el=document.getElementById('teamSetupGuide');
|
|
3954
4190
|
if(!el) return;
|
|
3955
|
-
|
|
3956
|
-
var isConfigured=sharingData&&sharingData.enabled;
|
|
3957
|
-
el.style.display=isConfigured?'none':'block';
|
|
3958
|
-
}
|
|
3959
|
-
function dismissTeamGuide(){
|
|
3960
|
-
localStorage.setItem(TEAM_GUIDE_DISMISSED_KEY,'1');
|
|
3961
|
-
var el=document.getElementById('teamSetupGuide');
|
|
3962
|
-
if(el) el.style.display='none';
|
|
4191
|
+
el.style.display='block';
|
|
3963
4192
|
}
|
|
3964
4193
|
function guideGoToHub(role){
|
|
3965
4194
|
switchSettingsTab('hub',document.querySelector('.settings-tab-btn[data-tab="hub"]'));
|
|
@@ -3973,6 +4202,7 @@ function guideGoToHub(role){
|
|
|
3973
4202
|
|
|
3974
4203
|
/* ─── Hub Admin Panel ─── */
|
|
3975
4204
|
var adminDataCache={users:[],groups:[],tasks:[],skills:[],memories:[]};
|
|
4205
|
+
var _lastAdminFingerprint='';
|
|
3976
4206
|
var hubTasksCache=[];
|
|
3977
4207
|
var hubSkillsCache=[];
|
|
3978
4208
|
var ADMIN_PAGE_SIZE=20;
|
|
@@ -3991,7 +4221,7 @@ function adminPaginateHtml(total,page,refilterFn){
|
|
|
3991
4221
|
if(end<pages) html+=(end<pages-1?'<span class="pg-info">...</span>':'')+'<button class="pg-btn" onclick="'+refilterFn+'Page('+(pages-1)+')">'+pages+'</button>';
|
|
3992
4222
|
html+='<button class="pg-btn'+(page>=pages-1?' disabled':'')+'" onclick="'+refilterFn+'Page('+(page+1)+')">\\u2192</button>';
|
|
3993
4223
|
html+='<span class="pg-info">'+total+' '+t('pagination.total')+'</span>';
|
|
3994
|
-
|
|
4224
|
+
html+='</div>';
|
|
3995
4225
|
return html;
|
|
3996
4226
|
}
|
|
3997
4227
|
|
|
@@ -4053,12 +4283,12 @@ async function loadAdminData(){
|
|
|
4053
4283
|
var fetches;
|
|
4054
4284
|
if(isAdmin){
|
|
4055
4285
|
fetches=await Promise.all([
|
|
4056
|
-
|
|
4057
|
-
|
|
4058
|
-
|
|
4059
|
-
|
|
4060
|
-
|
|
4061
|
-
|
|
4286
|
+
fetch('/api/sharing/users').then(function(r){return r.json();}),
|
|
4287
|
+
fetch('/api/admin/shared-tasks').then(function(r){return r.json();}),
|
|
4288
|
+
fetch('/api/admin/shared-skills').then(function(r){return r.json();}),
|
|
4289
|
+
fetch('/api/sharing/pending-users').then(function(r){return r.json();}),
|
|
4290
|
+
fetch('/api/admin/shared-memories').then(function(r){return r.json();})
|
|
4291
|
+
]);
|
|
4062
4292
|
}else{
|
|
4063
4293
|
fetches=await Promise.all([
|
|
4064
4294
|
Promise.resolve({users:[]}),
|
|
@@ -4069,11 +4299,23 @@ async function loadAdminData(){
|
|
|
4069
4299
|
]);
|
|
4070
4300
|
}
|
|
4071
4301
|
var usersR=fetches[0],tasksR=fetches[1],skillsR=fetches[2],pendingR=fetches[3],memoriesR=fetches[4];
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4302
|
+
var _newUsers=Array.isArray(usersR.users)?usersR.users:[];
|
|
4303
|
+
var _newTasks=Array.isArray(tasksR.tasks)?tasksR.tasks:[];
|
|
4304
|
+
var _newSkills=Array.isArray(skillsR.skills)?skillsR.skills:[];
|
|
4305
|
+
var _newMemories=Array.isArray(memoriesR.memories)?memoriesR.memories:[];
|
|
4076
4306
|
var pending=isAdmin?(Array.isArray(pendingR.users)?pendingR.users:[]):[];
|
|
4307
|
+
var _fp=_newUsers.length+':'+_newTasks.length+':'+_newSkills.length+':'+_newMemories.length+':'+pending.length
|
|
4308
|
+
+':'+_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(',')
|
|
4309
|
+
+':'+_newMemories.map(function(m){return m.id}).join(',')
|
|
4310
|
+
+':'+_newTasks.map(function(t){return t.id+'|'+(t.status||'')}).join(',')
|
|
4311
|
+
+':'+_newSkills.map(function(s){return s.id+'|'+(s.status||'')}).join(',')
|
|
4312
|
+
+':'+pending.map(function(p){return p.id}).join(',');
|
|
4313
|
+
if(_fp===_lastAdminFingerprint) return;
|
|
4314
|
+
_lastAdminFingerprint=_fp;
|
|
4315
|
+
adminDataCache.users=_newUsers;
|
|
4316
|
+
adminDataCache.tasks=_newTasks;
|
|
4317
|
+
adminDataCache.skills=_newSkills;
|
|
4318
|
+
adminDataCache.memories=_newMemories;
|
|
4077
4319
|
adminDataCache._pending=pending;
|
|
4078
4320
|
var badge=document.getElementById('adminPendingBadge');
|
|
4079
4321
|
if(badge){if(pending.length>0){badge.textContent=pending.length;badge.style.display='inline';}else{badge.style.display='none';}}
|
|
@@ -4116,11 +4358,15 @@ function updateAdminTabsVisibility(){
|
|
|
4116
4358
|
if(subEl) subEl.textContent=isAdmin?t('admin.subtitle'):t('admin.subtitle.member');
|
|
4117
4359
|
}
|
|
4118
4360
|
|
|
4361
|
+
var _lastAdminStatsFp='';
|
|
4119
4362
|
function renderAdminStats(pendingCount){
|
|
4120
4363
|
var el=document.getElementById('adminStats');
|
|
4121
4364
|
if(!el) return;
|
|
4122
4365
|
var isAdmin=!!window._isHubAdmin;
|
|
4123
4366
|
var onlineCount=adminDataCache.users.filter(function(u){return !!u.isOnline;}).length;
|
|
4367
|
+
var sfp=onlineCount+':'+adminDataCache.users.length+':'+pendingCount+':'+(adminDataCache.memories||[]).length+':'+adminDataCache.tasks.length+':'+adminDataCache.skills.length+':'+isAdmin;
|
|
4368
|
+
if(sfp===_lastAdminStatsFp) return;
|
|
4369
|
+
_lastAdminStatsFp=sfp;
|
|
4124
4370
|
el.innerHTML=
|
|
4125
4371
|
(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>'+
|
|
4126
4372
|
'<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>':'')+
|
|
@@ -4142,9 +4388,10 @@ function auRelativeTime(ts){
|
|
|
4142
4388
|
return t('notif.timeAgo.day').replace('{n}',Math.floor(diff/86400000));
|
|
4143
4389
|
}
|
|
4144
4390
|
|
|
4145
|
-
function renderAdminUserCard(u,adminCount){
|
|
4391
|
+
function renderAdminUserCard(u,adminCount,myUserId){
|
|
4146
4392
|
var uid=escAttr(u.id);
|
|
4147
4393
|
var uname=escAttr(u.username||'');
|
|
4394
|
+
var isSelf=!!(myUserId&&u.id===myUserId);
|
|
4148
4395
|
var online=!!u.isOnline;
|
|
4149
4396
|
var statusCls=online?'online':'offline';
|
|
4150
4397
|
|
|
@@ -4178,7 +4425,9 @@ function renderAdminUserCard(u,adminCount){
|
|
|
4178
4425
|
var infoHtml='<div class="au-info">'+infoRows.join('')+'</div>';
|
|
4179
4426
|
|
|
4180
4427
|
var actions='';
|
|
4181
|
-
if(
|
|
4428
|
+
if(isSelf){
|
|
4429
|
+
actions+='<span style="font-size:11px;color:var(--text-muted);padding:4px 0">'+t('admin.selfHint')+'</span>';
|
|
4430
|
+
}else if(u.isOwner){
|
|
4182
4431
|
actions+='<span style="font-size:11px;color:var(--text-muted);padding:4px 0">'+t('admin.ownerHint')+'</span>';
|
|
4183
4432
|
}else if(u.role!=='admin'){
|
|
4184
4433
|
actions+='<button class="btn btn-sm btn-ghost" onclick="adminToggleRole("'+uid+'","admin")" style="color:var(--accent)">'+t('admin.promoteAdmin')+'</button>';
|
|
@@ -4189,14 +4438,15 @@ function renderAdminUserCard(u,adminCount){
|
|
|
4189
4438
|
}else{
|
|
4190
4439
|
actions+='<span style="font-size:11px;color:var(--text-muted);padding:4px 0">'+t('admin.lastAdminHint')+'</span>';
|
|
4191
4440
|
}
|
|
4192
|
-
var
|
|
4441
|
+
var badgesHtml='<div class="au-badges">'+statusLabel+
|
|
4442
|
+
'<span class="admin-badge '+(u.role==='admin'?'admin':'member')+'">'+esc(u.role||'member').toUpperCase()+'</span>'+
|
|
4443
|
+
(u.isOwner?'<span class="admin-badge owner">OWNER</span>':'')+
|
|
4444
|
+
'</div>';
|
|
4193
4445
|
|
|
4194
|
-
return '<div class="admin-card au-card au-'+statusCls+'"><div class="admin-card-header"><div style="flex:1;min-width:0
|
|
4195
|
-
|
|
4196
|
-
'</div>'+
|
|
4197
|
-
'<span class="admin-badge '+(u.role==='admin'?'admin':'member')+'">'+esc(u.role||'member')+'</span>'+ownerBadge+'</div>'+
|
|
4446
|
+
return '<div class="admin-card au-card au-'+statusCls+'"><div class="admin-card-header"><div style="flex:1;min-width:0">'+titleDisplay+editRow+'</div>'+
|
|
4447
|
+
badgesHtml+'</div>'+
|
|
4198
4448
|
contribHtml+infoHtml+
|
|
4199
|
-
(actions?'<div class="admin-card-actions" style="border-top:1px
|
|
4449
|
+
(actions?'<div class="admin-card-actions" style="border-top:1px solid rgba(99,102,241,.08);padding-top:12px;margin-top:6px">'+actions+'</div>':'')+
|
|
4200
4450
|
'</div>';
|
|
4201
4451
|
}
|
|
4202
4452
|
|
|
@@ -4210,14 +4460,15 @@ function renderAdminUsers(users,pending){
|
|
|
4210
4460
|
}
|
|
4211
4461
|
var html='';
|
|
4212
4462
|
if(pending&&pending.length>0){
|
|
4213
|
-
html+='<div
|
|
4463
|
+
html+='<div class="admin-pending-section"><h3>'+t('admin.pendingApproval')+' <span class="pending-count">'+pending.length+'</span></h3>';
|
|
4214
4464
|
for(var p=0;p<pending.length;p++){
|
|
4215
4465
|
var pu=pending[p];
|
|
4216
|
-
html+='<div class="admin-
|
|
4217
|
-
'<div class="
|
|
4218
|
-
'<div class="
|
|
4219
|
-
|
|
4220
|
-
'<button class="btn
|
|
4466
|
+
html+='<div class="admin-pending-card">'+
|
|
4467
|
+
'<div class="apc-name">'+esc(pu.username||pu.id||'Unknown')+'</div>'+
|
|
4468
|
+
'<div class="apc-meta"><span>\u{1F4BB} '+esc(pu.deviceName||'unknown')+'</span>'+(pu.createdAt?'<span>\u{1F552} '+formatDateTimeSeconds(pu.createdAt)+'</span>':'')+'</div>'+
|
|
4469
|
+
'<div class="apc-actions">'+
|
|
4470
|
+
'<button class="btn-approve" onclick="adminApproveUser("'+escAttr(pu.id)+'","'+escAttr(pu.username||'')+'")">'+t('admin.approve')+'</button>'+
|
|
4471
|
+
'<button class="btn-reject" onclick="adminRejectUser("'+escAttr(pu.id)+'")">'+t('admin.reject')+'</button>'+
|
|
4221
4472
|
'</div></div>';
|
|
4222
4473
|
}
|
|
4223
4474
|
html+='</div>';
|
|
@@ -4228,6 +4479,7 @@ function renderAdminUsers(users,pending){
|
|
|
4228
4479
|
offlineUsers.sort(function(a,b){return (b.lastActiveAt||0)-(a.lastActiveAt||0);});
|
|
4229
4480
|
var sorted=onlineUsers.concat(offlineUsers);
|
|
4230
4481
|
var adminCount=users.filter(function(x){return x.role==='admin';}).length;
|
|
4482
|
+
var myUserId=sharingStatusCache&&sharingStatusCache.connection&&sharingStatusCache.connection.user?sharingStatusCache.connection.user.id:null;
|
|
4231
4483
|
|
|
4232
4484
|
if(sorted.length===0){
|
|
4233
4485
|
html+='<div class="admin-empty"><span class="ae-icon">\u{1F465}</span>'+t('admin.noActiveUsers')+'</div>';
|
|
@@ -4236,13 +4488,13 @@ function renderAdminUsers(users,pending){
|
|
|
4236
4488
|
if(onlineUsers.length===0){
|
|
4237
4489
|
html+='<div style="font-size:12px;color:var(--text-muted);padding:8px 0 12px">\u2014</div>';
|
|
4238
4490
|
}else{
|
|
4239
|
-
for(var i=0;i<onlineUsers.length;i++) html+=renderAdminUserCard(onlineUsers[i],adminCount);
|
|
4491
|
+
for(var i=0;i<onlineUsers.length;i++) html+=renderAdminUserCard(onlineUsers[i],adminCount,myUserId);
|
|
4240
4492
|
}
|
|
4241
4493
|
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>';
|
|
4242
4494
|
if(offlineUsers.length===0){
|
|
4243
4495
|
html+='<div style="font-size:12px;color:var(--text-muted);padding:8px 0 12px">\u2014</div>';
|
|
4244
4496
|
}else{
|
|
4245
|
-
for(var j=0;j<offlineUsers.length;j++) html+=renderAdminUserCard(offlineUsers[j],adminCount);
|
|
4497
|
+
for(var j=0;j<offlineUsers.length;j++) html+=renderAdminUserCard(offlineUsers[j],adminCount,myUserId);
|
|
4246
4498
|
}
|
|
4247
4499
|
}
|
|
4248
4500
|
el.innerHTML=html;
|
|
@@ -4253,7 +4505,7 @@ async function adminApproveUser(userId,username){
|
|
|
4253
4505
|
try{
|
|
4254
4506
|
var r=await fetch('/api/sharing/approve-user',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:userId,username:username})});
|
|
4255
4507
|
var d=await r.json();
|
|
4256
|
-
if(d.ok){toast(t('toast.userApproved'),'success');loadAdminData();}else{toast(d.error||t('toast.approveFail'),'error');}
|
|
4508
|
+
if(d.ok){toast(t('toast.userApproved'),'success');_lastAdminFingerprint='';loadAdminData();}else{toast(d.error||t('toast.approveFail'),'error');}
|
|
4257
4509
|
}catch(e){toast(t('toast.approveFail')+': '+e.message,'error');}
|
|
4258
4510
|
}
|
|
4259
4511
|
async function adminRejectUser(userId){
|
|
@@ -4261,7 +4513,7 @@ async function adminRejectUser(userId){
|
|
|
4261
4513
|
try{
|
|
4262
4514
|
var r=await fetch('/api/sharing/reject-user',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:userId})});
|
|
4263
4515
|
var d=await r.json();
|
|
4264
|
-
if(d.ok){toast(t('toast.userRejected'),'success');loadAdminData();}else{toast(d.error||t('toast.rejectFail'),'error');}
|
|
4516
|
+
if(d.ok){toast(t('toast.userRejected'),'success');_lastAdminFingerprint='';loadAdminData();}else{toast(d.error||t('toast.rejectFail'),'error');}
|
|
4265
4517
|
}catch(e){toast(t('toast.rejectFail')+': '+e.message,'error');}
|
|
4266
4518
|
}
|
|
4267
4519
|
async function adminToggleRole(userId,newRole){
|
|
@@ -4270,7 +4522,14 @@ async function adminToggleRole(userId,newRole){
|
|
|
4270
4522
|
try{
|
|
4271
4523
|
var r=await fetch('/api/sharing/change-role',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:userId,role:newRole})});
|
|
4272
4524
|
var d=await r.json();
|
|
4273
|
-
if(d.ok){
|
|
4525
|
+
if(d.ok){
|
|
4526
|
+
toast(t('toast.roleChanged'),'success');
|
|
4527
|
+
_lastAdminFingerprint='';
|
|
4528
|
+
_lastSettingsFingerprint='';
|
|
4529
|
+
_lastSidebarFingerprint='';
|
|
4530
|
+
await loadSharingStatus(false);
|
|
4531
|
+
loadAdminData();
|
|
4532
|
+
}
|
|
4274
4533
|
else if(d.error==='cannot_demote_owner'){toast(t('admin.ownerHint'),'error');}
|
|
4275
4534
|
else{toast(d.error||t('toast.roleChangeFail'),'error');}
|
|
4276
4535
|
}catch(e){toast(t('toast.roleChangeFail')+': '+e.message,'error');}
|
|
@@ -4296,13 +4555,24 @@ async function adminSaveEditName(userId){
|
|
|
4296
4555
|
var inputEl=document.getElementById('au_input_'+userId);
|
|
4297
4556
|
if(!inputEl) return;
|
|
4298
4557
|
var newName=inputEl.value.trim();
|
|
4299
|
-
if(!newName||newName.length<2||newName.length>32){
|
|
4558
|
+
if(!newName||newName.length<2||newName.length>32){
|
|
4559
|
+
alertModal(t('toast.invalidUsername'),{title:t('admin.editName')});
|
|
4560
|
+
return;
|
|
4561
|
+
}
|
|
4300
4562
|
inputEl.disabled=true;
|
|
4301
4563
|
try{
|
|
4302
4564
|
var r=await fetch('/api/sharing/rename-user',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:userId,username:newName})});
|
|
4303
4565
|
var d=await r.json();
|
|
4304
|
-
if(d.ok){toast(t('toast.usernameChanged'),'success');
|
|
4305
|
-
|
|
4566
|
+
if(d.ok){toast(t('toast.usernameChanged'),'success');adminCancelEditName(userId);loadAdminData();}
|
|
4567
|
+
else{
|
|
4568
|
+
inputEl.disabled=false;
|
|
4569
|
+
if(d.error==='username_taken'){
|
|
4570
|
+
alertModal(t('sharing.username.taken'),{title:t('admin.editName'),danger:true});
|
|
4571
|
+
}else{
|
|
4572
|
+
alertModal(d.error||t('toast.renameFail'),{title:t('admin.editName'),danger:true});
|
|
4573
|
+
}
|
|
4574
|
+
}
|
|
4575
|
+
}catch(e){inputEl.disabled=false;alertModal(t('toast.renameFail'),{title:t('admin.editName'),danger:true});}
|
|
4306
4576
|
}
|
|
4307
4577
|
|
|
4308
4578
|
async function adminRemoveUser(userId,username){
|
|
@@ -4311,7 +4581,7 @@ async function adminRemoveUser(userId,username){
|
|
|
4311
4581
|
try{
|
|
4312
4582
|
var r=await fetch('/api/sharing/remove-user',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:userId,cleanResources:clean})});
|
|
4313
4583
|
var d=await r.json();
|
|
4314
|
-
if(d.ok){toast(t('toast.userRemoved'),'success');loadAdminData();}
|
|
4584
|
+
if(d.ok){toast(t('toast.userRemoved'),'success');_lastAdminFingerprint='';loadAdminData();}
|
|
4315
4585
|
else if(d.error==='cannot_remove_owner'){toast(t('admin.ownerHint'),'error');}
|
|
4316
4586
|
else{toast(d.error||t('toast.removeFail'),'error');}
|
|
4317
4587
|
}catch(e){toast(t('toast.removeFail')+': '+e.message,'error');}
|
|
@@ -4380,7 +4650,7 @@ function renderAdminTasks(tasks){
|
|
|
4380
4650
|
'<div class="admin-card-header"><div class="admin-card-title">'+esc(tk.title||tk.id)+'</div></div>'+
|
|
4381
4651
|
'<div class="admin-card-tags">'+
|
|
4382
4652
|
'<div class="admin-card-tags-left">'+
|
|
4383
|
-
'<span class="admin-card-tag tag-owner">\u{1F464} '+
|
|
4653
|
+
'<span class="admin-card-tag tag-owner">\u{1F464} '+fmtOwner(tk)+'</span>'+
|
|
4384
4654
|
(tk.status?'<span class="admin-card-tag tag-status">'+esc(tk.status)+'</span>':'')+
|
|
4385
4655
|
(tk.chunkCount!=null?'<span class="admin-card-tag tag-kind">\u{1F4DD} '+tk.chunkCount+' '+t('admin.chunks')+'</span>':'')+
|
|
4386
4656
|
'</div>'+
|
|
@@ -4442,7 +4712,7 @@ function renderAdminSkills(skills){
|
|
|
4442
4712
|
'<div class="admin-card-header"><div class="admin-card-title">'+esc(s.name||s.id)+'</div></div>'+
|
|
4443
4713
|
'<div class="admin-card-tags">'+
|
|
4444
4714
|
'<div class="admin-card-tags-left">'+
|
|
4445
|
-
'<span class="admin-card-tag tag-owner">\u{1F464} '+
|
|
4715
|
+
'<span class="admin-card-tag tag-owner">\u{1F464} '+fmtOwner(s)+'</span>'+
|
|
4446
4716
|
(s.status?'<span class="admin-card-tag tag-status">'+esc(s.status)+'</span>':'')+
|
|
4447
4717
|
(s.version!=null?'<span class="admin-card-tag tag-version">v'+s.version+'</span>':'')+
|
|
4448
4718
|
(qs!=null?'<span class="admin-card-tag tag-kind">\u2605 '+Number(qs).toFixed(1)+'</span>':'')+
|
|
@@ -4507,7 +4777,7 @@ function renderAdminMemories(memories){
|
|
|
4507
4777
|
'<div class="admin-card-header"><div class="admin-card-title">'+esc(m.summary||m.content?.slice(0,80)||m.id)+'</div></div>'+
|
|
4508
4778
|
'<div class="admin-card-tags">'+
|
|
4509
4779
|
'<div class="admin-card-tags-left">'+
|
|
4510
|
-
'<span class="admin-card-tag tag-owner">\u{1F464} '+
|
|
4780
|
+
'<span class="admin-card-tag tag-owner">\u{1F464} '+fmtOwner(m)+'</span>'+
|
|
4511
4781
|
(m.role?'<span class="admin-card-tag tag-role">'+esc(m.role)+'</span>':'')+
|
|
4512
4782
|
(m.kind?'<span class="admin-card-tag tag-kind">'+esc(m.kind)+'</span>':'')+
|
|
4513
4783
|
'</div>'+
|
|
@@ -4551,7 +4821,7 @@ function toggleAdminMemoryCard(cardId,idx){
|
|
|
4551
4821
|
(m.kind?'<span class="meta-item">'+t('admin.kind')+esc(m.kind)+'</span>':'')+
|
|
4552
4822
|
(m.role?'<span class="meta-item">'+t('admin.role')+esc(m.role)+'</span>':'')+
|
|
4553
4823
|
(m.visibility?'<span class="meta-item">'+t('admin.visibility')+esc(m.visibility)+'</span>':'')+
|
|
4554
|
-
'<span class="meta-item">'+t('admin.owner')+
|
|
4824
|
+
'<span class="meta-item">'+t('admin.owner')+fmtOwner(m)+'</span>'+
|
|
4555
4825
|
(m.groupName?'<span class="meta-item">'+t('admin.group')+esc(m.groupName)+'</span>':'')+
|
|
4556
4826
|
'<span class="meta-item">'+new Date(m.updatedAt||m.createdAt||0).toLocaleString(dateLoc())+'</span>'+
|
|
4557
4827
|
'</div>';
|
|
@@ -4607,7 +4877,7 @@ async function toggleAdminTaskCard(cardId,idx){
|
|
|
4607
4877
|
var metaHtml='<div class="admin-card-detail-meta admin-task-meta">'+
|
|
4608
4878
|
(tk.status?'<span class="meta-item"><span class="task-status-badge '+tk.status+'">'+esc(tk.status)+'</span></span>':'')+
|
|
4609
4879
|
(tk.visibility?'<span class="meta-item">'+t('admin.visibility')+esc(tk.visibility)+'</span>':'')+
|
|
4610
|
-
'<span class="meta-item">'+t('admin.owner')+
|
|
4880
|
+
'<span class="meta-item">'+t('admin.owner')+fmtOwner(tk)+'</span>'+
|
|
4611
4881
|
(tk.groupName?'<span class="meta-item">'+t('admin.group')+esc(tk.groupName)+'</span>':'')+
|
|
4612
4882
|
(task.chunks&&task.chunks.length?'<span class="meta-item">\u{1F4AC} '+task.chunks.length+' '+t('tasks.chunks.label')+'</span>':'')+
|
|
4613
4883
|
(task.startedAt?'<span class="meta-item">\u{1F4C5} '+formatDateTimeSeconds(task.startedAt)+'</span>':'')+
|
|
@@ -4694,7 +4964,7 @@ async function toggleAdminSkillCard(cardId,idx){
|
|
|
4694
4964
|
(localSkill.status?'<span class="meta-item"><span class="skill-badge status-'+localSkill.status+'">'+esc(localSkill.status)+'</span></span>':'')+
|
|
4695
4965
|
(sk.visibility?'<span class="meta-item">'+t('admin.visibility')+esc(sk.visibility||'hub')+'</span>':'')+
|
|
4696
4966
|
(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>':'')+
|
|
4697
|
-
'<span class="meta-item">'+t('admin.owner')+
|
|
4967
|
+
'<span class="meta-item">'+t('admin.owner')+fmtOwner(sk)+'</span>'+
|
|
4698
4968
|
(sk.groupName?'<span class="meta-item">'+t('admin.group')+esc(sk.groupName)+'</span>':'')+
|
|
4699
4969
|
'<span class="meta-item">'+t('admin.updated')+new Date(sk.updatedAt||sk.createdAt||0).toLocaleString(dateLoc())+'</span>'+
|
|
4700
4970
|
'</div>';
|
|
@@ -4763,7 +5033,7 @@ function renderSharingMemorySearchResults(data,query){
|
|
|
4763
5033
|
'<div class="summary">'+(idx+1)+'. '+esc(hit.summary||'(no summary)')+'</div>'+
|
|
4764
5034
|
'<div class="excerpt">'+esc(hit.excerpt||'')+'</div>'+
|
|
4765
5035
|
'<div class="hub-hit-meta">'+
|
|
4766
|
-
'<span class="meta-chip">owner: '+
|
|
5036
|
+
'<span class="meta-chip">owner: '+fmtOwner(hit)+'</span>'+
|
|
4767
5037
|
(hit.groupName?'<span class="meta-chip">group: '+esc(hit.groupName)+'</span>':'')+
|
|
4768
5038
|
'<span class="meta-chip">visibility: '+esc(hit.visibility||'hub')+'</span>'+
|
|
4769
5039
|
'</div>'+
|
|
@@ -4848,7 +5118,7 @@ function openHubTaskDetailFromCache(cacheKey,idx){
|
|
|
4848
5118
|
var meta=[
|
|
4849
5119
|
'<span class="meta-item">\\u{1F310} '+t('scope.hub')+'</span>',
|
|
4850
5120
|
task.status?'<span class="meta-item"><span class="task-status-badge '+task.status+'">'+esc(task.status)+'</span></span>':'',
|
|
4851
|
-
'<span class="meta-item">'+t('admin.owner')+
|
|
5121
|
+
'<span class="meta-item">'+t('admin.owner')+fmtOwner(task)+'</span>',
|
|
4852
5122
|
task.groupName?'<span class="meta-item">'+t('admin.group')+esc(task.groupName)+'</span>':'',
|
|
4853
5123
|
task.visibility?'<span class="meta-item">'+t('admin.visibility')+esc(task.visibility)+'</span>':'',
|
|
4854
5124
|
task.chunkCount!=null?'<span class="meta-item">\\u{1F4DD} '+esc(String(task.chunkCount))+' '+t('tasks.chunks.label')+'</span>':'',
|
|
@@ -4879,14 +5149,14 @@ function openHubSkillDetailFromCache(cacheKey,idx){
|
|
|
4879
5149
|
skill.status?'<span class="meta-item"><span class="skill-badge status-'+skill.status+'">'+esc(skill.status)+'</span></span>':'',
|
|
4880
5150
|
'<span class="meta-item">visibility: '+esc(skill.visibility||'hub')+'</span>',
|
|
4881
5151
|
qsBadge,
|
|
4882
|
-
'<span class="meta-item">'+t('admin.owner')+
|
|
5152
|
+
'<span class="meta-item">'+t('admin.owner')+fmtOwner(skill)+'</span>',
|
|
4883
5153
|
skill.groupName?'<span class="meta-item">'+t('admin.group')+esc(skill.groupName)+'</span>':'',
|
|
4884
5154
|
(skill.updatedAt||skill.createdAt)?'<span class="meta-item">'+t('admin.updated')+new Date(skill.updatedAt||skill.createdAt).toLocaleString(dateLoc())+'</span>':'',
|
|
4885
5155
|
].filter(Boolean);
|
|
4886
5156
|
document.getElementById('skillDetailMeta').innerHTML=meta.join('');
|
|
4887
5157
|
document.getElementById('skillDetailDesc').textContent=skill.description||'';
|
|
4888
5158
|
document.getElementById('skillFilesList').innerHTML='';
|
|
4889
|
-
document.getElementById('skillDetailContent').innerHTML=skill.content?
|
|
5159
|
+
document.getElementById('skillDetailContent').innerHTML=skill.content?renderSkillMarkdown(skill.content):'';
|
|
4890
5160
|
document.getElementById('skillVersionsList').innerHTML='';
|
|
4891
5161
|
document.getElementById('skillRelatedTasks').innerHTML='';
|
|
4892
5162
|
var visBtn=document.getElementById('skillVisibilityBtn');
|
|
@@ -4929,6 +5199,7 @@ function openScopeSelectorModal(resourceType, resourceId, currentScope, onConfir
|
|
|
4929
5199
|
var existing=document.getElementById('scopeSelectorOverlay');
|
|
4930
5200
|
if(existing) existing.remove();
|
|
4931
5201
|
var teamEnabled=sharingStatusCache&&sharingStatusCache.enabled;
|
|
5202
|
+
var teamConnected=teamEnabled&&sharingStatusCache.connection&&sharingStatusCache.connection.connected;
|
|
4932
5203
|
var overlay=document.createElement('div');
|
|
4933
5204
|
overlay.id='scopeSelectorOverlay';
|
|
4934
5205
|
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';
|
|
@@ -4942,7 +5213,7 @@ function openScopeSelectorModal(resourceType, resourceId, currentScope, onConfir
|
|
|
4942
5213
|
for(var i=0;i<scopes.length;i++){
|
|
4943
5214
|
var sc=scopes[i];
|
|
4944
5215
|
var isCurrent=sc===currentScope;
|
|
4945
|
-
var isDisabled=sc==='team'
|
|
5216
|
+
var isDisabled=sc==='team'&&(!teamEnabled||!teamConnected);
|
|
4946
5217
|
var color=getScopeColor(sc);
|
|
4947
5218
|
var cursor=isDisabled?'not-allowed':'pointer';
|
|
4948
5219
|
var opacity=isDisabled?'0.4':'1';
|
|
@@ -5011,7 +5282,8 @@ async function confirmScopeSelection(){
|
|
|
5011
5282
|
if(st.onConfirm) st.onConfirm(newScope);
|
|
5012
5283
|
else loadAll();
|
|
5013
5284
|
}else{
|
|
5014
|
-
|
|
5285
|
+
var errMsg=d.error==='inactive_memory'?t('share.scope.inactiveDisabled'):(d.message||d.error||t('share.scope.changeFail'));
|
|
5286
|
+
toast(errMsg,'error');
|
|
5015
5287
|
}
|
|
5016
5288
|
}catch(e){toast(t('share.scope.changeFail')+': '+e.message,'error');}
|
|
5017
5289
|
}
|
|
@@ -5262,6 +5534,13 @@ function parseMemoryAddEntries(out){
|
|
|
5262
5534
|
return results;
|
|
5263
5535
|
}
|
|
5264
5536
|
|
|
5537
|
+
function recallOriginBadge(origin){
|
|
5538
|
+
if(origin==='local-shared') return '<span class="recall-origin local-shared">'+t('recall.origin.localShared')+'</span>';
|
|
5539
|
+
if(origin==='hub-memory') return '<span class="recall-origin hub-memory">'+t('recall.origin.hubMemory')+'</span>';
|
|
5540
|
+
if(origin==='hub-remote') return '<span class="recall-origin hub-remote">'+t('recall.origin.hubRemote')+'</span>';
|
|
5541
|
+
return '';
|
|
5542
|
+
}
|
|
5543
|
+
|
|
5265
5544
|
function buildLogSummary(lg){
|
|
5266
5545
|
let inputObj=null;
|
|
5267
5546
|
try{inputObj=JSON.parse(lg.input);}catch(_){}
|
|
@@ -5286,8 +5565,9 @@ function buildLogSummary(lg){
|
|
|
5286
5565
|
var scoreClass=c.score>=0.7?'high':c.score>=0.5?'mid':'low';
|
|
5287
5566
|
var shortText=escapeHtml(c.summary||c.content||c.original_excerpt||'');
|
|
5288
5567
|
var fullText=escapeHtml(c.content||c.original_excerpt||c.summary||'');
|
|
5568
|
+
var oBadge=recallOriginBadge(c.origin);
|
|
5289
5569
|
html+='<div class="recall-item" onclick="event.stopPropagation();this.classList.toggle(\\\'expanded\\\')">';
|
|
5290
|
-
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
|
|
5570
|
+
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>';
|
|
5291
5571
|
html+='<div class="recall-summary-full">'+fullText+'</div>';
|
|
5292
5572
|
html+='</div>';
|
|
5293
5573
|
});
|
|
@@ -5300,8 +5580,9 @@ function buildLogSummary(lg){
|
|
|
5300
5580
|
var scoreClass=f.score>=0.7?'high':f.score>=0.5?'mid':'low';
|
|
5301
5581
|
var shortText=escapeHtml(f.summary||f.content||f.original_excerpt||'');
|
|
5302
5582
|
var fullText=escapeHtml(f.content||f.original_excerpt||f.summary||'');
|
|
5583
|
+
var oBadge=recallOriginBadge(f.origin);
|
|
5303
5584
|
html+='<div class="recall-item" onclick="event.stopPropagation();this.classList.toggle(\\\'expanded\\\')">';
|
|
5304
|
-
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
|
|
5585
|
+
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>';
|
|
5305
5586
|
html+='<div class="recall-summary-full">'+fullText+'</div>';
|
|
5306
5587
|
html+='</div>';
|
|
5307
5588
|
});
|
|
@@ -5365,8 +5646,9 @@ function buildRecallDetailHtml(rd){
|
|
|
5365
5646
|
var scoreClass=c.score>=0.7?'high':c.score>=0.5?'mid':'low';
|
|
5366
5647
|
var shortText=escapeHtml(c.summary||c.content||c.original_excerpt||'');
|
|
5367
5648
|
var fullText=escapeHtml(c.content||c.original_excerpt||c.summary||'');
|
|
5649
|
+
var oBadge=recallOriginBadge(c.origin);
|
|
5368
5650
|
html+='<div class="recall-item" onclick="event.stopPropagation();this.classList.toggle(\\\'expanded\\\')">';
|
|
5369
|
-
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
|
|
5651
|
+
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>';
|
|
5370
5652
|
html+='<div class="recall-summary-full">'+fullText+'</div>';
|
|
5371
5653
|
html+='</div>';
|
|
5372
5654
|
});
|
|
@@ -5380,8 +5662,9 @@ function buildRecallDetailHtml(rd){
|
|
|
5380
5662
|
var scoreClass=f.score>=0.7?'high':f.score>=0.5?'mid':'low';
|
|
5381
5663
|
var shortText=escapeHtml(f.summary||f.content||f.original_excerpt||'');
|
|
5382
5664
|
var fullText=escapeHtml(f.content||f.original_excerpt||f.summary||'');
|
|
5665
|
+
var oBadge=recallOriginBadge(f.origin);
|
|
5383
5666
|
html+='<div class="recall-item" onclick="event.stopPropagation();this.classList.toggle(\\\'expanded\\\')">';
|
|
5384
|
-
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
|
|
5667
|
+
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>';
|
|
5385
5668
|
html+='<div class="recall-summary-full">'+fullText+'</div>';
|
|
5386
5669
|
html+='</div>';
|
|
5387
5670
|
});
|
|
@@ -5511,12 +5794,12 @@ function setTaskStatusFilter(btn,status){
|
|
|
5511
5794
|
loadTasks();
|
|
5512
5795
|
}
|
|
5513
5796
|
|
|
5514
|
-
async function loadTasks(){
|
|
5797
|
+
async function loadTasks(silent){
|
|
5515
5798
|
const scope=document.getElementById('taskSearchScope')?document.getElementById('taskSearchScope').value:taskSearchScope;
|
|
5516
5799
|
taskSearchScope=scope||'local';
|
|
5517
5800
|
if(taskSearchScope==='hub'){ return loadHubTasks(); }
|
|
5518
5801
|
const list=document.getElementById('tasksList');
|
|
5519
|
-
list.innerHTML='<div class="spinner"></div>';
|
|
5802
|
+
if(!silent) list.innerHTML='<div class="spinner"></div>';
|
|
5520
5803
|
try{
|
|
5521
5804
|
const params=new URLSearchParams({limit:String(TASKS_PER_PAGE),offset:String(tasksPage*TASKS_PER_PAGE)});
|
|
5522
5805
|
if(tasksStatusFilter) params.set('status',tasksStatusFilter);
|
|
@@ -5530,6 +5813,14 @@ async function loadTasks(){
|
|
|
5530
5813
|
fetch('/api/tasks?status=completed&limit=1&offset=0&'+baseP).then(r=>r.json()),
|
|
5531
5814
|
fetch('/api/tasks?status=skipped&limit=1&offset=0&'+baseP).then(r=>r.json())
|
|
5532
5815
|
]);
|
|
5816
|
+
if(silent){
|
|
5817
|
+
var fp=JSON.stringify((data.tasks||[]).map(function(tk){return tk.id+'|'+tk.status+'|'+(tk.updatedAt||tk.startedAt)}));
|
|
5818
|
+
fp+=':'+allD.total+':'+activeD.total+':'+compD.total+':'+skipD.total;
|
|
5819
|
+
if(fp===_lastTasksFingerprint) return;
|
|
5820
|
+
_lastTasksFingerprint=fp;
|
|
5821
|
+
}else{
|
|
5822
|
+
_lastTasksFingerprint='';
|
|
5823
|
+
}
|
|
5533
5824
|
document.getElementById('tasksTotalCount').textContent=formatNum(allD.total);
|
|
5534
5825
|
document.getElementById('tasksActiveCount').textContent=formatNum(activeD.total);
|
|
5535
5826
|
document.getElementById('tasksCompletedCount').textContent=formatNum(compD.total);
|
|
@@ -5815,17 +6106,17 @@ function updateSkillCardBadge(skillId,newScope){
|
|
|
5815
6106
|
}
|
|
5816
6107
|
}
|
|
5817
6108
|
|
|
5818
|
-
async function loadSkills(){
|
|
6109
|
+
async function loadSkills(silent){
|
|
5819
6110
|
const list=document.getElementById('skillsList');
|
|
5820
6111
|
const hubList=document.getElementById('hubSkillsList');
|
|
5821
|
-
list.innerHTML='<div class="spinner"></div>';
|
|
6112
|
+
if(!silent) list.innerHTML='<div class="spinner"></div>';
|
|
5822
6113
|
var hubSection=document.getElementById('hubSkillsSection');
|
|
5823
6114
|
if(hubList){
|
|
5824
6115
|
if(skillSearchScope==='local'||skillSearchScope==='allLocal'){
|
|
5825
6116
|
if(hubSection) hubSection.style.display='none';
|
|
5826
6117
|
}else{
|
|
5827
6118
|
if(hubSection) hubSection.style.display='block';
|
|
5828
|
-
hubList.innerHTML='<div class="spinner"></div>';
|
|
6119
|
+
if(!silent) hubList.innerHTML='<div class="spinner"></div>';
|
|
5829
6120
|
}
|
|
5830
6121
|
}
|
|
5831
6122
|
|
|
@@ -5849,6 +6140,13 @@ async function loadSkills(){
|
|
|
5849
6140
|
return haystack.includes(q);
|
|
5850
6141
|
});
|
|
5851
6142
|
}
|
|
6143
|
+
if(silent){
|
|
6144
|
+
var fp=JSON.stringify(localSkills.map(function(s){return s.id+'|'+s.status+'|'+s.version+'|'+(s.visibility||'')}));
|
|
6145
|
+
if(fp===_lastSkillsFingerprint) return;
|
|
6146
|
+
_lastSkillsFingerprint=fp;
|
|
6147
|
+
}else{
|
|
6148
|
+
_lastSkillsFingerprint='';
|
|
6149
|
+
}
|
|
5852
6150
|
|
|
5853
6151
|
const renderLocalCards=function(skills){
|
|
5854
6152
|
if(!skills||skills.length===0){
|
|
@@ -5907,7 +6205,8 @@ async function loadSkills(){
|
|
|
5907
6205
|
|
|
5908
6206
|
if(!query){
|
|
5909
6207
|
if(hubSection) hubSection.style.display='block';
|
|
5910
|
-
|
|
6208
|
+
var localIds=new Set(localSkills.map(function(s){return s.id;}));
|
|
6209
|
+
if(hubList){ loadHubSkills(hubList, localIds); }
|
|
5911
6210
|
document.getElementById('skillSearchMeta').textContent=t('skills.search.local')+' '+localSkills.length;
|
|
5912
6211
|
document.getElementById('skillsTotalCount').textContent=formatNum(localSkills.length);
|
|
5913
6212
|
document.getElementById('skillsActiveCount').textContent=formatNum(localSkills.filter(s=>s.status==='active').length);
|
|
@@ -5941,7 +6240,7 @@ async function loadSkills(){
|
|
|
5941
6240
|
'<div class="summary">'+esc(skill.name)+'</div>'+
|
|
5942
6241
|
'<div class="excerpt">'+esc(skill.description||'')+'</div>'+
|
|
5943
6242
|
'<div class="hub-skill-meta">'+
|
|
5944
|
-
'<span class="meta-chip">owner: '+
|
|
6243
|
+
'<span class="meta-chip">owner: '+fmtOwner(skill)+'</span>'+
|
|
5945
6244
|
(skill.groupName?'<span class="meta-chip">group: '+esc(skill.groupName)+'</span>':'')+
|
|
5946
6245
|
'<span class="meta-chip">visibility: '+esc(skill.visibility||'hub')+'</span>'+
|
|
5947
6246
|
(skill.version!=null?'<span class="meta-chip">v'+skill.version+'</span>':'')+
|
|
@@ -5988,12 +6287,12 @@ async function loadHubTasks(){
|
|
|
5988
6287
|
return '<div class="task-card" onclick="openHubTaskDetailFromCache(\\x27hub\\x27,'+idx+')" style="cursor:pointer">'+
|
|
5989
6288
|
'<div class="task-card-top">'+
|
|
5990
6289
|
'<div class="task-card-title">'+esc(task.title||'(no title)')+'</div>'+
|
|
5991
|
-
'<div class="task-card-badges"
|
|
6290
|
+
'<div class="task-card-badges">'+renderScopeBadge('team')+'</div>'+
|
|
5992
6291
|
'</div>'+
|
|
5993
6292
|
(task.summary?'<div class="task-card-summary">'+esc(task.summary)+'</div>':'')+
|
|
5994
6293
|
'<div class="task-card-bottom">'+
|
|
5995
6294
|
(timeStr?'<span class="tag"><span class="icon">\\u{1F4C5}</span> '+timeStr+'</span>':'')+
|
|
5996
|
-
'<span class="tag"><span class="icon">\\u{1F464}</span> '+
|
|
6295
|
+
'<span class="tag"><span class="icon">\\u{1F464}</span> '+fmtOwner(task)+'</span>'+
|
|
5997
6296
|
(task.chunkCount!=null?'<span class="tag"><span class="icon">\\u{1F4DD}</span> '+task.chunkCount+' '+t('tasks.chunks.label')+'</span>':'')+
|
|
5998
6297
|
'</div>'+
|
|
5999
6298
|
'</div>';
|
|
@@ -6005,7 +6304,7 @@ async function loadHubTasks(){
|
|
|
6005
6304
|
}
|
|
6006
6305
|
}
|
|
6007
6306
|
|
|
6008
|
-
async function loadHubSkills(hubList){
|
|
6307
|
+
async function loadHubSkills(hubList, localIds){
|
|
6009
6308
|
if(!hubList) hubList=document.getElementById('hubSkillsList');
|
|
6010
6309
|
if(!hubList) return;
|
|
6011
6310
|
var hubSection=document.getElementById('hubSkillsSection');
|
|
@@ -6013,7 +6312,8 @@ async function loadHubSkills(hubList){
|
|
|
6013
6312
|
try{
|
|
6014
6313
|
const r=await fetch('/api/sharing/skills/list?limit=40');
|
|
6015
6314
|
const d=await r.json();
|
|
6016
|
-
|
|
6315
|
+
var allSkills=Array.isArray(d.skills)?d.skills:[];
|
|
6316
|
+
const skills=localIds?allSkills.filter(function(s){return !localIds.has(s.sourceSkillId);}):allSkills;
|
|
6017
6317
|
hubSkillsCache=skills;
|
|
6018
6318
|
if(!skills.length){
|
|
6019
6319
|
if(hubSection) hubSection.style.display='none';
|
|
@@ -6025,12 +6325,12 @@ async function loadHubSkills(hubList){
|
|
|
6025
6325
|
'<div class="summary">'+esc(skill.name)+'</div>'+
|
|
6026
6326
|
'<div class="excerpt">'+esc(skill.description||'')+'</div>'+
|
|
6027
6327
|
'<div class="hub-skill-meta">'+
|
|
6028
|
-
'<span class="meta-chip">owner: '+
|
|
6328
|
+
'<span class="meta-chip">owner: '+fmtOwner(skill)+'</span>'+
|
|
6029
6329
|
(skill.groupName?'<span class="meta-chip">group: '+esc(skill.groupName)+'</span>':'')+
|
|
6030
6330
|
'<span class="meta-chip">visibility: '+esc(skill.visibility||'hub')+'</span>'+
|
|
6031
6331
|
(skill.version!=null?'<span class="meta-chip">v'+skill.version+'</span>':'')+
|
|
6032
6332
|
'</div>'+
|
|
6033
|
-
'<div class="hub-skill-actions"><button class="btn btn-sm" onclick="event.stopPropagation();pullHubSkill(\\''+escAttr(skill.
|
|
6333
|
+
'<div class="hub-skill-actions"><button class="btn btn-sm" onclick="event.stopPropagation();pullHubSkill(\\''+escAttr(skill.id)+'\\')">'+t('skill.pullToLocal')+'</button></div>'+
|
|
6034
6334
|
'</div>';
|
|
6035
6335
|
}).join('');
|
|
6036
6336
|
}catch(e){
|
|
@@ -6364,6 +6664,7 @@ async function loadConfig(){
|
|
|
6364
6664
|
document.getElementById('cfgHubTeamName').value=hub.teamName||'';
|
|
6365
6665
|
document.getElementById('cfgHubTeamToken').value=hub.teamToken||'';
|
|
6366
6666
|
document.getElementById('cfgClientHubAddress').value=client.hubAddress||'';
|
|
6667
|
+
_loadedClientHubAddress=client.hubAddress||'';
|
|
6367
6668
|
document.getElementById('cfgClientTeamToken').value=client.teamToken||'';
|
|
6368
6669
|
document.getElementById('cfgClientNickname').value=client.nickname||'';
|
|
6369
6670
|
document.getElementById('cfgClientUserToken').value=client.userToken||'';
|
|
@@ -6409,20 +6710,24 @@ function flashSaved(id){
|
|
|
6409
6710
|
}
|
|
6410
6711
|
|
|
6411
6712
|
async function doSaveConfig(cfg, btnEl, savedId){
|
|
6412
|
-
btnEl.disabled=true;btnEl.textContent=t('settings.test.loading');
|
|
6413
|
-
function done(){btnEl.disabled=false;btnEl.textContent=t('settings.save');}
|
|
6713
|
+
if(btnEl){btnEl.disabled=true;btnEl.textContent=t('settings.test.loading');}
|
|
6714
|
+
function done(){if(btnEl){btnEl.disabled=false;btnEl.textContent=t('settings.save');}}
|
|
6414
6715
|
try{
|
|
6415
6716
|
const r=await fetch('/api/config',{method:'PUT',headers:{'Content-Type':'application/json'},body:JSON.stringify(cfg)});
|
|
6416
|
-
if(r.status===401){done();toast(t('settings.session.expired'),'error');return
|
|
6717
|
+
if(r.status===401){done();toast(t('settings.session.expired'),'error');return null;}
|
|
6417
6718
|
if(!r.ok) throw new Error(await r.text());
|
|
6719
|
+
var data=await r.json().catch(function(){return {ok:true};});
|
|
6418
6720
|
flashSaved(savedId);
|
|
6419
|
-
|
|
6420
|
-
|
|
6421
|
-
|
|
6721
|
+
if(data&&data.restart){
|
|
6722
|
+
showRestartOverlay(t('settings.restart.waiting'));
|
|
6723
|
+
}else{
|
|
6724
|
+
done();
|
|
6725
|
+
}
|
|
6726
|
+
return data;
|
|
6422
6727
|
}catch(e){
|
|
6423
6728
|
toast(t('settings.save.fail')+': '+e.message,'error');
|
|
6424
6729
|
done();
|
|
6425
|
-
return
|
|
6730
|
+
return null;
|
|
6426
6731
|
}
|
|
6427
6732
|
}
|
|
6428
6733
|
|
|
@@ -6517,11 +6822,19 @@ async function saveModelsConfig(){
|
|
|
6517
6822
|
await doSaveConfig(cfg, saveBtn, 'modelsSaved');
|
|
6518
6823
|
}
|
|
6519
6824
|
|
|
6825
|
+
function _hubSaveBtnLabel(){
|
|
6826
|
+
var on=document.getElementById('cfgSharingEnabled');
|
|
6827
|
+
if(on&&on.checked&&_sharingRole==='client'){
|
|
6828
|
+
var prevClient=sharingStatusCache&&sharingStatusCache.enabled&&sharingStatusCache.role==='client';
|
|
6829
|
+
return prevClient?t('settings.save'):t('sharing.joinTeam');
|
|
6830
|
+
}
|
|
6831
|
+
return t('settings.save');
|
|
6832
|
+
}
|
|
6520
6833
|
async function saveHubConfig(){
|
|
6521
6834
|
var card=document.getElementById('settingsSharingConfig');
|
|
6522
6835
|
var saveBtn=card.querySelector('.settings-actions .btn-primary');
|
|
6523
6836
|
saveBtn.disabled=true;saveBtn.textContent=t('settings.test.loading');
|
|
6524
|
-
function done(){saveBtn.disabled=false;saveBtn.textContent=
|
|
6837
|
+
function done(){saveBtn.disabled=false;saveBtn.textContent=_hubSaveBtnLabel();}
|
|
6525
6838
|
|
|
6526
6839
|
const cfg={};
|
|
6527
6840
|
var sharingEnabled=document.getElementById('cfgSharingEnabled').checked;
|
|
@@ -6535,7 +6848,7 @@ async function saveHubConfig(){
|
|
|
6535
6848
|
var hubTeamName=document.getElementById('cfgHubTeamName').value.trim();
|
|
6536
6849
|
var hubTeamToken=document.getElementById('cfgHubTeamToken').value.trim();
|
|
6537
6850
|
var hubAdminName=document.getElementById('cfgHubAdminName').value.trim();
|
|
6538
|
-
cfg.sharing.hub={port:
|
|
6851
|
+
if(hubPort) cfg.sharing.hub={port:Number(hubPort)}; else cfg.sharing.hub={};
|
|
6539
6852
|
if(hubTeamName) cfg.sharing.hub.teamName=hubTeamName;
|
|
6540
6853
|
if(hubTeamToken) cfg.sharing.hub.teamToken=hubTeamToken;
|
|
6541
6854
|
cfg.sharing.client={hubAddress:'',userToken:'',teamToken:''};
|
|
@@ -6545,21 +6858,29 @@ async function saveHubConfig(){
|
|
|
6545
6858
|
var clientTeamToken=document.getElementById('cfgClientTeamToken').value.trim();
|
|
6546
6859
|
var clientUserToken=document.getElementById('cfgClientUserToken').value.trim();
|
|
6547
6860
|
var clientNickname=document.getElementById('cfgClientNickname').value.trim();
|
|
6861
|
+
if(!clientAddr){done();toast(t('settings.hub.test.noAddr'),'error');return;}
|
|
6862
|
+
if(!clientTeamToken){done();toast(t('settings.hub.teamToken.required'),'error');return;}
|
|
6548
6863
|
cfg.sharing.client={};
|
|
6549
6864
|
if(clientAddr) cfg.sharing.client.hubAddress=clientAddr;
|
|
6550
6865
|
if(clientNickname) cfg.sharing.client.nickname=clientNickname;
|
|
6551
6866
|
if(clientTeamToken) cfg.sharing.client.teamToken=clientTeamToken;
|
|
6552
6867
|
if(clientUserToken) cfg.sharing.client.userToken=clientUserToken;
|
|
6553
|
-
cfg.sharing.hub={
|
|
6868
|
+
cfg.sharing.hub={teamName:'',teamToken:''};
|
|
6554
6869
|
if(clientAddr){
|
|
6555
6870
|
try{
|
|
6556
|
-
var ips=await fetch('/api/local-ips').then(function(r){return r.json();});
|
|
6557
|
-
var localAddrs=['127.0.0.1','localhost','0.0.0.0'].concat(ips.ips||[]);
|
|
6558
|
-
var parsed=new URL(clientAddr.indexOf('://')>-1?clientAddr:'http://'+clientAddr);
|
|
6559
|
-
if(localAddrs.indexOf(parsed.hostname)>=0){
|
|
6560
|
-
done();toast(t('sharing.cannotJoinSelf'),'error');return;
|
|
6561
|
-
}
|
|
6562
6871
|
}catch(e){}
|
|
6872
|
+
try{
|
|
6873
|
+
var testUrl=clientAddr.indexOf('://')>-1?clientAddr:'http://'+clientAddr;
|
|
6874
|
+
testUrl=testUrl.replace(/\\/+$/,'');
|
|
6875
|
+
var tr=await fetch('/api/sharing/test-hub',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({hubUrl:testUrl})});
|
|
6876
|
+
var td=await tr.json();
|
|
6877
|
+
if(!td.ok){
|
|
6878
|
+
var errMsg=td.error==='cannot_join_self'?t('sharing.cannotJoinSelf'):(td.error||t('settings.hub.test.fail'));
|
|
6879
|
+
done();toast(errMsg,'error');return;
|
|
6880
|
+
}
|
|
6881
|
+
}catch(e){
|
|
6882
|
+
done();toast(t('settings.hub.test.fail')+': '+String(e),'error');return;
|
|
6883
|
+
}
|
|
6563
6884
|
}
|
|
6564
6885
|
}
|
|
6565
6886
|
|
|
@@ -6569,21 +6890,44 @@ async function saveHubConfig(){
|
|
|
6569
6890
|
var confirmMsg=prevRole==='hub'?t('sharing.disable.confirm.hub'):t('sharing.disable.confirm.client');
|
|
6570
6891
|
if(!(await confirmModal(confirmMsg,{danger:true}))){done();return;}
|
|
6571
6892
|
}
|
|
6893
|
+
if(prevSharingEnabled&&sharingEnabled&&prevRole&&prevRole!==_sharingRole){
|
|
6894
|
+
var switchMsg=prevRole==='hub'?t('sharing.switch.hubToClient'):t('sharing.switch.clientToHub');
|
|
6895
|
+
if(!(await confirmModal(switchMsg,{danger:true}))){done();return;}
|
|
6896
|
+
}
|
|
6897
|
+
if(prevSharingEnabled&&sharingEnabled&&prevRole==='client'&&_sharingRole==='client'){
|
|
6898
|
+
var newAddr=(document.getElementById('cfgClientHubAddress').value||'').trim();
|
|
6899
|
+
if(_loadedClientHubAddress&&newAddr&&newAddr!==_loadedClientHubAddress){
|
|
6900
|
+
if(!(await confirmModal(t('sharing.switch.hubAddress'),{danger:true}))){done();return;}
|
|
6901
|
+
}
|
|
6902
|
+
}
|
|
6572
6903
|
|
|
6573
|
-
var
|
|
6574
|
-
if(
|
|
6904
|
+
var result=await doSaveConfig(cfg, saveBtn, 'hubSaved');
|
|
6905
|
+
if(result){
|
|
6575
6906
|
if(sharingEnabled&&_sharingRole==='hub'){
|
|
6576
6907
|
var adminNameEl=document.getElementById('cfgHubAdminName');
|
|
6577
6908
|
if(adminNameEl&&adminNameEl.value.trim()){
|
|
6578
6909
|
try{await fetch('/api/sharing/update-username',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({username:adminNameEl.value.trim()})});}catch(e){}
|
|
6579
6910
|
}
|
|
6580
6911
|
}
|
|
6581
|
-
|
|
6582
|
-
|
|
6583
|
-
|
|
6584
|
-
|
|
6585
|
-
|
|
6912
|
+
if(sharingEnabled&&_sharingRole==='client'&&result.joinStatus){
|
|
6913
|
+
if(result.joinStatus==='pending'){
|
|
6914
|
+
toast(t('sharing.joinSent.pending'),'success');
|
|
6915
|
+
}else if(result.joinStatus==='active'){
|
|
6916
|
+
toast(t('sharing.joinSent.active'),'success');
|
|
6917
|
+
}else{
|
|
6918
|
+
toast(t('settings.saved'),'success');
|
|
6919
|
+
}
|
|
6920
|
+
}else{
|
|
6921
|
+
toast(t('settings.saved'),'success');
|
|
6586
6922
|
}
|
|
6923
|
+
_lastSidebarFingerprint='';
|
|
6924
|
+
_lastSettingsFingerprint='';
|
|
6925
|
+
_lastSharingConnStatus='';
|
|
6926
|
+
_lastAdminFingerprint='';
|
|
6927
|
+
_lastAdminStatsFp='';
|
|
6928
|
+
if(sharingEnabled) updateHubShareInfo();
|
|
6929
|
+
loadSharingStatus(true);
|
|
6930
|
+
if(_activeView==='admin') loadAdminData();
|
|
6587
6931
|
}
|
|
6588
6932
|
}
|
|
6589
6933
|
|
|
@@ -6673,6 +7017,8 @@ function renderSkillMarkdown(md){
|
|
|
6673
7017
|
function closeSkillDetail(event){
|
|
6674
7018
|
if(event && event.target!==document.getElementById('skillDetailOverlay')) return;
|
|
6675
7019
|
document.getElementById('skillDetailOverlay').classList.remove('show');
|
|
7020
|
+
currentSkillId='';
|
|
7021
|
+
currentSkillDetail=null;
|
|
6676
7022
|
}
|
|
6677
7023
|
|
|
6678
7024
|
async function deleteSkill(skillId){
|
|
@@ -7007,16 +7353,29 @@ var _livePollBusy=false;
|
|
|
7007
7353
|
async function _livePollTick(){
|
|
7008
7354
|
if(_livePollBusy||document.hidden) return;
|
|
7009
7355
|
_livePollBusy=true;
|
|
7356
|
+
var _savedScrollY=window.scrollY;
|
|
7357
|
+
var _scrollTargets=['memoryList','tasksList','skillsList','adminUsersPanel','adminMemoriesPanel','adminTasksPanel','adminSkillsPanel'];
|
|
7358
|
+
var _savedScrollMap={};
|
|
7359
|
+
_scrollTargets.forEach(function(id){var el=document.getElementById(id);if(el&&el.scrollTop)_savedScrollMap[id]=el.scrollTop;});
|
|
7010
7360
|
try{
|
|
7011
|
-
if(sharingStatusCache&&sharingStatusCache.enabled) loadSharingStatus(false);
|
|
7012
|
-
if(!_notifSSEConnected) pollNotifCount();
|
|
7013
|
-
pollAdminPending();
|
|
7014
|
-
if(_activeView==='admin') loadAdminData();
|
|
7015
|
-
else if(_activeView==='memories'){
|
|
7016
|
-
|
|
7017
|
-
|
|
7018
|
-
|
|
7361
|
+
if(sharingStatusCache&&sharingStatusCache.enabled&&_lastSharingConnStatus!=='rejected') await loadSharingStatus(false);
|
|
7362
|
+
if(!_notifSSEConnected) await pollNotifCount();
|
|
7363
|
+
await pollAdminPending();
|
|
7364
|
+
if(_activeView==='admin') await loadAdminData();
|
|
7365
|
+
else if(_activeView==='memories'){
|
|
7366
|
+
var _searchVal=(document.getElementById('searchInput')||{}).value||'';
|
|
7367
|
+
if(!_searchVal.trim()){
|
|
7368
|
+
if(memorySearchScope==='hub') await loadHubMemories(true);
|
|
7369
|
+
else{var _pollOwner=memorySearchScope==='local'?_currentAgentOwner:undefined;await loadStats(_pollOwner);await loadMemories(null,true);}
|
|
7370
|
+
}
|
|
7371
|
+
}
|
|
7372
|
+
else if(_activeView==='tasks') await loadTasks(true);
|
|
7373
|
+
else if(_activeView==='skills') await loadSkills(true);
|
|
7374
|
+
else if(_activeView==='analytics') await loadMetrics();
|
|
7019
7375
|
}catch(e){}
|
|
7376
|
+
await new Promise(function(r){requestAnimationFrame(r);});
|
|
7377
|
+
window.scrollTo(0,_savedScrollY);
|
|
7378
|
+
for(var _sid in _savedScrollMap){var _sel=document.getElementById(_sid);if(_sel)_sel.scrollTop=_savedScrollMap[_sid];}
|
|
7020
7379
|
_livePollBusy=false;
|
|
7021
7380
|
}
|
|
7022
7381
|
|
|
@@ -7060,6 +7419,9 @@ function connectNotifSSE(){
|
|
|
7060
7419
|
_notifUnread=d.unreadCount||0;
|
|
7061
7420
|
renderNotifBadge();
|
|
7062
7421
|
if(_notifUnread>prev&&_notifPanelOpen) loadNotifications();
|
|
7422
|
+
if(_notifUnread>prev&&_activeView==='memories'&&memorySearchScope!=='hub'){
|
|
7423
|
+
syncTeamShareRemovedFromNotifications().then(function(){ loadMemories(currentPage,true); });
|
|
7424
|
+
}
|
|
7063
7425
|
}
|
|
7064
7426
|
if(d.type==='cleared'){
|
|
7065
7427
|
_notifUnread=0;_notifCache=[];
|
|
@@ -7109,7 +7471,12 @@ function notifTimeAgo(ts){
|
|
|
7109
7471
|
function notifIcon(resource,type){
|
|
7110
7472
|
if(type==='user_online') return '\\u{1F7E2}';
|
|
7111
7473
|
if(type==='user_offline') return '\\u{1F534}';
|
|
7474
|
+
if(type==='user_left') return '\\u{1F6AA}';
|
|
7112
7475
|
if(type==='user_join_request') return '\\u{1F464}';
|
|
7476
|
+
if(type==='membership_removed') return '\\u{26D4}';
|
|
7477
|
+
if(type==='hub_shutdown') return '\\u{1F6D1}';
|
|
7478
|
+
if(type==='role_promoted') return '\\u{2B06}';
|
|
7479
|
+
if(type==='role_demoted') return '\\u{2B07}';
|
|
7113
7480
|
if(resource==='memory') return '\\u{1F4DD}';
|
|
7114
7481
|
if(resource==='task') return '\\u{1F4CB}';
|
|
7115
7482
|
if(resource==='skill') return '\\u{1F9E0}';
|
|
@@ -7135,6 +7502,27 @@ function notifTypeText(n){
|
|
|
7135
7502
|
if(n.type==='user_offline'){
|
|
7136
7503
|
return t('notif.userOffline');
|
|
7137
7504
|
}
|
|
7505
|
+
if(n.type==='user_left'){
|
|
7506
|
+
return t('notif.userLeft');
|
|
7507
|
+
}
|
|
7508
|
+
if(n.type==='membership_approved'){
|
|
7509
|
+
return t('notif.membershipApproved');
|
|
7510
|
+
}
|
|
7511
|
+
if(n.type==='membership_rejected'){
|
|
7512
|
+
return t('notif.membershipRejected');
|
|
7513
|
+
}
|
|
7514
|
+
if(n.type==='membership_removed'){
|
|
7515
|
+
return t('notif.membershipRemoved');
|
|
7516
|
+
}
|
|
7517
|
+
if(n.type==='hub_shutdown'){
|
|
7518
|
+
return t('notif.hubShutdown');
|
|
7519
|
+
}
|
|
7520
|
+
if(n.type==='role_promoted'){
|
|
7521
|
+
return t('notif.rolePromoted');
|
|
7522
|
+
}
|
|
7523
|
+
if(n.type==='role_demoted'){
|
|
7524
|
+
return t('notif.roleDemoted');
|
|
7525
|
+
}
|
|
7138
7526
|
return n.message||n.type;
|
|
7139
7527
|
}
|
|
7140
7528
|
|
|
@@ -7169,6 +7557,21 @@ function renderNotifBadge(){
|
|
|
7169
7557
|
}
|
|
7170
7558
|
}
|
|
7171
7559
|
|
|
7560
|
+
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};
|
|
7561
|
+
function notifDisplayTitle(n){
|
|
7562
|
+
if(_notifKnownTypes[n.type]) return notifTypeText(n);
|
|
7563
|
+
return n.title||notifTypeText(n);
|
|
7564
|
+
}
|
|
7565
|
+
function notifDisplayDetail(n){
|
|
7566
|
+
if(_notifKnownTypes[n.type]){
|
|
7567
|
+
if(n.type==='resource_removed'||n.type==='resource_shared'||n.type==='resource_unshared') return n.title||'';
|
|
7568
|
+
var m=n.title&&n.title.match(/["\u201C]([^"\u201D]+)["\u201D]/);
|
|
7569
|
+
if(m) return m[1];
|
|
7570
|
+
if(n.type==='user_left'||n.type==='user_online'||n.type==='user_offline'||n.type==='user_join_request') return n.title||'';
|
|
7571
|
+
return '';
|
|
7572
|
+
}
|
|
7573
|
+
return n.title||'';
|
|
7574
|
+
}
|
|
7172
7575
|
function renderNotifPanel(){
|
|
7173
7576
|
var body=document.getElementById('notifPanelBody');
|
|
7174
7577
|
if(!body) return;
|
|
@@ -7178,11 +7581,12 @@ function renderNotifPanel(){
|
|
|
7178
7581
|
}
|
|
7179
7582
|
body.innerHTML=_notifCache.map(function(n){
|
|
7180
7583
|
var cls='notif-item'+(n.read?'':' unread');
|
|
7584
|
+
var detail=notifDisplayDetail(n);
|
|
7181
7585
|
return '<div class="'+cls+'" onclick="markNotifRead("'+esc(n.id)+'")">'+
|
|
7182
7586
|
'<div class="notif-item-icon">'+notifIcon(n.resource,n.type)+'</div>'+
|
|
7183
7587
|
'<div class="notif-item-body">'+
|
|
7184
|
-
'<div class="notif-item-title">'+esc(
|
|
7185
|
-
'<div class="notif-item-name">'+esc(
|
|
7588
|
+
'<div class="notif-item-title">'+esc(notifDisplayTitle(n))+'</div>'+
|
|
7589
|
+
(detail?'<div class="notif-item-name">'+esc(detail)+'</div>':'')+
|
|
7186
7590
|
'<div class="notif-item-time">'+notifTimeAgo(n.createdAt)+'</div>'+
|
|
7187
7591
|
'</div>'+
|
|
7188
7592
|
'<div class="notif-item-dot"></div>'+
|
|
@@ -7225,7 +7629,10 @@ function stopNotifPoll(){ }
|
|
|
7225
7629
|
|
|
7226
7630
|
/* ─── Data loading ─── */
|
|
7227
7631
|
async function loadAll(){
|
|
7228
|
-
await
|
|
7632
|
+
await loadStats();
|
|
7633
|
+
var initOwner=memorySearchScope==='local'?_currentAgentOwner:undefined;
|
|
7634
|
+
if(initOwner) await loadStats(initOwner);
|
|
7635
|
+
await Promise.all([loadMemories(),loadSharingStatus(false)]);
|
|
7229
7636
|
checkMigrateStatus();
|
|
7230
7637
|
connectPPSSE();
|
|
7231
7638
|
checkForUpdate();
|
|
@@ -7233,6 +7640,7 @@ async function loadAll(){
|
|
|
7233
7640
|
startLivePoller();
|
|
7234
7641
|
}
|
|
7235
7642
|
|
|
7643
|
+
var _lastStatsFp='';
|
|
7236
7644
|
async function loadStats(ownerFilter){
|
|
7237
7645
|
let d;
|
|
7238
7646
|
try{
|
|
@@ -7242,28 +7650,22 @@ async function loadStats(ownerFilter){
|
|
|
7242
7650
|
d=await r.json();
|
|
7243
7651
|
}catch(e){ d={}; }
|
|
7244
7652
|
if(!d||typeof d!=='object') d={};
|
|
7653
|
+
if(d.currentAgentOwner) _currentAgentOwner=d.currentAgentOwner;
|
|
7245
7654
|
const tm=d.totalMemories||0;
|
|
7246
7655
|
const dedupB=d.dedupBreakdown||{};
|
|
7247
7656
|
const activeCount=dedupB.active||tm;
|
|
7248
7657
|
const inactiveCount=(dedupB.duplicate||0)+(dedupB.merged||0);
|
|
7658
|
+
var agentCount=(d.owners&&d.owners.length)?d.owners.length:1;
|
|
7659
|
+
var sfp=tm+':'+(d.totalSessions||0)+':'+(d.totalEmbeddings||0)+':'+agentCount+':'+(d.embeddingProvider||'none')+':'+(ownerFilter||'');
|
|
7660
|
+
if(sfp===_lastStatsFp) return;
|
|
7661
|
+
_lastStatsFp=sfp;
|
|
7249
7662
|
document.getElementById('statTotal').textContent=tm;
|
|
7250
7663
|
if(inactiveCount>0){
|
|
7251
7664
|
document.getElementById('statTotal').title=activeCount+' '+t('stat.active')+', '+inactiveCount+' '+t('stat.deduped');
|
|
7252
7665
|
}
|
|
7253
7666
|
document.getElementById('statSessions').textContent=d.totalSessions||0;
|
|
7254
7667
|
document.getElementById('statEmbeddings').textContent=d.totalEmbeddings||0;
|
|
7255
|
-
|
|
7256
|
-
if(d.timeRange&&d.timeRange.earliest!=null&&d.timeRange.latest!=null){
|
|
7257
|
-
let e=Number(d.timeRange.earliest), l=Number(d.timeRange.latest);
|
|
7258
|
-
if(Number.isFinite(e)&&Number.isFinite(l)){
|
|
7259
|
-
if(e<1e12) e*=1000;
|
|
7260
|
-
if(l<1e12) l*=1000;
|
|
7261
|
-
days=Math.round((l-e)/86400000);
|
|
7262
|
-
days=Math.max(0,Math.min(36500,days));
|
|
7263
|
-
if(days===0) days=1;
|
|
7264
|
-
}
|
|
7265
|
-
}
|
|
7266
|
-
document.getElementById('statTimeSpan').textContent=days;
|
|
7668
|
+
document.getElementById('statAgents').textContent=agentCount;
|
|
7267
7669
|
|
|
7268
7670
|
const provEl=document.getElementById('embeddingStatus');
|
|
7269
7671
|
if(d.embeddingProvider && d.embeddingProvider!=='none'){
|
|
@@ -7355,55 +7757,108 @@ function getFilterParams(){
|
|
|
7355
7757
|
if(dt) p.set('dateTo',dt);
|
|
7356
7758
|
const sort=document.getElementById('filterSort').value;
|
|
7357
7759
|
if(sort==='oldest') p.set('sort','oldest');
|
|
7760
|
+
const scope=memorySearchScope||'local';
|
|
7761
|
+
if(scope==='local'){
|
|
7762
|
+
p.set('owner',_currentAgentOwner);
|
|
7763
|
+
}else if(scope==='allLocal'){
|
|
7358
7764
|
const owner=document.getElementById('filterOwner').value;
|
|
7359
7765
|
if(owner) p.set('owner',owner);
|
|
7766
|
+
}
|
|
7360
7767
|
return p;
|
|
7361
7768
|
}
|
|
7362
7769
|
|
|
7363
|
-
|
|
7770
|
+
/** Hub admin removed a shared memory — badge-only: clear team_shared_chunks (never touches chunks/embeddings/hub_memories recall data). */
|
|
7771
|
+
async function syncTeamShareRemovedFromNotifications(){
|
|
7772
|
+
try{
|
|
7773
|
+
var r=await fetch('/api/sharing/notifications');
|
|
7774
|
+
var d=await r.json();
|
|
7775
|
+
var list=d.notifications||[];
|
|
7776
|
+
for(var i=0;i<list.length;i++){
|
|
7777
|
+
var n=list[i];
|
|
7778
|
+
if(n.type!=='resource_removed'||n.resource!=='memory'||!n.message) continue;
|
|
7779
|
+
try{
|
|
7780
|
+
var meta=JSON.parse(n.message);
|
|
7781
|
+
if(meta.sourceChunkId){
|
|
7782
|
+
await fetch('/api/sharing/sync-hub-removal',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({sourceChunkId:meta.sourceChunkId,memoryId:meta.memoryId||''})});
|
|
7783
|
+
}
|
|
7784
|
+
}catch(e){}
|
|
7785
|
+
}
|
|
7786
|
+
}catch(e){}
|
|
7787
|
+
}
|
|
7788
|
+
|
|
7789
|
+
async function loadMemories(page,silent){
|
|
7364
7790
|
if(page) currentPage=page;
|
|
7365
7791
|
const list=document.getElementById('memoryList');
|
|
7366
|
-
list.innerHTML='<div class="spinner"></div>';
|
|
7792
|
+
if(!silent) list.innerHTML='<div class="spinner"></div>';
|
|
7367
7793
|
try{
|
|
7794
|
+
if(!silent) await syncTeamShareRemovedFromNotifications();
|
|
7368
7795
|
const p=getFilterParams();
|
|
7369
7796
|
p.set('limit',PAGE_SIZE);
|
|
7370
7797
|
p.set('page',currentPage);
|
|
7371
7798
|
const r=await fetch('/api/memories?'+p.toString());
|
|
7372
7799
|
const d=await r.json();
|
|
7800
|
+
var items=d.memories||[];
|
|
7801
|
+
if(silent){
|
|
7802
|
+
var fp=JSON.stringify(items.map(function(m){return m.id+'|'+m.updated_at}));
|
|
7803
|
+
if(fp===_lastMemoriesFingerprint) return;
|
|
7804
|
+
_lastMemoriesFingerprint=fp;
|
|
7805
|
+
}else{
|
|
7806
|
+
_lastMemoriesFingerprint=JSON.stringify(items.map(function(m){return m.id+'|'+m.updated_at}));
|
|
7807
|
+
}
|
|
7373
7808
|
totalPages=d.totalPages||1;
|
|
7374
7809
|
totalCount=d.total||0;
|
|
7375
7810
|
document.getElementById('searchMeta').textContent=totalCount+t('search.meta.total');
|
|
7376
|
-
renderMemories(
|
|
7811
|
+
renderMemories(items);
|
|
7377
7812
|
renderPagination();
|
|
7378
7813
|
}catch(e){
|
|
7814
|
+
if(!silent){
|
|
7379
7815
|
list.innerHTML='';
|
|
7380
7816
|
totalPages=1;totalCount=0;
|
|
7817
|
+
_lastMemoriesFingerprint='';
|
|
7381
7818
|
renderMemories([]);
|
|
7382
7819
|
renderPagination();
|
|
7820
|
+
}
|
|
7383
7821
|
}
|
|
7384
7822
|
}
|
|
7385
7823
|
|
|
7386
|
-
async function loadHubMemories(){
|
|
7824
|
+
async function loadHubMemories(silent){
|
|
7387
7825
|
const list=document.getElementById('memoryList');
|
|
7388
|
-
list.innerHTML='<div class="spinner"></div>';
|
|
7826
|
+
if(!silent) list.innerHTML='<div class="spinner"></div>';
|
|
7389
7827
|
try{
|
|
7390
7828
|
const r=await fetch('/api/sharing/memories/list?limit='+PAGE_SIZE);
|
|
7391
7829
|
const d=await r.json();
|
|
7392
7830
|
const items=d.memories||[];
|
|
7831
|
+
if(silent){
|
|
7832
|
+
var fp=JSON.stringify(items.map(function(m){return m.id+'|'+(m.updated_at||m.created_at)}));
|
|
7833
|
+
if(fp===_lastMemoriesFingerprint) return;
|
|
7834
|
+
_lastMemoriesFingerprint=fp;
|
|
7835
|
+
}else{
|
|
7836
|
+
_lastMemoriesFingerprint=JSON.stringify(items.map(function(m){return m.id+'|'+(m.updated_at||m.created_at)}));
|
|
7837
|
+
}
|
|
7838
|
+
totalPages=1;totalCount=items.length;currentPage=1;
|
|
7393
7839
|
document.getElementById('searchMeta').textContent=items.length+t('search.meta.total');
|
|
7394
7840
|
document.getElementById('sharingSearchMeta').textContent='';
|
|
7395
7841
|
renderMemories(items);
|
|
7396
7842
|
document.getElementById('pagination').innerHTML='';
|
|
7397
7843
|
}catch(e){
|
|
7844
|
+
if(!silent){
|
|
7845
|
+
_lastMemoriesFingerprint='';
|
|
7398
7846
|
document.getElementById('searchMeta').textContent='0'+t('search.meta.results');
|
|
7399
7847
|
renderMemories([]);
|
|
7400
7848
|
document.getElementById('pagination').innerHTML='';
|
|
7849
|
+
}
|
|
7401
7850
|
}
|
|
7402
7851
|
}
|
|
7403
7852
|
|
|
7404
7853
|
async function doSearch(query){
|
|
7405
7854
|
query=(query||'').trim();
|
|
7406
|
-
if(!query){
|
|
7855
|
+
if(!query){
|
|
7856
|
+
currentPage=1;
|
|
7857
|
+
if(memorySearchScope==='hub') loadHubMemories();
|
|
7858
|
+
else loadMemories();
|
|
7859
|
+
return;
|
|
7860
|
+
}
|
|
7861
|
+
currentPage=1;
|
|
7407
7862
|
var scope=document.getElementById('memorySearchScope')?.value||memorySearchScope||'local';
|
|
7408
7863
|
var list=document.getElementById('memoryList');
|
|
7409
7864
|
list.innerHTML='<div class="spinner"></div>';
|
|
@@ -7415,6 +7870,7 @@ async function doSearch(query){
|
|
|
7415
7870
|
body:JSON.stringify({query:query,scope:scope,maxResults:20,role:activeRole||undefined})
|
|
7416
7871
|
});
|
|
7417
7872
|
var data=await r.json();
|
|
7873
|
+
totalPages=1;totalCount=(data.results||[]).length;
|
|
7418
7874
|
renderSharingMemorySearchResults(data,query);
|
|
7419
7875
|
}catch(e){
|
|
7420
7876
|
document.getElementById('searchMeta').textContent='0'+t('search.meta.results');
|
|
@@ -7429,6 +7885,7 @@ async function doSearch(query){
|
|
|
7429
7885
|
var r=await fetch('/api/search?'+p.toString());
|
|
7430
7886
|
var d=await r.json();
|
|
7431
7887
|
var total=d.total||0;
|
|
7888
|
+
totalPages=1;totalCount=total;
|
|
7432
7889
|
var meta=[];
|
|
7433
7890
|
if(d.vectorCount>0) meta.push(d.vectorCount+t('search.meta.semantic'));
|
|
7434
7891
|
if(d.ftsCount>0) meta.push(d.ftsCount+t('search.meta.text'));
|
|
@@ -7509,7 +7966,7 @@ function renderMemories(items){
|
|
|
7509
7966
|
const mergeBadge=mc>0?'<span class="merge-badge">\\u{1F504} '+t('card.evolved')+' '+mc+t('card.times')+'</span>':'';
|
|
7510
7967
|
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>':'';
|
|
7511
7968
|
const ds=m.dedup_status||'active';
|
|
7512
|
-
const isInactive=ds==='merged';
|
|
7969
|
+
const isInactive=ds==='merged'||ds==='duplicate';
|
|
7513
7970
|
const dedupBadge=ds==='duplicate'?'<span class="dedup-badge duplicate">'+t('card.dedupDuplicate')+'</span>':ds==='merged'?'<span class="dedup-badge merged">'+t('card.dedupMerged')+'</span>':'';
|
|
7514
7971
|
const isImported=sid.startsWith('openclaw-import-')||sid.startsWith('openclaw-session-');
|
|
7515
7972
|
const importBadge=isImported?'<span class="import-badge">\u{1F990} '+t('card.imported')+'</span>':'';
|
|
@@ -7517,8 +7974,9 @@ function renderMemories(items){
|
|
|
7517
7974
|
const isPublicMem=ownerVal==='public';
|
|
7518
7975
|
const localManaged=!!m.localSharingManaged;
|
|
7519
7976
|
const memShared=m.sharingVisibility||null;
|
|
7977
|
+
const isHubScope=memorySearchScope==='hub';
|
|
7520
7978
|
const memScope=memShared?'team':isPublicMem?'local':'private';
|
|
7521
|
-
const memScopeBadge=renderScopeBadge(memScope);
|
|
7979
|
+
const memScopeBadge=isHubScope?renderScopeBadge('team'):renderScopeBadge(memScope);
|
|
7522
7980
|
let dedupInfo='';
|
|
7523
7981
|
if(ds==='duplicate'||ds==='merged'){
|
|
7524
7982
|
const reason=m.dedup_reason?'<span style="font-size:11px;color:var(--text-muted)">'+t('card.dedupReason')+esc(m.dedup_reason)+'</span>':'';
|
|
@@ -7622,7 +8080,8 @@ function renderPagination(){
|
|
|
7622
8080
|
function goPage(p){
|
|
7623
8081
|
if(p<1||p>totalPages||p===currentPage) return;
|
|
7624
8082
|
currentPage=p;
|
|
7625
|
-
|
|
8083
|
+
if(memorySearchScope==='hub') loadHubMemories();
|
|
8084
|
+
else loadMemories();
|
|
7626
8085
|
document.getElementById('memoryList').scrollIntoView({behavior:'smooth',block:'start'});
|
|
7627
8086
|
}
|
|
7628
8087
|
|
|
@@ -7702,6 +8161,11 @@ function esc(s){
|
|
|
7702
8161
|
if(!s)return'';
|
|
7703
8162
|
return s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
|
|
7704
8163
|
}
|
|
8164
|
+
function fmtOwner(item){
|
|
8165
|
+
var name=item.ownerName||item.sourceUserId||'unknown';
|
|
8166
|
+
if(item.ownerStatus==='removed') return esc(name)+' <span style="color:#ef4444;font-size:0.9em">'+t('sharing.ownerRemoved')+'</span>';
|
|
8167
|
+
return esc(name);
|
|
8168
|
+
}
|
|
7705
8169
|
|
|
7706
8170
|
function renderSummaryHtml(raw){
|
|
7707
8171
|
if(!raw)return'';
|
|
@@ -8428,18 +8892,25 @@ function confirmModal(message,opts){
|
|
|
8428
8892
|
_confirmResolve=resolve;
|
|
8429
8893
|
var overlay=document.getElementById('confirmOverlay');
|
|
8430
8894
|
document.getElementById('confirmTitle').textContent=opts.title||t('confirm.title')||'\u786E\u8BA4';
|
|
8431
|
-
document.getElementById('confirmBody').
|
|
8895
|
+
document.getElementById('confirmBody').innerText=message||'';
|
|
8432
8896
|
var okBtn=document.getElementById('confirmOkBtn');
|
|
8433
8897
|
okBtn.textContent=opts.okText||t('confirm.ok')||'\u786E\u5B9A';
|
|
8434
8898
|
okBtn.className='btn-confirm-ok'+(opts.danger?' danger':'');
|
|
8435
|
-
document.getElementById('confirmCancelBtn')
|
|
8899
|
+
var cancelBtn=document.getElementById('confirmCancelBtn');
|
|
8900
|
+
cancelBtn.textContent=opts.cancelText||t('confirm.cancel')||'\u53D6\u6D88';
|
|
8901
|
+
cancelBtn.style.display=opts.hideCancel?'none':'';
|
|
8436
8902
|
overlay.classList.add('show');
|
|
8437
8903
|
});
|
|
8438
8904
|
}
|
|
8439
8905
|
function confirmModalClose(result){
|
|
8440
8906
|
document.getElementById('confirmOverlay').classList.remove('show');
|
|
8907
|
+
document.getElementById('confirmCancelBtn').style.display='';
|
|
8441
8908
|
if(_confirmResolve){var r=_confirmResolve;_confirmResolve=null;r(result);}
|
|
8442
8909
|
}
|
|
8910
|
+
function alertModal(message,opts){
|
|
8911
|
+
opts=opts||{};
|
|
8912
|
+
return confirmModal(message,Object.assign({},opts,{hideCancel:true,okText:opts.okText||t('confirm.ok')||'\u77E5\u9053\u4E86'}));
|
|
8913
|
+
}
|
|
8443
8914
|
|
|
8444
8915
|
/* ─── Theme ─── */
|
|
8445
8916
|
const VIEWER_THEME_KEY='memos-viewer-theme';
|
|
@@ -8462,14 +8933,35 @@ function showRestartOverlay(msg){
|
|
|
8462
8933
|
/* ─── Update check ─── */
|
|
8463
8934
|
function waitForGatewayAndReload(maxAttempts,attempt){
|
|
8464
8935
|
attempt=attempt||0;
|
|
8936
|
+
var phase=arguments.length>2?arguments[2]:'waitDown';
|
|
8937
|
+
var MAX_WAIT_DOWN=8;
|
|
8465
8938
|
function forceReload(){window.location.href=window.location.pathname+'?_t='+Date.now();}
|
|
8466
8939
|
if(attempt>=maxAttempts){forceReload();return;}
|
|
8940
|
+
var delay=phase==='waitDown'?1500:2500;
|
|
8467
8941
|
setTimeout(function(){
|
|
8468
8942
|
fetch('/api/auth/status').then(function(r){
|
|
8469
|
-
if(
|
|
8470
|
-
|
|
8471
|
-
|
|
8472
|
-
|
|
8943
|
+
if(phase==='waitDown'){
|
|
8944
|
+
if(r.ok||r.status===401||r.status===403){
|
|
8945
|
+
if(attempt>=MAX_WAIT_DOWN){
|
|
8946
|
+
forceReload();
|
|
8947
|
+
}else{
|
|
8948
|
+
waitForGatewayAndReload(maxAttempts,attempt+1,'waitDown');
|
|
8949
|
+
}
|
|
8950
|
+
}else{
|
|
8951
|
+
waitForGatewayAndReload(maxAttempts,0,'waitUp');
|
|
8952
|
+
}
|
|
8953
|
+
}else{
|
|
8954
|
+
if(r.ok||r.status===401||r.status===403) forceReload();
|
|
8955
|
+
else waitForGatewayAndReload(maxAttempts,attempt+1,'waitUp');
|
|
8956
|
+
}
|
|
8957
|
+
}).catch(function(){
|
|
8958
|
+
if(phase==='waitDown'){
|
|
8959
|
+
waitForGatewayAndReload(maxAttempts,0,'waitUp');
|
|
8960
|
+
}else{
|
|
8961
|
+
waitForGatewayAndReload(maxAttempts,attempt+1,'waitUp');
|
|
8962
|
+
}
|
|
8963
|
+
});
|
|
8964
|
+
},delay);
|
|
8473
8965
|
}
|
|
8474
8966
|
function doUpdateInstall(packageSpec,btnEl,statusEl){
|
|
8475
8967
|
btnEl.disabled=true;
|
|
@@ -8503,9 +8995,12 @@ async function checkForUpdate(){
|
|
|
8503
8995
|
const d=await r.json();
|
|
8504
8996
|
if(!d.updateAvailable)return;
|
|
8505
8997
|
const pkgSpec=d.installCommand?d.installCommand.replace(/^(?:npx\s+)?openclaw\s+plugins\s+install\s+/,''):(d.packageName+'@'+d.latest);
|
|
8998
|
+
var bannerWrap=document.createElement('div');
|
|
8999
|
+
bannerWrap.id='updateBannerWrap';
|
|
9000
|
+
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';
|
|
8506
9001
|
var banner=document.createElement('div');
|
|
8507
9002
|
banner.id='updateBanner';
|
|
8508
|
-
banner.style.cssText='display:flex;align-items:center;gap:12px;padding:10px 32px;max-width:1400px;margin:0 auto;
|
|
9003
|
+
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)';
|
|
8509
9004
|
var textNode=document.createElement('div');
|
|
8510
9005
|
textNode.style.cssText='display:flex;align-items:center;gap:8px;flex-shrink:0;font-size:13px';
|
|
8511
9006
|
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>';
|
|
@@ -8525,20 +9020,32 @@ async function checkForUpdate(){
|
|
|
8525
9020
|
btnClose.innerHTML='×';
|
|
8526
9021
|
btnClose.onmouseenter=function(){this.style.opacity='1'};
|
|
8527
9022
|
btnClose.onmouseleave=function(){this.style.opacity='.5'};
|
|
8528
|
-
btnClose.onclick=function(){
|
|
9023
|
+
btnClose.onclick=function(){bannerWrap.remove()};
|
|
9024
|
+
var spacerL=document.createElement('div');
|
|
9025
|
+
spacerL.style.cssText='flex:1';
|
|
9026
|
+
banner.appendChild(spacerL);
|
|
8529
9027
|
banner.appendChild(textNode);
|
|
8530
9028
|
banner.appendChild(statusDiv);
|
|
8531
9029
|
banner.appendChild(spacer);
|
|
8532
9030
|
banner.appendChild(btnClose);
|
|
9031
|
+
bannerWrap.appendChild(banner);
|
|
8533
9032
|
var tb=document.querySelector('.topbar');
|
|
8534
|
-
if(tb&&tb.parentNode){tb.parentNode.insertBefore(
|
|
8535
|
-
else{document.body.insertBefore(
|
|
9033
|
+
if(tb&&tb.parentNode){tb.parentNode.insertBefore(bannerWrap,tb);}
|
|
9034
|
+
else{document.body.insertBefore(bannerWrap,document.body.firstChild);}
|
|
8536
9035
|
}catch(e){}
|
|
8537
9036
|
}
|
|
8538
9037
|
|
|
8539
9038
|
/* ─── Init ─── */
|
|
9039
|
+
try{
|
|
9040
|
+
var savedScope=localStorage.getItem('memos_memorySearchScope');
|
|
9041
|
+
if(savedScope&&(savedScope==='local'||savedScope==='allLocal'||savedScope==='hub')){
|
|
9042
|
+
memorySearchScope=savedScope;
|
|
9043
|
+
var scopeEl=document.getElementById('memorySearchScope');
|
|
9044
|
+
if(scopeEl) scopeEl.value=savedScope;
|
|
9045
|
+
}
|
|
9046
|
+
}catch(e){}
|
|
8540
9047
|
document.getElementById('modalOverlay').addEventListener('click',e=>{if(e.target.id==='modalOverlay')closeModal()});
|
|
8541
|
-
document.getElementById('searchInput').addEventListener('keydown',e=>{if(e.key==='Escape'){e.target.value='';loadMemories()}});
|
|
9048
|
+
document.getElementById('searchInput').addEventListener('keydown',e=>{if(e.key==='Escape'){e.target.value='';currentPage=1;if(memorySearchScope==='hub')loadHubMemories();else loadMemories();}});
|
|
8542
9049
|
applyI18n();
|
|
8543
9050
|
checkAuth();
|
|
8544
9051
|
</script>
|