@memtensor/memos-local-openclaw-plugin 1.0.4-beta.7 → 1.0.4-beta.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/capture/index.d.ts.map +1 -1
- package/dist/capture/index.js +6 -0
- package/dist/capture/index.js.map +1 -1
- package/dist/client/connector.d.ts.map +1 -1
- package/dist/client/connector.js +17 -4
- package/dist/client/connector.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +0 -2
- package/dist/config.js.map +1 -1
- package/dist/hub/server.d.ts +7 -0
- package/dist/hub/server.d.ts.map +1 -1
- package/dist/hub/server.js +160 -5
- package/dist/hub/server.js.map +1 -1
- package/dist/ingest/providers/index.d.ts.map +1 -1
- package/dist/ingest/providers/index.js +37 -6
- package/dist/ingest/providers/index.js.map +1 -1
- package/dist/shared/llm-call.d.ts +1 -0
- package/dist/shared/llm-call.d.ts.map +1 -1
- package/dist/shared/llm-call.js +82 -8
- package/dist/shared/llm-call.js.map +1 -1
- package/dist/skill/evolver.d.ts +2 -0
- package/dist/skill/evolver.d.ts.map +1 -1
- package/dist/skill/evolver.js +3 -0
- package/dist/skill/evolver.js.map +1 -1
- package/dist/storage/sqlite.d.ts +4 -1
- package/dist/storage/sqlite.d.ts.map +1 -1
- package/dist/storage/sqlite.js +8 -4
- package/dist/storage/sqlite.js.map +1 -1
- package/dist/telemetry.d.ts +12 -5
- package/dist/telemetry.d.ts.map +1 -1
- package/dist/telemetry.js +135 -38
- package/dist/telemetry.js.map +1 -1
- package/dist/types.d.ts +1 -2
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/viewer/html.d.ts.map +1 -1
- package/dist/viewer/html.js +473 -191
- package/dist/viewer/html.js.map +1 -1
- package/dist/viewer/server.d.ts +14 -0
- package/dist/viewer/server.d.ts.map +1 -1
- package/dist/viewer/server.js +233 -20
- package/dist/viewer/server.js.map +1 -1
- package/index.ts +26 -2
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -2
- package/scripts/postinstall.cjs +1 -1
- package/src/capture/index.ts +8 -0
- package/src/client/connector.ts +17 -4
- package/src/config.ts +0 -2
- package/src/hub/server.ts +157 -5
- package/src/ingest/providers/index.ts +41 -7
- package/src/shared/llm-call.ts +97 -9
- package/src/skill/evolver.ts +5 -0
- package/src/storage/sqlite.ts +11 -6
- package/src/telemetry.ts +152 -39
- package/src/types.ts +1 -2
- package/src/viewer/html.ts +473 -191
- package/src/viewer/server.ts +208 -20
package/dist/viewer/html.js
CHANGED
|
@@ -15,6 +15,7 @@ function viewerHTML(pluginVersion) {
|
|
|
15
15
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
16
16
|
<style>
|
|
17
17
|
*{margin:0;padding:0;box-sizing:border-box}
|
|
18
|
+
html{overflow-y:scroll}
|
|
18
19
|
:root{
|
|
19
20
|
--bg:#0b0d11;--bg-card:#12141a;--bg-card-hover:#1a1d25;
|
|
20
21
|
--border:rgba(255,255,255,.08);--border-glow:rgba(255,255,255,.14);
|
|
@@ -109,7 +110,8 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
109
110
|
|
|
110
111
|
/* ─── App Layout (dark dashboard, same as www) ─── */
|
|
111
112
|
.app{display:none;flex-direction:column;min-height:100vh}
|
|
112
|
-
.topbar{background:rgba(11,13,17,.88);border-bottom:1px solid var(--border);
|
|
113
|
+
.topbar{background:rgba(11,13,17,.88);border-bottom:1px solid var(--border);height:56px;display:flex;align-items:center;position:sticky;top:0;z-index:100;backdrop-filter:blur(12px)}
|
|
114
|
+
.topbar-inner{display:flex;align-items:center;width:100%;max-width:1400px;margin:0 auto;padding:0 32px}
|
|
113
115
|
.topbar .brand{display:flex;align-items:center;gap:8px;font-weight:700;font-size:15px;color:var(--text);letter-spacing:-.02em;flex-shrink:0}
|
|
114
116
|
.topbar .brand .icon{width:24px;height:24px;display:flex;align-items:center;justify-content:center;font-size:18px;background:none;border-radius:0}
|
|
115
117
|
.topbar .brand .brand-title{font-size:13px;font-weight:500;opacity:.7}
|
|
@@ -236,6 +238,21 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
236
238
|
.au-contrib-num{font-size:18px;font-weight:700;line-height:1}
|
|
237
239
|
.au-info{display:flex;flex-wrap:wrap;gap:6px 14px;padding:8px 0;font-size:12px}
|
|
238
240
|
.au-info-item{color:var(--text-muted);white-space:nowrap}
|
|
241
|
+
.au-status-dot{display:inline-block;width:8px;height:8px;border-radius:50%;margin-right:4px;vertical-align:middle;flex-shrink:0}
|
|
242
|
+
.au-status-dot.online{background:#22c55e;box-shadow:0 0 6px rgba(34,197,94,.5)}
|
|
243
|
+
.au-status-dot.offline{background:#9ca3af}
|
|
244
|
+
.au-status-text{font-size:11px;font-weight:500}
|
|
245
|
+
.au-status-text.online{color:#22c55e}
|
|
246
|
+
.au-status-text.offline{color:#9ca3af}
|
|
247
|
+
.au-group-header{font-size:13px;font-weight:600;color:var(--text-sec);margin:18px 0 8px;display:flex;align-items:center;gap:8px}
|
|
248
|
+
.au-group-header:first-child{margin-top:0}
|
|
249
|
+
.au-group-header .au-group-dot{display:inline-block;width:8px;height:8px;border-radius:50%}
|
|
250
|
+
.au-group-header .au-group-dot.online{background:#22c55e}
|
|
251
|
+
.au-group-header .au-group-dot.offline{background:#9ca3af}
|
|
252
|
+
.au-group-header .au-group-count{font-size:12px;font-weight:400;color:var(--text-muted)}
|
|
253
|
+
.au-card.au-offline{opacity:.7}
|
|
254
|
+
.au-card.au-offline::before{background:#9ca3af}
|
|
255
|
+
.au-card.au-online::before{background:#22c55e}
|
|
239
256
|
.admin-card-tags{display:flex;gap:5px;margin:8px 0;align-items:center}
|
|
240
257
|
.admin-card-tags-left{display:flex;flex-wrap:wrap;gap:5px;align-items:center;flex:1;min-width:0}
|
|
241
258
|
.admin-card-tag{display:inline-flex;align-items:center;gap:3px;padding:2px 8px;border-radius:6px;font-size:11px;font-weight:500}
|
|
@@ -542,8 +559,10 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
542
559
|
.pagination .pg-info{font-size:12px;color:var(--text-sec);padding:0 12px}
|
|
543
560
|
|
|
544
561
|
/* ─── Tasks 视图 ─── */
|
|
545
|
-
.
|
|
546
|
-
.
|
|
562
|
+
.view-container{flex:1;min-width:0}
|
|
563
|
+
.view-container>.vp{display:none;flex-direction:column}
|
|
564
|
+
.view-container>.vp.show{display:flex}
|
|
565
|
+
.tasks-view{flex:1;min-width:0;flex-direction:column;gap:16px}
|
|
547
566
|
.tasks-header{display:flex;flex-direction:column;gap:14px}
|
|
548
567
|
.tasks-stats{display:flex;gap:16px}
|
|
549
568
|
.tasks-stat{display:flex;align-items:center;gap:8px;background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius);padding:12px 18px;flex:1;transition:all .2s}
|
|
@@ -621,8 +640,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
621
640
|
[data-theme="light"] .tasks-stat{background:#fff}
|
|
622
641
|
|
|
623
642
|
/* ─── Skills ─── */
|
|
624
|
-
.skills-view{
|
|
625
|
-
.skills-view.show{display:flex}
|
|
643
|
+
.skills-view{flex:1;min-width:0;flex-direction:column;gap:16px}
|
|
626
644
|
.skill-card{background:var(--bg-card);border:1px solid var(--border);border-radius:var(--radius-lg);padding:18px 20px;cursor:pointer;transition:all .25s;position:relative;overflow:hidden}
|
|
627
645
|
.skill-card:hover{border-color:var(--border-glow);background:var(--bg-card-hover);transform:translateY(-1px);box-shadow:var(--shadow)}
|
|
628
646
|
.skill-card::before{content:'';position:absolute;top:0;left:0;bottom:0;width:3px;border-radius:3px 0 0 3px;background:var(--violet)}
|
|
@@ -696,9 +714,8 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
696
714
|
.nav-tabs .tab.active{color:var(--text);background:rgba(255,255,255,.1);border-color:var(--border);box-shadow:0 1px 4px rgba(0,0,0,.15)}
|
|
697
715
|
[data-theme="light"] .nav-tabs{background:rgba(0,0,0,.05)}
|
|
698
716
|
[data-theme="light"] .nav-tabs .tab.active{background:#fff;border-color:rgba(0,0,0,.1);box-shadow:0 1px 3px rgba(0,0,0,.08);color:var(--text)}
|
|
699
|
-
.analytics-view,.settings-view,.logs-view,.migrate-view,.admin-view{
|
|
700
|
-
.analytics-view
|
|
701
|
-
.feed-wrap,.tasks-view,.skills-view,.analytics-view,.settings-view,.logs-view,.migrate-view,.admin-view{max-width:960px}
|
|
717
|
+
.analytics-view,.settings-view,.logs-view,.migrate-view,.admin-view{flex:1;min-width:0;flex-direction:column;gap:20px}
|
|
718
|
+
.feed-wrap,.tasks-view,.skills-view,.analytics-view,.settings-view,.logs-view,.migrate-view,.admin-view{max-width:960px;margin:0 auto}
|
|
702
719
|
|
|
703
720
|
/* ─── Logs ─── */
|
|
704
721
|
.logs-toolbar{display:flex;align-items:center;justify-content:space-between;padding:8px 0}
|
|
@@ -900,7 +917,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
900
917
|
.test-result.ok{color:#22c55e}
|
|
901
918
|
.test-result.fail{color:var(--rose)}
|
|
902
919
|
.test-result.loading{color:var(--text-muted)}
|
|
903
|
-
.settings-actions{display:flex;gap:12px;justify-content:flex-end;align-items:center;margin-top:20px;padding-top:16px;
|
|
920
|
+
.settings-actions{display:flex;gap:12px;justify-content:flex-end;align-items:center;margin-top:20px;padding-top:16px;flex-wrap:nowrap}
|
|
904
921
|
.settings-actions .btn{flex:0 0 auto;min-width:0;padding:8px 24px;font-size:13px}
|
|
905
922
|
.settings-actions .btn-primary{background:rgba(99,102,241,.08);color:var(--pri);border:1px solid rgba(99,102,241,.25);font-weight:600}
|
|
906
923
|
.settings-actions .btn-primary:hover{background:rgba(99,102,241,.14);border-color:var(--pri)}
|
|
@@ -971,8 +988,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
971
988
|
.migrate-log-item .log-meta .tag.error{background:rgba(239,68,68,.1);color:#ef4444}
|
|
972
989
|
.migrate-log-item .log-meta .tag.duplicate{background:rgba(245,158,11,.1);color:#f59e0b}
|
|
973
990
|
@keyframes migrateFadeIn{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}
|
|
974
|
-
.feed-wrap{flex:1;min-width:0;
|
|
975
|
-
.feed-wrap.hide{display:none}
|
|
991
|
+
.feed-wrap{flex:1;min-width:0;flex-direction:column}
|
|
976
992
|
.analytics-view{flex-direction:column;gap:20px}
|
|
977
993
|
.analytics-cards{display:grid;grid-template-columns:repeat(4,1fr);gap:14px}
|
|
978
994
|
.analytics-card{position:relative;overflow:hidden;border-radius:var(--radius-lg);padding:18px 16px;transition:all .2s ease;border:1px solid var(--border);background:var(--bg-card)}
|
|
@@ -1056,7 +1072,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1056
1072
|
[data-theme="light"] .auth-theme-toggle .theme-icon-dark{display:none}
|
|
1057
1073
|
|
|
1058
1074
|
@media(max-width:1100px){.analytics-cards{grid-template-columns:repeat(3,1fr)}}
|
|
1059
|
-
@media(max-width:900px){.main-content{flex-direction:column;padding:20px}.sidebar{width:100%}.sidebar .stats-grid{grid-template-columns:repeat(4,1fr)}.analytics-cards{grid-template-columns:repeat(2,1fr)}.topbar{padding:0 16px;gap:8px}.topbar .brand .brand-title{display:none}.topbar .brand .brand-powered{display:none}.topbar-center{justify-content:flex-start}}
|
|
1075
|
+
@media(max-width:900px){.main-content{flex-direction:column;padding:20px}.sidebar{width:100%}.sidebar .stats-grid{grid-template-columns:repeat(4,1fr)}.analytics-cards{grid-template-columns:repeat(2,1fr)}.topbar-inner{padding:0 16px;gap:8px}.topbar .brand .brand-title{display:none}.topbar .brand .brand-powered{display:none}.topbar-center{justify-content:flex-start}}
|
|
1060
1076
|
</style>
|
|
1061
1077
|
</head>
|
|
1062
1078
|
<body>
|
|
@@ -1141,6 +1157,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1141
1157
|
<!-- ─── Main App ─── -->
|
|
1142
1158
|
<div class="app" id="app">
|
|
1143
1159
|
<div class="topbar">
|
|
1160
|
+
<div class="topbar-inner">
|
|
1144
1161
|
<div class="brand">
|
|
1145
1162
|
<span class="memos-logo"><svg width="28" height="28" viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg"><defs><linearGradient id="topLG" x1="0%" y1="0%" x2="100%" y2="100%"><stop offset="0%" stop-color="#ff4d4d"/><stop offset="100%" stop-color="#991b1b"/></linearGradient></defs><path d="M60 10C30 10 15 35 15 55C15 75 30 95 45 100L45 110L55 110L55 100C55 100 60 102 65 100L65 110L75 110L75 100C90 95 105 75 105 55C105 35 90 10 60 10Z" fill="url(#topLG)"/><path d="M20 45C5 40 0 50 5 60C10 70 20 65 25 55C28 48 25 45 20 45Z" fill="url(#topLG)"/><path d="M100 45C115 40 120 50 115 60C110 70 100 65 95 55C92 48 95 45 100 45Z" fill="url(#topLG)"/><path d="M45 15Q35 5 30 8" stroke="#ff4d4d" stroke-width="2" stroke-linecap="round"/><path d="M75 15Q85 5 90 8" stroke="#ff4d4d" stroke-width="2" stroke-linecap="round"/><circle cx="45" cy="35" r="6" fill="#050810"/><circle cx="75" cy="35" r="6" fill="#050810"/><circle cx="46" cy="34" r="2" fill="#00e5cc"/><circle cx="76" cy="34" r="2" fill="#00e5cc"/></svg></span>
|
|
1146
1163
|
<div class="brand-col"><span data-i18n="title" class="brand-title">MemOS</span><span data-i18n="subtitle" class="brand-powered">Powered by MemOS</span></div>${vBadge}
|
|
@@ -1167,10 +1184,10 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1167
1184
|
<div class="notif-panel-body" id="notifPanelBody"><div class="notif-empty" data-i18n="notif.empty">No notifications</div></div>
|
|
1168
1185
|
</div>
|
|
1169
1186
|
</div>
|
|
1170
|
-
<button class="btn btn-ghost btn-sm" onclick="loadAll()" data-i18n="refresh">\u21BB Refresh</button>
|
|
1171
1187
|
<button class="btn btn-ghost btn-sm" onclick="doLogout()" data-i18n="logout">Logout</button>
|
|
1172
1188
|
</div>
|
|
1173
1189
|
</div>
|
|
1190
|
+
</div>
|
|
1174
1191
|
|
|
1175
1192
|
<div class="main-content">
|
|
1176
1193
|
<div class="sidebar" id="sidebar">
|
|
@@ -1192,18 +1209,19 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1192
1209
|
<button class="btn btn-sm btn-ghost" style="width:100%;margin-top:20px;justify-content:center;color:var(--text-muted);font-size:11px" onclick="clearAll()" data-i18n="sidebar.clear">\u{1F5D1} Clear All Data</button>
|
|
1193
1210
|
</div>
|
|
1194
1211
|
|
|
1195
|
-
<div class="
|
|
1212
|
+
<div class="view-container">
|
|
1213
|
+
<div class="feed-wrap vp show" id="feedWrap">
|
|
1196
1214
|
<div class="feed">
|
|
1197
1215
|
<div class="search-bar">
|
|
1198
1216
|
<span class="search-icon">\u{1F50D}</span>
|
|
1199
1217
|
<input type="text" id="searchInput" data-i18n-ph="search.placeholder" placeholder="Search memories (supports semantic search)..." oninput="debounceSearch()">
|
|
1200
1218
|
<select id="filterOwner" class="filter-select" onchange="onOwnerFilterChange()">
|
|
1201
|
-
<option value="" data-i18n="filter.
|
|
1202
|
-
<option value="public" data-i18n="filter.public">Public</option>
|
|
1219
|
+
<option value="" data-i18n="filter.allagents">All agents</option>
|
|
1203
1220
|
</select>
|
|
1204
1221
|
<select id="memorySearchScope" class="filter-select" onchange="onMemoryScopeChange()">
|
|
1205
|
-
<option value="local" data-i18n="scope.
|
|
1206
|
-
<option value="
|
|
1222
|
+
<option value="local" data-i18n="scope.thisAgent">This Agent</option>
|
|
1223
|
+
<option value="allLocal" data-i18n="scope.thisDevice">This Device</option>
|
|
1224
|
+
<option value="hub" data-i18n="scope.hub">Team</option>
|
|
1207
1225
|
</select>
|
|
1208
1226
|
</div>
|
|
1209
1227
|
<div class="search-meta" id="searchMeta"></div>
|
|
@@ -1232,7 +1250,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1232
1250
|
<div class="pagination" id="pagination"></div>
|
|
1233
1251
|
</div>
|
|
1234
1252
|
</div>
|
|
1235
|
-
<div class="tasks-view" id="tasksView">
|
|
1253
|
+
<div class="tasks-view vp" id="tasksView">
|
|
1236
1254
|
<div class="tasks-header">
|
|
1237
1255
|
<div class="tasks-stats">
|
|
1238
1256
|
<div class="tasks-stat"><span class="tasks-stat-value" id="tasksTotalCount">-</span><span class="tasks-stat-label" data-i18n="tasks.total">Total Tasks</span></div>
|
|
@@ -1246,10 +1264,10 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1246
1264
|
<button class="filter-chip" data-task-status="completed" onclick="setTaskStatusFilter(this,'completed')" data-i18n="tasks.status.completed">Completed</button>
|
|
1247
1265
|
<button class="filter-chip" data-task-status="skipped" onclick="setTaskStatusFilter(this,'skipped')" data-i18n="tasks.status.skipped">Skipped</button>
|
|
1248
1266
|
<select id="taskSearchScope" class="scope-select" onchange="onTaskScopeChange()">
|
|
1249
|
-
<option value="local" data-i18n="scope.
|
|
1250
|
-
<option value="
|
|
1267
|
+
<option value="local" data-i18n="scope.thisAgent">This Agent</option>
|
|
1268
|
+
<option value="allLocal" data-i18n="scope.thisDevice">This Device</option>
|
|
1269
|
+
<option value="hub" data-i18n="scope.hub">Team</option>
|
|
1251
1270
|
</select>
|
|
1252
|
-
<button class="btn btn-sm btn-ghost" onclick="loadTasks()" style="margin-left:auto" data-i18n="refresh">\u21BB Refresh</button>
|
|
1253
1271
|
</div>
|
|
1254
1272
|
</div>
|
|
1255
1273
|
<div class="tasks-list" id="tasksList"><div class="spinner"></div></div>
|
|
@@ -1283,13 +1301,14 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1283
1301
|
<div class="content" id="sharedMemoryContent"></div>
|
|
1284
1302
|
</div>
|
|
1285
1303
|
</div>
|
|
1286
|
-
<div class="skills-view" id="skillsView">
|
|
1304
|
+
<div class="skills-view vp" id="skillsView">
|
|
1287
1305
|
<div class="search-bar">
|
|
1288
1306
|
<span class="search-icon">🔍</span>
|
|
1289
1307
|
<input type="text" id="skillSearchInput" placeholder="Search skills..." data-i18n-ph="skills.search.placeholder" oninput="debounceSkillSearch()">
|
|
1290
1308
|
<select id="skillSearchScope" class="scope-select" onchange="onSkillScopeChange()">
|
|
1291
|
-
<option value="local" data-i18n="scope.
|
|
1292
|
-
<option value="
|
|
1309
|
+
<option value="local" data-i18n="scope.thisAgent">This Agent</option>
|
|
1310
|
+
<option value="allLocal" data-i18n="scope.thisDevice">This Device</option>
|
|
1311
|
+
<option value="hub" data-i18n="scope.hub">Team</option>
|
|
1293
1312
|
</select>
|
|
1294
1313
|
</div>
|
|
1295
1314
|
<div class="search-meta" id="skillSearchMeta"></div>
|
|
@@ -1312,7 +1331,6 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1312
1331
|
<option value="public" data-i18n="filter.public">Public</option>
|
|
1313
1332
|
<option value="private" data-i18n="filter.private">Private</option>
|
|
1314
1333
|
</select>
|
|
1315
|
-
<button class="btn btn-sm btn-ghost" onclick="loadSkills()" style="margin-left:auto" data-i18n="refresh">\u21BB Refresh</button>
|
|
1316
1334
|
</div>
|
|
1317
1335
|
</div>
|
|
1318
1336
|
<div class="tasks-list" id="skillsList"><div class="spinner"></div></div>
|
|
@@ -1345,7 +1363,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1345
1363
|
<div id="skillDetailActions" style="display:flex;gap:8px;margin-top:16px;padding-top:12px;border-top:1px solid var(--border)"></div>
|
|
1346
1364
|
</div>
|
|
1347
1365
|
</div>
|
|
1348
|
-
<div class="analytics-view" id="analyticsView">
|
|
1366
|
+
<div class="analytics-view vp" id="analyticsView">
|
|
1349
1367
|
<div class="metrics-toolbar" style="margin-bottom:0">
|
|
1350
1368
|
<span style="font-size:12px;color:var(--text-sec);font-weight:600" data-i18n="range">Range</span>
|
|
1351
1369
|
<button class="range-btn" data-days="7" onclick="setMetricsDays(7)">7 <span data-i18n="range.days">days</span></button>
|
|
@@ -1389,7 +1407,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1389
1407
|
</div>
|
|
1390
1408
|
|
|
1391
1409
|
<!-- ─── Logs View ─── -->
|
|
1392
|
-
<div class="logs-view" id="logsView">
|
|
1410
|
+
<div class="logs-view vp" id="logsView">
|
|
1393
1411
|
<div class="logs-toolbar">
|
|
1394
1412
|
<div class="logs-toolbar-left">
|
|
1395
1413
|
<select id="logToolFilter" onchange="onLogFilterChange()" style="font-size:12px;padding:4px 8px;border-radius:6px;border:1px solid var(--border);background:var(--card);color:var(--text);min-width:120px">
|
|
@@ -1406,7 +1424,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1406
1424
|
</div>
|
|
1407
1425
|
|
|
1408
1426
|
<!-- ─── Settings View ─── -->
|
|
1409
|
-
<div class="settings-view" id="settingsView">
|
|
1427
|
+
<div class="settings-view vp" id="settingsView">
|
|
1410
1428
|
<div class="settings-tabs-bar">
|
|
1411
1429
|
<button class="settings-tab-btn active" data-tab="models" onclick="switchSettingsTab('models',this)"><span class="stab-dot"></span><span data-i18n="settings.models">AI Models</span></button>
|
|
1412
1430
|
<button class="settings-tab-btn" data-tab="hub" onclick="switchSettingsTab('hub',this)"><span class="stab-dot"></span><span data-i18n="settings.hub">Team Sharing</span></button>
|
|
@@ -1572,7 +1590,6 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1572
1590
|
</div>
|
|
1573
1591
|
</div>
|
|
1574
1592
|
|
|
1575
|
-
<div class="settings-card-divider"></div>
|
|
1576
1593
|
<div class="settings-actions">
|
|
1577
1594
|
<span class="settings-saved" id="modelsSaved">\u2713 <span data-i18n="settings.saved">Saved</span></span>
|
|
1578
1595
|
<button class="btn btn-ghost" onclick="loadConfig()" data-i18n="settings.reset">Reset</button>
|
|
@@ -1661,6 +1678,11 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1661
1678
|
<input type="text" id="cfgHubTeamName" placeholder="My Team">
|
|
1662
1679
|
<div class="field-hint" data-i18n="settings.hub.teamName.hint">Your team display name</div>
|
|
1663
1680
|
</div>
|
|
1681
|
+
<div class="settings-field">
|
|
1682
|
+
<label data-i18n="settings.hub.adminName">Admin Name</label>
|
|
1683
|
+
<input type="text" id="cfgHubAdminName" placeholder="" maxlength="32">
|
|
1684
|
+
<div class="field-hint" data-i18n="settings.hub.adminName.hint">Your display name as team admin</div>
|
|
1685
|
+
</div>
|
|
1664
1686
|
</div>
|
|
1665
1687
|
<div id="hubShareInfo" style="display:none;margin-top:14px;background:var(--bg);border:1px solid var(--border);border-radius:10px;padding:14px 18px">
|
|
1666
1688
|
<div style="font-size:11px;font-weight:600;color:var(--text-muted);text-transform:uppercase;letter-spacing:.04em;margin-bottom:10px" data-i18n="settings.hub.shareInfo.title">Share this info with your team members:</div>
|
|
@@ -1689,6 +1711,11 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1689
1711
|
<input type="text" id="cfgClientTeamToken" placeholder="">
|
|
1690
1712
|
<div class="field-hint" data-i18n="settings.hub.teamTokenClient.hint">Get this from your team admin to join</div>
|
|
1691
1713
|
</div>
|
|
1714
|
+
<div class="settings-field">
|
|
1715
|
+
<label data-i18n="settings.hub.nickname">Nickname</label>
|
|
1716
|
+
<input type="text" id="cfgClientNickname" placeholder="" maxlength="32">
|
|
1717
|
+
<div class="field-hint" data-i18n="settings.hub.nickname.hint">Your display name in the team. If empty, uses system username.</div>
|
|
1718
|
+
</div>
|
|
1692
1719
|
<input type="hidden" id="cfgClientUserToken" value="">
|
|
1693
1720
|
</div>
|
|
1694
1721
|
<div style="margin-top:12px">
|
|
@@ -1743,7 +1770,6 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1743
1770
|
</div>
|
|
1744
1771
|
<div class="field-hint" style="margin-top:6px" data-i18n="settings.telemetry.hint">Anonymous usage analytics to help improve the plugin. Only sends tool names, latencies, and version info. No memory content, queries, or personal data is ever sent.</div>
|
|
1745
1772
|
|
|
1746
|
-
<div class="settings-card-divider"></div>
|
|
1747
1773
|
<div class="settings-actions">
|
|
1748
1774
|
<span class="settings-saved" id="generalSaved">\u2713 <span data-i18n="settings.saved">Saved</span></span>
|
|
1749
1775
|
<button class="btn btn-ghost" onclick="loadConfig()" data-i18n="settings.reset">Reset</button>
|
|
@@ -1758,7 +1784,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1758
1784
|
</div>
|
|
1759
1785
|
|
|
1760
1786
|
<!-- ─── Admin Page ─── -->
|
|
1761
|
-
<div class="admin-view" id="adminView">
|
|
1787
|
+
<div class="admin-view vp" id="adminView">
|
|
1762
1788
|
<div id="adminNotEnabled" style="display:none"></div>
|
|
1763
1789
|
<div id="adminMainContent">
|
|
1764
1790
|
<div class="admin-header">
|
|
@@ -1783,7 +1809,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1783
1809
|
</div>
|
|
1784
1810
|
|
|
1785
1811
|
<!-- ─── Import Page ─── -->
|
|
1786
|
-
<div class="migrate-view" id="migrateView">
|
|
1812
|
+
<div class="migrate-view vp" id="migrateView">
|
|
1787
1813
|
<div class="settings-section" style="border:1px solid rgba(99,102,241,.15)">
|
|
1788
1814
|
<h3><span class="icon">\u{1F4E5}</span> <span data-i18n="migrate.title">Import OpenClaw Memory</span></h3>
|
|
1789
1815
|
<p style="font-size:12px;color:var(--text-sec);margin-bottom:12px;line-height:1.6" data-i18n="migrate.desc">Migrate your existing OpenClaw built-in memories and conversation history into this plugin. The import process uses smart deduplication to avoid duplicates.</p>
|
|
@@ -1953,6 +1979,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1953
1979
|
|
|
1954
1980
|
</div>
|
|
1955
1981
|
|
|
1982
|
+
</div>
|
|
1956
1983
|
</div>
|
|
1957
1984
|
</div>
|
|
1958
1985
|
|
|
@@ -2027,6 +2054,8 @@ const I18N={
|
|
|
2027
2054
|
'skills.load.error':'Failed to load skills',
|
|
2028
2055
|
'skills.hub.title':'\u{1F310} Team Skills',
|
|
2029
2056
|
'scope.local':'Local',
|
|
2057
|
+
'scope.thisAgent':'This Agent',
|
|
2058
|
+
'scope.thisDevice':'This Device',
|
|
2030
2059
|
'scope.group':'Group',
|
|
2031
2060
|
'scope.all':'All',
|
|
2032
2061
|
'skills.visibility.public':'Shared Locally',
|
|
@@ -2055,6 +2084,15 @@ const I18N={
|
|
|
2055
2084
|
'notif.removed.memory':'Your shared memory was removed by admin',
|
|
2056
2085
|
'notif.removed.task':'Your shared task was removed by admin',
|
|
2057
2086
|
'notif.removed.skill':'Your shared skill was removed by admin',
|
|
2087
|
+
'notif.shared.memory':'A new memory was shared',
|
|
2088
|
+
'notif.shared.task':'A new task was shared',
|
|
2089
|
+
'notif.shared.skill':'A new skill was shared',
|
|
2090
|
+
'notif.unshared.memory':'A memory was unshared',
|
|
2091
|
+
'notif.unshared.task':'A task was unshared',
|
|
2092
|
+
'notif.unshared.skill':'A skill was unshared',
|
|
2093
|
+
'notif.userJoin':'New user requests to join the team',
|
|
2094
|
+
'notif.userOnline':'User came online',
|
|
2095
|
+
'notif.userOffline':'User went offline',
|
|
2058
2096
|
'notif.clearAll':'Clear all',
|
|
2059
2097
|
'notif.timeAgo.just':'just now',
|
|
2060
2098
|
'notif.timeAgo.min':'{n}m ago',
|
|
@@ -2078,6 +2116,7 @@ const I18N={
|
|
|
2078
2116
|
'filter.newest':'Newest first',
|
|
2079
2117
|
'filter.oldest':'Oldest first',
|
|
2080
2118
|
'filter.allowners':'All owners',
|
|
2119
|
+
'filter.allagents':'All agents',
|
|
2081
2120
|
'filter.allsessions':'All sessions',
|
|
2082
2121
|
'filter.public':'Public',
|
|
2083
2122
|
'filter.private':'Private',
|
|
@@ -2326,6 +2365,8 @@ const I18N={
|
|
|
2326
2365
|
'settings.hub.port.hint':'Port for team server. Default: 18800',
|
|
2327
2366
|
'settings.hub.teamName':'Team Name',
|
|
2328
2367
|
'settings.hub.teamName.hint':'Display name for your team',
|
|
2368
|
+
'settings.hub.adminName':'Admin Name',
|
|
2369
|
+
'settings.hub.adminName.hint':'Your display name as team admin',
|
|
2329
2370
|
'settings.hub.teamToken':'Team Token',
|
|
2330
2371
|
'settings.hub.teamToken.hint':'Auto-generated secret for clients to join. Click to copy. Share this with your team members.',
|
|
2331
2372
|
'settings.hub.tokenCopied':'Team Token copied!',
|
|
@@ -2345,6 +2386,8 @@ const I18N={
|
|
|
2345
2386
|
'settings.hub.hubAddress.hint':'Team server address, e.g. 192.168.1.100:18800',
|
|
2346
2387
|
'settings.hub.teamTokenClient':'Team Token',
|
|
2347
2388
|
'settings.hub.teamTokenClient.hint':'Get this from your team admin to join',
|
|
2389
|
+
'settings.hub.nickname':'Nickname',
|
|
2390
|
+
'settings.hub.nickname.hint':'Your display name in the team. If empty, uses system username.',
|
|
2348
2391
|
'settings.hub.userToken':'User Token',
|
|
2349
2392
|
'settings.hub.userToken.hint':'Usually auto-obtained after joining. Only fill if given by admin.',
|
|
2350
2393
|
'settings.hub.testConnection':'Test Connection',
|
|
@@ -2383,6 +2426,7 @@ const I18N={
|
|
|
2383
2426
|
'memory.detail.viewTarget':'View target: ',
|
|
2384
2427
|
'admin.title':'Team Admin Panel',
|
|
2385
2428
|
'admin.subtitle':'Manage team members and shared resources',
|
|
2429
|
+
'admin.subtitle.member':'Browse shared memories, tasks and skills from your team',
|
|
2386
2430
|
'admin.refresh':'\u21BB Refresh',
|
|
2387
2431
|
'admin.tab.users':'Users',
|
|
2388
2432
|
'admin.tab.tasks':'Shared Tasks',
|
|
@@ -2398,6 +2442,12 @@ const I18N={
|
|
|
2398
2442
|
'admin.pendingApproval':'Pending Approval',
|
|
2399
2443
|
'admin.activeUsers':'Active Users',
|
|
2400
2444
|
'admin.noActiveUsers':'No active users.',
|
|
2445
|
+
'admin.onlineUsers':'Online',
|
|
2446
|
+
'admin.offlineUsers':'Offline',
|
|
2447
|
+
'admin.online':'Online',
|
|
2448
|
+
'admin.offline':'Offline',
|
|
2449
|
+
'admin.offlineFor':'Offline for {time}',
|
|
2450
|
+
'admin.onlineNow':'Online now',
|
|
2401
2451
|
'admin.approve':'Approve',
|
|
2402
2452
|
'admin.reject':'Reject',
|
|
2403
2453
|
'admin.device':'Device: ',
|
|
@@ -2414,6 +2464,7 @@ const I18N={
|
|
|
2414
2464
|
'admin.demoteMember':'Demote to Member',
|
|
2415
2465
|
'admin.editName':'Edit Name',
|
|
2416
2466
|
'admin.lastAdminHint':'Last admin — cannot remove or demote',
|
|
2467
|
+
'admin.ownerHint':'Hub owner — cannot be demoted or removed',
|
|
2417
2468
|
'admin.editNamePrompt':'Enter new username:',
|
|
2418
2469
|
'confirm.promoteAdmin':'Promote this user to admin? They will be able to manage all team members and resources.',
|
|
2419
2470
|
'confirm.demoteMember':'Demote this admin to member?',
|
|
@@ -2708,6 +2759,8 @@ const I18N={
|
|
|
2708
2759
|
'skills.load.error':'加载技能失败',
|
|
2709
2760
|
'skills.hub.title':'\u{1F310} 团队共享技能',
|
|
2710
2761
|
'scope.local':'本地',
|
|
2762
|
+
'scope.thisAgent':'当前智能体',
|
|
2763
|
+
'scope.thisDevice':'本机全部',
|
|
2711
2764
|
'scope.group':'团队',
|
|
2712
2765
|
'scope.all':'全部',
|
|
2713
2766
|
'skills.visibility.public':'本机共享',
|
|
@@ -2736,6 +2789,15 @@ const I18N={
|
|
|
2736
2789
|
'notif.removed.memory':'你共享的记忆被管理员移除',
|
|
2737
2790
|
'notif.removed.task':'你共享的任务被管理员移除',
|
|
2738
2791
|
'notif.removed.skill':'你共享的技能被管理员移除',
|
|
2792
|
+
'notif.shared.memory':'有新的记忆被共享',
|
|
2793
|
+
'notif.shared.task':'有新的任务被共享',
|
|
2794
|
+
'notif.shared.skill':'有新的技能被共享',
|
|
2795
|
+
'notif.unshared.memory':'有记忆取消了共享',
|
|
2796
|
+
'notif.unshared.task':'有任务取消了共享',
|
|
2797
|
+
'notif.unshared.skill':'有技能取消了共享',
|
|
2798
|
+
'notif.userJoin':'有新用户申请加入团队',
|
|
2799
|
+
'notif.userOnline':'用户上线了',
|
|
2800
|
+
'notif.userOffline':'用户下线了',
|
|
2739
2801
|
'notif.clearAll':'清除全部',
|
|
2740
2802
|
'notif.timeAgo.just':'刚刚',
|
|
2741
2803
|
'notif.timeAgo.min':'{n}分钟前',
|
|
@@ -2759,6 +2821,7 @@ const I18N={
|
|
|
2759
2821
|
'filter.newest':'最新优先',
|
|
2760
2822
|
'filter.oldest':'最早优先',
|
|
2761
2823
|
'filter.allowners':'所有归属',
|
|
2824
|
+
'filter.allagents':'全部智能体',
|
|
2762
2825
|
'filter.allsessions':'全部会话',
|
|
2763
2826
|
'filter.public':'公开',
|
|
2764
2827
|
'filter.private':'私有',
|
|
@@ -3007,6 +3070,8 @@ const I18N={
|
|
|
3007
3070
|
'settings.hub.port.hint':'团队服务端口,默认 18800',
|
|
3008
3071
|
'settings.hub.teamName':'团队名称',
|
|
3009
3072
|
'settings.hub.teamName.hint':'你的团队显示名称',
|
|
3073
|
+
'settings.hub.adminName':'管理员名称',
|
|
3074
|
+
'settings.hub.adminName.hint':'你在团队中的显示名称',
|
|
3010
3075
|
'settings.hub.teamToken':'团队令牌',
|
|
3011
3076
|
'settings.hub.teamToken.hint':'自动生成的密钥,点击可复制。请将此令牌分享给团队成员。',
|
|
3012
3077
|
'settings.hub.tokenCopied':'团队令牌已复制!',
|
|
@@ -3026,6 +3091,8 @@ const I18N={
|
|
|
3026
3091
|
'settings.hub.hubAddress.hint':'团队服务器地址,如 192.168.1.100:18800',
|
|
3027
3092
|
'settings.hub.teamTokenClient':'团队令牌',
|
|
3028
3093
|
'settings.hub.teamTokenClient.hint':'向团队管理员获取此令牌以加入团队',
|
|
3094
|
+
'settings.hub.nickname':'昵称',
|
|
3095
|
+
'settings.hub.nickname.hint':'你在团队中的显示名称。留空则使用系统用户名。',
|
|
3029
3096
|
'settings.hub.userToken':'用户令牌',
|
|
3030
3097
|
'settings.hub.userToken.hint':'通常在加入团队后自动获取,无需手动填写。',
|
|
3031
3098
|
'settings.hub.testConnection':'测试连接',
|
|
@@ -3064,6 +3131,7 @@ const I18N={
|
|
|
3064
3131
|
'memory.detail.viewTarget':'查看目标: ',
|
|
3065
3132
|
'admin.title':'团队管理面板',
|
|
3066
3133
|
'admin.subtitle':'管理团队成员和共享资源',
|
|
3134
|
+
'admin.subtitle.member':'浏览团队共享的记忆、任务和技能',
|
|
3067
3135
|
'admin.refresh':'\u21BB 刷新',
|
|
3068
3136
|
'admin.tab.users':'用户',
|
|
3069
3137
|
'admin.tab.tasks':'共享任务',
|
|
@@ -3079,6 +3147,12 @@ const I18N={
|
|
|
3079
3147
|
'admin.pendingApproval':'待审批',
|
|
3080
3148
|
'admin.activeUsers':'活跃用户',
|
|
3081
3149
|
'admin.noActiveUsers':'暂无活跃用户。',
|
|
3150
|
+
'admin.onlineUsers':'在线',
|
|
3151
|
+
'admin.offlineUsers':'离线',
|
|
3152
|
+
'admin.online':'在线',
|
|
3153
|
+
'admin.offline':'离线',
|
|
3154
|
+
'admin.offlineFor':'离线 {time}',
|
|
3155
|
+
'admin.onlineNow':'当前在线',
|
|
3082
3156
|
'admin.approve':'批准',
|
|
3083
3157
|
'admin.reject':'拒绝',
|
|
3084
3158
|
'admin.device':'设备:',
|
|
@@ -3095,6 +3169,7 @@ const I18N={
|
|
|
3095
3169
|
'admin.demoteMember':'降为成员',
|
|
3096
3170
|
'admin.editName':'编辑名称',
|
|
3097
3171
|
'admin.lastAdminHint':'唯一管理员 — 无法删除或降级',
|
|
3172
|
+
'admin.ownerHint':'Hub 创建者 — 不可降级或移除',
|
|
3098
3173
|
'admin.editNamePrompt':'请输入新用户名:',
|
|
3099
3174
|
'confirm.promoteAdmin':'确定要将此用户提升为管理员吗?管理员可以管理所有团队成员和资源。',
|
|
3100
3175
|
'confirm.demoteMember':'确定要将此管理员降为普通成员吗?',
|
|
@@ -3552,59 +3627,41 @@ function switchSettingsTab(tab,btn){
|
|
|
3552
3627
|
});
|
|
3553
3628
|
}
|
|
3554
3629
|
|
|
3630
|
+
var _activeView='memories';
|
|
3555
3631
|
function switchView(view){
|
|
3632
|
+
_activeView=view;
|
|
3556
3633
|
document.querySelectorAll('.nav-tabs .tab').forEach(t=>t.classList.toggle('active',t.dataset.view===view));
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
const settingsView=document.getElementById('settingsView');
|
|
3563
|
-
const migrateView=document.getElementById('migrateView');
|
|
3564
|
-
const adminView=document.getElementById('adminView');
|
|
3565
|
-
const sidebar=document.getElementById('sidebar');
|
|
3566
|
-
feedWrap.classList.add('hide');
|
|
3567
|
-
analyticsView.classList.remove('show');
|
|
3568
|
-
tasksView.classList.remove('show');
|
|
3569
|
-
skillsView.classList.remove('show');
|
|
3570
|
-
logsView.classList.remove('show');
|
|
3571
|
-
settingsView.classList.remove('show');
|
|
3572
|
-
migrateView.classList.remove('show');
|
|
3573
|
-
if(adminView) adminView.classList.remove('show');
|
|
3634
|
+
var viewMap={memories:'feedWrap',tasks:'tasksView',skills:'skillsView',analytics:'analyticsView',logs:'logsView',settings:'settingsView',import:'migrateView',admin:'adminView'};
|
|
3635
|
+
for(var k in viewMap){
|
|
3636
|
+
var el=document.getElementById(viewMap[k]);
|
|
3637
|
+
if(el) el.classList.toggle('show',k===view);
|
|
3638
|
+
}
|
|
3574
3639
|
var sessionSection=document.getElementById('sidebarSessionSection');
|
|
3575
|
-
if(
|
|
3576
|
-
|
|
3577
|
-
|
|
3578
|
-
} else if(view==='tasks'||view==='skills'){
|
|
3579
|
-
if(sessionSection){sessionSection.style.visibility='hidden';sessionSection.style.pointerEvents='none';}
|
|
3580
|
-
if(view==='tasks'){tasksView.classList.add('show');loadTasks();}
|
|
3581
|
-
else{skillsView.classList.add('show');loadSkills();}
|
|
3582
|
-
} else {
|
|
3583
|
-
if(sessionSection){sessionSection.style.visibility='hidden';sessionSection.style.pointerEvents='none';}
|
|
3584
|
-
if(view==='analytics'){
|
|
3585
|
-
analyticsView.classList.add('show');
|
|
3586
|
-
loadMetrics();
|
|
3587
|
-
} else if(view==='logs'){
|
|
3588
|
-
logsView.classList.add('show');
|
|
3589
|
-
loadLogs();
|
|
3590
|
-
} else if(view==='settings'){
|
|
3591
|
-
settingsView.classList.add('show');
|
|
3592
|
-
loadConfig();
|
|
3593
|
-
loadModelHealth();
|
|
3594
|
-
} else if(view==='import'){
|
|
3595
|
-
migrateView.classList.add('show');
|
|
3596
|
-
if(!window._migrateRunning) migrateScan(false);
|
|
3597
|
-
} else if(view==='admin'){
|
|
3598
|
-
if(adminView){adminView.classList.add('show');loadAdminData();}
|
|
3599
|
-
}
|
|
3640
|
+
if(sessionSection){
|
|
3641
|
+
if(view==='memories'){sessionSection.style.visibility='';sessionSection.style.pointerEvents='';}
|
|
3642
|
+
else{sessionSection.style.visibility='hidden';sessionSection.style.pointerEvents='none';}
|
|
3600
3643
|
}
|
|
3644
|
+
if(view==='tasks') loadTasks();
|
|
3645
|
+
else if(view==='skills') loadSkills();
|
|
3646
|
+
else if(view==='analytics') loadMetrics();
|
|
3647
|
+
else if(view==='logs') loadLogs();
|
|
3648
|
+
else if(view==='settings'){loadConfig();loadModelHealth();}
|
|
3649
|
+
else if(view==='import'){if(!window._migrateRunning) migrateScan(false);}
|
|
3650
|
+
else if(view==='admin'){loadAdminData();}
|
|
3601
3651
|
}
|
|
3602
3652
|
|
|
3603
3653
|
function onMemoryScopeChange(){
|
|
3604
3654
|
memorySearchScope=document.getElementById('memorySearchScope')?.value||'local';
|
|
3655
|
+
var isHub=memorySearchScope==='hub';
|
|
3656
|
+
var ownerSel=document.getElementById('filterOwner');
|
|
3657
|
+
var filterBar=document.getElementById('filterBar');
|
|
3658
|
+
var dateFilter=document.querySelector('.date-filter');
|
|
3659
|
+
if(ownerSel) ownerSel.style.display=isHub?'none':'';
|
|
3660
|
+
if(filterBar) filterBar.style.display=isHub?'none':'';
|
|
3661
|
+
if(dateFilter) dateFilter.style.display=isHub?'none':'';
|
|
3605
3662
|
if(document.getElementById('searchInput').value.trim()) doSearch(document.getElementById('searchInput').value);
|
|
3606
|
-
else if(
|
|
3607
|
-
else { document.getElementById('sharingSearchMeta').textContent=''; loadMemories(); }
|
|
3663
|
+
else if(isHub) { document.getElementById('sharingSearchMeta').textContent=''; loadHubMemories(); }
|
|
3664
|
+
else { document.getElementById('sharingSearchMeta').textContent=''; loadStats(); loadMemories(); }
|
|
3608
3665
|
}
|
|
3609
3666
|
|
|
3610
3667
|
function onSkillScopeChange(){
|
|
@@ -3722,8 +3779,12 @@ function renderSharingSettings(data){
|
|
|
3722
3779
|
var hubAdminBtn=document.getElementById('hubAdminEntryBtn');
|
|
3723
3780
|
|
|
3724
3781
|
if(actualRole==='hub'){
|
|
3725
|
-
|
|
3782
|
+
teamEl.innerHTML='';adminEl.innerHTML='';statusEl.innerHTML='';statusEl.style.display='none';
|
|
3726
3783
|
if(hubAdminBtn) hubAdminBtn.style.display=isAdmin?'':'none';
|
|
3784
|
+
var hubUser=conn.user||{};
|
|
3785
|
+
var hubName=hubUser.username||'admin';
|
|
3786
|
+
var adminNameInput=document.getElementById('cfgHubAdminName');
|
|
3787
|
+
if(adminNameInput) adminNameInput.value=hubName;
|
|
3727
3788
|
return;
|
|
3728
3789
|
}
|
|
3729
3790
|
|
|
@@ -3915,6 +3976,8 @@ function guideGoToHub(role){
|
|
|
3915
3976
|
|
|
3916
3977
|
/* ─── Hub Admin Panel ─── */
|
|
3917
3978
|
var adminDataCache={users:[],groups:[],tasks:[],skills:[],memories:[]};
|
|
3979
|
+
var hubTasksCache=[];
|
|
3980
|
+
var hubSkillsCache=[];
|
|
3918
3981
|
var ADMIN_PAGE_SIZE=20;
|
|
3919
3982
|
var adminPage={users:0,tasks:0,skills:0,memories:0};
|
|
3920
3983
|
|
|
@@ -3936,12 +3999,9 @@ function adminPaginateHtml(total,page,refilterFn){
|
|
|
3936
3999
|
}
|
|
3937
4000
|
|
|
3938
4001
|
var _adminPollTimer=null;
|
|
3939
|
-
function startAdminPoll(){
|
|
3940
|
-
if(_adminPollTimer) return;
|
|
3941
|
-
_adminPollTimer=setInterval(function(){pollAdminPending();},30000);
|
|
3942
|
-
pollAdminPending();
|
|
3943
|
-
}
|
|
4002
|
+
function startAdminPoll(){ startLivePoller(); }
|
|
3944
4003
|
async function pollAdminPending(){
|
|
4004
|
+
if(!window._isHubAdmin) return;
|
|
3945
4005
|
try{
|
|
3946
4006
|
var r=await fetch('/api/sharing/pending-users');
|
|
3947
4007
|
var d=await r.json();
|
|
@@ -3991,24 +4051,32 @@ async function loadAdminData(){
|
|
|
3991
4051
|
}
|
|
3992
4052
|
if(notEnabledEl) notEnabledEl.style.display='none';
|
|
3993
4053
|
if(mainEl) mainEl.style.display='';
|
|
3994
|
-
|
|
3995
|
-
var statsEl=document.getElementById('adminStats');
|
|
3996
|
-
if(statsEl) statsEl.innerHTML='<div class="admin-empty">'+t('admin.noPermission')+'</div>';
|
|
3997
|
-
return;
|
|
3998
|
-
}
|
|
4054
|
+
var isAdmin=!!window._isHubAdmin;
|
|
3999
4055
|
try{
|
|
4000
|
-
var
|
|
4001
|
-
|
|
4002
|
-
|
|
4003
|
-
|
|
4004
|
-
|
|
4005
|
-
|
|
4006
|
-
|
|
4056
|
+
var fetches;
|
|
4057
|
+
if(isAdmin){
|
|
4058
|
+
fetches=await Promise.all([
|
|
4059
|
+
fetch('/api/sharing/users').then(function(r){return r.json();}),
|
|
4060
|
+
fetch('/api/admin/shared-tasks').then(function(r){return r.json();}),
|
|
4061
|
+
fetch('/api/admin/shared-skills').then(function(r){return r.json();}),
|
|
4062
|
+
fetch('/api/sharing/pending-users').then(function(r){return r.json();}),
|
|
4063
|
+
fetch('/api/admin/shared-memories').then(function(r){return r.json();})
|
|
4064
|
+
]);
|
|
4065
|
+
}else{
|
|
4066
|
+
fetches=await Promise.all([
|
|
4067
|
+
Promise.resolve({users:[]}),
|
|
4068
|
+
fetch('/api/sharing/tasks/list?limit=500').then(function(r){return r.json();}),
|
|
4069
|
+
fetch('/api/sharing/skills/list?limit=500').then(function(r){return r.json();}),
|
|
4070
|
+
Promise.resolve({users:[]}),
|
|
4071
|
+
fetch('/api/sharing/memories/list?limit=500').then(function(r){return r.json();})
|
|
4072
|
+
]);
|
|
4073
|
+
}
|
|
4074
|
+
var usersR=fetches[0],tasksR=fetches[1],skillsR=fetches[2],pendingR=fetches[3],memoriesR=fetches[4];
|
|
4007
4075
|
adminDataCache.users=Array.isArray(usersR.users)?usersR.users:[];
|
|
4008
4076
|
adminDataCache.tasks=Array.isArray(tasksR.tasks)?tasksR.tasks:[];
|
|
4009
4077
|
adminDataCache.skills=Array.isArray(skillsR.skills)?skillsR.skills:[];
|
|
4010
4078
|
adminDataCache.memories=Array.isArray(memoriesR.memories)?memoriesR.memories:[];
|
|
4011
|
-
var pending=Array.isArray(pendingR.users)?pendingR.users:[];
|
|
4079
|
+
var pending=isAdmin?(Array.isArray(pendingR.users)?pendingR.users:[]):[];
|
|
4012
4080
|
adminDataCache._pending=pending;
|
|
4013
4081
|
var badge=document.getElementById('adminPendingBadge');
|
|
4014
4082
|
if(badge){if(pending.length>0){badge.textContent=pending.length;badge.style.display='inline';}else{badge.style.display='none';}}
|
|
@@ -4017,18 +4085,48 @@ async function loadAdminData(){
|
|
|
4017
4085
|
renderAdminTasks(adminDataCache.tasks);
|
|
4018
4086
|
renderAdminSkills(adminDataCache.skills);
|
|
4019
4087
|
renderAdminMemories(adminDataCache.memories);
|
|
4088
|
+
updateAdminTabsVisibility();
|
|
4020
4089
|
}catch(e){
|
|
4021
4090
|
var statsEl=document.getElementById('adminStats');
|
|
4022
4091
|
if(statsEl) statsEl.innerHTML='<div class="admin-empty">'+t('admin.loadFailed')+esc(String(e))+'</div>';
|
|
4023
4092
|
}
|
|
4024
4093
|
}
|
|
4094
|
+
function updateAdminTabsVisibility(){
|
|
4095
|
+
var bar=document.getElementById('adminTabsBar');
|
|
4096
|
+
if(!bar) return;
|
|
4097
|
+
var tabs=bar.querySelectorAll('.admin-tab');
|
|
4098
|
+
var isAdmin=!!window._isHubAdmin;
|
|
4099
|
+
tabs.forEach(function(tab){
|
|
4100
|
+
var onclick=tab.getAttribute('onclick')||'';
|
|
4101
|
+
if(onclick.indexOf("'users'")!==-1){
|
|
4102
|
+
tab.style.display=isAdmin?'':'none';
|
|
4103
|
+
}
|
|
4104
|
+
});
|
|
4105
|
+
if(!isAdmin){
|
|
4106
|
+
var usersPanel=document.getElementById('adminUsersPanel');
|
|
4107
|
+
if(usersPanel&&usersPanel.classList.contains('active')){
|
|
4108
|
+
usersPanel.classList.remove('active');
|
|
4109
|
+
var memPanel=document.getElementById('adminMemoriesPanel');
|
|
4110
|
+
if(memPanel) memPanel.classList.add('active');
|
|
4111
|
+
tabs.forEach(function(tab){
|
|
4112
|
+
tab.classList.remove('active');
|
|
4113
|
+
var onclick=tab.getAttribute('onclick')||'';
|
|
4114
|
+
if(onclick.indexOf("'memories'")!==-1) tab.classList.add('active');
|
|
4115
|
+
});
|
|
4116
|
+
}
|
|
4117
|
+
}
|
|
4118
|
+
var subEl=document.querySelector('.admin-header-sub');
|
|
4119
|
+
if(subEl) subEl.textContent=isAdmin?t('admin.subtitle'):t('admin.subtitle.member');
|
|
4120
|
+
}
|
|
4025
4121
|
|
|
4026
4122
|
function renderAdminStats(pendingCount){
|
|
4027
4123
|
var el=document.getElementById('adminStats');
|
|
4028
4124
|
if(!el) return;
|
|
4125
|
+
var isAdmin=!!window._isHubAdmin;
|
|
4126
|
+
var onlineCount=adminDataCache.users.filter(function(u){return !!u.isOnline;}).length;
|
|
4029
4127
|
el.innerHTML=
|
|
4030
|
-
'<div class="admin-stat-box"><span class="as-icon">\u{1F465}</span><div class="val">'+adminDataCache.users.length+'</div><div class="lbl">'+t('admin.stat.activeUsers')+'</div></div>'+
|
|
4031
|
-
'<div class="admin-stat-box"><span class="as-icon">\u{23F3}</span><div class="val">'+pendingCount+'</div><div class="lbl">'+t('admin.stat.pending')+'</div></div>'+
|
|
4128
|
+
(isAdmin?'<div class="admin-stat-box"><span class="as-icon">\u{1F465}</span><div class="val">'+onlineCount+' / '+adminDataCache.users.length+'</div><div class="lbl">'+t('admin.stat.activeUsers')+'</div></div>'+
|
|
4129
|
+
'<div class="admin-stat-box"><span class="as-icon">\u{23F3}</span><div class="val">'+pendingCount+'</div><div class="lbl">'+t('admin.stat.pending')+'</div></div>':'')+
|
|
4032
4130
|
'<div class="admin-stat-box"><span class="as-icon">\u{1F4AD}</span><div class="val">'+(adminDataCache.memories||[]).length+'</div><div class="lbl">'+t('admin.stat.sharedMemories')+'</div></div>'+
|
|
4033
4131
|
'<div class="admin-stat-box"><span class="as-icon">\u{1F4CB}</span><div class="val">'+adminDataCache.tasks.length+'</div><div class="lbl">'+t('admin.stat.sharedTasks')+'</div></div>'+
|
|
4034
4132
|
'<div class="admin-stat-box"><span class="as-icon">\u{1F9E0}</span><div class="val">'+adminDataCache.skills.length+'</div><div class="lbl">'+t('admin.stat.sharedSkills')+'</div></div>';
|
|
@@ -4038,9 +4136,81 @@ function renderAdminStats(pendingCount){
|
|
|
4038
4136
|
tc=document.getElementById('adminTabCountSkills');if(tc)tc.textContent=adminDataCache.skills.length;
|
|
4039
4137
|
}
|
|
4040
4138
|
|
|
4139
|
+
function auRelativeTime(ts){
|
|
4140
|
+
if(!ts) return t('admin.neverActive');
|
|
4141
|
+
var diff=Date.now()-ts;
|
|
4142
|
+
if(diff<60000) return t('notif.timeAgo.just');
|
|
4143
|
+
if(diff<3600000) return t('notif.timeAgo.min').replace('{n}',Math.floor(diff/60000));
|
|
4144
|
+
if(diff<86400000) return t('notif.timeAgo.hour').replace('{n}',Math.floor(diff/3600000));
|
|
4145
|
+
return t('notif.timeAgo.day').replace('{n}',Math.floor(diff/86400000));
|
|
4146
|
+
}
|
|
4147
|
+
|
|
4148
|
+
function renderAdminUserCard(u,adminCount){
|
|
4149
|
+
var uid=escAttr(u.id);
|
|
4150
|
+
var uname=escAttr(u.username||'');
|
|
4151
|
+
var online=!!u.isOnline;
|
|
4152
|
+
var statusCls=online?'online':'offline';
|
|
4153
|
+
|
|
4154
|
+
var statusIndicator='<span class="au-status-dot '+statusCls+'"></span>';
|
|
4155
|
+
var statusLabel=online
|
|
4156
|
+
?'<span class="au-status-text online">'+t('admin.onlineNow')+'</span>'
|
|
4157
|
+
:'<span class="au-status-text offline">'+auRelativeTime(u.lastActiveAt)+'</span>';
|
|
4158
|
+
|
|
4159
|
+
var titleDisplay='<span class="admin-card-title" id="au_name_'+uid+'">'+statusIndicator+esc(u.username||u.id)+
|
|
4160
|
+
' <button onclick="adminStartEditName(this,"'+uid+'","'+uname+'")" style="background:none;border:none;cursor:pointer;color:var(--text-muted);padding:2px;font-size:13px;vertical-align:middle;opacity:.5;transition:opacity .15s" onmouseenter="this.style.opacity=1" onmouseleave="this.style.opacity=.5" title="'+t('admin.editName')+'">\u270E</button></span>';
|
|
4161
|
+
|
|
4162
|
+
var editRow='<div id="au_edit_'+uid+'" style="display:none;align-items:center;gap:6px">'+
|
|
4163
|
+
'<input id="au_input_'+uid+'" type="text" value="'+uname+'" style="flex:1;padding:5px 10px;border:1px solid var(--pri);border-radius:8px;font-size:13px;font-weight:600;background:var(--bg);color:var(--text);outline:none;min-width:0" onkeydown="if(event.key==="Enter")adminSaveEditName("'+uid+'");if(event.key==="Escape")adminCancelEditName("'+uid+'")">'+
|
|
4164
|
+
'<button onclick="adminSaveEditName("'+uid+'")" class="btn btn-sm btn-primary" style="padding:4px 12px;font-size:11px;white-space:nowrap">\u2713</button>'+
|
|
4165
|
+
'<button onclick="adminCancelEditName("'+uid+'")" class="btn btn-sm btn-ghost" style="padding:4px 8px;font-size:11px;color:var(--text-muted)">\u2717</button></div>';
|
|
4166
|
+
|
|
4167
|
+
var mc=u.memoryCount||0, tc=u.taskCount||0, sc=u.skillCount||0;
|
|
4168
|
+
var contribHtml='<div class="au-contrib">'+
|
|
4169
|
+
'<span class="au-contrib-item"><span class="au-contrib-num" style="color:var(--pri)">'+mc+'</span> '+t('admin.contrib.memories')+'</span>'+
|
|
4170
|
+
'<span class="au-contrib-item"><span class="au-contrib-num" style="color:var(--green)">'+tc+'</span> '+t('admin.contrib.tasks')+'</span>'+
|
|
4171
|
+
'<span class="au-contrib-item"><span class="au-contrib-num" style="color:var(--amber)">'+sc+'</span> '+t('admin.contrib.skills')+'</span>'+
|
|
4172
|
+
'</div>';
|
|
4173
|
+
|
|
4174
|
+
var infoRows=[];
|
|
4175
|
+
if(u.deviceName) infoRows.push('<span class="au-info-item">\u{1F4BB} '+t('admin.device')+esc(u.deviceName)+'</span>');
|
|
4176
|
+
if(u.lastIp) infoRows.push('<span class="au-info-item">\u{1F310} '+t('admin.ip')+esc(u.lastIp)+'</span>');
|
|
4177
|
+
if(u.createdAt) infoRows.push('<span class="au-info-item">\u{1F4C5} '+t('admin.joined')+formatDateTimeSeconds(u.createdAt)+'</span>');
|
|
4178
|
+
if(u.approvedAt) infoRows.push('<span class="au-info-item">\u2705 '+t('admin.approved')+formatDateTimeSeconds(u.approvedAt)+'</span>');
|
|
4179
|
+
var lastAct=u.lastActiveAt||u.approvedAt||u.createdAt;
|
|
4180
|
+
infoRows.push('<span class="au-info-item">\u{1F552} '+t('admin.lastActive')+(lastAct?formatDateTimeSeconds(lastAct):t('admin.neverActive'))+'</span>');
|
|
4181
|
+
var infoHtml='<div class="au-info">'+infoRows.join('')+'</div>';
|
|
4182
|
+
|
|
4183
|
+
var actions='';
|
|
4184
|
+
if(u.isOwner){
|
|
4185
|
+
actions+='<span style="font-size:11px;color:var(--text-muted);padding:4px 0">'+t('admin.ownerHint')+'</span>';
|
|
4186
|
+
}else if(u.role!=='admin'){
|
|
4187
|
+
actions+='<button class="btn btn-sm btn-ghost" onclick="adminToggleRole("'+uid+'","admin")" style="color:var(--accent)">'+t('admin.promoteAdmin')+'</button>';
|
|
4188
|
+
actions+='<button class="btn btn-sm btn-ghost" onclick="adminRemoveUser("'+uid+'","'+uname+'")" style="color:var(--rose)">'+t('admin.remove')+'</button>';
|
|
4189
|
+
}else if(adminCount>1){
|
|
4190
|
+
actions+='<button class="btn btn-sm btn-ghost" onclick="adminToggleRole("'+uid+'","member")">'+t('admin.demoteMember')+'</button>';
|
|
4191
|
+
actions+='<button class="btn btn-sm btn-ghost" onclick="adminRemoveUser("'+uid+'","'+uname+'")" style="color:var(--rose)">'+t('admin.remove')+'</button>';
|
|
4192
|
+
}else{
|
|
4193
|
+
actions+='<span style="font-size:11px;color:var(--text-muted);padding:4px 0">'+t('admin.lastAdminHint')+'</span>';
|
|
4194
|
+
}
|
|
4195
|
+
var ownerBadge=u.isOwner?' <span style="font-size:10px;background:linear-gradient(135deg,var(--amber),#f59e0b);color:#fff;padding:1px 6px;border-radius:4px;font-weight:600;vertical-align:middle;margin-left:4px">Owner</span>':'';
|
|
4196
|
+
|
|
4197
|
+
return '<div class="admin-card au-card au-'+statusCls+'"><div class="admin-card-header"><div style="flex:1;min-width:0;display:flex;align-items:center;gap:8px;flex-wrap:wrap">'+
|
|
4198
|
+
'<div style="flex:1;min-width:0">'+titleDisplay+editRow+'</div>'+statusLabel+
|
|
4199
|
+
'</div>'+
|
|
4200
|
+
'<span class="admin-badge '+(u.role==='admin'?'admin':'member')+'">'+esc(u.role||'member')+'</span>'+ownerBadge+'</div>'+
|
|
4201
|
+
contribHtml+infoHtml+
|
|
4202
|
+
(actions?'<div class="admin-card-actions" style="border-top:1px dashed var(--border);padding-top:10px;margin-top:4px">'+actions+'</div>':'')+
|
|
4203
|
+
'</div>';
|
|
4204
|
+
}
|
|
4205
|
+
|
|
4041
4206
|
function renderAdminUsers(users,pending){
|
|
4042
4207
|
var el=document.getElementById('adminUsersPanel');
|
|
4043
4208
|
if(!el) return;
|
|
4209
|
+
var isAdmin=!!window._isHubAdmin;
|
|
4210
|
+
if(!isAdmin){
|
|
4211
|
+
el.innerHTML='<div class="admin-empty" style="padding:32px;text-align:center;color:var(--text-sec)">'+t('admin.noPermission')+'</div>';
|
|
4212
|
+
return;
|
|
4213
|
+
}
|
|
4044
4214
|
var html='';
|
|
4045
4215
|
if(pending&&pending.length>0){
|
|
4046
4216
|
html+='<div style="margin-bottom:16px"><h3 style="font-size:14px;font-weight:600;color:var(--amber);margin-bottom:10px">'+t('admin.pendingApproval')+' ('+pending.length+')</h3>';
|
|
@@ -4055,65 +4225,32 @@ function renderAdminUsers(users,pending){
|
|
|
4055
4225
|
}
|
|
4056
4226
|
html+='</div>';
|
|
4057
4227
|
}
|
|
4058
|
-
|
|
4059
|
-
|
|
4228
|
+
|
|
4229
|
+
var onlineUsers=users.filter(function(u){return !!u.isOnline;});
|
|
4230
|
+
var offlineUsers=users.filter(function(u){return !u.isOnline;});
|
|
4231
|
+
offlineUsers.sort(function(a,b){return (b.lastActiveAt||0)-(a.lastActiveAt||0);});
|
|
4232
|
+
var sorted=onlineUsers.concat(offlineUsers);
|
|
4233
|
+
var adminCount=users.filter(function(x){return x.role==='admin';}).length;
|
|
4234
|
+
|
|
4235
|
+
if(sorted.length===0){
|
|
4060
4236
|
html+='<div class="admin-empty"><span class="ae-icon">\u{1F465}</span>'+t('admin.noActiveUsers')+'</div>';
|
|
4061
4237
|
}else{
|
|
4062
|
-
|
|
4063
|
-
|
|
4064
|
-
|
|
4065
|
-
|
|
4066
|
-
|
|
4067
|
-
|
|
4068
|
-
|
|
4069
|
-
|
|
4070
|
-
|
|
4071
|
-
|
|
4072
|
-
|
|
4073
|
-
var titleDisplay='<span class="admin-card-title" id="au_name_'+uid+'">'+esc(u.username||u.id)+
|
|
4074
|
-
' <button onclick="adminStartEditName(this,"'+uid+'","'+uname+'")" style="background:none;border:none;cursor:pointer;color:var(--text-muted);padding:2px;font-size:13px;vertical-align:middle;opacity:.5;transition:opacity .15s" onmouseenter="this.style.opacity=1" onmouseleave="this.style.opacity=.5" title="'+t('admin.editName')+'">\u270E</button></span>';
|
|
4075
|
-
|
|
4076
|
-
var editRow='<div id="au_edit_'+uid+'" style="display:none;align-items:center;gap:6px">'+
|
|
4077
|
-
'<input id="au_input_'+uid+'" type="text" value="'+uname+'" style="flex:1;padding:5px 10px;border:1px solid var(--pri);border-radius:8px;font-size:13px;font-weight:600;background:var(--bg);color:var(--text);outline:none;min-width:0" onkeydown="if(event.key==="Enter")adminSaveEditName("'+uid+'");if(event.key==="Escape")adminCancelEditName("'+uid+'")">'+
|
|
4078
|
-
'<button onclick="adminSaveEditName("'+uid+'")" class="btn btn-sm btn-primary" style="padding:4px 12px;font-size:11px;white-space:nowrap">\u2713</button>'+
|
|
4079
|
-
'<button onclick="adminCancelEditName("'+uid+'")" class="btn btn-sm btn-ghost" style="padding:4px 8px;font-size:11px;color:var(--text-muted)">\u2717</button></div>';
|
|
4080
|
-
|
|
4081
|
-
var mc=u.memoryCount||0, tc=u.taskCount||0, sc=u.skillCount||0;
|
|
4082
|
-
var contribHtml='<div class="au-contrib">'+
|
|
4083
|
-
'<span class="au-contrib-item"><span class="au-contrib-num" style="color:var(--pri)">'+mc+'</span> '+t('admin.contrib.memories')+'</span>'+
|
|
4084
|
-
'<span class="au-contrib-item"><span class="au-contrib-num" style="color:var(--green)">'+tc+'</span> '+t('admin.contrib.tasks')+'</span>'+
|
|
4085
|
-
'<span class="au-contrib-item"><span class="au-contrib-num" style="color:var(--amber)">'+sc+'</span> '+t('admin.contrib.skills')+'</span>'+
|
|
4086
|
-
'</div>';
|
|
4087
|
-
|
|
4088
|
-
var infoRows=[];
|
|
4089
|
-
if(u.deviceName) infoRows.push('<span class="au-info-item">\u{1F4BB} '+t('admin.device')+esc(u.deviceName)+'</span>');
|
|
4090
|
-
if(u.lastIp) infoRows.push('<span class="au-info-item">\u{1F310} '+t('admin.ip')+esc(u.lastIp)+'</span>');
|
|
4091
|
-
if(u.createdAt) infoRows.push('<span class="au-info-item">\u{1F4C5} '+t('admin.joined')+formatDateTimeSeconds(u.createdAt)+'</span>');
|
|
4092
|
-
if(u.approvedAt) infoRows.push('<span class="au-info-item">\u2705 '+t('admin.approved')+formatDateTimeSeconds(u.approvedAt)+'</span>');
|
|
4093
|
-
infoRows.push('<span class="au-info-item">\u{1F552} '+t('admin.lastActive')+(u.lastActiveAt?formatDateTimeSeconds(u.lastActiveAt):t('admin.neverActive'))+'</span>');
|
|
4094
|
-
var infoHtml='<div class="au-info">'+infoRows.join('')+'</div>';
|
|
4095
|
-
|
|
4096
|
-
var actions='';
|
|
4097
|
-
if(u.role!=='admin'){
|
|
4098
|
-
actions+='<button class="btn btn-sm btn-ghost" onclick="adminToggleRole("'+uid+'","admin")" style="color:var(--accent)">'+t('admin.promoteAdmin')+'</button>';
|
|
4099
|
-
actions+='<button class="btn btn-sm btn-ghost" onclick="adminRemoveUser("'+uid+'","'+uname+'")" style="color:var(--rose)">'+t('admin.remove')+'</button>';
|
|
4100
|
-
}else if(adminCount>1){
|
|
4101
|
-
actions+='<button class="btn btn-sm btn-ghost" onclick="adminToggleRole("'+uid+'","member")">'+t('admin.demoteMember')+'</button>';
|
|
4102
|
-
actions+='<button class="btn btn-sm btn-ghost" onclick="adminRemoveUser("'+uid+'","'+uname+'")" style="color:var(--rose)">'+t('admin.remove')+'</button>';
|
|
4103
|
-
}else{
|
|
4104
|
-
actions+='<span style="font-size:11px;color:var(--text-muted);padding:4px 0">'+t('admin.lastAdminHint')+'</span>';
|
|
4105
|
-
}
|
|
4106
|
-
html+='<div class="admin-card au-card"><div class="admin-card-header"><div style="flex:1;min-width:0">'+titleDisplay+editRow+'</div>'+
|
|
4107
|
-
'<span class="admin-badge '+(u.role==='admin'?'admin':'member')+'">'+esc(u.role||'member')+'</span></div>'+
|
|
4108
|
-
contribHtml+infoHtml+
|
|
4109
|
-
(actions?'<div class="admin-card-actions" style="border-top:1px dashed var(--border);padding-top:10px;margin-top:4px">'+actions+'</div>':'')+
|
|
4110
|
-
'</div>';
|
|
4238
|
+
html+='<div class="au-group-header"><span class="au-group-dot online"></span>'+t('admin.onlineUsers')+' <span class="au-group-count">('+onlineUsers.length+')</span></div>';
|
|
4239
|
+
if(onlineUsers.length===0){
|
|
4240
|
+
html+='<div style="font-size:12px;color:var(--text-muted);padding:8px 0 12px">\u2014</div>';
|
|
4241
|
+
}else{
|
|
4242
|
+
for(var i=0;i<onlineUsers.length;i++) html+=renderAdminUserCard(onlineUsers[i],adminCount);
|
|
4243
|
+
}
|
|
4244
|
+
html+='<div class="au-group-header"><span class="au-group-dot offline"></span>'+t('admin.offlineUsers')+' <span class="au-group-count">('+offlineUsers.length+')</span></div>';
|
|
4245
|
+
if(offlineUsers.length===0){
|
|
4246
|
+
html+='<div style="font-size:12px;color:var(--text-muted);padding:8px 0 12px">\u2014</div>';
|
|
4247
|
+
}else{
|
|
4248
|
+
for(var j=0;j<offlineUsers.length;j++) html+=renderAdminUserCard(offlineUsers[j],adminCount);
|
|
4111
4249
|
}
|
|
4112
|
-
html+=adminPaginateHtml(totalUsers,adminPage.users,'adminUsers');
|
|
4113
4250
|
}
|
|
4114
4251
|
el.innerHTML=html;
|
|
4115
4252
|
}
|
|
4116
|
-
function adminUsersPage(p){
|
|
4253
|
+
function adminUsersPage(p){renderAdminUsers(adminDataCache.users,adminDataCache._pending||[]);}
|
|
4117
4254
|
|
|
4118
4255
|
async function adminApproveUser(userId,username){
|
|
4119
4256
|
try{
|
|
@@ -4136,7 +4273,9 @@ async function adminToggleRole(userId,newRole){
|
|
|
4136
4273
|
try{
|
|
4137
4274
|
var r=await fetch('/api/sharing/change-role',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:userId,role:newRole})});
|
|
4138
4275
|
var d=await r.json();
|
|
4139
|
-
if(d.ok){toast(t('toast.roleChanged'),'success');loadAdminData();}
|
|
4276
|
+
if(d.ok){toast(t('toast.roleChanged'),'success');loadAdminData();}
|
|
4277
|
+
else if(d.error==='cannot_demote_owner'){toast(t('admin.ownerHint'),'error');}
|
|
4278
|
+
else{toast(d.error||t('toast.roleChangeFail'),'error');}
|
|
4140
4279
|
}catch(e){toast(t('toast.roleChangeFail')+': '+e.message,'error');}
|
|
4141
4280
|
}
|
|
4142
4281
|
function adminStartEditName(btn,userId,currentName){
|
|
@@ -4175,7 +4314,9 @@ async function adminRemoveUser(userId,username){
|
|
|
4175
4314
|
try{
|
|
4176
4315
|
var r=await fetch('/api/sharing/remove-user',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:userId,cleanResources:clean})});
|
|
4177
4316
|
var d=await r.json();
|
|
4178
|
-
if(d.ok){toast(t('toast.userRemoved'),'success');loadAdminData();}
|
|
4317
|
+
if(d.ok){toast(t('toast.userRemoved'),'success');loadAdminData();}
|
|
4318
|
+
else if(d.error==='cannot_remove_owner'){toast(t('admin.ownerHint'),'error');}
|
|
4319
|
+
else{toast(d.error||t('toast.removeFail'),'error');}
|
|
4179
4320
|
}catch(e){toast(t('toast.removeFail')+': '+e.message,'error');}
|
|
4180
4321
|
}
|
|
4181
4322
|
|
|
@@ -4247,7 +4388,7 @@ function renderAdminTasks(tasks){
|
|
|
4247
4388
|
(tk.chunkCount!=null?'<span class="admin-card-tag tag-kind">\u{1F4DD} '+tk.chunkCount+' '+t('admin.chunks')+'</span>':'')+
|
|
4248
4389
|
'</div>'+
|
|
4249
4390
|
'<span class="admin-card-actions" onclick="event.stopPropagation()">'+
|
|
4250
|
-
'<button class="btn btn-sm btn-ghost" onclick="adminDeleteTask("'+escAttr(tk.id)+'","'+escAttr(tk.title||tk.id)+'")" style="color:var(--rose)">'+t('admin.remove')+'</button>'+
|
|
4391
|
+
(window._isHubAdmin?'<button class="btn btn-sm btn-ghost" onclick="adminDeleteTask("'+escAttr(tk.id)+'","'+escAttr(tk.title||tk.id)+'")" style="color:var(--rose)">'+t('admin.remove')+'</button>':'')+
|
|
4251
4392
|
'<button class="btn btn-sm btn-ghost admin-card-expand-btn" onclick="toggleAdminTaskCard("'+cardId+'",'+i+')">'+t('admin.expand')+'</button>'+
|
|
4252
4393
|
'<span class="admin-card-time">'+(timeRange||formatDateTimeSeconds(tk.updatedAt||tk.createdAt))+'</span>'+
|
|
4253
4394
|
'</span>'+
|
|
@@ -4310,7 +4451,7 @@ function renderAdminSkills(skills){
|
|
|
4310
4451
|
(qs!=null?'<span class="admin-card-tag tag-kind">\u2605 '+Number(qs).toFixed(1)+'</span>':'')+
|
|
4311
4452
|
'</div>'+
|
|
4312
4453
|
'<span class="admin-card-actions" onclick="event.stopPropagation()">'+
|
|
4313
|
-
'<button class="btn btn-sm btn-ghost" onclick="adminDeleteSkill("'+escAttr(s.id)+'","'+escAttr(s.name||s.id)+'")" style="color:var(--rose)">'+t('admin.remove')+'</button>'+
|
|
4454
|
+
(window._isHubAdmin?'<button class="btn btn-sm btn-ghost" onclick="adminDeleteSkill("'+escAttr(s.id)+'","'+escAttr(s.name||s.id)+'")" style="color:var(--rose)">'+t('admin.remove')+'</button>':'')+
|
|
4314
4455
|
'<button class="btn btn-sm btn-ghost admin-card-expand-btn" onclick="toggleAdminSkillCard("'+cardId+'",'+i+')">'+t('admin.expand')+'</button>'+
|
|
4315
4456
|
(s.sourceSkillId?'<button class="btn btn-sm btn-ghost" onclick="window.open("/api/skill/'+encodeURIComponent(s.sourceSkillId)+'/download","_blank")" style="color:var(--pri)">\u2B07</button>':'')+
|
|
4316
4457
|
'<span class="admin-card-time">'+formatDateTimeSeconds(s.updatedAt||s.createdAt)+'</span>'+
|
|
@@ -4374,7 +4515,7 @@ function renderAdminMemories(memories){
|
|
|
4374
4515
|
(m.kind?'<span class="admin-card-tag tag-kind">'+esc(m.kind)+'</span>':'')+
|
|
4375
4516
|
'</div>'+
|
|
4376
4517
|
'<span class="admin-card-actions">'+
|
|
4377
|
-
'<button class="btn btn-sm btn-ghost" onclick="event.stopPropagation();adminDeleteMemory("'+escAttr(m.id)+'","'+escAttr(m.summary||m.id)+'")" style="color:var(--rose)">'+t('admin.remove')+'</button>'+
|
|
4518
|
+
(window._isHubAdmin?'<button class="btn btn-sm btn-ghost" onclick="event.stopPropagation();adminDeleteMemory("'+escAttr(m.id)+'","'+escAttr(m.summary||m.id)+'")" style="color:var(--rose)">'+t('admin.remove')+'</button>':'')+
|
|
4378
4519
|
'<button class="btn btn-sm btn-ghost admin-card-expand-btn" onclick="event.stopPropagation();toggleAdminMemoryCard("'+cardId+'",'+i+')">'+t('admin.expand')+'</button>'+
|
|
4379
4520
|
'<span class="admin-card-time">'+formatDateTimeSeconds(m.updatedAt||m.createdAt)+'</span>'+
|
|
4380
4521
|
'</span>'+
|
|
@@ -4452,12 +4593,19 @@ async function toggleAdminTaskCard(cardId,idx){
|
|
|
4452
4593
|
var tk=(adminTasksCache||[])[idx];
|
|
4453
4594
|
if(!tk){detail.innerHTML='<div style="color:var(--text-muted);font-size:14px;padding:12px">'+t('admin.noContent')+'</div>';return;}
|
|
4454
4595
|
var localTaskId=tk.sourceTaskId||tk.id;
|
|
4596
|
+
var hubTaskId=tk.id;
|
|
4455
4597
|
detail.innerHTML='<div class="spinner"></div>';
|
|
4456
4598
|
var task=null;
|
|
4457
4599
|
try{
|
|
4458
4600
|
var r=await fetch('/api/task/'+encodeURIComponent(localTaskId));
|
|
4459
4601
|
if(r.ok) task=await r.json();
|
|
4460
4602
|
}catch(e){}
|
|
4603
|
+
if(!task){
|
|
4604
|
+
try{
|
|
4605
|
+
var r2=await fetch('/api/admin/shared-tasks/'+encodeURIComponent(hubTaskId)+'/detail');
|
|
4606
|
+
if(r2.ok) task=await r2.json();
|
|
4607
|
+
}catch(e2){}
|
|
4608
|
+
}
|
|
4461
4609
|
if(!task){detail.innerHTML='<div style="color:var(--text-muted);font-size:14px;padding:12px">'+t('admin.noContent')+'</div>';return;}
|
|
4462
4610
|
var metaHtml='<div class="admin-card-detail-meta admin-task-meta">'+
|
|
4463
4611
|
(tk.status?'<span class="meta-item"><span class="task-status-badge '+tk.status+'">'+esc(tk.status)+'</span></span>':'')+
|
|
@@ -4528,11 +4676,18 @@ async function toggleAdminSkillCard(cardId,idx){
|
|
|
4528
4676
|
if(!sk){detail.innerHTML='<div style="color:var(--text-muted);font-size:13px">'+t('admin.noContent')+'</div>';return;}
|
|
4529
4677
|
detail.innerHTML='<div class="spinner"></div>';
|
|
4530
4678
|
var localSkillId=sk.sourceSkillId||sk.id;
|
|
4679
|
+
var hubSkillId=sk.id;
|
|
4531
4680
|
var localData=null;
|
|
4532
4681
|
try{
|
|
4533
4682
|
var lr=await fetch('/api/skill/'+encodeURIComponent(localSkillId));
|
|
4534
4683
|
if(lr.ok) localData=await lr.json();
|
|
4535
4684
|
}catch(e){}
|
|
4685
|
+
if(!localData){
|
|
4686
|
+
try{
|
|
4687
|
+
var hr=await fetch('/api/admin/shared-skills/'+encodeURIComponent(hubSkillId)+'/detail');
|
|
4688
|
+
if(hr.ok) localData=await hr.json();
|
|
4689
|
+
}catch(e2){}
|
|
4690
|
+
}
|
|
4536
4691
|
var localSkill=localData&&localData.skill?localData.skill:sk;
|
|
4537
4692
|
var files=localData&&localData.files?localData.files:[];
|
|
4538
4693
|
var versions=localData&&localData.versions?localData.versions:[];
|
|
@@ -5362,18 +5517,21 @@ function setTaskStatusFilter(btn,status){
|
|
|
5362
5517
|
async function loadTasks(){
|
|
5363
5518
|
const scope=document.getElementById('taskSearchScope')?document.getElementById('taskSearchScope').value:taskSearchScope;
|
|
5364
5519
|
taskSearchScope=scope||'local';
|
|
5365
|
-
if(taskSearchScope
|
|
5520
|
+
if(taskSearchScope==='hub'){ return loadHubTasks(); }
|
|
5366
5521
|
const list=document.getElementById('tasksList');
|
|
5367
5522
|
list.innerHTML='<div class="spinner"></div>';
|
|
5368
5523
|
try{
|
|
5369
5524
|
const params=new URLSearchParams({limit:String(TASKS_PER_PAGE),offset:String(tasksPage*TASKS_PER_PAGE)});
|
|
5370
5525
|
if(tasksStatusFilter) params.set('status',tasksStatusFilter);
|
|
5526
|
+
if(taskSearchScope==='local') params.set('owner','agent:main');
|
|
5527
|
+
var baseP=new URLSearchParams();
|
|
5528
|
+
if(taskSearchScope==='local') baseP.set('owner','agent:main');
|
|
5371
5529
|
const [data,allD,activeD,compD,skipD]=await Promise.all([
|
|
5372
5530
|
fetch('/api/tasks?'+params).then(r=>r.json()),
|
|
5373
|
-
fetch('/api/tasks?limit=1&offset=0').then(r=>r.json()),
|
|
5374
|
-
fetch('/api/tasks?status=active&limit=1&offset=0').then(r=>r.json()),
|
|
5375
|
-
fetch('/api/tasks?status=completed&limit=1&offset=0').then(r=>r.json()),
|
|
5376
|
-
fetch('/api/tasks?status=skipped&limit=1&offset=0').then(r=>r.json())
|
|
5531
|
+
fetch('/api/tasks?limit=1&offset=0&'+baseP).then(r=>r.json()),
|
|
5532
|
+
fetch('/api/tasks?status=active&limit=1&offset=0&'+baseP).then(r=>r.json()),
|
|
5533
|
+
fetch('/api/tasks?status=completed&limit=1&offset=0&'+baseP).then(r=>r.json()),
|
|
5534
|
+
fetch('/api/tasks?status=skipped&limit=1&offset=0&'+baseP).then(r=>r.json())
|
|
5377
5535
|
]);
|
|
5378
5536
|
document.getElementById('tasksTotalCount').textContent=formatNum(allD.total);
|
|
5379
5537
|
document.getElementById('tasksActiveCount').textContent=formatNum(activeD.total);
|
|
@@ -5666,7 +5824,7 @@ async function loadSkills(){
|
|
|
5666
5824
|
list.innerHTML='<div class="spinner"></div>';
|
|
5667
5825
|
var hubSection=document.getElementById('hubSkillsSection');
|
|
5668
5826
|
if(hubList){
|
|
5669
|
-
if(skillSearchScope==='local'){
|
|
5827
|
+
if(skillSearchScope==='local'||skillSearchScope==='allLocal'){
|
|
5670
5828
|
if(hubSection) hubSection.style.display='none';
|
|
5671
5829
|
}else{
|
|
5672
5830
|
if(hubSection) hubSection.style.display='block';
|
|
@@ -5739,7 +5897,7 @@ async function loadSkills(){
|
|
|
5739
5897
|
|
|
5740
5898
|
list.innerHTML=renderLocalCards(localSkills);
|
|
5741
5899
|
|
|
5742
|
-
if(skillSearchScope==='local'){
|
|
5900
|
+
if(skillSearchScope==='local'||skillSearchScope==='allLocal'){
|
|
5743
5901
|
if(hubSection) hubSection.style.display='none';
|
|
5744
5902
|
document.getElementById('skillSearchMeta').textContent=query?(t('skills.search.local')+' '+localSkills.length):'';
|
|
5745
5903
|
document.getElementById('skillsTotalCount').textContent=formatNum(localSkills.length);
|
|
@@ -5810,6 +5968,46 @@ async function loadSkills(){
|
|
|
5810
5968
|
}
|
|
5811
5969
|
}
|
|
5812
5970
|
|
|
5971
|
+
async function loadHubTasks(){
|
|
5972
|
+
var list=document.getElementById('tasksList');
|
|
5973
|
+
if(!list) return;
|
|
5974
|
+
list.innerHTML='<div class="spinner"></div>';
|
|
5975
|
+
try{
|
|
5976
|
+
var r=await fetch('/api/sharing/tasks/list?limit=40');
|
|
5977
|
+
var d=await r.json();
|
|
5978
|
+
var tasks=Array.isArray(d.tasks)?d.tasks:[];
|
|
5979
|
+
hubTasksCache=tasks;
|
|
5980
|
+
document.getElementById('tasksTotalCount').textContent=formatNum(tasks.length);
|
|
5981
|
+
document.getElementById('tasksActiveCount').textContent='-';
|
|
5982
|
+
document.getElementById('tasksCompletedCount').textContent='-';
|
|
5983
|
+
document.getElementById('tasksSkippedCount').textContent='-';
|
|
5984
|
+
if(!tasks.length){
|
|
5985
|
+
list.innerHTML='<div style="text-align:center;padding:48px;color:var(--text-muted);font-size:14px">'+t('tasks.empty')+'</div>';
|
|
5986
|
+
document.getElementById('tasksPagination').innerHTML='';
|
|
5987
|
+
return;
|
|
5988
|
+
}
|
|
5989
|
+
list.innerHTML=tasks.map(function(task,idx){
|
|
5990
|
+
var timeStr=task.updatedAt?formatTime(task.updatedAt):(task.createdAt?formatTime(task.createdAt):'');
|
|
5991
|
+
return '<div class="task-card" onclick="openHubTaskDetailFromCache(\\x27hub\\x27,'+idx+')" style="cursor:pointer">'+
|
|
5992
|
+
'<div class="task-card-top">'+
|
|
5993
|
+
'<div class="task-card-title">'+esc(task.title||'(no title)')+'</div>'+
|
|
5994
|
+
'<div class="task-card-badges"><span class="scope-badge team">\\u{1F310} '+t('scope.hub')+'</span></div>'+
|
|
5995
|
+
'</div>'+
|
|
5996
|
+
(task.summary?'<div class="task-card-summary">'+esc(task.summary)+'</div>':'')+
|
|
5997
|
+
'<div class="task-card-bottom">'+
|
|
5998
|
+
(timeStr?'<span class="tag"><span class="icon">\\u{1F4C5}</span> '+timeStr+'</span>':'')+
|
|
5999
|
+
'<span class="tag"><span class="icon">\\u{1F464}</span> '+esc(task.ownerName||'unknown')+'</span>'+
|
|
6000
|
+
(task.chunkCount!=null?'<span class="tag"><span class="icon">\\u{1F4DD}</span> '+task.chunkCount+' '+t('tasks.chunks.label')+'</span>':'')+
|
|
6001
|
+
'</div>'+
|
|
6002
|
+
'</div>';
|
|
6003
|
+
}).join('');
|
|
6004
|
+
document.getElementById('tasksPagination').innerHTML='';
|
|
6005
|
+
}catch(e){
|
|
6006
|
+
list.innerHTML='<div style="text-align:center;padding:48px;color:var(--text-muted);font-size:14px">'+t('tasks.empty')+'</div>';
|
|
6007
|
+
document.getElementById('tasksPagination').innerHTML='';
|
|
6008
|
+
}
|
|
6009
|
+
}
|
|
6010
|
+
|
|
5813
6011
|
async function loadHubSkills(hubList){
|
|
5814
6012
|
if(!hubList) hubList=document.getElementById('hubSkillsList');
|
|
5815
6013
|
if(!hubList) return;
|
|
@@ -6170,6 +6368,7 @@ async function loadConfig(){
|
|
|
6170
6368
|
document.getElementById('cfgHubTeamToken').value=hub.teamToken||'';
|
|
6171
6369
|
document.getElementById('cfgClientHubAddress').value=client.hubAddress||'';
|
|
6172
6370
|
document.getElementById('cfgClientTeamToken').value=client.teamToken||'';
|
|
6371
|
+
document.getElementById('cfgClientNickname').value=client.nickname||'';
|
|
6173
6372
|
document.getElementById('cfgClientUserToken').value=client.userToken||'';
|
|
6174
6373
|
onSharingToggle();
|
|
6175
6374
|
updateHubShareInfo();
|
|
@@ -6338,6 +6537,7 @@ async function saveHubConfig(){
|
|
|
6338
6537
|
var hubPort=document.getElementById('cfgHubPort').value.trim();
|
|
6339
6538
|
var hubTeamName=document.getElementById('cfgHubTeamName').value.trim();
|
|
6340
6539
|
var hubTeamToken=document.getElementById('cfgHubTeamToken').value.trim();
|
|
6540
|
+
var hubAdminName=document.getElementById('cfgHubAdminName').value.trim();
|
|
6341
6541
|
cfg.sharing.hub={port:hubPort?Number(hubPort):18800};
|
|
6342
6542
|
if(hubTeamName) cfg.sharing.hub.teamName=hubTeamName;
|
|
6343
6543
|
if(hubTeamToken) cfg.sharing.hub.teamToken=hubTeamToken;
|
|
@@ -6347,8 +6547,10 @@ async function saveHubConfig(){
|
|
|
6347
6547
|
var clientAddr=document.getElementById('cfgClientHubAddress').value.trim();
|
|
6348
6548
|
var clientTeamToken=document.getElementById('cfgClientTeamToken').value.trim();
|
|
6349
6549
|
var clientUserToken=document.getElementById('cfgClientUserToken').value.trim();
|
|
6550
|
+
var clientNickname=document.getElementById('cfgClientNickname').value.trim();
|
|
6350
6551
|
cfg.sharing.client={};
|
|
6351
6552
|
if(clientAddr) cfg.sharing.client.hubAddress=clientAddr;
|
|
6553
|
+
if(clientNickname) cfg.sharing.client.nickname=clientNickname;
|
|
6352
6554
|
if(clientTeamToken) cfg.sharing.client.teamToken=clientTeamToken;
|
|
6353
6555
|
if(clientUserToken) cfg.sharing.client.userToken=clientUserToken;
|
|
6354
6556
|
cfg.sharing.hub={port:18800,teamName:'',teamToken:''};
|
|
@@ -6373,6 +6575,12 @@ async function saveHubConfig(){
|
|
|
6373
6575
|
|
|
6374
6576
|
var ok=await doSaveConfig(cfg, saveBtn, 'hubSaved');
|
|
6375
6577
|
if(ok){
|
|
6578
|
+
if(sharingEnabled&&_sharingRole==='hub'){
|
|
6579
|
+
var adminNameEl=document.getElementById('cfgHubAdminName');
|
|
6580
|
+
if(adminNameEl&&adminNameEl.value.trim()){
|
|
6581
|
+
try{await fetch('/api/sharing/update-username',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({username:adminNameEl.value.trim()})});}catch(e){}
|
|
6582
|
+
}
|
|
6583
|
+
}
|
|
6376
6584
|
loadSharingStatus(false);
|
|
6377
6585
|
var needsRestart=sharingEnabled||(prevSharingEnabled&&!sharingEnabled);
|
|
6378
6586
|
if(sharingEnabled) updateHubShareInfo();
|
|
@@ -6794,23 +7002,83 @@ function renderToolAgg(data){
|
|
|
6794
7002
|
'</tbody></table>';
|
|
6795
7003
|
}
|
|
6796
7004
|
|
|
6797
|
-
/* ───
|
|
6798
|
-
var
|
|
6799
|
-
|
|
6800
|
-
|
|
6801
|
-
|
|
7005
|
+
/* ─── Unified live-data poller ─── */
|
|
7006
|
+
var _livePoller=null;
|
|
7007
|
+
var _LIVE_POLL_MS=15000;
|
|
7008
|
+
var _livePollBusy=false;
|
|
7009
|
+
|
|
7010
|
+
async function _livePollTick(){
|
|
7011
|
+
if(_livePollBusy||document.hidden) return;
|
|
7012
|
+
_livePollBusy=true;
|
|
7013
|
+
try{
|
|
6802
7014
|
if(sharingStatusCache&&sharingStatusCache.enabled) loadSharingStatus(false);
|
|
6803
|
-
|
|
7015
|
+
if(!_notifSSEConnected) pollNotifCount();
|
|
7016
|
+
pollAdminPending();
|
|
7017
|
+
if(_activeView==='admin') loadAdminData();
|
|
7018
|
+
else if(_activeView==='memories'){loadStats();loadMemories();}
|
|
7019
|
+
else if(_activeView==='tasks') loadTasks();
|
|
7020
|
+
else if(_activeView==='skills') loadSkills();
|
|
7021
|
+
else if(_activeView==='analytics') loadMetrics();
|
|
7022
|
+
}catch(e){}
|
|
7023
|
+
_livePollBusy=false;
|
|
7024
|
+
}
|
|
7025
|
+
|
|
7026
|
+
function startLivePoller(){
|
|
7027
|
+
stopLivePoller();
|
|
7028
|
+
_livePoller=setInterval(_livePollTick,_LIVE_POLL_MS);
|
|
6804
7029
|
}
|
|
6805
|
-
function
|
|
6806
|
-
if(
|
|
7030
|
+
function stopLivePoller(){
|
|
7031
|
+
if(_livePoller){clearInterval(_livePoller);_livePoller=null;}
|
|
6807
7032
|
}
|
|
6808
7033
|
|
|
6809
|
-
|
|
7034
|
+
document.addEventListener('visibilitychange',function(){
|
|
7035
|
+
if(document.hidden){
|
|
7036
|
+
stopLivePoller();
|
|
7037
|
+
}else{
|
|
7038
|
+
_livePollTick();
|
|
7039
|
+
startLivePoller();
|
|
7040
|
+
if(!_notifSSE||!_notifSSEConnected) connectNotifSSE();
|
|
7041
|
+
}
|
|
7042
|
+
});
|
|
7043
|
+
|
|
7044
|
+
/* ─── Notifications (SSE push + fallback poll) ─── */
|
|
6810
7045
|
var _notifCache=[];
|
|
6811
7046
|
var _notifUnread=0;
|
|
6812
7047
|
var _notifPollTimer=null;
|
|
6813
7048
|
var _notifPanelOpen=false;
|
|
7049
|
+
var _notifSSE=null;
|
|
7050
|
+
var _notifSSEConnected=false;
|
|
7051
|
+
var _notifSSERetryMs=1000;
|
|
7052
|
+
|
|
7053
|
+
function connectNotifSSE(){
|
|
7054
|
+
if(_notifSSE) return;
|
|
7055
|
+
try{
|
|
7056
|
+
_notifSSE=new EventSource('/api/notifications/stream');
|
|
7057
|
+
_notifSSE.onmessage=function(ev){
|
|
7058
|
+
try{
|
|
7059
|
+
var d=JSON.parse(ev.data);
|
|
7060
|
+
if(d.type==='connected'){_notifSSEConnected=true;_notifSSERetryMs=1000;return;}
|
|
7061
|
+
if(d.type==='update'){
|
|
7062
|
+
var prev=_notifUnread;
|
|
7063
|
+
_notifUnread=d.unreadCount||0;
|
|
7064
|
+
renderNotifBadge();
|
|
7065
|
+
if(_notifUnread>prev&&_notifPanelOpen) loadNotifications();
|
|
7066
|
+
}
|
|
7067
|
+
if(d.type==='cleared'){
|
|
7068
|
+
_notifUnread=0;_notifCache=[];
|
|
7069
|
+
renderNotifBadge();renderNotifPanel();
|
|
7070
|
+
}
|
|
7071
|
+
}catch(e){}
|
|
7072
|
+
};
|
|
7073
|
+
_notifSSE.onerror=function(){
|
|
7074
|
+
_notifSSEConnected=false;
|
|
7075
|
+
if(_notifSSE){_notifSSE.close();_notifSSE=null;}
|
|
7076
|
+
setTimeout(connectNotifSSE,Math.min(_notifSSERetryMs,30000));
|
|
7077
|
+
_notifSSERetryMs=Math.min(_notifSSERetryMs*2,30000);
|
|
7078
|
+
};
|
|
7079
|
+
}catch(e){}
|
|
7080
|
+
}
|
|
7081
|
+
connectNotifSSE();
|
|
6814
7082
|
|
|
6815
7083
|
function toggleNotifPanel(e){
|
|
6816
7084
|
if(e)e.stopPropagation();
|
|
@@ -6841,7 +7109,10 @@ function notifTimeAgo(ts){
|
|
|
6841
7109
|
return t('notif.timeAgo.day').replace('{n}',Math.floor(diff/86400000));
|
|
6842
7110
|
}
|
|
6843
7111
|
|
|
6844
|
-
function notifIcon(resource){
|
|
7112
|
+
function notifIcon(resource,type){
|
|
7113
|
+
if(type==='user_online') return '\\u{1F7E2}';
|
|
7114
|
+
if(type==='user_offline') return '\\u{1F534}';
|
|
7115
|
+
if(type==='user_join_request') return '\\u{1F464}';
|
|
6845
7116
|
if(resource==='memory') return '\\u{1F4DD}';
|
|
6846
7117
|
if(resource==='task') return '\\u{1F4CB}';
|
|
6847
7118
|
if(resource==='skill') return '\\u{1F9E0}';
|
|
@@ -6852,6 +7123,21 @@ function notifTypeText(n){
|
|
|
6852
7123
|
if(n.type==='resource_removed'){
|
|
6853
7124
|
return t('notif.removed.'+n.resource)||t('notif.removed.memory');
|
|
6854
7125
|
}
|
|
7126
|
+
if(n.type==='resource_shared'){
|
|
7127
|
+
return t('notif.shared.'+n.resource)||t('notif.shared.memory');
|
|
7128
|
+
}
|
|
7129
|
+
if(n.type==='resource_unshared'){
|
|
7130
|
+
return t('notif.unshared.'+n.resource)||t('notif.unshared.memory');
|
|
7131
|
+
}
|
|
7132
|
+
if(n.type==='user_join_request'){
|
|
7133
|
+
return t('notif.userJoin');
|
|
7134
|
+
}
|
|
7135
|
+
if(n.type==='user_online'){
|
|
7136
|
+
return t('notif.userOnline');
|
|
7137
|
+
}
|
|
7138
|
+
if(n.type==='user_offline'){
|
|
7139
|
+
return t('notif.userOffline');
|
|
7140
|
+
}
|
|
6855
7141
|
return n.message||n.type;
|
|
6856
7142
|
}
|
|
6857
7143
|
|
|
@@ -6896,7 +7182,7 @@ function renderNotifPanel(){
|
|
|
6896
7182
|
body.innerHTML=_notifCache.map(function(n){
|
|
6897
7183
|
var cls='notif-item'+(n.read?'':' unread');
|
|
6898
7184
|
return '<div class="'+cls+'" onclick="markNotifRead("'+esc(n.id)+'")">'+
|
|
6899
|
-
'<div class="notif-item-icon">'+notifIcon(n.resource)+'</div>'+
|
|
7185
|
+
'<div class="notif-item-icon">'+notifIcon(n.resource,n.type)+'</div>'+
|
|
6900
7186
|
'<div class="notif-item-body">'+
|
|
6901
7187
|
'<div class="notif-item-title">'+esc(notifTypeText(n))+'</div>'+
|
|
6902
7188
|
'<div class="notif-item-name">'+esc(n.title)+'</div>'+
|
|
@@ -6937,15 +7223,8 @@ async function clearAllNotifs(){
|
|
|
6937
7223
|
}catch(e){}
|
|
6938
7224
|
}
|
|
6939
7225
|
|
|
6940
|
-
function startNotifPoll(){
|
|
6941
|
-
|
|
6942
|
-
pollNotifCount();
|
|
6943
|
-
_notifPollTimer=setInterval(pollNotifCount,15000);
|
|
6944
|
-
}
|
|
6945
|
-
|
|
6946
|
-
function stopNotifPoll(){
|
|
6947
|
-
if(_notifPollTimer){clearInterval(_notifPollTimer);_notifPollTimer=null;}
|
|
6948
|
-
}
|
|
7226
|
+
function startNotifPoll(){ startLivePoller(); }
|
|
7227
|
+
function stopNotifPoll(){ }
|
|
6949
7228
|
|
|
6950
7229
|
/* ─── Data loading ─── */
|
|
6951
7230
|
async function loadAll(){
|
|
@@ -6953,8 +7232,8 @@ async function loadAll(){
|
|
|
6953
7232
|
checkMigrateStatus();
|
|
6954
7233
|
connectPPSSE();
|
|
6955
7234
|
checkForUpdate();
|
|
6956
|
-
|
|
6957
|
-
|
|
7235
|
+
pollNotifCount();
|
|
7236
|
+
startLivePoller();
|
|
6958
7237
|
}
|
|
6959
7238
|
|
|
6960
7239
|
async function loadStats(ownerFilter){
|
|
@@ -7032,11 +7311,14 @@ async function loadStats(ownerFilter){
|
|
|
7032
7311
|
const ownerSel=document.getElementById('filterOwner');
|
|
7033
7312
|
if(ownerSel && d.owners && d.owners.length>0){
|
|
7034
7313
|
const curVal=ownerSel.value;
|
|
7035
|
-
|
|
7036
|
-
|
|
7037
|
-
|
|
7314
|
+
var agents=d.owners.filter(function(o){return o && o.indexOf('agent:')===0;});
|
|
7315
|
+
ownerSel.innerHTML='<option value="">'+t('filter.allagents')+'</option>';
|
|
7316
|
+
agents.forEach(function(o){
|
|
7317
|
+
var label=o.replace('agent:','');
|
|
7318
|
+
ownerSel.innerHTML+='<option value="'+o+'"'+(o===curVal?' selected':'')+'>'+label+'</option>';
|
|
7038
7319
|
});
|
|
7039
|
-
ownerSel.
|
|
7320
|
+
if(agents.length<=1) ownerSel.style.display='none';
|
|
7321
|
+
else ownerSel.style.display='';
|
|
7040
7322
|
}
|
|
7041
7323
|
}
|
|
7042
7324
|
|
|
@@ -7128,7 +7410,7 @@ async function doSearch(query){
|
|
|
7128
7410
|
var scope=document.getElementById('memorySearchScope')?.value||memorySearchScope||'local';
|
|
7129
7411
|
var list=document.getElementById('memoryList');
|
|
7130
7412
|
list.innerHTML='<div class="spinner"></div>';
|
|
7131
|
-
if(scope
|
|
7413
|
+
if(scope==='hub'){
|
|
7132
7414
|
try{
|
|
7133
7415
|
var r=await fetch('/api/sharing/search/memories',{
|
|
7134
7416
|
method:'POST',
|
|
@@ -8226,7 +8508,7 @@ async function checkForUpdate(){
|
|
|
8226
8508
|
const pkgSpec=d.installCommand?d.installCommand.replace(/^(?:npx\s+)?openclaw\s+plugins\s+install\s+/,''):(d.packageName+'@'+d.latest);
|
|
8227
8509
|
var banner=document.createElement('div');
|
|
8228
8510
|
banner.id='updateBanner';
|
|
8229
|
-
banner.style.cssText='display:flex;align-items:center;gap:12px;padding:10px max
|
|
8511
|
+
banner.style.cssText='display:flex;align-items:center;gap:12px;padding:10px 32px;max-width:1400px;margin:0 auto;width:100%;font-size:13px;font-weight:500;box-sizing:border-box;animation:slideIn .3s ease;background:linear-gradient(135deg,rgba(99,102,241,.08),rgba(139,92,246,.06));color:var(--pri);border-bottom:1px solid rgba(99,102,241,.18);backdrop-filter:blur(8px)';
|
|
8230
8512
|
var textNode=document.createElement('div');
|
|
8231
8513
|
textNode.style.cssText='display:flex;align-items:center;gap:8px;flex-shrink:0;font-size:13px';
|
|
8232
8514
|
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>';
|