@memtensor/memos-local-openclaw-plugin 1.0.4-beta.9 → 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 +89 -8
- 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 +240 -35
- 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 +22 -4
- 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 +57 -0
- package/dist/storage/sqlite.d.ts.map +1 -1
- package/dist/storage/sqlite.js +290 -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 +564 -225
- package/dist/viewer/html.js.map +1 -1
- package/dist/viewer/server.d.ts +9 -0
- package/dist/viewer/server.d.ts.map +1 -1
- package/dist/viewer/server.js +357 -108
- 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 +92 -8
- package/src/config.ts +2 -1
- package/src/hub/server.ts +235 -35
- 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 +20 -4
- 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 +318 -40
- package/src/telemetry.ts +27 -9
- package/src/types.ts +11 -0
- package/src/viewer/html.ts +564 -225
- package/src/viewer/server.ts +333 -105
- 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)}
|
|
@@ -248,9 +248,11 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
248
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
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
250
|
.au-status-dot.offline{background:#6b7280;box-shadow:none}
|
|
251
|
-
.au-status-text{font-size:
|
|
252
|
-
.au-status-text.online{color:#22c55e;text-shadow:0 0 8px rgba(34,197,94,.
|
|
253
|
-
.au-status-text.offline{color:#6b7280}
|
|
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)}
|
|
254
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}
|
|
255
257
|
.au-group-header:first-child{margin-top:0}
|
|
256
258
|
.au-group-header .au-group-dot{display:inline-block;width:8px;height:8px;border-radius:50%}
|
|
@@ -285,7 +287,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
285
287
|
.admin-card-tag.tag-version{background:rgba(139,92,246,.1);color:#8b5cf6}
|
|
286
288
|
.admin-card-tag.tag-visibility{background:rgba(99,102,241,.08);color:var(--pri)}
|
|
287
289
|
.admin-card-tag.tag-group{background:rgba(139,92,246,.08);color:#8b5cf6}
|
|
288
|
-
.admin-card-preview{font-size:12px;color:var(--text-sec);line-height:1.5;margin:8px 0;padding:10px 12px;background:rgba(99,102,241,.02);border-radius:10px;border:1px solid rgba(99,102,241,.08);max-height:
|
|
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%)}
|
|
289
291
|
.admin-card-actions{display:inline-flex;gap:6px;margin-left:auto;align-items:center;flex-shrink:0}
|
|
290
292
|
.admin-card-time{font-size:11px;color:var(--text-muted)}
|
|
291
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}
|
|
@@ -320,7 +322,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
320
322
|
.adm-msg-side.assistant .adm-msg-role{color:var(--green)}
|
|
321
323
|
.adm-msg-time{font-size:9px;color:var(--text-muted)}
|
|
322
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}
|
|
323
|
-
.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)}
|
|
324
326
|
.adm-msg-toggle{display:none;padding:0 16px 8px;font-size:11px;color:var(--pri);cursor:pointer;transition:color .15s}
|
|
325
327
|
.adm-msg-toggle:hover{color:var(--pri-dark)}
|
|
326
328
|
.admin-card-expand-btn{font-size:12px;color:var(--pri);cursor:pointer;background:none;border:none;padding:2px 6px;font-family:inherit}
|
|
@@ -328,17 +330,21 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
328
330
|
.admin-toolbar{display:flex;align-items:center;gap:10px;margin-bottom:14px;flex-wrap:wrap}
|
|
329
331
|
.admin-toolbar h3{font-size:14px;font-weight:600;color:var(--text);white-space:nowrap;margin:0;margin-right:auto;line-height:32px}
|
|
330
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}
|
|
331
|
-
.admin-badge{display:inline-flex;align-items:center;gap:4px;font-size:
|
|
332
|
-
.admin-badge.admin{background:linear-gradient(135deg,rgba(34,197,94,.
|
|
333
|
-
.admin-badge.
|
|
334
|
-
.admin-badge.
|
|
335
|
-
.admin-badge.
|
|
336
|
-
.admin-badge.
|
|
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}
|
|
337
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)}
|
|
338
343
|
.admin-empty .ae-icon{font-size:32px;display:block;margin-bottom:10px;opacity:.4}
|
|
339
|
-
[data-theme="light"] .admin-badge.admin{background:rgba(5,150,105,.
|
|
340
|
-
[data-theme="light"] .admin-badge.member{background:rgba(0,0,0,.
|
|
341
|
-
[data-theme="light"] .admin-badge.pending{background:rgba(245,158,11,.
|
|
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)}
|
|
342
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%)}
|
|
343
349
|
[data-theme="light"] .admin-stat-box{background:rgba(255,255,255,.8)}
|
|
344
350
|
[data-theme="light"] .admin-pending-section{background:linear-gradient(135deg,rgba(251,191,36,.03),rgba(245,158,11,.015))}
|
|
@@ -739,7 +745,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
739
745
|
[data-theme="light"] .nav-tabs{background:rgba(0,0,0,.05)}
|
|
740
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)}
|
|
741
747
|
.analytics-view,.settings-view,.logs-view,.migrate-view,.admin-view{flex:1;min-width:0;flex-direction:column;gap:20px}
|
|
742
|
-
.feed-wrap,.tasks-view,.skills-view,.analytics-view,.
|
|
748
|
+
.feed-wrap,.tasks-view,.skills-view,.analytics-view,.logs-view,.migrate-view,.admin-view,.settings-view{max-width:960px}
|
|
743
749
|
|
|
744
750
|
/* ─── Logs ─── */
|
|
745
751
|
.logs-toolbar{display:flex;align-items:center;justify-content:space-between;padding:8px 0}
|
|
@@ -798,6 +804,10 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
798
804
|
.recall-score.high{background:rgba(34,197,94,.12);color:#22c55e}
|
|
799
805
|
.recall-score.mid{background:rgba(251,191,36,.12);color:#f59e0b}
|
|
800
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}
|
|
801
811
|
.recall-summary-short{flex:1;color:var(--text-sec);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
|
|
802
812
|
.recall-expand-icon{flex-shrink:0;font-size:10px;color:var(--text-muted);transition:transform .15s}
|
|
803
813
|
.recall-item.expanded .recall-expand-icon{transform:rotate(90deg)}
|
|
@@ -966,8 +976,6 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
966
976
|
.team-guide-steps li::marker{color:var(--pri);font-weight:700;font-size:11px}
|
|
967
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}
|
|
968
978
|
.team-guide-opt .btn-guide:hover{background:rgba(99,102,241,.14);border-color:var(--pri)}
|
|
969
|
-
.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}
|
|
970
|
-
.team-guide-dismiss:hover{opacity:1}
|
|
971
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)}
|
|
972
980
|
[data-theme="light"] .team-guide-opt{box-shadow:0 1px 3px rgba(0,0,0,.03)}
|
|
973
981
|
[data-theme="light"] .team-guide-opt:hover{box-shadow:0 4px 16px rgba(0,0,0,.04)}
|
|
@@ -1210,7 +1218,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1210
1218
|
</div>
|
|
1211
1219
|
<button class="btn btn-ghost btn-sm" onclick="doLogout()" data-i18n="logout">Logout</button>
|
|
1212
1220
|
</div>
|
|
1213
|
-
|
|
1221
|
+
</div>
|
|
1214
1222
|
</div>
|
|
1215
1223
|
|
|
1216
1224
|
<div class="main-content">
|
|
@@ -1219,7 +1227,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1219
1227
|
<div class="stat-card pri"><div class="stat-value" id="statTotal">-</div><div class="stat-label" data-i18n="stat.memories">Memories</div></div>
|
|
1220
1228
|
<div class="stat-card green"><div class="stat-value" id="statSessions">-</div><div class="stat-label" data-i18n="stat.sessions">Sessions</div></div>
|
|
1221
1229
|
<div class="stat-card amber"><div class="stat-value" id="statEmbeddings">-</div><div class="stat-label" data-i18n="stat.embeddings">Embeddings</div></div>
|
|
1222
|
-
<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>
|
|
1223
1231
|
</div>
|
|
1224
1232
|
<div id="sidebarSharingSection" style="display:none">
|
|
1225
1233
|
<div class="sharing-sidebar-card">
|
|
@@ -1242,7 +1250,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1242
1250
|
<select id="filterOwner" class="filter-select" onchange="onOwnerFilterChange()">
|
|
1243
1251
|
<option value="" data-i18n="filter.allagents">All agents</option>
|
|
1244
1252
|
</select>
|
|
1245
|
-
<select id="memorySearchScope" class="filter-select" onchange="onMemoryScopeChange()">
|
|
1253
|
+
<select id="memorySearchScope" class="filter-select" onchange="onMemoryScopeChange()" style="display:none">
|
|
1246
1254
|
<option value="local" data-i18n="scope.thisAgent">This Agent</option>
|
|
1247
1255
|
<option value="allLocal" data-i18n="scope.thisDevice">This Device</option>
|
|
1248
1256
|
<option value="hub" data-i18n="scope.hub">Team</option>
|
|
@@ -1254,7 +1262,6 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1254
1262
|
<button class="filter-chip active" data-role="" onclick="setRoleFilter(this,'')" data-i18n="filter.all">All</button>
|
|
1255
1263
|
<button class="filter-chip" data-role="user" onclick="setRoleFilter(this,'user')">User</button>
|
|
1256
1264
|
<button class="filter-chip" data-role="assistant" onclick="setRoleFilter(this,'assistant')">Assistant</button>
|
|
1257
|
-
<button class="filter-chip" data-role="system" onclick="setRoleFilter(this,'system')">System</button>
|
|
1258
1265
|
<span class="filter-sep"></span>
|
|
1259
1266
|
<select id="filterSort" class="filter-select" onchange="applyFilters()">
|
|
1260
1267
|
<option value="newest" data-i18n="filter.newest">Newest first</option>
|
|
@@ -1287,7 +1294,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1287
1294
|
<button class="filter-chip" data-task-status="active" onclick="setTaskStatusFilter(this,'active')" data-i18n="tasks.status.active">Active</button>
|
|
1288
1295
|
<button class="filter-chip" data-task-status="completed" onclick="setTaskStatusFilter(this,'completed')" data-i18n="tasks.status.completed">Completed</button>
|
|
1289
1296
|
<button class="filter-chip" data-task-status="skipped" onclick="setTaskStatusFilter(this,'skipped')" data-i18n="tasks.status.skipped">Skipped</button>
|
|
1290
|
-
<select id="taskSearchScope" class="scope-select" onchange="onTaskScopeChange()">
|
|
1297
|
+
<select id="taskSearchScope" class="scope-select" onchange="onTaskScopeChange()" style="display:none">
|
|
1291
1298
|
<option value="local" data-i18n="scope.thisAgent">This Agent</option>
|
|
1292
1299
|
<option value="allLocal" data-i18n="scope.thisDevice">This Device</option>
|
|
1293
1300
|
<option value="hub" data-i18n="scope.hub">Team</option>
|
|
@@ -1329,13 +1336,13 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1329
1336
|
<div class="search-bar">
|
|
1330
1337
|
<span class="search-icon">🔍</span>
|
|
1331
1338
|
<input type="text" id="skillSearchInput" placeholder="Search skills..." data-i18n-ph="skills.search.placeholder" oninput="debounceSkillSearch()">
|
|
1332
|
-
<select id="skillSearchScope" class="scope-select" onchange="onSkillScopeChange()">
|
|
1339
|
+
<select id="skillSearchScope" class="scope-select" onchange="onSkillScopeChange()" style="display:none">
|
|
1333
1340
|
<option value="local" data-i18n="scope.thisAgent">This Agent</option>
|
|
1334
1341
|
<option value="allLocal" data-i18n="scope.thisDevice">This Device</option>
|
|
1335
1342
|
<option value="hub" data-i18n="scope.hub">Team</option>
|
|
1336
1343
|
</select>
|
|
1337
1344
|
</div>
|
|
1338
|
-
<div class="search-meta" id="skillSearchMeta"></div>
|
|
1345
|
+
<div class="search-meta" id="skillSearchMeta" style="display:none"></div>
|
|
1339
1346
|
<div class="tasks-header">
|
|
1340
1347
|
<div class="tasks-stats">
|
|
1341
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>
|
|
@@ -1349,8 +1356,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1349
1356
|
<button class="filter-chip" data-skill-status="active" onclick="setSkillStatusFilter(this,'active')" data-i18n="skills.filter.active">Active</button>
|
|
1350
1357
|
<button class="filter-chip" data-skill-status="draft" onclick="setSkillStatusFilter(this,'draft')" data-i18n="skills.filter.draft">Draft</button>
|
|
1351
1358
|
<button class="filter-chip" data-skill-status="archived" onclick="setSkillStatusFilter(this,'archived')" data-i18n="skills.filter.archived">Archived</button>
|
|
1352
|
-
<
|
|
1353
|
-
<select id="skillVisibilityFilter" class="filter-select" onchange="loadSkills()">
|
|
1359
|
+
<select id="skillVisibilityFilter" class="filter-select" onchange="loadSkills()" style="display:none">
|
|
1354
1360
|
<option value="" data-i18n="filter.allvisibility">All visibility</option>
|
|
1355
1361
|
<option value="public" data-i18n="filter.public">Public</option>
|
|
1356
1362
|
<option value="private" data-i18n="filter.private">Private</option>
|
|
@@ -1437,7 +1443,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1437
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">
|
|
1438
1444
|
<option value="" data-i18n="logs.allTools">All Tools</option>
|
|
1439
1445
|
</select>
|
|
1440
|
-
|
|
1446
|
+
|
|
1441
1447
|
</div>
|
|
1442
1448
|
<div class="logs-toolbar-right">
|
|
1443
1449
|
<input type="checkbox" id="logAutoRefresh" style="display:none">
|
|
@@ -1633,9 +1639,8 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1633
1639
|
</div>
|
|
1634
1640
|
</div>
|
|
1635
1641
|
<div class="settings-card-body">
|
|
1636
|
-
<!-- team setup guide (inside Hub card) -->
|
|
1642
|
+
<!-- team setup guide (inside Hub card) — always visible when sharing is not configured -->
|
|
1637
1643
|
<div class="team-guide" id="teamSetupGuide">
|
|
1638
|
-
<button class="team-guide-dismiss" onclick="dismissTeamGuide()" title="Dismiss">×</button>
|
|
1639
1644
|
<div class="team-guide-title">\u{1F680} <span data-i18n="guide.title">Get Started with Team Collaboration</span></div>
|
|
1640
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>
|
|
1641
1646
|
<div class="team-guide-options">
|
|
@@ -1649,7 +1654,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1649
1654
|
<li><span data-i18n="guide.join.s1">Ask your team admin for the Server Address and Team Token</span></li>
|
|
1650
1655
|
<li><span data-i18n="guide.join.s2">Enable sharing above, select "Client" mode</span></li>
|
|
1651
1656
|
<li><span data-i18n="guide.join.s3">Fill in Server Address and Team Token, click "Test Connection"</span></li>
|
|
1652
|
-
<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>
|
|
1653
1658
|
</ol>
|
|
1654
1659
|
<button class="btn-guide" onclick="guideGoToHub('client')" data-i18n="guide.join.btn">\u2192 Configure Client Mode</button>
|
|
1655
1660
|
</div>
|
|
@@ -1661,7 +1666,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1661
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>
|
|
1662
1667
|
<ol class="team-guide-steps">
|
|
1663
1668
|
<li><span data-i18n="guide.hub.s1">Enable sharing above, select "Server" mode</span></li>
|
|
1664
|
-
<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>
|
|
1665
1670
|
<li><span data-i18n="guide.hub.s3">Share the Server Address and Team Token with your team members</span></li>
|
|
1666
1671
|
<li><span data-i18n="guide.hub.s4">Approve join requests in the Admin Panel</span></li>
|
|
1667
1672
|
</ol>
|
|
@@ -1722,7 +1727,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1722
1727
|
<div style="font-weight:700;color:var(--text);margin-bottom:4px" data-i18n="settings.hub.clientSteps.title">Quick Setup (3 steps)</div>
|
|
1723
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>
|
|
1724
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>
|
|
1725
|
-
<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>
|
|
1726
1731
|
</div>
|
|
1727
1732
|
<div class="settings-grid">
|
|
1728
1733
|
<div class="settings-field full-width">
|
|
@@ -2079,8 +2084,8 @@ const I18N={
|
|
|
2079
2084
|
'skills.load.error':'Failed to load skills',
|
|
2080
2085
|
'skills.hub.title':'\u{1F310} Team Skills',
|
|
2081
2086
|
'scope.local':'Local',
|
|
2082
|
-
'scope.thisAgent':'This Agent',
|
|
2083
|
-
'scope.thisDevice':'
|
|
2087
|
+
'scope.thisAgent':'This Agent Only',
|
|
2088
|
+
'scope.thisDevice':'All Local Agents',
|
|
2084
2089
|
'scope.group':'Group',
|
|
2085
2090
|
'scope.all':'All',
|
|
2086
2091
|
'skills.visibility.public':'Shared Locally',
|
|
@@ -2118,6 +2123,13 @@ const I18N={
|
|
|
2118
2123
|
'notif.userJoin':'New user requests to join the team',
|
|
2119
2124
|
'notif.userOnline':'User came online',
|
|
2120
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',
|
|
2121
2133
|
'notif.clearAll':'Clear all',
|
|
2122
2134
|
'notif.timeAgo.just':'just now',
|
|
2123
2135
|
'notif.timeAgo.min':'{n}m ago',
|
|
@@ -2126,7 +2138,7 @@ const I18N={
|
|
|
2126
2138
|
'stat.memories':'Memories',
|
|
2127
2139
|
'stat.sessions':'Sessions',
|
|
2128
2140
|
'stat.embeddings':'Embeddings',
|
|
2129
|
-
'stat.
|
|
2141
|
+
'stat.agents':'Agents',
|
|
2130
2142
|
'stat.active':'active',
|
|
2131
2143
|
'stat.deduped':'deduped',
|
|
2132
2144
|
'sidebar.sessions':'Sessions',
|
|
@@ -2225,6 +2237,9 @@ const I18N={
|
|
|
2225
2237
|
'logs.recall.noHits':'No matching memories',
|
|
2226
2238
|
'logs.recall.noneRelevant':'LLM filter: none relevant',
|
|
2227
2239
|
'logs.recall.more':'{n} more...',
|
|
2240
|
+
'recall.origin.localShared':'Local Shared',
|
|
2241
|
+
'recall.origin.hubMemory':'Team Cache',
|
|
2242
|
+
'recall.origin.hubRemote':'Team',
|
|
2228
2243
|
'tab.import':'\u{1F4E5} Import',
|
|
2229
2244
|
'tab.settings':'\u2699 Settings',
|
|
2230
2245
|
'settings.modelconfig':'Model Configuration',
|
|
@@ -2265,12 +2280,12 @@ const I18N={
|
|
|
2265
2280
|
'settings.test.ok':'Connected',
|
|
2266
2281
|
'settings.test.fail':'Failed',
|
|
2267
2282
|
'settings.session.expired':'Session expired, please refresh the page to log in again',
|
|
2268
|
-
'settings.save':'Save
|
|
2283
|
+
'settings.save':'Save & Apply',
|
|
2269
2284
|
'settings.reset':'Reset',
|
|
2270
2285
|
'settings.saved':'Saved',
|
|
2271
|
-
'settings.restart.hint':'
|
|
2272
|
-
'settings.restart.autoRefresh':'
|
|
2273
|
-
'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...',
|
|
2274
2289
|
'settings.save.fail':'Failed to save settings',
|
|
2275
2290
|
'settings.save.emb.required':'Embedding model is required. Please configure an embedding model before saving.',
|
|
2276
2291
|
'settings.save.emb.fail':'Embedding model test failed, cannot save',
|
|
@@ -2397,16 +2412,16 @@ const I18N={
|
|
|
2397
2412
|
'settings.hub.tokenCopied':'Team Token copied!',
|
|
2398
2413
|
'settings.hub.hubSteps.title':'Quick Setup (3 steps)',
|
|
2399
2414
|
'settings.hub.hubSteps.s1':'Fill in Team Name below (or keep default)',
|
|
2400
|
-
'settings.hub.hubSteps.s2':'Click "Save
|
|
2415
|
+
'settings.hub.hubSteps.s2':'Click "Save & Apply" — the service will restart automatically',
|
|
2401
2416
|
'settings.hub.hubSteps.s3':'Share the Server Address and Team Token below with your team members',
|
|
2402
2417
|
'settings.hub.clientSteps.title':'Quick Setup (3 steps)',
|
|
2403
2418
|
'settings.hub.clientSteps.s1':'Ask your team admin for the Server Address and Team Token',
|
|
2404
2419
|
'settings.hub.clientSteps.s2':'Fill them in below, click "Test Connection" to verify',
|
|
2405
|
-
'settings.hub.clientSteps.s3':'Click "Save
|
|
2420
|
+
'settings.hub.clientSteps.s3':'Click "Save & Apply" — the service will restart and page refreshes automatically',
|
|
2406
2421
|
'settings.hub.shareInfo.title':'Share this info with your team members:',
|
|
2407
2422
|
'settings.hub.shareInfo.yourIP':'your-IP',
|
|
2408
2423
|
'settings.hub.shareInfo.clickCopy':'Click to copy',
|
|
2409
|
-
'settings.hub.restartAlert':'Team sharing config saved!
|
|
2424
|
+
'settings.hub.restartAlert':'Team sharing config saved! The service will restart automatically to apply changes.',
|
|
2410
2425
|
'settings.hub.hubAddress':'Server Address',
|
|
2411
2426
|
'settings.hub.hubAddress.hint':'Team server address, e.g. 192.168.1.100:18800',
|
|
2412
2427
|
'settings.hub.teamTokenClient':'Team Token',
|
|
@@ -2427,6 +2442,10 @@ const I18N={
|
|
|
2427
2442
|
'sidebar.hub':'\u{1F310} Team Sharing',
|
|
2428
2443
|
'sharing.sidebar.connected':'Connected',
|
|
2429
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',
|
|
2430
2449
|
'sharing.sidebar.pending':'Pending Approval',
|
|
2431
2450
|
'sharing.sidebar.rejected':'Rejected',
|
|
2432
2451
|
'sharing.sidebar.starting':'Starting...',
|
|
@@ -2436,11 +2455,21 @@ const I18N={
|
|
|
2436
2455
|
'sharing.sidebar.targetHub':'Team Server:',
|
|
2437
2456
|
'sharing.pendingApproval.hint':'Your join request has been submitted. Please wait for the team admin to approve.',
|
|
2438
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!',
|
|
2439
2462
|
'sharing.retryJoin':'Retry Join',
|
|
2440
2463
|
'sharing.retryJoin.hint':'Clears local data and re-submits the join request',
|
|
2441
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',
|
|
2442
2470
|
'sharing.retryJoin.success':'Join request re-submitted. Waiting for admin approval.',
|
|
2443
2471
|
'sharing.retryJoin.fail':'Failed to retry join',
|
|
2472
|
+
'sharing.ownerRemoved':'(removed)',
|
|
2444
2473
|
'sharing.cannotJoinSelf':'Cannot join your own server. Please enter a remote server address.',
|
|
2445
2474
|
'scope.hub':'Team',
|
|
2446
2475
|
'memory.detail.title':'Memory Detail',
|
|
@@ -2491,6 +2520,7 @@ const I18N={
|
|
|
2491
2520
|
'admin.editName':'Edit Name',
|
|
2492
2521
|
'admin.lastAdminHint':'Last admin — cannot remove or demote',
|
|
2493
2522
|
'admin.ownerHint':'Hub owner — cannot be demoted or removed',
|
|
2523
|
+
'admin.selfHint':'This is you',
|
|
2494
2524
|
'admin.editNamePrompt':'Enter new username:',
|
|
2495
2525
|
'confirm.promoteAdmin':'Promote this user to admin? They will be able to manage all team members and resources.',
|
|
2496
2526
|
'confirm.demoteMember':'Demote this admin to member?',
|
|
@@ -2552,6 +2582,8 @@ const I18N={
|
|
|
2552
2582
|
'toast.userApproved':'User approved',
|
|
2553
2583
|
'sharing.approved.toast':'Your join request has been approved!',
|
|
2554
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.',
|
|
2555
2587
|
'toast.userRejected':'User rejected',
|
|
2556
2588
|
'toast.approveFail':'Approve failed',
|
|
2557
2589
|
'toast.rejectFail':'Reject failed',
|
|
@@ -2644,9 +2676,9 @@ const I18N={
|
|
|
2644
2676
|
'share.status.agents':'Local',
|
|
2645
2677
|
'share.status.hub':'Team',
|
|
2646
2678
|
'share.scope.title':'Sharing Scope',
|
|
2647
|
-
'share.scope.private':'
|
|
2648
|
-
'share.scope.local':'
|
|
2649
|
-
'share.scope.team':'Team',
|
|
2679
|
+
'share.scope.private':'Private',
|
|
2680
|
+
'share.scope.local':'Local Shared',
|
|
2681
|
+
'share.scope.team':'Team Shared',
|
|
2650
2682
|
'share.scope.current':'Current',
|
|
2651
2683
|
'share.scope.teamDisabled':'Not connected to team server',
|
|
2652
2684
|
'share.scope.teamIncludes':'Includes visibility to all local agents',
|
|
@@ -2711,9 +2743,10 @@ const I18N={
|
|
|
2711
2743
|
'update.dismiss':'Dismiss',
|
|
2712
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?',
|
|
2713
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?',
|
|
2714
|
-
'sharing.disable.restartAlert':'Sharing has been disabled.
|
|
2715
|
-
'sharing.switch.hubToClient':'You are about to switch from Server to Client mode.\\n\\nWhat will happen:\\n\\u2022 The Hub server will shut down after
|
|
2716
|
-
'sharing.switch.clientToHub':'You are about to switch from Client to Server mode.\\n\\nWhat will happen:\\n\\u2022 You will disconnect from the current team\\n\\u2022 A new Hub server will start after
|
|
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?',
|
|
2717
2750
|
'admin.notEnabled.title':'Team sharing is not enabled',
|
|
2718
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.',
|
|
2719
2752
|
'admin.notEnabled.setupHub':'Set Up as Team Server',
|
|
@@ -2731,12 +2764,12 @@ const I18N={
|
|
|
2731
2764
|
'guide.join.s1':'Ask your team admin for the Server Address and Team Token',
|
|
2732
2765
|
'guide.join.s2':'Go to Settings \u2192 Team Sharing, enable sharing, select "Client" mode',
|
|
2733
2766
|
'guide.join.s3':'Fill in Server Address and Team Token, click "Test Connection"',
|
|
2734
|
-
'guide.join.s4':'Save
|
|
2767
|
+
'guide.join.s4':'Click "Save & Apply" — the service restarts automatically (page refreshes)',
|
|
2735
2768
|
'guide.join.btn':'\u2192 Configure Client Mode',
|
|
2736
2769
|
'guide.hub.title':'Start Your Own Team Server',
|
|
2737
2770
|
'guide.hub.desc':'Be the team server. Run it on this device so others can connect and share memories with you.',
|
|
2738
2771
|
'guide.hub.s1':'Go to Settings \u2192 Team Sharing, enable sharing, select "Server" mode',
|
|
2739
|
-
'guide.hub.s2':'Set a team name,
|
|
2772
|
+
'guide.hub.s2':'Set a team name, click "Save & Apply" — the service restarts automatically',
|
|
2740
2773
|
'guide.hub.s3':'Share the Server Address and Team Token with your team members',
|
|
2741
2774
|
'guide.hub.s4':'Approve join requests in the Admin Panel',
|
|
2742
2775
|
'guide.hub.btn':'\u2192 Configure Server Mode'
|
|
@@ -2788,8 +2821,8 @@ const I18N={
|
|
|
2788
2821
|
'skills.load.error':'加载技能失败',
|
|
2789
2822
|
'skills.hub.title':'\u{1F310} 团队共享技能',
|
|
2790
2823
|
'scope.local':'本地',
|
|
2791
|
-
'scope.thisAgent':'
|
|
2792
|
-
'scope.thisDevice':'
|
|
2824
|
+
'scope.thisAgent':'仅本智能体',
|
|
2825
|
+
'scope.thisDevice':'本机所有智能体',
|
|
2793
2826
|
'scope.group':'团队',
|
|
2794
2827
|
'scope.all':'全部',
|
|
2795
2828
|
'skills.visibility.public':'本机共享',
|
|
@@ -2827,6 +2860,13 @@ const I18N={
|
|
|
2827
2860
|
'notif.userJoin':'有新用户申请加入团队',
|
|
2828
2861
|
'notif.userOnline':'用户上线了',
|
|
2829
2862
|
'notif.userOffline':'用户下线了',
|
|
2863
|
+
'notif.userLeft':'用户已退出团队',
|
|
2864
|
+
'notif.membershipApproved':'你的团队加入申请已通过',
|
|
2865
|
+
'notif.membershipRejected':'你的团队加入申请已被拒绝',
|
|
2866
|
+
'notif.membershipRemoved':'你已被管理员移出团队',
|
|
2867
|
+
'notif.hubShutdown':'团队服务已关闭',
|
|
2868
|
+
'notif.rolePromoted':'你已被提升为管理员',
|
|
2869
|
+
'notif.roleDemoted':'你已被设为普通成员',
|
|
2830
2870
|
'notif.clearAll':'清除全部',
|
|
2831
2871
|
'notif.timeAgo.just':'刚刚',
|
|
2832
2872
|
'notif.timeAgo.min':'{n}分钟前',
|
|
@@ -2835,7 +2875,7 @@ const I18N={
|
|
|
2835
2875
|
'stat.memories':'记忆',
|
|
2836
2876
|
'stat.sessions':'会话',
|
|
2837
2877
|
'stat.embeddings':'嵌入',
|
|
2838
|
-
'stat.
|
|
2878
|
+
'stat.agents':'智能体',
|
|
2839
2879
|
'stat.active':'活跃',
|
|
2840
2880
|
'stat.deduped':'已去重',
|
|
2841
2881
|
'sidebar.sessions':'会话列表',
|
|
@@ -2934,6 +2974,9 @@ const I18N={
|
|
|
2934
2974
|
'logs.recall.noHits':'未匹配到记忆',
|
|
2935
2975
|
'logs.recall.noneRelevant':'LLM 过滤:无相关记忆',
|
|
2936
2976
|
'logs.recall.more':'还有 {n} 条...',
|
|
2977
|
+
'recall.origin.localShared':'本机共享',
|
|
2978
|
+
'recall.origin.hubMemory':'团队缓存',
|
|
2979
|
+
'recall.origin.hubRemote':'团队',
|
|
2937
2980
|
'tab.import':'\u{1F4E5} 导入',
|
|
2938
2981
|
'tab.settings':'\u2699 设置',
|
|
2939
2982
|
'settings.modelconfig':'模型配置',
|
|
@@ -2974,12 +3017,12 @@ const I18N={
|
|
|
2974
3017
|
'settings.test.ok':'连接成功',
|
|
2975
3018
|
'settings.test.fail':'连接失败',
|
|
2976
3019
|
'settings.session.expired':'登录已过期,请刷新页面重新登录',
|
|
2977
|
-
'settings.save':'
|
|
3020
|
+
'settings.save':'保存并应用',
|
|
2978
3021
|
'settings.reset':'重置',
|
|
2979
3022
|
'settings.saved':'已保存',
|
|
2980
|
-
'settings.restart.hint':'
|
|
2981
|
-
'settings.restart.autoRefresh':'
|
|
2982
|
-
'settings.restart.waiting':'
|
|
3023
|
+
'settings.restart.hint':'修改将在服务自动重启后生效。',
|
|
3024
|
+
'settings.restart.autoRefresh':'服务重启中,页面将自动刷新...',
|
|
3025
|
+
'settings.restart.waiting':'配置已保存,服务正在重启...',
|
|
2983
3026
|
'settings.save.fail':'保存设置失败',
|
|
2984
3027
|
'settings.save.emb.required':'嵌入模型为必填项,请先配置嵌入模型再保存。',
|
|
2985
3028
|
'settings.save.emb.fail':'嵌入模型测试失败,无法保存',
|
|
@@ -3106,16 +3149,16 @@ const I18N={
|
|
|
3106
3149
|
'settings.hub.tokenCopied':'团队令牌已复制!',
|
|
3107
3150
|
'settings.hub.hubSteps.title':'快速配置(3 步)',
|
|
3108
3151
|
'settings.hub.hubSteps.s1':'填写下方团队名称(或保持默认)',
|
|
3109
|
-
'settings.hub.hubSteps.s2':'
|
|
3152
|
+
'settings.hub.hubSteps.s2':'点击「保存并应用」,服务将自动重启',
|
|
3110
3153
|
'settings.hub.hubSteps.s3':'将下方的服务器地址和团队令牌分享给团队成员',
|
|
3111
3154
|
'settings.hub.clientSteps.title':'快速配置(3 步)',
|
|
3112
3155
|
'settings.hub.clientSteps.s1':'向团队管理员获取服务器地址和团队令牌',
|
|
3113
3156
|
'settings.hub.clientSteps.s2':'填入下方,点击"测试连接"验证连通性',
|
|
3114
|
-
'settings.hub.clientSteps.s3':'
|
|
3157
|
+
'settings.hub.clientSteps.s3':'点击「保存并应用」,服务将自动重启(页面会自动刷新)',
|
|
3115
3158
|
'settings.hub.shareInfo.title':'请将以下信息分享给团队成员:',
|
|
3116
3159
|
'settings.hub.shareInfo.yourIP':'你的IP',
|
|
3117
3160
|
'settings.hub.shareInfo.clickCopy':'点击复制',
|
|
3118
|
-
'settings.hub.restartAlert':'
|
|
3161
|
+
'settings.hub.restartAlert':'团队共享配置已保存!服务将自动重启以应用更改。',
|
|
3119
3162
|
'settings.hub.hubAddress':'服务器地址',
|
|
3120
3163
|
'settings.hub.hubAddress.hint':'团队服务器地址,如 192.168.1.100:18800',
|
|
3121
3164
|
'settings.hub.teamTokenClient':'团队令牌',
|
|
@@ -3136,6 +3179,10 @@ const I18N={
|
|
|
3136
3179
|
'sidebar.hub':'\u{1F310} 团队共享',
|
|
3137
3180
|
'sharing.sidebar.connected':'已连接',
|
|
3138
3181
|
'sharing.sidebar.disconnected':'已断开',
|
|
3182
|
+
'sharing.sidebar.hubRunning':'服务运行中',
|
|
3183
|
+
'sharing.sidebar.teamName':'团队',
|
|
3184
|
+
'sharing.sidebar.members':'成员',
|
|
3185
|
+
'sharing.sidebar.online':'在线',
|
|
3139
3186
|
'sharing.sidebar.pending':'等待审核',
|
|
3140
3187
|
'sharing.sidebar.rejected':'已拒绝',
|
|
3141
3188
|
'sharing.sidebar.starting':'启动中...',
|
|
@@ -3145,11 +3192,21 @@ const I18N={
|
|
|
3145
3192
|
'sharing.sidebar.targetHub':'团队服务器:',
|
|
3146
3193
|
'sharing.pendingApproval.hint':'加入申请已提交,请等待团队管理员审核通过。',
|
|
3147
3194
|
'sharing.rejected.hint':'您的加入申请已被团队管理员拒绝,请联系管理员或重新申请。',
|
|
3195
|
+
'sharing.removed.hint':'您已被管理员从团队中移除,可以重新申请加入。',
|
|
3196
|
+
'sharing.joinTeam':'加入团队',
|
|
3197
|
+
'sharing.joinSent.pending':'加入申请已发送,等待管理员审批。',
|
|
3198
|
+
'sharing.joinSent.active':'成功加入团队!',
|
|
3148
3199
|
'sharing.retryJoin':'重新申请',
|
|
3149
3200
|
'sharing.retryJoin.hint':'清除本地连接数据并重新提交加入申请',
|
|
3150
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':'该团队',
|
|
3151
3207
|
'sharing.retryJoin.success':'加入申请已重新提交,请等待管理员审核。',
|
|
3152
3208
|
'sharing.retryJoin.fail':'重新申请失败',
|
|
3209
|
+
'sharing.ownerRemoved':'(已移除)',
|
|
3153
3210
|
'sharing.cannotJoinSelf':'不能加入自己的服务端,请输入远程服务器地址。',
|
|
3154
3211
|
'scope.hub':'团队',
|
|
3155
3212
|
'memory.detail.title':'记忆详情',
|
|
@@ -3200,6 +3257,7 @@ const I18N={
|
|
|
3200
3257
|
'admin.editName':'编辑名称',
|
|
3201
3258
|
'admin.lastAdminHint':'唯一管理员 — 无法删除或降级',
|
|
3202
3259
|
'admin.ownerHint':'Hub 创建者 — 不可降级或移除',
|
|
3260
|
+
'admin.selfHint':'这是你自己',
|
|
3203
3261
|
'admin.editNamePrompt':'请输入新用户名:',
|
|
3204
3262
|
'confirm.promoteAdmin':'确定要将此用户提升为管理员吗?管理员可以管理所有团队成员和资源。',
|
|
3205
3263
|
'confirm.demoteMember':'确定要将此管理员降为普通成员吗?',
|
|
@@ -3261,6 +3319,8 @@ const I18N={
|
|
|
3261
3319
|
'toast.userApproved':'用户已批准',
|
|
3262
3320
|
'sharing.approved.toast':'您的加入申请已通过审核!',
|
|
3263
3321
|
'sharing.rejected.toast':'您的加入申请已被管理员拒绝。',
|
|
3322
|
+
'sharing.hubOffline.toast':'团队服务已离线,恢复后将自动重新连接。',
|
|
3323
|
+
'sharing.hubReconnected.toast':'团队服务已恢复上线,连接已自动恢复!',
|
|
3264
3324
|
'toast.userRejected':'用户已拒绝',
|
|
3265
3325
|
'toast.approveFail':'批准失败',
|
|
3266
3326
|
'toast.rejectFail':'拒绝失败',
|
|
@@ -3353,9 +3413,9 @@ const I18N={
|
|
|
3353
3413
|
'share.status.agents':'本机',
|
|
3354
3414
|
'share.status.hub':'团队',
|
|
3355
3415
|
'share.scope.title':'共享范围',
|
|
3356
|
-
'share.scope.private':'
|
|
3357
|
-
'share.scope.local':'
|
|
3358
|
-
'share.scope.team':'
|
|
3416
|
+
'share.scope.private':'私有',
|
|
3417
|
+
'share.scope.local':'本机共享',
|
|
3418
|
+
'share.scope.team':'团队共享',
|
|
3359
3419
|
'share.scope.current':'当前',
|
|
3360
3420
|
'share.scope.teamDisabled':'未连接团队服务器',
|
|
3361
3421
|
'share.scope.teamIncludes':'包含本机所有智能体的可见性',
|
|
@@ -3420,9 +3480,10 @@ const I18N={
|
|
|
3420
3480
|
'update.dismiss':'关闭',
|
|
3421
3481
|
'sharing.disable.confirm.hub':'你即将关闭团队服务。\\n\\n关闭后将会:\\n\\u2022 所有已连接的团队成员将断开连接\\n\\u2022 他们将无法继续同步记忆、任务和技能\\n\\u2022 已共享的数据会保留,重新开启后仍可使用\\n\\n确定要关闭吗?',
|
|
3422
3482
|
'sharing.disable.confirm.client':'你即将断开与团队的连接。\\n\\n断开后将会:\\n\\u2022 你将无法再接收团队共享的记忆、任务和技能\\n\\u2022 你的本地数据不受影响,会完整保留\\n\\u2022 之后可以随时重新开启共享来恢复连接\\n\\n确定要断开吗?',
|
|
3423
|
-
'sharing.disable.restartAlert':'
|
|
3424
|
-
'sharing.switch.hubToClient':'你即将从服务端模式切换为客户端模式。\\n\\n切换后将会:\\n\\u2022 Hub
|
|
3425
|
-
'sharing.switch.clientToHub':'你即将从客户端模式切换为服务端模式。\\n\\n切换后将会:\\n\\u2022 你将断开与当前团队的连接\\n\\u2022
|
|
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确定要切换吗?',
|
|
3426
3487
|
'admin.notEnabled.title':'团队共享尚未开启',
|
|
3427
3488
|
'admin.notEnabled.desc':'管理面板用于管理团队成员、共享的记忆、任务和技能。使用此功能前,需要先开启团队共享。',
|
|
3428
3489
|
'admin.notEnabled.setupHub':'配置为团队服务端',
|
|
@@ -3440,12 +3501,12 @@ const I18N={
|
|
|
3440
3501
|
'guide.join.s1':'向团队管理员索取服务器地址和团队令牌',
|
|
3441
3502
|
'guide.join.s2':'前往「设置 → 团队共享」,开启共享,选择「客户端」模式',
|
|
3442
3503
|
'guide.join.s3':'填写服务器地址和团队令牌,点击「测试连接」',
|
|
3443
|
-
'guide.join.s4':'
|
|
3504
|
+
'guide.join.s4':'点击「保存并应用」,服务将自动重启(页面会自动刷新)',
|
|
3444
3505
|
'guide.join.btn':'\u2192 配置客户端模式',
|
|
3445
3506
|
'guide.hub.title':'自建团队服务',
|
|
3446
3507
|
'guide.hub.desc':'将本机作为团队服务端,让其他成员连接过来共享记忆。',
|
|
3447
3508
|
'guide.hub.s1':'前往「设置 → 团队共享」,开启共享,选择「服务端」模式',
|
|
3448
|
-
'guide.hub.s2':'
|
|
3509
|
+
'guide.hub.s2':'设置团队名称,点击「保存并应用」,服务将自动重启',
|
|
3449
3510
|
'guide.hub.s3':'将服务器地址和团队令牌分享给团队成员',
|
|
3450
3511
|
'guide.hub.s4':'在管理面板中审批加入请求',
|
|
3451
3512
|
'guide.hub.btn':'\u2192 配置服务端模式'
|
|
@@ -3551,12 +3612,28 @@ async function doReset(){
|
|
|
3551
3612
|
}
|
|
3552
3613
|
|
|
3553
3614
|
var _sharingRole='client';
|
|
3615
|
+
var _loadedClientHubAddress='';
|
|
3554
3616
|
function _genToken(len){
|
|
3555
3617
|
var a=new Uint8Array(len||18);crypto.getRandomValues(a);
|
|
3556
3618
|
return btoa(String.fromCharCode.apply(null,a)).replace(/\\+/g,'-').replace(/\\//g,'_').replace(/=+$/,'');
|
|
3557
3619
|
}
|
|
3558
|
-
function onSharingToggle(){
|
|
3559
|
-
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
|
+
}
|
|
3560
3637
|
document.getElementById('sharingConfigPanel').style.display=on?'block':'none';
|
|
3561
3638
|
var pw=document.getElementById('sharingPanelsWrap');
|
|
3562
3639
|
if(pw) pw.style.display=on?'':'none';
|
|
@@ -3574,20 +3651,25 @@ function selectSharingRole(role){
|
|
|
3574
3651
|
var tp=document.getElementById('sharingTeamPanel');
|
|
3575
3652
|
var ap=document.getElementById('sharingAdminPanel');
|
|
3576
3653
|
if(role==='client'){
|
|
3577
|
-
if(sp) sp.style.display='none';
|
|
3654
|
+
if(sp) { sp.style.display='none'; sp.innerHTML=''; }
|
|
3578
3655
|
if(tp) tp.style.display='none';
|
|
3579
3656
|
if(ap) ap.style.display='none';
|
|
3580
3657
|
}else{
|
|
3581
|
-
if(sp) sp.style.display='';
|
|
3658
|
+
if(sp) { sp.style.display='none'; sp.innerHTML=''; }
|
|
3582
3659
|
if(tp) tp.style.display='';
|
|
3583
3660
|
if(ap) ap.style.display='';
|
|
3584
3661
|
}
|
|
3662
|
+
_lastSettingsFingerprint='';
|
|
3663
|
+
setTimeout(function(){ loadSharingStatus(true); },200);
|
|
3585
3664
|
if(role==='hub'){
|
|
3586
3665
|
var tk=document.getElementById('cfgHubTeamToken');
|
|
3587
3666
|
if(!tk.value.trim()) tk.value=_genToken(18);
|
|
3588
3667
|
var tn=document.getElementById('cfgHubTeamName');
|
|
3589
3668
|
if(!tn.value.trim()) tn.value='My Team';
|
|
3590
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();
|
|
3591
3673
|
}
|
|
3592
3674
|
var _cachedLocalIP='';
|
|
3593
3675
|
function updateHubShareInfo(){
|
|
@@ -3622,13 +3704,6 @@ async function testHubConnection(){
|
|
|
3622
3704
|
if(!addr){result.innerHTML='<span style="color:var(--rose)">\u274C '+t('settings.hub.test.noAddr')+'</span>';return;}
|
|
3623
3705
|
btn.disabled=true;result.innerHTML=t('settings.hub.test.testing');
|
|
3624
3706
|
try{
|
|
3625
|
-
var ipsData=await fetch('/api/local-ips').then(function(r){return r.json();});
|
|
3626
|
-
var localAddrs=['127.0.0.1','localhost','0.0.0.0'].concat(ipsData.ips||[]);
|
|
3627
|
-
var parsed=new URL(addr.indexOf('://')>-1?addr:'http://'+addr);
|
|
3628
|
-
if(localAddrs.indexOf(parsed.hostname)>=0){
|
|
3629
|
-
result.innerHTML='<span style="color:var(--rose)">\u274C '+t('sharing.cannotJoinSelf')+'</span>';
|
|
3630
|
-
btn.disabled=false;return;
|
|
3631
|
-
}
|
|
3632
3707
|
}catch(e){}
|
|
3633
3708
|
try{
|
|
3634
3709
|
var url=addr.match(/^https?:\\/\\//)?addr:'http://'+addr;
|
|
@@ -3678,13 +3753,20 @@ function switchView(view){
|
|
|
3678
3753
|
else if(view==='skills') loadSkills();
|
|
3679
3754
|
else if(view==='analytics') loadMetrics();
|
|
3680
3755
|
else if(view==='logs') loadLogs();
|
|
3681
|
-
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();}
|
|
3682
3763
|
else if(view==='import'){if(!window._migrateRunning) migrateScan(false);}
|
|
3683
|
-
else if(view==='admin'){loadAdminData();}
|
|
3764
|
+
else if(view==='admin'){_lastAdminFingerprint='';loadAdminData();}
|
|
3684
3765
|
}
|
|
3685
3766
|
|
|
3686
3767
|
function onMemoryScopeChange(){
|
|
3687
3768
|
memorySearchScope=document.getElementById('memorySearchScope')?.value||'local';
|
|
3769
|
+
try{localStorage.setItem('memos_memorySearchScope',memorySearchScope);}catch(e){}
|
|
3688
3770
|
currentPage=1;
|
|
3689
3771
|
activeSession=null;activeRole='';
|
|
3690
3772
|
_lastMemoriesFingerprint='';
|
|
@@ -3693,7 +3775,7 @@ function onMemoryScopeChange(){
|
|
|
3693
3775
|
var ownerSel=document.getElementById('filterOwner');
|
|
3694
3776
|
var filterBar=document.getElementById('filterBar');
|
|
3695
3777
|
var dateFilter=document.querySelector('.date-filter');
|
|
3696
|
-
if(ownerSel)
|
|
3778
|
+
if(ownerSel){ownerSel.style.display=(isHub||isLocal)?'none':'';if(isHub||isLocal)ownerSel.value='';}
|
|
3697
3779
|
if(filterBar) filterBar.style.display=isHub?'none':'';
|
|
3698
3780
|
if(dateFilter) dateFilter.style.display=isHub?'none':'';
|
|
3699
3781
|
if(document.getElementById('searchInput').value.trim()) doSearch(document.getElementById('searchInput').value);
|
|
@@ -3718,6 +3800,13 @@ function onTaskScopeChange(){
|
|
|
3718
3800
|
|
|
3719
3801
|
var _clientPendingPollTimer=null;
|
|
3720
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
|
+
}
|
|
3721
3810
|
async function loadSharingStatus(forcePending){
|
|
3722
3811
|
try{
|
|
3723
3812
|
const r=await fetch('/api/sharing/status');
|
|
@@ -3730,19 +3819,36 @@ async function loadSharingStatus(forcePending){
|
|
|
3730
3819
|
if(!d||!d.enabled){
|
|
3731
3820
|
if(_clientPendingPollTimer){clearInterval(_clientPendingPollTimer);_clientPendingPollTimer=null;}
|
|
3732
3821
|
_lastSharingConnStatus='';
|
|
3822
|
+
_updateScopeSelectorsVisibility(false);
|
|
3733
3823
|
return;
|
|
3734
3824
|
}
|
|
3735
3825
|
var conn=d.connection||{};
|
|
3736
3826
|
var curStatus=conn.rejected?'rejected':conn.pendingApproval?'pending':conn.connected?'connected':'none';
|
|
3737
|
-
|
|
3827
|
+
var hubActive=d.role==='hub'||curStatus==='connected';
|
|
3828
|
+
_updateScopeSelectorsVisibility(hubActive);
|
|
3829
|
+
if(_lastSharingConnStatus==='pending'&&curStatus==='rejected'&&d.role==='client'){
|
|
3738
3830
|
toast(t('sharing.rejected.toast'),'error');
|
|
3739
3831
|
}
|
|
3740
|
-
if(_lastSharingConnStatus==='pending'&&curStatus==='connected'){
|
|
3832
|
+
if(_lastSharingConnStatus==='pending'&&curStatus==='connected'&&d.role==='client'){
|
|
3741
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();
|
|
3742
3848
|
}
|
|
3743
3849
|
_lastSharingConnStatus=curStatus;
|
|
3744
3850
|
if(curStatus==='pending'&&!_clientPendingPollTimer){
|
|
3745
|
-
_clientPendingPollTimer=setInterval(function(){loadSharingStatus(false);},
|
|
3851
|
+
_clientPendingPollTimer=setInterval(function(){loadSharingStatus(false);},5000);
|
|
3746
3852
|
}
|
|
3747
3853
|
if(curStatus!=='pending'&&_clientPendingPollTimer){
|
|
3748
3854
|
clearInterval(_clientPendingPollTimer);
|
|
@@ -3752,6 +3858,7 @@ async function loadSharingStatus(forcePending){
|
|
|
3752
3858
|
renderSharingSidebar(null);
|
|
3753
3859
|
renderSharingSettings(null);
|
|
3754
3860
|
updateTeamGuide(null);
|
|
3861
|
+
_updateScopeSelectorsVisibility(false);
|
|
3755
3862
|
}
|
|
3756
3863
|
}
|
|
3757
3864
|
|
|
@@ -3763,7 +3870,8 @@ function renderSharingSidebar(data){
|
|
|
3763
3870
|
var badgeEl=document.getElementById('sharingSidebarConnBadge');
|
|
3764
3871
|
if(!statusEl||!hintEl) return;
|
|
3765
3872
|
var conn=data&&data.connection||{};
|
|
3766
|
-
var
|
|
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});
|
|
3767
3875
|
if(fp===_lastSidebarFingerprint) return;
|
|
3768
3876
|
_lastSidebarFingerprint=fp;
|
|
3769
3877
|
if(!data||!data.enabled){
|
|
@@ -3778,8 +3886,16 @@ function renderSharingSidebar(data){
|
|
|
3778
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>';
|
|
3779
3887
|
}
|
|
3780
3888
|
if(data.role==='hub'){
|
|
3781
|
-
setBadge('#34d399',t('sharing.sidebar.
|
|
3782
|
-
|
|
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;
|
|
3783
3899
|
hintEl.textContent='';
|
|
3784
3900
|
}else if(conn.pendingApproval&&conn.user){
|
|
3785
3901
|
setBadge('#fbbf24',t('sharing.sidebar.pending'),false);
|
|
@@ -3795,8 +3911,18 @@ function renderSharingSidebar(data){
|
|
|
3795
3911
|
html+='<span class="label">'+t('sharing.sidebar.identity')+'</span><span class="value">'+esc(conn.user.username||'-')+'</span>';
|
|
3796
3912
|
if(conn.teamName) html+='<span class="label">'+t('sharing.team')+'</span><span class="value">'+esc(conn.teamName)+'</span>';
|
|
3797
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>';
|
|
3798
3915
|
statusEl.innerHTML=html;
|
|
3799
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');
|
|
3800
3926
|
}else if(conn.connected&&conn.user){
|
|
3801
3927
|
var isAdmin=conn.user.role==='admin';
|
|
3802
3928
|
setBadge('#34d399',t('sharing.sidebar.connected'),true);
|
|
@@ -3831,16 +3957,29 @@ function renderSharingSettings(data){
|
|
|
3831
3957
|
if(!data||!data.enabled){
|
|
3832
3958
|
statusEl.innerHTML='';teamEl.innerHTML='';adminEl.innerHTML='';
|
|
3833
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');
|
|
3834
3963
|
return;
|
|
3835
3964
|
}
|
|
3836
3965
|
if(panelsWrap) panelsWrap.style.display='';
|
|
3837
3966
|
var conn=data.connection||{};
|
|
3838
3967
|
var user=conn.user||{};
|
|
3839
3968
|
var actualRole=data.role||_sharingRole||'client';
|
|
3840
|
-
|
|
3969
|
+
var prevIsAdmin=!!window._isHubAdmin;
|
|
3841
3970
|
var isAdmin=(data.admin&&data.admin.canManageUsers)||(conn.connected&&user.role==='admin')||(actualRole==='hub');
|
|
3842
3971
|
window._isHubAdmin=isAdmin;
|
|
3843
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
|
+
}
|
|
3844
3983
|
var hubAdminBtn=document.getElementById('hubAdminEntryBtn');
|
|
3845
3984
|
|
|
3846
3985
|
if(actualRole==='hub'){
|
|
@@ -3862,6 +4001,8 @@ function renderSharingSettings(data){
|
|
|
3862
4001
|
connBadge='<span class="hic-badge pending"><span class="hic-dot amber"></span>'+t('sharing.sidebar.pending')+'</span>';
|
|
3863
4002
|
}else if(conn.rejected){
|
|
3864
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>';
|
|
3865
4006
|
}else if(conn.connected){
|
|
3866
4007
|
connBadge='<span class="hic-badge connected"><span class="hic-dot green"></span>'+t('sharing.sidebar.connected')+'</span>';
|
|
3867
4008
|
}else{
|
|
@@ -3877,13 +4018,21 @@ function renderSharingSettings(data){
|
|
|
3877
4018
|
sh+='</div><div class="hic-empty" style="color:#ef4444">'+t('sharing.rejected.hint')+'</div>'+
|
|
3878
4019
|
'<div style="margin-top:10px;padding:0 16px 14px"><button class="btn btn-sm btn-primary" onclick="retryHubJoin()">'+t('sharing.retryJoin')+'</button>'+
|
|
3879
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>';
|
|
3880
4026
|
}else if(conn.connected&&user.username){
|
|
3881
4027
|
sh+='<span class="hic-label">'+t('sharing.user')+'</span><span class="hic-value" style="display:flex;align-items:center;gap:6px">'+
|
|
3882
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" />'+
|
|
3883
4029
|
'<button class="btn btn-sm" onclick="updateHubUsername()" style="padding:2px 10px;font-size:11px">'+t('sharing.saveUsername')+'</button>'+
|
|
3884
4030
|
'</span>';
|
|
3885
4031
|
sh+='<span class="hic-label">'+t('sharing.team')+'</span><span class="hic-value">'+esc(conn.teamName||'-')+'</span>';
|
|
3886
|
-
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>';
|
|
3887
4036
|
}else{
|
|
3888
4037
|
sh+='</div><div class="hic-empty" style="color:var(--text-muted)">'+t('sharing.disconnected.hint')+'</div>'+
|
|
3889
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>'+
|
|
@@ -3902,6 +4051,7 @@ async function retryConnection(){
|
|
|
3902
4051
|
var result=document.getElementById('retryConnResult');
|
|
3903
4052
|
if(btn){btn.disabled=true;btn.textContent=t('sharing.retryConnection.loading');}
|
|
3904
4053
|
if(result) result.innerHTML='<span style="color:var(--text-muted)">'+t('sharing.retryConnection.loading')+'</span>';
|
|
4054
|
+
toast(t('sharing.retryConnection.loading'),'info');
|
|
3905
4055
|
try{
|
|
3906
4056
|
await loadSharingStatus(false);
|
|
3907
4057
|
var d=sharingStatusCache;
|
|
@@ -3909,9 +4059,11 @@ async function retryConnection(){
|
|
|
3909
4059
|
toast(t('sharing.retryConnection.success'),'success');
|
|
3910
4060
|
if(result) result.innerHTML='<span style="color:#22c55e">\\u2705 '+t('sharing.retryConnection.success')+'</span>';
|
|
3911
4061
|
}else{
|
|
4062
|
+
toast(t('sharing.retryConnection.fail'),'error');
|
|
3912
4063
|
if(result) result.innerHTML='<span style="color:#ef4444">'+t('sharing.retryConnection.fail')+'</span>';
|
|
3913
4064
|
}
|
|
3914
4065
|
}catch(e){
|
|
4066
|
+
toast(t('sharing.retryConnection.fail'),'error');
|
|
3915
4067
|
if(result) result.innerHTML='<span style="color:#ef4444">'+t('sharing.retryConnection.fail')+'</span>';
|
|
3916
4068
|
}
|
|
3917
4069
|
if(btn){btn.disabled=false;btn.textContent=t('sharing.retryConnection');}
|
|
@@ -3924,19 +4076,36 @@ async function retryHubJoin(){
|
|
|
3924
4076
|
var d=await r.json();
|
|
3925
4077
|
if(d.ok){
|
|
3926
4078
|
toast(t('sharing.retryJoin.success'),'success');
|
|
3927
|
-
|
|
4079
|
+
_lastSidebarFingerprint='';_lastSettingsFingerprint='';_lastSharingConnStatus='';
|
|
4080
|
+
setTimeout(function(){loadSharingStatus(true);},800);
|
|
3928
4081
|
}else{
|
|
3929
4082
|
toast(d.error||t('sharing.retryJoin.fail'),'error');
|
|
3930
4083
|
}
|
|
3931
4084
|
}catch(e){toast(t('sharing.retryJoin.fail')+': '+e.message,'error');}
|
|
3932
4085
|
}
|
|
3933
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
|
+
|
|
3934
4103
|
async function updateHubUsername(){
|
|
3935
4104
|
var input=document.getElementById('hubUsernameInput');
|
|
3936
4105
|
if(!input) return;
|
|
3937
4106
|
var newName=input.value.trim();
|
|
3938
4107
|
if(!newName||newName.length<2||newName.length>32){
|
|
3939
|
-
|
|
4108
|
+
alertModal(t('sharing.username.invalid'));
|
|
3940
4109
|
return;
|
|
3941
4110
|
}
|
|
3942
4111
|
try{
|
|
@@ -3947,17 +4116,17 @@ async function updateHubUsername(){
|
|
|
3947
4116
|
});
|
|
3948
4117
|
var d=await r.json();
|
|
3949
4118
|
if(d.error==='username_taken'){
|
|
3950
|
-
|
|
4119
|
+
alertModal(t('sharing.username.taken'),{danger:true});
|
|
3951
4120
|
return;
|
|
3952
4121
|
}
|
|
3953
4122
|
if(d.error){
|
|
3954
|
-
|
|
4123
|
+
alertModal(d.error,{danger:true});
|
|
3955
4124
|
return;
|
|
3956
4125
|
}
|
|
3957
4126
|
toast(t('sharing.username.updated'),'success');
|
|
3958
4127
|
loadSharingStatus(false);
|
|
3959
4128
|
}catch(e){
|
|
3960
|
-
|
|
4129
|
+
alertModal(t('sharing.username.error'),{danger:true});
|
|
3961
4130
|
}
|
|
3962
4131
|
}
|
|
3963
4132
|
|
|
@@ -4003,7 +4172,7 @@ async function approveSharingUser(userId,username){
|
|
|
4003
4172
|
try{
|
|
4004
4173
|
const r=await fetch('/api/sharing/approve-user',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:userId,username:username})});
|
|
4005
4174
|
const d=await r.json();
|
|
4006
|
-
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');}
|
|
4007
4176
|
}catch(e){toast(t('toast.approveFail')+': '+e.message,'error');}
|
|
4008
4177
|
}
|
|
4009
4178
|
|
|
@@ -4011,23 +4180,15 @@ async function rejectSharingUser(userId,username){
|
|
|
4011
4180
|
try{
|
|
4012
4181
|
const r=await fetch('/api/sharing/reject-user',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:userId,username:username})});
|
|
4013
4182
|
const d=await r.json();
|
|
4014
|
-
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');}
|
|
4015
4184
|
}catch(e){toast(t('toast.rejectFail')+': '+e.message,'error');}
|
|
4016
4185
|
}
|
|
4017
4186
|
|
|
4018
4187
|
/* ─── Team Setup Guide ─── */
|
|
4019
|
-
var TEAM_GUIDE_DISMISSED_KEY='memos-team-guide-dismissed';
|
|
4020
4188
|
function updateTeamGuide(sharingData){
|
|
4021
4189
|
var el=document.getElementById('teamSetupGuide');
|
|
4022
4190
|
if(!el) return;
|
|
4023
|
-
|
|
4024
|
-
var isConfigured=sharingData&&sharingData.enabled;
|
|
4025
|
-
el.style.display=isConfigured?'none':'block';
|
|
4026
|
-
}
|
|
4027
|
-
function dismissTeamGuide(){
|
|
4028
|
-
localStorage.setItem(TEAM_GUIDE_DISMISSED_KEY,'1');
|
|
4029
|
-
var el=document.getElementById('teamSetupGuide');
|
|
4030
|
-
if(el) el.style.display='none';
|
|
4191
|
+
el.style.display='block';
|
|
4031
4192
|
}
|
|
4032
4193
|
function guideGoToHub(role){
|
|
4033
4194
|
switchSettingsTab('hub',document.querySelector('.settings-tab-btn[data-tab="hub"]'));
|
|
@@ -4060,7 +4221,7 @@ function adminPaginateHtml(total,page,refilterFn){
|
|
|
4060
4221
|
if(end<pages) html+=(end<pages-1?'<span class="pg-info">...</span>':'')+'<button class="pg-btn" onclick="'+refilterFn+'Page('+(pages-1)+')">'+pages+'</button>';
|
|
4061
4222
|
html+='<button class="pg-btn'+(page>=pages-1?' disabled':'')+'" onclick="'+refilterFn+'Page('+(page+1)+')">\\u2192</button>';
|
|
4062
4223
|
html+='<span class="pg-info">'+total+' '+t('pagination.total')+'</span>';
|
|
4063
|
-
|
|
4224
|
+
html+='</div>';
|
|
4064
4225
|
return html;
|
|
4065
4226
|
}
|
|
4066
4227
|
|
|
@@ -4122,12 +4283,12 @@ async function loadAdminData(){
|
|
|
4122
4283
|
var fetches;
|
|
4123
4284
|
if(isAdmin){
|
|
4124
4285
|
fetches=await Promise.all([
|
|
4125
|
-
|
|
4126
|
-
|
|
4127
|
-
|
|
4128
|
-
|
|
4129
|
-
|
|
4130
|
-
|
|
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
|
+
]);
|
|
4131
4292
|
}else{
|
|
4132
4293
|
fetches=await Promise.all([
|
|
4133
4294
|
Promise.resolve({users:[]}),
|
|
@@ -4144,7 +4305,7 @@ async function loadAdminData(){
|
|
|
4144
4305
|
var _newMemories=Array.isArray(memoriesR.memories)?memoriesR.memories:[];
|
|
4145
4306
|
var pending=isAdmin?(Array.isArray(pendingR.users)?pendingR.users:[]):[];
|
|
4146
4307
|
var _fp=_newUsers.length+':'+_newTasks.length+':'+_newSkills.length+':'+_newMemories.length+':'+pending.length
|
|
4147
|
-
+':'+_newUsers.map(function(u){return u.id+'|'+(u.isOnline?1:0)+'|'+(u.role||'')}).join(',')
|
|
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(',')
|
|
4148
4309
|
+':'+_newMemories.map(function(m){return m.id}).join(',')
|
|
4149
4310
|
+':'+_newTasks.map(function(t){return t.id+'|'+(t.status||'')}).join(',')
|
|
4150
4311
|
+':'+_newSkills.map(function(s){return s.id+'|'+(s.status||'')}).join(',')
|
|
@@ -4197,11 +4358,15 @@ function updateAdminTabsVisibility(){
|
|
|
4197
4358
|
if(subEl) subEl.textContent=isAdmin?t('admin.subtitle'):t('admin.subtitle.member');
|
|
4198
4359
|
}
|
|
4199
4360
|
|
|
4361
|
+
var _lastAdminStatsFp='';
|
|
4200
4362
|
function renderAdminStats(pendingCount){
|
|
4201
4363
|
var el=document.getElementById('adminStats');
|
|
4202
4364
|
if(!el) return;
|
|
4203
4365
|
var isAdmin=!!window._isHubAdmin;
|
|
4204
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;
|
|
4205
4370
|
el.innerHTML=
|
|
4206
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>'+
|
|
4207
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>':'')+
|
|
@@ -4223,9 +4388,10 @@ function auRelativeTime(ts){
|
|
|
4223
4388
|
return t('notif.timeAgo.day').replace('{n}',Math.floor(diff/86400000));
|
|
4224
4389
|
}
|
|
4225
4390
|
|
|
4226
|
-
function renderAdminUserCard(u,adminCount){
|
|
4391
|
+
function renderAdminUserCard(u,adminCount,myUserId){
|
|
4227
4392
|
var uid=escAttr(u.id);
|
|
4228
4393
|
var uname=escAttr(u.username||'');
|
|
4394
|
+
var isSelf=!!(myUserId&&u.id===myUserId);
|
|
4229
4395
|
var online=!!u.isOnline;
|
|
4230
4396
|
var statusCls=online?'online':'offline';
|
|
4231
4397
|
|
|
@@ -4259,7 +4425,9 @@ function renderAdminUserCard(u,adminCount){
|
|
|
4259
4425
|
var infoHtml='<div class="au-info">'+infoRows.join('')+'</div>';
|
|
4260
4426
|
|
|
4261
4427
|
var actions='';
|
|
4262
|
-
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){
|
|
4263
4431
|
actions+='<span style="font-size:11px;color:var(--text-muted);padding:4px 0">'+t('admin.ownerHint')+'</span>';
|
|
4264
4432
|
}else if(u.role!=='admin'){
|
|
4265
4433
|
actions+='<button class="btn btn-sm btn-ghost" onclick="adminToggleRole("'+uid+'","admin")" style="color:var(--accent)">'+t('admin.promoteAdmin')+'</button>';
|
|
@@ -4270,12 +4438,13 @@ function renderAdminUserCard(u,adminCount){
|
|
|
4270
4438
|
}else{
|
|
4271
4439
|
actions+='<span style="font-size:11px;color:var(--text-muted);padding:4px 0">'+t('admin.lastAdminHint')+'</span>';
|
|
4272
4440
|
}
|
|
4273
|
-
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>';
|
|
4274
4445
|
|
|
4275
|
-
return '<div class="admin-card au-card au-'+statusCls+'"><div class="admin-card-header"><div style="flex:1;min-width:0
|
|
4276
|
-
|
|
4277
|
-
'</div>'+
|
|
4278
|
-
'<div style="display:flex;align-items:center;gap:6px"><span class="admin-badge '+(u.role==='admin'?'admin':'member')+'">'+esc(u.role||'member')+'</span>'+ownerBadge+'</div></div>'+
|
|
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>'+
|
|
4279
4448
|
contribHtml+infoHtml+
|
|
4280
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>':'')+
|
|
4281
4450
|
'</div>';
|
|
@@ -4310,6 +4479,7 @@ function renderAdminUsers(users,pending){
|
|
|
4310
4479
|
offlineUsers.sort(function(a,b){return (b.lastActiveAt||0)-(a.lastActiveAt||0);});
|
|
4311
4480
|
var sorted=onlineUsers.concat(offlineUsers);
|
|
4312
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;
|
|
4313
4483
|
|
|
4314
4484
|
if(sorted.length===0){
|
|
4315
4485
|
html+='<div class="admin-empty"><span class="ae-icon">\u{1F465}</span>'+t('admin.noActiveUsers')+'</div>';
|
|
@@ -4318,13 +4488,13 @@ function renderAdminUsers(users,pending){
|
|
|
4318
4488
|
if(onlineUsers.length===0){
|
|
4319
4489
|
html+='<div style="font-size:12px;color:var(--text-muted);padding:8px 0 12px">\u2014</div>';
|
|
4320
4490
|
}else{
|
|
4321
|
-
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);
|
|
4322
4492
|
}
|
|
4323
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>';
|
|
4324
4494
|
if(offlineUsers.length===0){
|
|
4325
4495
|
html+='<div style="font-size:12px;color:var(--text-muted);padding:8px 0 12px">\u2014</div>';
|
|
4326
4496
|
}else{
|
|
4327
|
-
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);
|
|
4328
4498
|
}
|
|
4329
4499
|
}
|
|
4330
4500
|
el.innerHTML=html;
|
|
@@ -4335,7 +4505,7 @@ async function adminApproveUser(userId,username){
|
|
|
4335
4505
|
try{
|
|
4336
4506
|
var r=await fetch('/api/sharing/approve-user',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:userId,username:username})});
|
|
4337
4507
|
var d=await r.json();
|
|
4338
|
-
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');}
|
|
4339
4509
|
}catch(e){toast(t('toast.approveFail')+': '+e.message,'error');}
|
|
4340
4510
|
}
|
|
4341
4511
|
async function adminRejectUser(userId){
|
|
@@ -4343,7 +4513,7 @@ async function adminRejectUser(userId){
|
|
|
4343
4513
|
try{
|
|
4344
4514
|
var r=await fetch('/api/sharing/reject-user',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:userId})});
|
|
4345
4515
|
var d=await r.json();
|
|
4346
|
-
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');}
|
|
4347
4517
|
}catch(e){toast(t('toast.rejectFail')+': '+e.message,'error');}
|
|
4348
4518
|
}
|
|
4349
4519
|
async function adminToggleRole(userId,newRole){
|
|
@@ -4352,7 +4522,14 @@ async function adminToggleRole(userId,newRole){
|
|
|
4352
4522
|
try{
|
|
4353
4523
|
var r=await fetch('/api/sharing/change-role',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:userId,role:newRole})});
|
|
4354
4524
|
var d=await r.json();
|
|
4355
|
-
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
|
+
}
|
|
4356
4533
|
else if(d.error==='cannot_demote_owner'){toast(t('admin.ownerHint'),'error');}
|
|
4357
4534
|
else{toast(d.error||t('toast.roleChangeFail'),'error');}
|
|
4358
4535
|
}catch(e){toast(t('toast.roleChangeFail')+': '+e.message,'error');}
|
|
@@ -4378,13 +4555,24 @@ async function adminSaveEditName(userId){
|
|
|
4378
4555
|
var inputEl=document.getElementById('au_input_'+userId);
|
|
4379
4556
|
if(!inputEl) return;
|
|
4380
4557
|
var newName=inputEl.value.trim();
|
|
4381
|
-
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
|
+
}
|
|
4382
4562
|
inputEl.disabled=true;
|
|
4383
4563
|
try{
|
|
4384
4564
|
var r=await fetch('/api/sharing/rename-user',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:userId,username:newName})});
|
|
4385
4565
|
var d=await r.json();
|
|
4386
|
-
if(d.ok){toast(t('toast.usernameChanged'),'success');
|
|
4387
|
-
|
|
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});}
|
|
4388
4576
|
}
|
|
4389
4577
|
|
|
4390
4578
|
async function adminRemoveUser(userId,username){
|
|
@@ -4393,7 +4581,7 @@ async function adminRemoveUser(userId,username){
|
|
|
4393
4581
|
try{
|
|
4394
4582
|
var r=await fetch('/api/sharing/remove-user',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:userId,cleanResources:clean})});
|
|
4395
4583
|
var d=await r.json();
|
|
4396
|
-
if(d.ok){toast(t('toast.userRemoved'),'success');loadAdminData();}
|
|
4584
|
+
if(d.ok){toast(t('toast.userRemoved'),'success');_lastAdminFingerprint='';loadAdminData();}
|
|
4397
4585
|
else if(d.error==='cannot_remove_owner'){toast(t('admin.ownerHint'),'error');}
|
|
4398
4586
|
else{toast(d.error||t('toast.removeFail'),'error');}
|
|
4399
4587
|
}catch(e){toast(t('toast.removeFail')+': '+e.message,'error');}
|
|
@@ -4462,7 +4650,7 @@ function renderAdminTasks(tasks){
|
|
|
4462
4650
|
'<div class="admin-card-header"><div class="admin-card-title">'+esc(tk.title||tk.id)+'</div></div>'+
|
|
4463
4651
|
'<div class="admin-card-tags">'+
|
|
4464
4652
|
'<div class="admin-card-tags-left">'+
|
|
4465
|
-
'<span class="admin-card-tag tag-owner">\u{1F464} '+
|
|
4653
|
+
'<span class="admin-card-tag tag-owner">\u{1F464} '+fmtOwner(tk)+'</span>'+
|
|
4466
4654
|
(tk.status?'<span class="admin-card-tag tag-status">'+esc(tk.status)+'</span>':'')+
|
|
4467
4655
|
(tk.chunkCount!=null?'<span class="admin-card-tag tag-kind">\u{1F4DD} '+tk.chunkCount+' '+t('admin.chunks')+'</span>':'')+
|
|
4468
4656
|
'</div>'+
|
|
@@ -4524,7 +4712,7 @@ function renderAdminSkills(skills){
|
|
|
4524
4712
|
'<div class="admin-card-header"><div class="admin-card-title">'+esc(s.name||s.id)+'</div></div>'+
|
|
4525
4713
|
'<div class="admin-card-tags">'+
|
|
4526
4714
|
'<div class="admin-card-tags-left">'+
|
|
4527
|
-
'<span class="admin-card-tag tag-owner">\u{1F464} '+
|
|
4715
|
+
'<span class="admin-card-tag tag-owner">\u{1F464} '+fmtOwner(s)+'</span>'+
|
|
4528
4716
|
(s.status?'<span class="admin-card-tag tag-status">'+esc(s.status)+'</span>':'')+
|
|
4529
4717
|
(s.version!=null?'<span class="admin-card-tag tag-version">v'+s.version+'</span>':'')+
|
|
4530
4718
|
(qs!=null?'<span class="admin-card-tag tag-kind">\u2605 '+Number(qs).toFixed(1)+'</span>':'')+
|
|
@@ -4589,7 +4777,7 @@ function renderAdminMemories(memories){
|
|
|
4589
4777
|
'<div class="admin-card-header"><div class="admin-card-title">'+esc(m.summary||m.content?.slice(0,80)||m.id)+'</div></div>'+
|
|
4590
4778
|
'<div class="admin-card-tags">'+
|
|
4591
4779
|
'<div class="admin-card-tags-left">'+
|
|
4592
|
-
'<span class="admin-card-tag tag-owner">\u{1F464} '+
|
|
4780
|
+
'<span class="admin-card-tag tag-owner">\u{1F464} '+fmtOwner(m)+'</span>'+
|
|
4593
4781
|
(m.role?'<span class="admin-card-tag tag-role">'+esc(m.role)+'</span>':'')+
|
|
4594
4782
|
(m.kind?'<span class="admin-card-tag tag-kind">'+esc(m.kind)+'</span>':'')+
|
|
4595
4783
|
'</div>'+
|
|
@@ -4633,7 +4821,7 @@ function toggleAdminMemoryCard(cardId,idx){
|
|
|
4633
4821
|
(m.kind?'<span class="meta-item">'+t('admin.kind')+esc(m.kind)+'</span>':'')+
|
|
4634
4822
|
(m.role?'<span class="meta-item">'+t('admin.role')+esc(m.role)+'</span>':'')+
|
|
4635
4823
|
(m.visibility?'<span class="meta-item">'+t('admin.visibility')+esc(m.visibility)+'</span>':'')+
|
|
4636
|
-
'<span class="meta-item">'+t('admin.owner')+
|
|
4824
|
+
'<span class="meta-item">'+t('admin.owner')+fmtOwner(m)+'</span>'+
|
|
4637
4825
|
(m.groupName?'<span class="meta-item">'+t('admin.group')+esc(m.groupName)+'</span>':'')+
|
|
4638
4826
|
'<span class="meta-item">'+new Date(m.updatedAt||m.createdAt||0).toLocaleString(dateLoc())+'</span>'+
|
|
4639
4827
|
'</div>';
|
|
@@ -4689,7 +4877,7 @@ async function toggleAdminTaskCard(cardId,idx){
|
|
|
4689
4877
|
var metaHtml='<div class="admin-card-detail-meta admin-task-meta">'+
|
|
4690
4878
|
(tk.status?'<span class="meta-item"><span class="task-status-badge '+tk.status+'">'+esc(tk.status)+'</span></span>':'')+
|
|
4691
4879
|
(tk.visibility?'<span class="meta-item">'+t('admin.visibility')+esc(tk.visibility)+'</span>':'')+
|
|
4692
|
-
'<span class="meta-item">'+t('admin.owner')+
|
|
4880
|
+
'<span class="meta-item">'+t('admin.owner')+fmtOwner(tk)+'</span>'+
|
|
4693
4881
|
(tk.groupName?'<span class="meta-item">'+t('admin.group')+esc(tk.groupName)+'</span>':'')+
|
|
4694
4882
|
(task.chunks&&task.chunks.length?'<span class="meta-item">\u{1F4AC} '+task.chunks.length+' '+t('tasks.chunks.label')+'</span>':'')+
|
|
4695
4883
|
(task.startedAt?'<span class="meta-item">\u{1F4C5} '+formatDateTimeSeconds(task.startedAt)+'</span>':'')+
|
|
@@ -4776,7 +4964,7 @@ async function toggleAdminSkillCard(cardId,idx){
|
|
|
4776
4964
|
(localSkill.status?'<span class="meta-item"><span class="skill-badge status-'+localSkill.status+'">'+esc(localSkill.status)+'</span></span>':'')+
|
|
4777
4965
|
(sk.visibility?'<span class="meta-item">'+t('admin.visibility')+esc(sk.visibility||'hub')+'</span>':'')+
|
|
4778
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>':'')+
|
|
4779
|
-
'<span class="meta-item">'+t('admin.owner')+
|
|
4967
|
+
'<span class="meta-item">'+t('admin.owner')+fmtOwner(sk)+'</span>'+
|
|
4780
4968
|
(sk.groupName?'<span class="meta-item">'+t('admin.group')+esc(sk.groupName)+'</span>':'')+
|
|
4781
4969
|
'<span class="meta-item">'+t('admin.updated')+new Date(sk.updatedAt||sk.createdAt||0).toLocaleString(dateLoc())+'</span>'+
|
|
4782
4970
|
'</div>';
|
|
@@ -4845,7 +5033,7 @@ function renderSharingMemorySearchResults(data,query){
|
|
|
4845
5033
|
'<div class="summary">'+(idx+1)+'. '+esc(hit.summary||'(no summary)')+'</div>'+
|
|
4846
5034
|
'<div class="excerpt">'+esc(hit.excerpt||'')+'</div>'+
|
|
4847
5035
|
'<div class="hub-hit-meta">'+
|
|
4848
|
-
'<span class="meta-chip">owner: '+
|
|
5036
|
+
'<span class="meta-chip">owner: '+fmtOwner(hit)+'</span>'+
|
|
4849
5037
|
(hit.groupName?'<span class="meta-chip">group: '+esc(hit.groupName)+'</span>':'')+
|
|
4850
5038
|
'<span class="meta-chip">visibility: '+esc(hit.visibility||'hub')+'</span>'+
|
|
4851
5039
|
'</div>'+
|
|
@@ -4930,7 +5118,7 @@ function openHubTaskDetailFromCache(cacheKey,idx){
|
|
|
4930
5118
|
var meta=[
|
|
4931
5119
|
'<span class="meta-item">\\u{1F310} '+t('scope.hub')+'</span>',
|
|
4932
5120
|
task.status?'<span class="meta-item"><span class="task-status-badge '+task.status+'">'+esc(task.status)+'</span></span>':'',
|
|
4933
|
-
'<span class="meta-item">'+t('admin.owner')+
|
|
5121
|
+
'<span class="meta-item">'+t('admin.owner')+fmtOwner(task)+'</span>',
|
|
4934
5122
|
task.groupName?'<span class="meta-item">'+t('admin.group')+esc(task.groupName)+'</span>':'',
|
|
4935
5123
|
task.visibility?'<span class="meta-item">'+t('admin.visibility')+esc(task.visibility)+'</span>':'',
|
|
4936
5124
|
task.chunkCount!=null?'<span class="meta-item">\\u{1F4DD} '+esc(String(task.chunkCount))+' '+t('tasks.chunks.label')+'</span>':'',
|
|
@@ -4961,14 +5149,14 @@ function openHubSkillDetailFromCache(cacheKey,idx){
|
|
|
4961
5149
|
skill.status?'<span class="meta-item"><span class="skill-badge status-'+skill.status+'">'+esc(skill.status)+'</span></span>':'',
|
|
4962
5150
|
'<span class="meta-item">visibility: '+esc(skill.visibility||'hub')+'</span>',
|
|
4963
5151
|
qsBadge,
|
|
4964
|
-
'<span class="meta-item">'+t('admin.owner')+
|
|
5152
|
+
'<span class="meta-item">'+t('admin.owner')+fmtOwner(skill)+'</span>',
|
|
4965
5153
|
skill.groupName?'<span class="meta-item">'+t('admin.group')+esc(skill.groupName)+'</span>':'',
|
|
4966
5154
|
(skill.updatedAt||skill.createdAt)?'<span class="meta-item">'+t('admin.updated')+new Date(skill.updatedAt||skill.createdAt).toLocaleString(dateLoc())+'</span>':'',
|
|
4967
5155
|
].filter(Boolean);
|
|
4968
5156
|
document.getElementById('skillDetailMeta').innerHTML=meta.join('');
|
|
4969
5157
|
document.getElementById('skillDetailDesc').textContent=skill.description||'';
|
|
4970
5158
|
document.getElementById('skillFilesList').innerHTML='';
|
|
4971
|
-
document.getElementById('skillDetailContent').innerHTML=skill.content?
|
|
5159
|
+
document.getElementById('skillDetailContent').innerHTML=skill.content?renderSkillMarkdown(skill.content):'';
|
|
4972
5160
|
document.getElementById('skillVersionsList').innerHTML='';
|
|
4973
5161
|
document.getElementById('skillRelatedTasks').innerHTML='';
|
|
4974
5162
|
var visBtn=document.getElementById('skillVisibilityBtn');
|
|
@@ -5011,6 +5199,7 @@ function openScopeSelectorModal(resourceType, resourceId, currentScope, onConfir
|
|
|
5011
5199
|
var existing=document.getElementById('scopeSelectorOverlay');
|
|
5012
5200
|
if(existing) existing.remove();
|
|
5013
5201
|
var teamEnabled=sharingStatusCache&&sharingStatusCache.enabled;
|
|
5202
|
+
var teamConnected=teamEnabled&&sharingStatusCache.connection&&sharingStatusCache.connection.connected;
|
|
5014
5203
|
var overlay=document.createElement('div');
|
|
5015
5204
|
overlay.id='scopeSelectorOverlay';
|
|
5016
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';
|
|
@@ -5024,7 +5213,7 @@ function openScopeSelectorModal(resourceType, resourceId, currentScope, onConfir
|
|
|
5024
5213
|
for(var i=0;i<scopes.length;i++){
|
|
5025
5214
|
var sc=scopes[i];
|
|
5026
5215
|
var isCurrent=sc===currentScope;
|
|
5027
|
-
var isDisabled=sc==='team'
|
|
5216
|
+
var isDisabled=sc==='team'&&(!teamEnabled||!teamConnected);
|
|
5028
5217
|
var color=getScopeColor(sc);
|
|
5029
5218
|
var cursor=isDisabled?'not-allowed':'pointer';
|
|
5030
5219
|
var opacity=isDisabled?'0.4':'1';
|
|
@@ -5093,7 +5282,8 @@ async function confirmScopeSelection(){
|
|
|
5093
5282
|
if(st.onConfirm) st.onConfirm(newScope);
|
|
5094
5283
|
else loadAll();
|
|
5095
5284
|
}else{
|
|
5096
|
-
|
|
5285
|
+
var errMsg=d.error==='inactive_memory'?t('share.scope.inactiveDisabled'):(d.message||d.error||t('share.scope.changeFail'));
|
|
5286
|
+
toast(errMsg,'error');
|
|
5097
5287
|
}
|
|
5098
5288
|
}catch(e){toast(t('share.scope.changeFail')+': '+e.message,'error');}
|
|
5099
5289
|
}
|
|
@@ -5344,6 +5534,13 @@ function parseMemoryAddEntries(out){
|
|
|
5344
5534
|
return results;
|
|
5345
5535
|
}
|
|
5346
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
|
+
|
|
5347
5544
|
function buildLogSummary(lg){
|
|
5348
5545
|
let inputObj=null;
|
|
5349
5546
|
try{inputObj=JSON.parse(lg.input);}catch(_){}
|
|
@@ -5368,8 +5565,9 @@ function buildLogSummary(lg){
|
|
|
5368
5565
|
var scoreClass=c.score>=0.7?'high':c.score>=0.5?'mid':'low';
|
|
5369
5566
|
var shortText=escapeHtml(c.summary||c.content||c.original_excerpt||'');
|
|
5370
5567
|
var fullText=escapeHtml(c.content||c.original_excerpt||c.summary||'');
|
|
5568
|
+
var oBadge=recallOriginBadge(c.origin);
|
|
5371
5569
|
html+='<div class="recall-item" onclick="event.stopPropagation();this.classList.toggle(\\\'expanded\\\')">';
|
|
5372
|
-
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>';
|
|
5373
5571
|
html+='<div class="recall-summary-full">'+fullText+'</div>';
|
|
5374
5572
|
html+='</div>';
|
|
5375
5573
|
});
|
|
@@ -5382,8 +5580,9 @@ function buildLogSummary(lg){
|
|
|
5382
5580
|
var scoreClass=f.score>=0.7?'high':f.score>=0.5?'mid':'low';
|
|
5383
5581
|
var shortText=escapeHtml(f.summary||f.content||f.original_excerpt||'');
|
|
5384
5582
|
var fullText=escapeHtml(f.content||f.original_excerpt||f.summary||'');
|
|
5583
|
+
var oBadge=recallOriginBadge(f.origin);
|
|
5385
5584
|
html+='<div class="recall-item" onclick="event.stopPropagation();this.classList.toggle(\\\'expanded\\\')">';
|
|
5386
|
-
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>';
|
|
5387
5586
|
html+='<div class="recall-summary-full">'+fullText+'</div>';
|
|
5388
5587
|
html+='</div>';
|
|
5389
5588
|
});
|
|
@@ -5447,8 +5646,9 @@ function buildRecallDetailHtml(rd){
|
|
|
5447
5646
|
var scoreClass=c.score>=0.7?'high':c.score>=0.5?'mid':'low';
|
|
5448
5647
|
var shortText=escapeHtml(c.summary||c.content||c.original_excerpt||'');
|
|
5449
5648
|
var fullText=escapeHtml(c.content||c.original_excerpt||c.summary||'');
|
|
5649
|
+
var oBadge=recallOriginBadge(c.origin);
|
|
5450
5650
|
html+='<div class="recall-item" onclick="event.stopPropagation();this.classList.toggle(\\\'expanded\\\')">';
|
|
5451
|
-
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>';
|
|
5452
5652
|
html+='<div class="recall-summary-full">'+fullText+'</div>';
|
|
5453
5653
|
html+='</div>';
|
|
5454
5654
|
});
|
|
@@ -5462,8 +5662,9 @@ function buildRecallDetailHtml(rd){
|
|
|
5462
5662
|
var scoreClass=f.score>=0.7?'high':f.score>=0.5?'mid':'low';
|
|
5463
5663
|
var shortText=escapeHtml(f.summary||f.content||f.original_excerpt||'');
|
|
5464
5664
|
var fullText=escapeHtml(f.content||f.original_excerpt||f.summary||'');
|
|
5665
|
+
var oBadge=recallOriginBadge(f.origin);
|
|
5465
5666
|
html+='<div class="recall-item" onclick="event.stopPropagation();this.classList.toggle(\\\'expanded\\\')">';
|
|
5466
|
-
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>';
|
|
5467
5668
|
html+='<div class="recall-summary-full">'+fullText+'</div>';
|
|
5468
5669
|
html+='</div>';
|
|
5469
5670
|
});
|
|
@@ -6039,7 +6240,7 @@ async function loadSkills(silent){
|
|
|
6039
6240
|
'<div class="summary">'+esc(skill.name)+'</div>'+
|
|
6040
6241
|
'<div class="excerpt">'+esc(skill.description||'')+'</div>'+
|
|
6041
6242
|
'<div class="hub-skill-meta">'+
|
|
6042
|
-
'<span class="meta-chip">owner: '+
|
|
6243
|
+
'<span class="meta-chip">owner: '+fmtOwner(skill)+'</span>'+
|
|
6043
6244
|
(skill.groupName?'<span class="meta-chip">group: '+esc(skill.groupName)+'</span>':'')+
|
|
6044
6245
|
'<span class="meta-chip">visibility: '+esc(skill.visibility||'hub')+'</span>'+
|
|
6045
6246
|
(skill.version!=null?'<span class="meta-chip">v'+skill.version+'</span>':'')+
|
|
@@ -6086,12 +6287,12 @@ async function loadHubTasks(){
|
|
|
6086
6287
|
return '<div class="task-card" onclick="openHubTaskDetailFromCache(\\x27hub\\x27,'+idx+')" style="cursor:pointer">'+
|
|
6087
6288
|
'<div class="task-card-top">'+
|
|
6088
6289
|
'<div class="task-card-title">'+esc(task.title||'(no title)')+'</div>'+
|
|
6089
|
-
'<div class="task-card-badges"
|
|
6290
|
+
'<div class="task-card-badges">'+renderScopeBadge('team')+'</div>'+
|
|
6090
6291
|
'</div>'+
|
|
6091
6292
|
(task.summary?'<div class="task-card-summary">'+esc(task.summary)+'</div>':'')+
|
|
6092
6293
|
'<div class="task-card-bottom">'+
|
|
6093
6294
|
(timeStr?'<span class="tag"><span class="icon">\\u{1F4C5}</span> '+timeStr+'</span>':'')+
|
|
6094
|
-
'<span class="tag"><span class="icon">\\u{1F464}</span> '+
|
|
6295
|
+
'<span class="tag"><span class="icon">\\u{1F464}</span> '+fmtOwner(task)+'</span>'+
|
|
6095
6296
|
(task.chunkCount!=null?'<span class="tag"><span class="icon">\\u{1F4DD}</span> '+task.chunkCount+' '+t('tasks.chunks.label')+'</span>':'')+
|
|
6096
6297
|
'</div>'+
|
|
6097
6298
|
'</div>';
|
|
@@ -6124,12 +6325,12 @@ async function loadHubSkills(hubList, localIds){
|
|
|
6124
6325
|
'<div class="summary">'+esc(skill.name)+'</div>'+
|
|
6125
6326
|
'<div class="excerpt">'+esc(skill.description||'')+'</div>'+
|
|
6126
6327
|
'<div class="hub-skill-meta">'+
|
|
6127
|
-
'<span class="meta-chip">owner: '+
|
|
6328
|
+
'<span class="meta-chip">owner: '+fmtOwner(skill)+'</span>'+
|
|
6128
6329
|
(skill.groupName?'<span class="meta-chip">group: '+esc(skill.groupName)+'</span>':'')+
|
|
6129
6330
|
'<span class="meta-chip">visibility: '+esc(skill.visibility||'hub')+'</span>'+
|
|
6130
6331
|
(skill.version!=null?'<span class="meta-chip">v'+skill.version+'</span>':'')+
|
|
6131
6332
|
'</div>'+
|
|
6132
|
-
'<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>'+
|
|
6133
6334
|
'</div>';
|
|
6134
6335
|
}).join('');
|
|
6135
6336
|
}catch(e){
|
|
@@ -6463,6 +6664,7 @@ async function loadConfig(){
|
|
|
6463
6664
|
document.getElementById('cfgHubTeamName').value=hub.teamName||'';
|
|
6464
6665
|
document.getElementById('cfgHubTeamToken').value=hub.teamToken||'';
|
|
6465
6666
|
document.getElementById('cfgClientHubAddress').value=client.hubAddress||'';
|
|
6667
|
+
_loadedClientHubAddress=client.hubAddress||'';
|
|
6466
6668
|
document.getElementById('cfgClientTeamToken').value=client.teamToken||'';
|
|
6467
6669
|
document.getElementById('cfgClientNickname').value=client.nickname||'';
|
|
6468
6670
|
document.getElementById('cfgClientUserToken').value=client.userToken||'';
|
|
@@ -6508,20 +6710,24 @@ function flashSaved(id){
|
|
|
6508
6710
|
}
|
|
6509
6711
|
|
|
6510
6712
|
async function doSaveConfig(cfg, btnEl, savedId){
|
|
6511
|
-
btnEl.disabled=true;btnEl.textContent=t('settings.test.loading');
|
|
6512
|
-
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');}}
|
|
6513
6715
|
try{
|
|
6514
6716
|
const r=await fetch('/api/config',{method:'PUT',headers:{'Content-Type':'application/json'},body:JSON.stringify(cfg)});
|
|
6515
|
-
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;}
|
|
6516
6718
|
if(!r.ok) throw new Error(await r.text());
|
|
6719
|
+
var data=await r.json().catch(function(){return {ok:true};});
|
|
6517
6720
|
flashSaved(savedId);
|
|
6518
|
-
|
|
6519
|
-
|
|
6520
|
-
|
|
6721
|
+
if(data&&data.restart){
|
|
6722
|
+
showRestartOverlay(t('settings.restart.waiting'));
|
|
6723
|
+
}else{
|
|
6724
|
+
done();
|
|
6725
|
+
}
|
|
6726
|
+
return data;
|
|
6521
6727
|
}catch(e){
|
|
6522
6728
|
toast(t('settings.save.fail')+': '+e.message,'error');
|
|
6523
6729
|
done();
|
|
6524
|
-
return
|
|
6730
|
+
return null;
|
|
6525
6731
|
}
|
|
6526
6732
|
}
|
|
6527
6733
|
|
|
@@ -6616,11 +6822,19 @@ async function saveModelsConfig(){
|
|
|
6616
6822
|
await doSaveConfig(cfg, saveBtn, 'modelsSaved');
|
|
6617
6823
|
}
|
|
6618
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
|
+
}
|
|
6619
6833
|
async function saveHubConfig(){
|
|
6620
6834
|
var card=document.getElementById('settingsSharingConfig');
|
|
6621
6835
|
var saveBtn=card.querySelector('.settings-actions .btn-primary');
|
|
6622
6836
|
saveBtn.disabled=true;saveBtn.textContent=t('settings.test.loading');
|
|
6623
|
-
function done(){saveBtn.disabled=false;saveBtn.textContent=
|
|
6837
|
+
function done(){saveBtn.disabled=false;saveBtn.textContent=_hubSaveBtnLabel();}
|
|
6624
6838
|
|
|
6625
6839
|
const cfg={};
|
|
6626
6840
|
var sharingEnabled=document.getElementById('cfgSharingEnabled').checked;
|
|
@@ -6634,7 +6848,7 @@ async function saveHubConfig(){
|
|
|
6634
6848
|
var hubTeamName=document.getElementById('cfgHubTeamName').value.trim();
|
|
6635
6849
|
var hubTeamToken=document.getElementById('cfgHubTeamToken').value.trim();
|
|
6636
6850
|
var hubAdminName=document.getElementById('cfgHubAdminName').value.trim();
|
|
6637
|
-
cfg.sharing.hub={port:
|
|
6851
|
+
if(hubPort) cfg.sharing.hub={port:Number(hubPort)}; else cfg.sharing.hub={};
|
|
6638
6852
|
if(hubTeamName) cfg.sharing.hub.teamName=hubTeamName;
|
|
6639
6853
|
if(hubTeamToken) cfg.sharing.hub.teamToken=hubTeamToken;
|
|
6640
6854
|
cfg.sharing.client={hubAddress:'',userToken:'',teamToken:''};
|
|
@@ -6651,15 +6865,9 @@ async function saveHubConfig(){
|
|
|
6651
6865
|
if(clientNickname) cfg.sharing.client.nickname=clientNickname;
|
|
6652
6866
|
if(clientTeamToken) cfg.sharing.client.teamToken=clientTeamToken;
|
|
6653
6867
|
if(clientUserToken) cfg.sharing.client.userToken=clientUserToken;
|
|
6654
|
-
cfg.sharing.hub={
|
|
6868
|
+
cfg.sharing.hub={teamName:'',teamToken:''};
|
|
6655
6869
|
if(clientAddr){
|
|
6656
6870
|
try{
|
|
6657
|
-
var ips=await fetch('/api/local-ips').then(function(r){return r.json();});
|
|
6658
|
-
var localAddrs=['127.0.0.1','localhost','0.0.0.0'].concat(ips.ips||[]);
|
|
6659
|
-
var parsed=new URL(clientAddr.indexOf('://')>-1?clientAddr:'http://'+clientAddr);
|
|
6660
|
-
if(localAddrs.indexOf(parsed.hostname)>=0){
|
|
6661
|
-
done();toast(t('sharing.cannotJoinSelf'),'error');return;
|
|
6662
|
-
}
|
|
6663
6871
|
}catch(e){}
|
|
6664
6872
|
try{
|
|
6665
6873
|
var testUrl=clientAddr.indexOf('://')>-1?clientAddr:'http://'+clientAddr;
|
|
@@ -6669,8 +6877,8 @@ async function saveHubConfig(){
|
|
|
6669
6877
|
if(!td.ok){
|
|
6670
6878
|
var errMsg=td.error==='cannot_join_self'?t('sharing.cannotJoinSelf'):(td.error||t('settings.hub.test.fail'));
|
|
6671
6879
|
done();toast(errMsg,'error');return;
|
|
6672
|
-
|
|
6673
|
-
|
|
6880
|
+
}
|
|
6881
|
+
}catch(e){
|
|
6674
6882
|
done();toast(t('settings.hub.test.fail')+': '+String(e),'error');return;
|
|
6675
6883
|
}
|
|
6676
6884
|
}
|
|
@@ -6686,25 +6894,40 @@ async function saveHubConfig(){
|
|
|
6686
6894
|
var switchMsg=prevRole==='hub'?t('sharing.switch.hubToClient'):t('sharing.switch.clientToHub');
|
|
6687
6895
|
if(!(await confirmModal(switchMsg,{danger:true}))){done();return;}
|
|
6688
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
|
+
}
|
|
6689
6903
|
|
|
6690
|
-
var
|
|
6691
|
-
if(
|
|
6904
|
+
var result=await doSaveConfig(cfg, saveBtn, 'hubSaved');
|
|
6905
|
+
if(result){
|
|
6692
6906
|
if(sharingEnabled&&_sharingRole==='hub'){
|
|
6693
6907
|
var adminNameEl=document.getElementById('cfgHubAdminName');
|
|
6694
6908
|
if(adminNameEl&&adminNameEl.value.trim()){
|
|
6695
6909
|
try{await fetch('/api/sharing/update-username',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({username:adminNameEl.value.trim()})});}catch(e){}
|
|
6696
6910
|
}
|
|
6697
6911
|
}
|
|
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');
|
|
6922
|
+
}
|
|
6698
6923
|
_lastSidebarFingerprint='';
|
|
6699
6924
|
_lastSettingsFingerprint='';
|
|
6700
|
-
|
|
6701
|
-
|
|
6702
|
-
|
|
6703
|
-
var needsRestart=enabledChanged||roleChanged;
|
|
6925
|
+
_lastSharingConnStatus='';
|
|
6926
|
+
_lastAdminFingerprint='';
|
|
6927
|
+
_lastAdminStatsFp='';
|
|
6704
6928
|
if(sharingEnabled) updateHubShareInfo();
|
|
6705
|
-
|
|
6706
|
-
|
|
6707
|
-
}
|
|
6929
|
+
loadSharingStatus(true);
|
|
6930
|
+
if(_activeView==='admin') loadAdminData();
|
|
6708
6931
|
}
|
|
6709
6932
|
}
|
|
6710
6933
|
|
|
@@ -6794,6 +7017,8 @@ function renderSkillMarkdown(md){
|
|
|
6794
7017
|
function closeSkillDetail(event){
|
|
6795
7018
|
if(event && event.target!==document.getElementById('skillDetailOverlay')) return;
|
|
6796
7019
|
document.getElementById('skillDetailOverlay').classList.remove('show');
|
|
7020
|
+
currentSkillId='';
|
|
7021
|
+
currentSkillDetail=null;
|
|
6797
7022
|
}
|
|
6798
7023
|
|
|
6799
7024
|
async function deleteSkill(skillId){
|
|
@@ -7128,22 +7353,29 @@ var _livePollBusy=false;
|
|
|
7128
7353
|
async function _livePollTick(){
|
|
7129
7354
|
if(_livePollBusy||document.hidden) return;
|
|
7130
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;});
|
|
7131
7360
|
try{
|
|
7132
|
-
if(sharingStatusCache&&sharingStatusCache.enabled&&_lastSharingConnStatus!=='rejected') loadSharingStatus(false);
|
|
7133
|
-
if(!_notifSSEConnected) pollNotifCount();
|
|
7134
|
-
pollAdminPending();
|
|
7135
|
-
if(_activeView==='admin') loadAdminData();
|
|
7361
|
+
if(sharingStatusCache&&sharingStatusCache.enabled&&_lastSharingConnStatus!=='rejected') await loadSharingStatus(false);
|
|
7362
|
+
if(!_notifSSEConnected) await pollNotifCount();
|
|
7363
|
+
await pollAdminPending();
|
|
7364
|
+
if(_activeView==='admin') await loadAdminData();
|
|
7136
7365
|
else if(_activeView==='memories'){
|
|
7137
7366
|
var _searchVal=(document.getElementById('searchInput')||{}).value||'';
|
|
7138
7367
|
if(!_searchVal.trim()){
|
|
7139
|
-
if(memorySearchScope==='hub') loadHubMemories(true);
|
|
7140
|
-
else{loadStats();loadMemories(null,true);}
|
|
7368
|
+
if(memorySearchScope==='hub') await loadHubMemories(true);
|
|
7369
|
+
else{var _pollOwner=memorySearchScope==='local'?_currentAgentOwner:undefined;await loadStats(_pollOwner);await loadMemories(null,true);}
|
|
7141
7370
|
}
|
|
7142
7371
|
}
|
|
7143
|
-
else if(_activeView==='tasks') loadTasks(true);
|
|
7144
|
-
else if(_activeView==='skills') loadSkills(true);
|
|
7145
|
-
else if(_activeView==='analytics') loadMetrics();
|
|
7372
|
+
else if(_activeView==='tasks') await loadTasks(true);
|
|
7373
|
+
else if(_activeView==='skills') await loadSkills(true);
|
|
7374
|
+
else if(_activeView==='analytics') await loadMetrics();
|
|
7146
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];}
|
|
7147
7379
|
_livePollBusy=false;
|
|
7148
7380
|
}
|
|
7149
7381
|
|
|
@@ -7187,6 +7419,9 @@ function connectNotifSSE(){
|
|
|
7187
7419
|
_notifUnread=d.unreadCount||0;
|
|
7188
7420
|
renderNotifBadge();
|
|
7189
7421
|
if(_notifUnread>prev&&_notifPanelOpen) loadNotifications();
|
|
7422
|
+
if(_notifUnread>prev&&_activeView==='memories'&&memorySearchScope!=='hub'){
|
|
7423
|
+
syncTeamShareRemovedFromNotifications().then(function(){ loadMemories(currentPage,true); });
|
|
7424
|
+
}
|
|
7190
7425
|
}
|
|
7191
7426
|
if(d.type==='cleared'){
|
|
7192
7427
|
_notifUnread=0;_notifCache=[];
|
|
@@ -7236,7 +7471,12 @@ function notifTimeAgo(ts){
|
|
|
7236
7471
|
function notifIcon(resource,type){
|
|
7237
7472
|
if(type==='user_online') return '\\u{1F7E2}';
|
|
7238
7473
|
if(type==='user_offline') return '\\u{1F534}';
|
|
7474
|
+
if(type==='user_left') return '\\u{1F6AA}';
|
|
7239
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}';
|
|
7240
7480
|
if(resource==='memory') return '\\u{1F4DD}';
|
|
7241
7481
|
if(resource==='task') return '\\u{1F4CB}';
|
|
7242
7482
|
if(resource==='skill') return '\\u{1F9E0}';
|
|
@@ -7262,6 +7502,27 @@ function notifTypeText(n){
|
|
|
7262
7502
|
if(n.type==='user_offline'){
|
|
7263
7503
|
return t('notif.userOffline');
|
|
7264
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
|
+
}
|
|
7265
7526
|
return n.message||n.type;
|
|
7266
7527
|
}
|
|
7267
7528
|
|
|
@@ -7296,6 +7557,21 @@ function renderNotifBadge(){
|
|
|
7296
7557
|
}
|
|
7297
7558
|
}
|
|
7298
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
|
+
}
|
|
7299
7575
|
function renderNotifPanel(){
|
|
7300
7576
|
var body=document.getElementById('notifPanelBody');
|
|
7301
7577
|
if(!body) return;
|
|
@@ -7305,11 +7581,12 @@ function renderNotifPanel(){
|
|
|
7305
7581
|
}
|
|
7306
7582
|
body.innerHTML=_notifCache.map(function(n){
|
|
7307
7583
|
var cls='notif-item'+(n.read?'':' unread');
|
|
7584
|
+
var detail=notifDisplayDetail(n);
|
|
7308
7585
|
return '<div class="'+cls+'" onclick="markNotifRead("'+esc(n.id)+'")">'+
|
|
7309
7586
|
'<div class="notif-item-icon">'+notifIcon(n.resource,n.type)+'</div>'+
|
|
7310
7587
|
'<div class="notif-item-body">'+
|
|
7311
|
-
'<div class="notif-item-title">'+esc(
|
|
7312
|
-
'<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>':'')+
|
|
7313
7590
|
'<div class="notif-item-time">'+notifTimeAgo(n.createdAt)+'</div>'+
|
|
7314
7591
|
'</div>'+
|
|
7315
7592
|
'<div class="notif-item-dot"></div>'+
|
|
@@ -7363,6 +7640,7 @@ async function loadAll(){
|
|
|
7363
7640
|
startLivePoller();
|
|
7364
7641
|
}
|
|
7365
7642
|
|
|
7643
|
+
var _lastStatsFp='';
|
|
7366
7644
|
async function loadStats(ownerFilter){
|
|
7367
7645
|
let d;
|
|
7368
7646
|
try{
|
|
@@ -7377,24 +7655,17 @@ async function loadStats(ownerFilter){
|
|
|
7377
7655
|
const dedupB=d.dedupBreakdown||{};
|
|
7378
7656
|
const activeCount=dedupB.active||tm;
|
|
7379
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;
|
|
7380
7662
|
document.getElementById('statTotal').textContent=tm;
|
|
7381
7663
|
if(inactiveCount>0){
|
|
7382
7664
|
document.getElementById('statTotal').title=activeCount+' '+t('stat.active')+', '+inactiveCount+' '+t('stat.deduped');
|
|
7383
7665
|
}
|
|
7384
7666
|
document.getElementById('statSessions').textContent=d.totalSessions||0;
|
|
7385
7667
|
document.getElementById('statEmbeddings').textContent=d.totalEmbeddings||0;
|
|
7386
|
-
|
|
7387
|
-
if(d.timeRange&&d.timeRange.earliest!=null&&d.timeRange.latest!=null){
|
|
7388
|
-
let e=Number(d.timeRange.earliest), l=Number(d.timeRange.latest);
|
|
7389
|
-
if(Number.isFinite(e)&&Number.isFinite(l)){
|
|
7390
|
-
if(e<1e12) e*=1000;
|
|
7391
|
-
if(l<1e12) l*=1000;
|
|
7392
|
-
days=Math.round((l-e)/86400000);
|
|
7393
|
-
days=Math.max(0,Math.min(36500,days));
|
|
7394
|
-
if(days===0) days=1;
|
|
7395
|
-
}
|
|
7396
|
-
}
|
|
7397
|
-
document.getElementById('statTimeSpan').textContent=days;
|
|
7668
|
+
document.getElementById('statAgents').textContent=agentCount;
|
|
7398
7669
|
|
|
7399
7670
|
const provEl=document.getElementById('embeddingStatus');
|
|
7400
7671
|
if(d.embeddingProvider && d.embeddingProvider!=='none'){
|
|
@@ -7489,18 +7760,38 @@ function getFilterParams(){
|
|
|
7489
7760
|
const scope=memorySearchScope||'local';
|
|
7490
7761
|
if(scope==='local'){
|
|
7491
7762
|
p.set('owner',_currentAgentOwner);
|
|
7492
|
-
}else{
|
|
7493
|
-
|
|
7494
|
-
|
|
7763
|
+
}else if(scope==='allLocal'){
|
|
7764
|
+
const owner=document.getElementById('filterOwner').value;
|
|
7765
|
+
if(owner) p.set('owner',owner);
|
|
7495
7766
|
}
|
|
7496
7767
|
return p;
|
|
7497
7768
|
}
|
|
7498
7769
|
|
|
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
|
+
|
|
7499
7789
|
async function loadMemories(page,silent){
|
|
7500
7790
|
if(page) currentPage=page;
|
|
7501
7791
|
const list=document.getElementById('memoryList');
|
|
7502
7792
|
if(!silent) list.innerHTML='<div class="spinner"></div>';
|
|
7503
7793
|
try{
|
|
7794
|
+
if(!silent) await syncTeamShareRemovedFromNotifications();
|
|
7504
7795
|
const p=getFilterParams();
|
|
7505
7796
|
p.set('limit',PAGE_SIZE);
|
|
7506
7797
|
p.set('page',currentPage);
|
|
@@ -7521,11 +7812,11 @@ async function loadMemories(page,silent){
|
|
|
7521
7812
|
renderPagination();
|
|
7522
7813
|
}catch(e){
|
|
7523
7814
|
if(!silent){
|
|
7524
|
-
|
|
7525
|
-
|
|
7815
|
+
list.innerHTML='';
|
|
7816
|
+
totalPages=1;totalCount=0;
|
|
7526
7817
|
_lastMemoriesFingerprint='';
|
|
7527
|
-
|
|
7528
|
-
|
|
7818
|
+
renderMemories([]);
|
|
7819
|
+
renderPagination();
|
|
7529
7820
|
}
|
|
7530
7821
|
}
|
|
7531
7822
|
}
|
|
@@ -7552,9 +7843,9 @@ async function loadHubMemories(silent){
|
|
|
7552
7843
|
}catch(e){
|
|
7553
7844
|
if(!silent){
|
|
7554
7845
|
_lastMemoriesFingerprint='';
|
|
7555
|
-
|
|
7556
|
-
|
|
7557
|
-
|
|
7846
|
+
document.getElementById('searchMeta').textContent='0'+t('search.meta.results');
|
|
7847
|
+
renderMemories([]);
|
|
7848
|
+
document.getElementById('pagination').innerHTML='';
|
|
7558
7849
|
}
|
|
7559
7850
|
}
|
|
7560
7851
|
}
|
|
@@ -7675,7 +7966,7 @@ function renderMemories(items){
|
|
|
7675
7966
|
const mergeBadge=mc>0?'<span class="merge-badge">\\u{1F504} '+t('card.evolved')+' '+mc+t('card.times')+'</span>':'';
|
|
7676
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>':'';
|
|
7677
7968
|
const ds=m.dedup_status||'active';
|
|
7678
|
-
const isInactive=ds==='merged';
|
|
7969
|
+
const isInactive=ds==='merged'||ds==='duplicate';
|
|
7679
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>':'';
|
|
7680
7971
|
const isImported=sid.startsWith('openclaw-import-')||sid.startsWith('openclaw-session-');
|
|
7681
7972
|
const importBadge=isImported?'<span class="import-badge">\u{1F990} '+t('card.imported')+'</span>':'';
|
|
@@ -7684,8 +7975,8 @@ function renderMemories(items){
|
|
|
7684
7975
|
const localManaged=!!m.localSharingManaged;
|
|
7685
7976
|
const memShared=m.sharingVisibility||null;
|
|
7686
7977
|
const isHubScope=memorySearchScope==='hub';
|
|
7687
|
-
const memScope=
|
|
7688
|
-
const memScopeBadge=renderScopeBadge(memScope);
|
|
7978
|
+
const memScope=memShared?'team':isPublicMem?'local':'private';
|
|
7979
|
+
const memScopeBadge=isHubScope?renderScopeBadge('team'):renderScopeBadge(memScope);
|
|
7689
7980
|
let dedupInfo='';
|
|
7690
7981
|
if(ds==='duplicate'||ds==='merged'){
|
|
7691
7982
|
const reason=m.dedup_reason?'<span style="font-size:11px;color:var(--text-muted)">'+t('card.dedupReason')+esc(m.dedup_reason)+'</span>':'';
|
|
@@ -7870,6 +8161,11 @@ function esc(s){
|
|
|
7870
8161
|
if(!s)return'';
|
|
7871
8162
|
return s.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>').replace(/"/g,'"');
|
|
7872
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
|
+
}
|
|
7873
8169
|
|
|
7874
8170
|
function renderSummaryHtml(raw){
|
|
7875
8171
|
if(!raw)return'';
|
|
@@ -8596,18 +8892,25 @@ function confirmModal(message,opts){
|
|
|
8596
8892
|
_confirmResolve=resolve;
|
|
8597
8893
|
var overlay=document.getElementById('confirmOverlay');
|
|
8598
8894
|
document.getElementById('confirmTitle').textContent=opts.title||t('confirm.title')||'\u786E\u8BA4';
|
|
8599
|
-
document.getElementById('confirmBody').
|
|
8895
|
+
document.getElementById('confirmBody').innerText=message||'';
|
|
8600
8896
|
var okBtn=document.getElementById('confirmOkBtn');
|
|
8601
8897
|
okBtn.textContent=opts.okText||t('confirm.ok')||'\u786E\u5B9A';
|
|
8602
8898
|
okBtn.className='btn-confirm-ok'+(opts.danger?' danger':'');
|
|
8603
|
-
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':'';
|
|
8604
8902
|
overlay.classList.add('show');
|
|
8605
8903
|
});
|
|
8606
8904
|
}
|
|
8607
8905
|
function confirmModalClose(result){
|
|
8608
8906
|
document.getElementById('confirmOverlay').classList.remove('show');
|
|
8907
|
+
document.getElementById('confirmCancelBtn').style.display='';
|
|
8609
8908
|
if(_confirmResolve){var r=_confirmResolve;_confirmResolve=null;r(result);}
|
|
8610
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
|
+
}
|
|
8611
8914
|
|
|
8612
8915
|
/* ─── Theme ─── */
|
|
8613
8916
|
const VIEWER_THEME_KEY='memos-viewer-theme';
|
|
@@ -8630,14 +8933,35 @@ function showRestartOverlay(msg){
|
|
|
8630
8933
|
/* ─── Update check ─── */
|
|
8631
8934
|
function waitForGatewayAndReload(maxAttempts,attempt){
|
|
8632
8935
|
attempt=attempt||0;
|
|
8936
|
+
var phase=arguments.length>2?arguments[2]:'waitDown';
|
|
8937
|
+
var MAX_WAIT_DOWN=8;
|
|
8633
8938
|
function forceReload(){window.location.href=window.location.pathname+'?_t='+Date.now();}
|
|
8634
8939
|
if(attempt>=maxAttempts){forceReload();return;}
|
|
8940
|
+
var delay=phase==='waitDown'?1500:2500;
|
|
8635
8941
|
setTimeout(function(){
|
|
8636
8942
|
fetch('/api/auth/status').then(function(r){
|
|
8637
|
-
if(
|
|
8638
|
-
|
|
8639
|
-
|
|
8640
|
-
|
|
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);
|
|
8641
8965
|
}
|
|
8642
8966
|
function doUpdateInstall(packageSpec,btnEl,statusEl){
|
|
8643
8967
|
btnEl.disabled=true;
|
|
@@ -8671,9 +8995,12 @@ async function checkForUpdate(){
|
|
|
8671
8995
|
const d=await r.json();
|
|
8672
8996
|
if(!d.updateAvailable)return;
|
|
8673
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';
|
|
8674
9001
|
var banner=document.createElement('div');
|
|
8675
9002
|
banner.id='updateBanner';
|
|
8676
|
-
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)';
|
|
8677
9004
|
var textNode=document.createElement('div');
|
|
8678
9005
|
textNode.style.cssText='display:flex;align-items:center;gap:8px;flex-shrink:0;font-size:13px';
|
|
8679
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>';
|
|
@@ -8693,18 +9020,30 @@ async function checkForUpdate(){
|
|
|
8693
9020
|
btnClose.innerHTML='×';
|
|
8694
9021
|
btnClose.onmouseenter=function(){this.style.opacity='1'};
|
|
8695
9022
|
btnClose.onmouseleave=function(){this.style.opacity='.5'};
|
|
8696
|
-
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);
|
|
8697
9027
|
banner.appendChild(textNode);
|
|
8698
9028
|
banner.appendChild(statusDiv);
|
|
8699
9029
|
banner.appendChild(spacer);
|
|
8700
9030
|
banner.appendChild(btnClose);
|
|
9031
|
+
bannerWrap.appendChild(banner);
|
|
8701
9032
|
var tb=document.querySelector('.topbar');
|
|
8702
|
-
if(tb&&tb.parentNode){tb.parentNode.insertBefore(
|
|
8703
|
-
else{document.body.insertBefore(
|
|
9033
|
+
if(tb&&tb.parentNode){tb.parentNode.insertBefore(bannerWrap,tb);}
|
|
9034
|
+
else{document.body.insertBefore(bannerWrap,document.body.firstChild);}
|
|
8704
9035
|
}catch(e){}
|
|
8705
9036
|
}
|
|
8706
9037
|
|
|
8707
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){}
|
|
8708
9047
|
document.getElementById('modalOverlay').addEventListener('click',e=>{if(e.target.id==='modalOverlay')closeModal()});
|
|
8709
9048
|
document.getElementById('searchInput').addEventListener('keydown',e=>{if(e.key==='Escape'){e.target.value='';currentPage=1;if(memorySearchScope==='hub')loadHubMemories();else loadMemories();}});
|
|
8710
9049
|
applyI18n();
|