@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/src/viewer/html.ts
CHANGED
|
@@ -12,6 +12,7 @@ return `<!DOCTYPE html>
|
|
|
12
12
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
|
13
13
|
<style>
|
|
14
14
|
*{margin:0;padding:0;box-sizing:border-box}
|
|
15
|
+
html{overflow-y:scroll}
|
|
15
16
|
:root{
|
|
16
17
|
--bg:#0b0d11;--bg-card:#12141a;--bg-card-hover:#1a1d25;
|
|
17
18
|
--border:rgba(255,255,255,.08);--border-glow:rgba(255,255,255,.14);
|
|
@@ -106,7 +107,8 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
106
107
|
|
|
107
108
|
/* ─── App Layout (dark dashboard, same as www) ─── */
|
|
108
109
|
.app{display:none;flex-direction:column;min-height:100vh}
|
|
109
|
-
.topbar{background:rgba(11,13,17,.88);border-bottom:1px solid var(--border);
|
|
110
|
+
.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)}
|
|
111
|
+
.topbar-inner{display:flex;align-items:center;width:100%;max-width:1400px;margin:0 auto;padding:0 32px}
|
|
110
112
|
.topbar .brand{display:flex;align-items:center;gap:8px;font-weight:700;font-size:15px;color:var(--text);letter-spacing:-.02em;flex-shrink:0}
|
|
111
113
|
.topbar .brand .icon{width:24px;height:24px;display:flex;align-items:center;justify-content:center;font-size:18px;background:none;border-radius:0}
|
|
112
114
|
.topbar .brand .brand-title{font-size:13px;font-weight:500;opacity:.7}
|
|
@@ -233,6 +235,21 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
233
235
|
.au-contrib-num{font-size:18px;font-weight:700;line-height:1}
|
|
234
236
|
.au-info{display:flex;flex-wrap:wrap;gap:6px 14px;padding:8px 0;font-size:12px}
|
|
235
237
|
.au-info-item{color:var(--text-muted);white-space:nowrap}
|
|
238
|
+
.au-status-dot{display:inline-block;width:8px;height:8px;border-radius:50%;margin-right:4px;vertical-align:middle;flex-shrink:0}
|
|
239
|
+
.au-status-dot.online{background:#22c55e;box-shadow:0 0 6px rgba(34,197,94,.5)}
|
|
240
|
+
.au-status-dot.offline{background:#9ca3af}
|
|
241
|
+
.au-status-text{font-size:11px;font-weight:500}
|
|
242
|
+
.au-status-text.online{color:#22c55e}
|
|
243
|
+
.au-status-text.offline{color:#9ca3af}
|
|
244
|
+
.au-group-header{font-size:13px;font-weight:600;color:var(--text-sec);margin:18px 0 8px;display:flex;align-items:center;gap:8px}
|
|
245
|
+
.au-group-header:first-child{margin-top:0}
|
|
246
|
+
.au-group-header .au-group-dot{display:inline-block;width:8px;height:8px;border-radius:50%}
|
|
247
|
+
.au-group-header .au-group-dot.online{background:#22c55e}
|
|
248
|
+
.au-group-header .au-group-dot.offline{background:#9ca3af}
|
|
249
|
+
.au-group-header .au-group-count{font-size:12px;font-weight:400;color:var(--text-muted)}
|
|
250
|
+
.au-card.au-offline{opacity:.7}
|
|
251
|
+
.au-card.au-offline::before{background:#9ca3af}
|
|
252
|
+
.au-card.au-online::before{background:#22c55e}
|
|
236
253
|
.admin-card-tags{display:flex;gap:5px;margin:8px 0;align-items:center}
|
|
237
254
|
.admin-card-tags-left{display:flex;flex-wrap:wrap;gap:5px;align-items:center;flex:1;min-width:0}
|
|
238
255
|
.admin-card-tag{display:inline-flex;align-items:center;gap:3px;padding:2px 8px;border-radius:6px;font-size:11px;font-weight:500}
|
|
@@ -539,8 +556,10 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
539
556
|
.pagination .pg-info{font-size:12px;color:var(--text-sec);padding:0 12px}
|
|
540
557
|
|
|
541
558
|
/* ─── Tasks 视图 ─── */
|
|
542
|
-
.
|
|
543
|
-
.
|
|
559
|
+
.view-container{flex:1;min-width:0}
|
|
560
|
+
.view-container>.vp{display:none;flex-direction:column}
|
|
561
|
+
.view-container>.vp.show{display:flex}
|
|
562
|
+
.tasks-view{flex:1;min-width:0;flex-direction:column;gap:16px}
|
|
544
563
|
.tasks-header{display:flex;flex-direction:column;gap:14px}
|
|
545
564
|
.tasks-stats{display:flex;gap:16px}
|
|
546
565
|
.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}
|
|
@@ -618,8 +637,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
618
637
|
[data-theme="light"] .tasks-stat{background:#fff}
|
|
619
638
|
|
|
620
639
|
/* ─── Skills ─── */
|
|
621
|
-
.skills-view{
|
|
622
|
-
.skills-view.show{display:flex}
|
|
640
|
+
.skills-view{flex:1;min-width:0;flex-direction:column;gap:16px}
|
|
623
641
|
.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}
|
|
624
642
|
.skill-card:hover{border-color:var(--border-glow);background:var(--bg-card-hover);transform:translateY(-1px);box-shadow:var(--shadow)}
|
|
625
643
|
.skill-card::before{content:'';position:absolute;top:0;left:0;bottom:0;width:3px;border-radius:3px 0 0 3px;background:var(--violet)}
|
|
@@ -693,9 +711,8 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
693
711
|
.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)}
|
|
694
712
|
[data-theme="light"] .nav-tabs{background:rgba(0,0,0,.05)}
|
|
695
713
|
[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)}
|
|
696
|
-
.analytics-view,.settings-view,.logs-view,.migrate-view,.admin-view{
|
|
697
|
-
.analytics-view
|
|
698
|
-
.feed-wrap,.tasks-view,.skills-view,.analytics-view,.settings-view,.logs-view,.migrate-view,.admin-view{max-width:960px}
|
|
714
|
+
.analytics-view,.settings-view,.logs-view,.migrate-view,.admin-view{flex:1;min-width:0;flex-direction:column;gap:20px}
|
|
715
|
+
.feed-wrap,.tasks-view,.skills-view,.analytics-view,.settings-view,.logs-view,.migrate-view,.admin-view{max-width:960px;margin:0 auto}
|
|
699
716
|
|
|
700
717
|
/* ─── Logs ─── */
|
|
701
718
|
.logs-toolbar{display:flex;align-items:center;justify-content:space-between;padding:8px 0}
|
|
@@ -897,7 +914,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
897
914
|
.test-result.ok{color:#22c55e}
|
|
898
915
|
.test-result.fail{color:var(--rose)}
|
|
899
916
|
.test-result.loading{color:var(--text-muted)}
|
|
900
|
-
.settings-actions{display:flex;gap:12px;justify-content:flex-end;align-items:center;margin-top:20px;padding-top:16px;
|
|
917
|
+
.settings-actions{display:flex;gap:12px;justify-content:flex-end;align-items:center;margin-top:20px;padding-top:16px;flex-wrap:nowrap}
|
|
901
918
|
.settings-actions .btn{flex:0 0 auto;min-width:0;padding:8px 24px;font-size:13px}
|
|
902
919
|
.settings-actions .btn-primary{background:rgba(99,102,241,.08);color:var(--pri);border:1px solid rgba(99,102,241,.25);font-weight:600}
|
|
903
920
|
.settings-actions .btn-primary:hover{background:rgba(99,102,241,.14);border-color:var(--pri)}
|
|
@@ -968,8 +985,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
968
985
|
.migrate-log-item .log-meta .tag.error{background:rgba(239,68,68,.1);color:#ef4444}
|
|
969
986
|
.migrate-log-item .log-meta .tag.duplicate{background:rgba(245,158,11,.1);color:#f59e0b}
|
|
970
987
|
@keyframes migrateFadeIn{from{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:translateY(0)}}
|
|
971
|
-
.feed-wrap{flex:1;min-width:0;
|
|
972
|
-
.feed-wrap.hide{display:none}
|
|
988
|
+
.feed-wrap{flex:1;min-width:0;flex-direction:column}
|
|
973
989
|
.analytics-view{flex-direction:column;gap:20px}
|
|
974
990
|
.analytics-cards{display:grid;grid-template-columns:repeat(4,1fr);gap:14px}
|
|
975
991
|
.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)}
|
|
@@ -1053,7 +1069,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1053
1069
|
[data-theme="light"] .auth-theme-toggle .theme-icon-dark{display:none}
|
|
1054
1070
|
|
|
1055
1071
|
@media(max-width:1100px){.analytics-cards{grid-template-columns:repeat(3,1fr)}}
|
|
1056
|
-
@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}}
|
|
1072
|
+
@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}}
|
|
1057
1073
|
</style>
|
|
1058
1074
|
</head>
|
|
1059
1075
|
<body>
|
|
@@ -1138,6 +1154,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1138
1154
|
<!-- ─── Main App ─── -->
|
|
1139
1155
|
<div class="app" id="app">
|
|
1140
1156
|
<div class="topbar">
|
|
1157
|
+
<div class="topbar-inner">
|
|
1141
1158
|
<div class="brand">
|
|
1142
1159
|
<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>
|
|
1143
1160
|
<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}
|
|
@@ -1164,10 +1181,10 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1164
1181
|
<div class="notif-panel-body" id="notifPanelBody"><div class="notif-empty" data-i18n="notif.empty">No notifications</div></div>
|
|
1165
1182
|
</div>
|
|
1166
1183
|
</div>
|
|
1167
|
-
<button class="btn btn-ghost btn-sm" onclick="loadAll()" data-i18n="refresh">\u21BB Refresh</button>
|
|
1168
1184
|
<button class="btn btn-ghost btn-sm" onclick="doLogout()" data-i18n="logout">Logout</button>
|
|
1169
1185
|
</div>
|
|
1170
1186
|
</div>
|
|
1187
|
+
</div>
|
|
1171
1188
|
|
|
1172
1189
|
<div class="main-content">
|
|
1173
1190
|
<div class="sidebar" id="sidebar">
|
|
@@ -1189,18 +1206,19 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1189
1206
|
<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>
|
|
1190
1207
|
</div>
|
|
1191
1208
|
|
|
1192
|
-
<div class="
|
|
1209
|
+
<div class="view-container">
|
|
1210
|
+
<div class="feed-wrap vp show" id="feedWrap">
|
|
1193
1211
|
<div class="feed">
|
|
1194
1212
|
<div class="search-bar">
|
|
1195
1213
|
<span class="search-icon">\u{1F50D}</span>
|
|
1196
1214
|
<input type="text" id="searchInput" data-i18n-ph="search.placeholder" placeholder="Search memories (supports semantic search)..." oninput="debounceSearch()">
|
|
1197
1215
|
<select id="filterOwner" class="filter-select" onchange="onOwnerFilterChange()">
|
|
1198
|
-
<option value="" data-i18n="filter.
|
|
1199
|
-
<option value="public" data-i18n="filter.public">Public</option>
|
|
1216
|
+
<option value="" data-i18n="filter.allagents">All agents</option>
|
|
1200
1217
|
</select>
|
|
1201
1218
|
<select id="memorySearchScope" class="filter-select" onchange="onMemoryScopeChange()">
|
|
1202
|
-
<option value="local" data-i18n="scope.
|
|
1203
|
-
<option value="
|
|
1219
|
+
<option value="local" data-i18n="scope.thisAgent">This Agent</option>
|
|
1220
|
+
<option value="allLocal" data-i18n="scope.thisDevice">This Device</option>
|
|
1221
|
+
<option value="hub" data-i18n="scope.hub">Team</option>
|
|
1204
1222
|
</select>
|
|
1205
1223
|
</div>
|
|
1206
1224
|
<div class="search-meta" id="searchMeta"></div>
|
|
@@ -1229,7 +1247,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1229
1247
|
<div class="pagination" id="pagination"></div>
|
|
1230
1248
|
</div>
|
|
1231
1249
|
</div>
|
|
1232
|
-
<div class="tasks-view" id="tasksView">
|
|
1250
|
+
<div class="tasks-view vp" id="tasksView">
|
|
1233
1251
|
<div class="tasks-header">
|
|
1234
1252
|
<div class="tasks-stats">
|
|
1235
1253
|
<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>
|
|
@@ -1243,10 +1261,10 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1243
1261
|
<button class="filter-chip" data-task-status="completed" onclick="setTaskStatusFilter(this,'completed')" data-i18n="tasks.status.completed">Completed</button>
|
|
1244
1262
|
<button class="filter-chip" data-task-status="skipped" onclick="setTaskStatusFilter(this,'skipped')" data-i18n="tasks.status.skipped">Skipped</button>
|
|
1245
1263
|
<select id="taskSearchScope" class="scope-select" onchange="onTaskScopeChange()">
|
|
1246
|
-
<option value="local" data-i18n="scope.
|
|
1247
|
-
<option value="
|
|
1264
|
+
<option value="local" data-i18n="scope.thisAgent">This Agent</option>
|
|
1265
|
+
<option value="allLocal" data-i18n="scope.thisDevice">This Device</option>
|
|
1266
|
+
<option value="hub" data-i18n="scope.hub">Team</option>
|
|
1248
1267
|
</select>
|
|
1249
|
-
<button class="btn btn-sm btn-ghost" onclick="loadTasks()" style="margin-left:auto" data-i18n="refresh">\u21BB Refresh</button>
|
|
1250
1268
|
</div>
|
|
1251
1269
|
</div>
|
|
1252
1270
|
<div class="tasks-list" id="tasksList"><div class="spinner"></div></div>
|
|
@@ -1280,13 +1298,14 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1280
1298
|
<div class="content" id="sharedMemoryContent"></div>
|
|
1281
1299
|
</div>
|
|
1282
1300
|
</div>
|
|
1283
|
-
<div class="skills-view" id="skillsView">
|
|
1301
|
+
<div class="skills-view vp" id="skillsView">
|
|
1284
1302
|
<div class="search-bar">
|
|
1285
1303
|
<span class="search-icon">🔍</span>
|
|
1286
1304
|
<input type="text" id="skillSearchInput" placeholder="Search skills..." data-i18n-ph="skills.search.placeholder" oninput="debounceSkillSearch()">
|
|
1287
1305
|
<select id="skillSearchScope" class="scope-select" onchange="onSkillScopeChange()">
|
|
1288
|
-
<option value="local" data-i18n="scope.
|
|
1289
|
-
<option value="
|
|
1306
|
+
<option value="local" data-i18n="scope.thisAgent">This Agent</option>
|
|
1307
|
+
<option value="allLocal" data-i18n="scope.thisDevice">This Device</option>
|
|
1308
|
+
<option value="hub" data-i18n="scope.hub">Team</option>
|
|
1290
1309
|
</select>
|
|
1291
1310
|
</div>
|
|
1292
1311
|
<div class="search-meta" id="skillSearchMeta"></div>
|
|
@@ -1309,7 +1328,6 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1309
1328
|
<option value="public" data-i18n="filter.public">Public</option>
|
|
1310
1329
|
<option value="private" data-i18n="filter.private">Private</option>
|
|
1311
1330
|
</select>
|
|
1312
|
-
<button class="btn btn-sm btn-ghost" onclick="loadSkills()" style="margin-left:auto" data-i18n="refresh">\u21BB Refresh</button>
|
|
1313
1331
|
</div>
|
|
1314
1332
|
</div>
|
|
1315
1333
|
<div class="tasks-list" id="skillsList"><div class="spinner"></div></div>
|
|
@@ -1342,7 +1360,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1342
1360
|
<div id="skillDetailActions" style="display:flex;gap:8px;margin-top:16px;padding-top:12px;border-top:1px solid var(--border)"></div>
|
|
1343
1361
|
</div>
|
|
1344
1362
|
</div>
|
|
1345
|
-
<div class="analytics-view" id="analyticsView">
|
|
1363
|
+
<div class="analytics-view vp" id="analyticsView">
|
|
1346
1364
|
<div class="metrics-toolbar" style="margin-bottom:0">
|
|
1347
1365
|
<span style="font-size:12px;color:var(--text-sec);font-weight:600" data-i18n="range">Range</span>
|
|
1348
1366
|
<button class="range-btn" data-days="7" onclick="setMetricsDays(7)">7 <span data-i18n="range.days">days</span></button>
|
|
@@ -1386,7 +1404,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1386
1404
|
</div>
|
|
1387
1405
|
|
|
1388
1406
|
<!-- ─── Logs View ─── -->
|
|
1389
|
-
<div class="logs-view" id="logsView">
|
|
1407
|
+
<div class="logs-view vp" id="logsView">
|
|
1390
1408
|
<div class="logs-toolbar">
|
|
1391
1409
|
<div class="logs-toolbar-left">
|
|
1392
1410
|
<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">
|
|
@@ -1403,7 +1421,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1403
1421
|
</div>
|
|
1404
1422
|
|
|
1405
1423
|
<!-- ─── Settings View ─── -->
|
|
1406
|
-
<div class="settings-view" id="settingsView">
|
|
1424
|
+
<div class="settings-view vp" id="settingsView">
|
|
1407
1425
|
<div class="settings-tabs-bar">
|
|
1408
1426
|
<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>
|
|
1409
1427
|
<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>
|
|
@@ -1569,7 +1587,6 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1569
1587
|
</div>
|
|
1570
1588
|
</div>
|
|
1571
1589
|
|
|
1572
|
-
<div class="settings-card-divider"></div>
|
|
1573
1590
|
<div class="settings-actions">
|
|
1574
1591
|
<span class="settings-saved" id="modelsSaved">\u2713 <span data-i18n="settings.saved">Saved</span></span>
|
|
1575
1592
|
<button class="btn btn-ghost" onclick="loadConfig()" data-i18n="settings.reset">Reset</button>
|
|
@@ -1658,6 +1675,11 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1658
1675
|
<input type="text" id="cfgHubTeamName" placeholder="My Team">
|
|
1659
1676
|
<div class="field-hint" data-i18n="settings.hub.teamName.hint">Your team display name</div>
|
|
1660
1677
|
</div>
|
|
1678
|
+
<div class="settings-field">
|
|
1679
|
+
<label data-i18n="settings.hub.adminName">Admin Name</label>
|
|
1680
|
+
<input type="text" id="cfgHubAdminName" placeholder="" maxlength="32">
|
|
1681
|
+
<div class="field-hint" data-i18n="settings.hub.adminName.hint">Your display name as team admin</div>
|
|
1682
|
+
</div>
|
|
1661
1683
|
</div>
|
|
1662
1684
|
<div id="hubShareInfo" style="display:none;margin-top:14px;background:var(--bg);border:1px solid var(--border);border-radius:10px;padding:14px 18px">
|
|
1663
1685
|
<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>
|
|
@@ -1686,6 +1708,11 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1686
1708
|
<input type="text" id="cfgClientTeamToken" placeholder="">
|
|
1687
1709
|
<div class="field-hint" data-i18n="settings.hub.teamTokenClient.hint">Get this from your team admin to join</div>
|
|
1688
1710
|
</div>
|
|
1711
|
+
<div class="settings-field">
|
|
1712
|
+
<label data-i18n="settings.hub.nickname">Nickname</label>
|
|
1713
|
+
<input type="text" id="cfgClientNickname" placeholder="" maxlength="32">
|
|
1714
|
+
<div class="field-hint" data-i18n="settings.hub.nickname.hint">Your display name in the team. If empty, uses system username.</div>
|
|
1715
|
+
</div>
|
|
1689
1716
|
<input type="hidden" id="cfgClientUserToken" value="">
|
|
1690
1717
|
</div>
|
|
1691
1718
|
<div style="margin-top:12px">
|
|
@@ -1740,7 +1767,6 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1740
1767
|
</div>
|
|
1741
1768
|
<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>
|
|
1742
1769
|
|
|
1743
|
-
<div class="settings-card-divider"></div>
|
|
1744
1770
|
<div class="settings-actions">
|
|
1745
1771
|
<span class="settings-saved" id="generalSaved">\u2713 <span data-i18n="settings.saved">Saved</span></span>
|
|
1746
1772
|
<button class="btn btn-ghost" onclick="loadConfig()" data-i18n="settings.reset">Reset</button>
|
|
@@ -1755,7 +1781,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1755
1781
|
</div>
|
|
1756
1782
|
|
|
1757
1783
|
<!-- ─── Admin Page ─── -->
|
|
1758
|
-
<div class="admin-view" id="adminView">
|
|
1784
|
+
<div class="admin-view vp" id="adminView">
|
|
1759
1785
|
<div id="adminNotEnabled" style="display:none"></div>
|
|
1760
1786
|
<div id="adminMainContent">
|
|
1761
1787
|
<div class="admin-header">
|
|
@@ -1780,7 +1806,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1780
1806
|
</div>
|
|
1781
1807
|
|
|
1782
1808
|
<!-- ─── Import Page ─── -->
|
|
1783
|
-
<div class="migrate-view" id="migrateView">
|
|
1809
|
+
<div class="migrate-view vp" id="migrateView">
|
|
1784
1810
|
<div class="settings-section" style="border:1px solid rgba(99,102,241,.15)">
|
|
1785
1811
|
<h3><span class="icon">\u{1F4E5}</span> <span data-i18n="migrate.title">Import OpenClaw Memory</span></h3>
|
|
1786
1812
|
<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>
|
|
@@ -1950,6 +1976,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1950
1976
|
|
|
1951
1977
|
</div>
|
|
1952
1978
|
|
|
1979
|
+
</div>
|
|
1953
1980
|
</div>
|
|
1954
1981
|
</div>
|
|
1955
1982
|
|
|
@@ -2024,6 +2051,8 @@ const I18N={
|
|
|
2024
2051
|
'skills.load.error':'Failed to load skills',
|
|
2025
2052
|
'skills.hub.title':'\u{1F310} Team Skills',
|
|
2026
2053
|
'scope.local':'Local',
|
|
2054
|
+
'scope.thisAgent':'This Agent',
|
|
2055
|
+
'scope.thisDevice':'This Device',
|
|
2027
2056
|
'scope.group':'Group',
|
|
2028
2057
|
'scope.all':'All',
|
|
2029
2058
|
'skills.visibility.public':'Shared Locally',
|
|
@@ -2052,6 +2081,15 @@ const I18N={
|
|
|
2052
2081
|
'notif.removed.memory':'Your shared memory was removed by admin',
|
|
2053
2082
|
'notif.removed.task':'Your shared task was removed by admin',
|
|
2054
2083
|
'notif.removed.skill':'Your shared skill was removed by admin',
|
|
2084
|
+
'notif.shared.memory':'A new memory was shared',
|
|
2085
|
+
'notif.shared.task':'A new task was shared',
|
|
2086
|
+
'notif.shared.skill':'A new skill was shared',
|
|
2087
|
+
'notif.unshared.memory':'A memory was unshared',
|
|
2088
|
+
'notif.unshared.task':'A task was unshared',
|
|
2089
|
+
'notif.unshared.skill':'A skill was unshared',
|
|
2090
|
+
'notif.userJoin':'New user requests to join the team',
|
|
2091
|
+
'notif.userOnline':'User came online',
|
|
2092
|
+
'notif.userOffline':'User went offline',
|
|
2055
2093
|
'notif.clearAll':'Clear all',
|
|
2056
2094
|
'notif.timeAgo.just':'just now',
|
|
2057
2095
|
'notif.timeAgo.min':'{n}m ago',
|
|
@@ -2075,6 +2113,7 @@ const I18N={
|
|
|
2075
2113
|
'filter.newest':'Newest first',
|
|
2076
2114
|
'filter.oldest':'Oldest first',
|
|
2077
2115
|
'filter.allowners':'All owners',
|
|
2116
|
+
'filter.allagents':'All agents',
|
|
2078
2117
|
'filter.allsessions':'All sessions',
|
|
2079
2118
|
'filter.public':'Public',
|
|
2080
2119
|
'filter.private':'Private',
|
|
@@ -2323,6 +2362,8 @@ const I18N={
|
|
|
2323
2362
|
'settings.hub.port.hint':'Port for team server. Default: 18800',
|
|
2324
2363
|
'settings.hub.teamName':'Team Name',
|
|
2325
2364
|
'settings.hub.teamName.hint':'Display name for your team',
|
|
2365
|
+
'settings.hub.adminName':'Admin Name',
|
|
2366
|
+
'settings.hub.adminName.hint':'Your display name as team admin',
|
|
2326
2367
|
'settings.hub.teamToken':'Team Token',
|
|
2327
2368
|
'settings.hub.teamToken.hint':'Auto-generated secret for clients to join. Click to copy. Share this with your team members.',
|
|
2328
2369
|
'settings.hub.tokenCopied':'Team Token copied!',
|
|
@@ -2342,6 +2383,8 @@ const I18N={
|
|
|
2342
2383
|
'settings.hub.hubAddress.hint':'Team server address, e.g. 192.168.1.100:18800',
|
|
2343
2384
|
'settings.hub.teamTokenClient':'Team Token',
|
|
2344
2385
|
'settings.hub.teamTokenClient.hint':'Get this from your team admin to join',
|
|
2386
|
+
'settings.hub.nickname':'Nickname',
|
|
2387
|
+
'settings.hub.nickname.hint':'Your display name in the team. If empty, uses system username.',
|
|
2345
2388
|
'settings.hub.userToken':'User Token',
|
|
2346
2389
|
'settings.hub.userToken.hint':'Usually auto-obtained after joining. Only fill if given by admin.',
|
|
2347
2390
|
'settings.hub.testConnection':'Test Connection',
|
|
@@ -2380,6 +2423,7 @@ const I18N={
|
|
|
2380
2423
|
'memory.detail.viewTarget':'View target: ',
|
|
2381
2424
|
'admin.title':'Team Admin Panel',
|
|
2382
2425
|
'admin.subtitle':'Manage team members and shared resources',
|
|
2426
|
+
'admin.subtitle.member':'Browse shared memories, tasks and skills from your team',
|
|
2383
2427
|
'admin.refresh':'\u21BB Refresh',
|
|
2384
2428
|
'admin.tab.users':'Users',
|
|
2385
2429
|
'admin.tab.tasks':'Shared Tasks',
|
|
@@ -2395,6 +2439,12 @@ const I18N={
|
|
|
2395
2439
|
'admin.pendingApproval':'Pending Approval',
|
|
2396
2440
|
'admin.activeUsers':'Active Users',
|
|
2397
2441
|
'admin.noActiveUsers':'No active users.',
|
|
2442
|
+
'admin.onlineUsers':'Online',
|
|
2443
|
+
'admin.offlineUsers':'Offline',
|
|
2444
|
+
'admin.online':'Online',
|
|
2445
|
+
'admin.offline':'Offline',
|
|
2446
|
+
'admin.offlineFor':'Offline for {time}',
|
|
2447
|
+
'admin.onlineNow':'Online now',
|
|
2398
2448
|
'admin.approve':'Approve',
|
|
2399
2449
|
'admin.reject':'Reject',
|
|
2400
2450
|
'admin.device':'Device: ',
|
|
@@ -2411,6 +2461,7 @@ const I18N={
|
|
|
2411
2461
|
'admin.demoteMember':'Demote to Member',
|
|
2412
2462
|
'admin.editName':'Edit Name',
|
|
2413
2463
|
'admin.lastAdminHint':'Last admin — cannot remove or demote',
|
|
2464
|
+
'admin.ownerHint':'Hub owner — cannot be demoted or removed',
|
|
2414
2465
|
'admin.editNamePrompt':'Enter new username:',
|
|
2415
2466
|
'confirm.promoteAdmin':'Promote this user to admin? They will be able to manage all team members and resources.',
|
|
2416
2467
|
'confirm.demoteMember':'Demote this admin to member?',
|
|
@@ -2705,6 +2756,8 @@ const I18N={
|
|
|
2705
2756
|
'skills.load.error':'加载技能失败',
|
|
2706
2757
|
'skills.hub.title':'\u{1F310} 团队共享技能',
|
|
2707
2758
|
'scope.local':'本地',
|
|
2759
|
+
'scope.thisAgent':'当前智能体',
|
|
2760
|
+
'scope.thisDevice':'本机全部',
|
|
2708
2761
|
'scope.group':'团队',
|
|
2709
2762
|
'scope.all':'全部',
|
|
2710
2763
|
'skills.visibility.public':'本机共享',
|
|
@@ -2733,6 +2786,15 @@ const I18N={
|
|
|
2733
2786
|
'notif.removed.memory':'你共享的记忆被管理员移除',
|
|
2734
2787
|
'notif.removed.task':'你共享的任务被管理员移除',
|
|
2735
2788
|
'notif.removed.skill':'你共享的技能被管理员移除',
|
|
2789
|
+
'notif.shared.memory':'有新的记忆被共享',
|
|
2790
|
+
'notif.shared.task':'有新的任务被共享',
|
|
2791
|
+
'notif.shared.skill':'有新的技能被共享',
|
|
2792
|
+
'notif.unshared.memory':'有记忆取消了共享',
|
|
2793
|
+
'notif.unshared.task':'有任务取消了共享',
|
|
2794
|
+
'notif.unshared.skill':'有技能取消了共享',
|
|
2795
|
+
'notif.userJoin':'有新用户申请加入团队',
|
|
2796
|
+
'notif.userOnline':'用户上线了',
|
|
2797
|
+
'notif.userOffline':'用户下线了',
|
|
2736
2798
|
'notif.clearAll':'清除全部',
|
|
2737
2799
|
'notif.timeAgo.just':'刚刚',
|
|
2738
2800
|
'notif.timeAgo.min':'{n}分钟前',
|
|
@@ -2756,6 +2818,7 @@ const I18N={
|
|
|
2756
2818
|
'filter.newest':'最新优先',
|
|
2757
2819
|
'filter.oldest':'最早优先',
|
|
2758
2820
|
'filter.allowners':'所有归属',
|
|
2821
|
+
'filter.allagents':'全部智能体',
|
|
2759
2822
|
'filter.allsessions':'全部会话',
|
|
2760
2823
|
'filter.public':'公开',
|
|
2761
2824
|
'filter.private':'私有',
|
|
@@ -3004,6 +3067,8 @@ const I18N={
|
|
|
3004
3067
|
'settings.hub.port.hint':'团队服务端口,默认 18800',
|
|
3005
3068
|
'settings.hub.teamName':'团队名称',
|
|
3006
3069
|
'settings.hub.teamName.hint':'你的团队显示名称',
|
|
3070
|
+
'settings.hub.adminName':'管理员名称',
|
|
3071
|
+
'settings.hub.adminName.hint':'你在团队中的显示名称',
|
|
3007
3072
|
'settings.hub.teamToken':'团队令牌',
|
|
3008
3073
|
'settings.hub.teamToken.hint':'自动生成的密钥,点击可复制。请将此令牌分享给团队成员。',
|
|
3009
3074
|
'settings.hub.tokenCopied':'团队令牌已复制!',
|
|
@@ -3023,6 +3088,8 @@ const I18N={
|
|
|
3023
3088
|
'settings.hub.hubAddress.hint':'团队服务器地址,如 192.168.1.100:18800',
|
|
3024
3089
|
'settings.hub.teamTokenClient':'团队令牌',
|
|
3025
3090
|
'settings.hub.teamTokenClient.hint':'向团队管理员获取此令牌以加入团队',
|
|
3091
|
+
'settings.hub.nickname':'昵称',
|
|
3092
|
+
'settings.hub.nickname.hint':'你在团队中的显示名称。留空则使用系统用户名。',
|
|
3026
3093
|
'settings.hub.userToken':'用户令牌',
|
|
3027
3094
|
'settings.hub.userToken.hint':'通常在加入团队后自动获取,无需手动填写。',
|
|
3028
3095
|
'settings.hub.testConnection':'测试连接',
|
|
@@ -3061,6 +3128,7 @@ const I18N={
|
|
|
3061
3128
|
'memory.detail.viewTarget':'查看目标: ',
|
|
3062
3129
|
'admin.title':'团队管理面板',
|
|
3063
3130
|
'admin.subtitle':'管理团队成员和共享资源',
|
|
3131
|
+
'admin.subtitle.member':'浏览团队共享的记忆、任务和技能',
|
|
3064
3132
|
'admin.refresh':'\u21BB 刷新',
|
|
3065
3133
|
'admin.tab.users':'用户',
|
|
3066
3134
|
'admin.tab.tasks':'共享任务',
|
|
@@ -3076,6 +3144,12 @@ const I18N={
|
|
|
3076
3144
|
'admin.pendingApproval':'待审批',
|
|
3077
3145
|
'admin.activeUsers':'活跃用户',
|
|
3078
3146
|
'admin.noActiveUsers':'暂无活跃用户。',
|
|
3147
|
+
'admin.onlineUsers':'在线',
|
|
3148
|
+
'admin.offlineUsers':'离线',
|
|
3149
|
+
'admin.online':'在线',
|
|
3150
|
+
'admin.offline':'离线',
|
|
3151
|
+
'admin.offlineFor':'离线 {time}',
|
|
3152
|
+
'admin.onlineNow':'当前在线',
|
|
3079
3153
|
'admin.approve':'批准',
|
|
3080
3154
|
'admin.reject':'拒绝',
|
|
3081
3155
|
'admin.device':'设备:',
|
|
@@ -3092,6 +3166,7 @@ const I18N={
|
|
|
3092
3166
|
'admin.demoteMember':'降为成员',
|
|
3093
3167
|
'admin.editName':'编辑名称',
|
|
3094
3168
|
'admin.lastAdminHint':'唯一管理员 — 无法删除或降级',
|
|
3169
|
+
'admin.ownerHint':'Hub 创建者 — 不可降级或移除',
|
|
3095
3170
|
'admin.editNamePrompt':'请输入新用户名:',
|
|
3096
3171
|
'confirm.promoteAdmin':'确定要将此用户提升为管理员吗?管理员可以管理所有团队成员和资源。',
|
|
3097
3172
|
'confirm.demoteMember':'确定要将此管理员降为普通成员吗?',
|
|
@@ -3549,59 +3624,41 @@ function switchSettingsTab(tab,btn){
|
|
|
3549
3624
|
});
|
|
3550
3625
|
}
|
|
3551
3626
|
|
|
3627
|
+
var _activeView='memories';
|
|
3552
3628
|
function switchView(view){
|
|
3629
|
+
_activeView=view;
|
|
3553
3630
|
document.querySelectorAll('.nav-tabs .tab').forEach(t=>t.classList.toggle('active',t.dataset.view===view));
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
const settingsView=document.getElementById('settingsView');
|
|
3560
|
-
const migrateView=document.getElementById('migrateView');
|
|
3561
|
-
const adminView=document.getElementById('adminView');
|
|
3562
|
-
const sidebar=document.getElementById('sidebar');
|
|
3563
|
-
feedWrap.classList.add('hide');
|
|
3564
|
-
analyticsView.classList.remove('show');
|
|
3565
|
-
tasksView.classList.remove('show');
|
|
3566
|
-
skillsView.classList.remove('show');
|
|
3567
|
-
logsView.classList.remove('show');
|
|
3568
|
-
settingsView.classList.remove('show');
|
|
3569
|
-
migrateView.classList.remove('show');
|
|
3570
|
-
if(adminView) adminView.classList.remove('show');
|
|
3631
|
+
var viewMap={memories:'feedWrap',tasks:'tasksView',skills:'skillsView',analytics:'analyticsView',logs:'logsView',settings:'settingsView',import:'migrateView',admin:'adminView'};
|
|
3632
|
+
for(var k in viewMap){
|
|
3633
|
+
var el=document.getElementById(viewMap[k]);
|
|
3634
|
+
if(el) el.classList.toggle('show',k===view);
|
|
3635
|
+
}
|
|
3571
3636
|
var sessionSection=document.getElementById('sidebarSessionSection');
|
|
3572
|
-
if(
|
|
3573
|
-
|
|
3574
|
-
|
|
3575
|
-
} else if(view==='tasks'||view==='skills'){
|
|
3576
|
-
if(sessionSection){sessionSection.style.visibility='hidden';sessionSection.style.pointerEvents='none';}
|
|
3577
|
-
if(view==='tasks'){tasksView.classList.add('show');loadTasks();}
|
|
3578
|
-
else{skillsView.classList.add('show');loadSkills();}
|
|
3579
|
-
} else {
|
|
3580
|
-
if(sessionSection){sessionSection.style.visibility='hidden';sessionSection.style.pointerEvents='none';}
|
|
3581
|
-
if(view==='analytics'){
|
|
3582
|
-
analyticsView.classList.add('show');
|
|
3583
|
-
loadMetrics();
|
|
3584
|
-
} else if(view==='logs'){
|
|
3585
|
-
logsView.classList.add('show');
|
|
3586
|
-
loadLogs();
|
|
3587
|
-
} else if(view==='settings'){
|
|
3588
|
-
settingsView.classList.add('show');
|
|
3589
|
-
loadConfig();
|
|
3590
|
-
loadModelHealth();
|
|
3591
|
-
} else if(view==='import'){
|
|
3592
|
-
migrateView.classList.add('show');
|
|
3593
|
-
if(!window._migrateRunning) migrateScan(false);
|
|
3594
|
-
} else if(view==='admin'){
|
|
3595
|
-
if(adminView){adminView.classList.add('show');loadAdminData();}
|
|
3596
|
-
}
|
|
3637
|
+
if(sessionSection){
|
|
3638
|
+
if(view==='memories'){sessionSection.style.visibility='';sessionSection.style.pointerEvents='';}
|
|
3639
|
+
else{sessionSection.style.visibility='hidden';sessionSection.style.pointerEvents='none';}
|
|
3597
3640
|
}
|
|
3641
|
+
if(view==='tasks') loadTasks();
|
|
3642
|
+
else if(view==='skills') loadSkills();
|
|
3643
|
+
else if(view==='analytics') loadMetrics();
|
|
3644
|
+
else if(view==='logs') loadLogs();
|
|
3645
|
+
else if(view==='settings'){loadConfig();loadModelHealth();}
|
|
3646
|
+
else if(view==='import'){if(!window._migrateRunning) migrateScan(false);}
|
|
3647
|
+
else if(view==='admin'){loadAdminData();}
|
|
3598
3648
|
}
|
|
3599
3649
|
|
|
3600
3650
|
function onMemoryScopeChange(){
|
|
3601
3651
|
memorySearchScope=document.getElementById('memorySearchScope')?.value||'local';
|
|
3652
|
+
var isHub=memorySearchScope==='hub';
|
|
3653
|
+
var ownerSel=document.getElementById('filterOwner');
|
|
3654
|
+
var filterBar=document.getElementById('filterBar');
|
|
3655
|
+
var dateFilter=document.querySelector('.date-filter');
|
|
3656
|
+
if(ownerSel) ownerSel.style.display=isHub?'none':'';
|
|
3657
|
+
if(filterBar) filterBar.style.display=isHub?'none':'';
|
|
3658
|
+
if(dateFilter) dateFilter.style.display=isHub?'none':'';
|
|
3602
3659
|
if(document.getElementById('searchInput').value.trim()) doSearch(document.getElementById('searchInput').value);
|
|
3603
|
-
else if(
|
|
3604
|
-
else { document.getElementById('sharingSearchMeta').textContent=''; loadMemories(); }
|
|
3660
|
+
else if(isHub) { document.getElementById('sharingSearchMeta').textContent=''; loadHubMemories(); }
|
|
3661
|
+
else { document.getElementById('sharingSearchMeta').textContent=''; loadStats(); loadMemories(); }
|
|
3605
3662
|
}
|
|
3606
3663
|
|
|
3607
3664
|
function onSkillScopeChange(){
|
|
@@ -3719,8 +3776,12 @@ function renderSharingSettings(data){
|
|
|
3719
3776
|
var hubAdminBtn=document.getElementById('hubAdminEntryBtn');
|
|
3720
3777
|
|
|
3721
3778
|
if(actualRole==='hub'){
|
|
3722
|
-
|
|
3779
|
+
teamEl.innerHTML='';adminEl.innerHTML='';statusEl.innerHTML='';statusEl.style.display='none';
|
|
3723
3780
|
if(hubAdminBtn) hubAdminBtn.style.display=isAdmin?'':'none';
|
|
3781
|
+
var hubUser=conn.user||{};
|
|
3782
|
+
var hubName=hubUser.username||'admin';
|
|
3783
|
+
var adminNameInput=document.getElementById('cfgHubAdminName');
|
|
3784
|
+
if(adminNameInput) adminNameInput.value=hubName;
|
|
3724
3785
|
return;
|
|
3725
3786
|
}
|
|
3726
3787
|
|
|
@@ -3912,6 +3973,8 @@ function guideGoToHub(role){
|
|
|
3912
3973
|
|
|
3913
3974
|
/* ─── Hub Admin Panel ─── */
|
|
3914
3975
|
var adminDataCache={users:[],groups:[],tasks:[],skills:[],memories:[]};
|
|
3976
|
+
var hubTasksCache=[];
|
|
3977
|
+
var hubSkillsCache=[];
|
|
3915
3978
|
var ADMIN_PAGE_SIZE=20;
|
|
3916
3979
|
var adminPage={users:0,tasks:0,skills:0,memories:0};
|
|
3917
3980
|
|
|
@@ -3933,12 +3996,9 @@ function adminPaginateHtml(total,page,refilterFn){
|
|
|
3933
3996
|
}
|
|
3934
3997
|
|
|
3935
3998
|
var _adminPollTimer=null;
|
|
3936
|
-
function startAdminPoll(){
|
|
3937
|
-
if(_adminPollTimer) return;
|
|
3938
|
-
_adminPollTimer=setInterval(function(){pollAdminPending();},30000);
|
|
3939
|
-
pollAdminPending();
|
|
3940
|
-
}
|
|
3999
|
+
function startAdminPoll(){ startLivePoller(); }
|
|
3941
4000
|
async function pollAdminPending(){
|
|
4001
|
+
if(!window._isHubAdmin) return;
|
|
3942
4002
|
try{
|
|
3943
4003
|
var r=await fetch('/api/sharing/pending-users');
|
|
3944
4004
|
var d=await r.json();
|
|
@@ -3988,24 +4048,32 @@ async function loadAdminData(){
|
|
|
3988
4048
|
}
|
|
3989
4049
|
if(notEnabledEl) notEnabledEl.style.display='none';
|
|
3990
4050
|
if(mainEl) mainEl.style.display='';
|
|
3991
|
-
|
|
3992
|
-
var statsEl=document.getElementById('adminStats');
|
|
3993
|
-
if(statsEl) statsEl.innerHTML='<div class="admin-empty">'+t('admin.noPermission')+'</div>';
|
|
3994
|
-
return;
|
|
3995
|
-
}
|
|
4051
|
+
var isAdmin=!!window._isHubAdmin;
|
|
3996
4052
|
try{
|
|
3997
|
-
var
|
|
3998
|
-
|
|
3999
|
-
|
|
4000
|
-
|
|
4001
|
-
|
|
4002
|
-
|
|
4003
|
-
|
|
4053
|
+
var fetches;
|
|
4054
|
+
if(isAdmin){
|
|
4055
|
+
fetches=await Promise.all([
|
|
4056
|
+
fetch('/api/sharing/users').then(function(r){return r.json();}),
|
|
4057
|
+
fetch('/api/admin/shared-tasks').then(function(r){return r.json();}),
|
|
4058
|
+
fetch('/api/admin/shared-skills').then(function(r){return r.json();}),
|
|
4059
|
+
fetch('/api/sharing/pending-users').then(function(r){return r.json();}),
|
|
4060
|
+
fetch('/api/admin/shared-memories').then(function(r){return r.json();})
|
|
4061
|
+
]);
|
|
4062
|
+
}else{
|
|
4063
|
+
fetches=await Promise.all([
|
|
4064
|
+
Promise.resolve({users:[]}),
|
|
4065
|
+
fetch('/api/sharing/tasks/list?limit=500').then(function(r){return r.json();}),
|
|
4066
|
+
fetch('/api/sharing/skills/list?limit=500').then(function(r){return r.json();}),
|
|
4067
|
+
Promise.resolve({users:[]}),
|
|
4068
|
+
fetch('/api/sharing/memories/list?limit=500').then(function(r){return r.json();})
|
|
4069
|
+
]);
|
|
4070
|
+
}
|
|
4071
|
+
var usersR=fetches[0],tasksR=fetches[1],skillsR=fetches[2],pendingR=fetches[3],memoriesR=fetches[4];
|
|
4004
4072
|
adminDataCache.users=Array.isArray(usersR.users)?usersR.users:[];
|
|
4005
4073
|
adminDataCache.tasks=Array.isArray(tasksR.tasks)?tasksR.tasks:[];
|
|
4006
4074
|
adminDataCache.skills=Array.isArray(skillsR.skills)?skillsR.skills:[];
|
|
4007
4075
|
adminDataCache.memories=Array.isArray(memoriesR.memories)?memoriesR.memories:[];
|
|
4008
|
-
var pending=Array.isArray(pendingR.users)?pendingR.users:[];
|
|
4076
|
+
var pending=isAdmin?(Array.isArray(pendingR.users)?pendingR.users:[]):[];
|
|
4009
4077
|
adminDataCache._pending=pending;
|
|
4010
4078
|
var badge=document.getElementById('adminPendingBadge');
|
|
4011
4079
|
if(badge){if(pending.length>0){badge.textContent=pending.length;badge.style.display='inline';}else{badge.style.display='none';}}
|
|
@@ -4014,18 +4082,48 @@ async function loadAdminData(){
|
|
|
4014
4082
|
renderAdminTasks(adminDataCache.tasks);
|
|
4015
4083
|
renderAdminSkills(adminDataCache.skills);
|
|
4016
4084
|
renderAdminMemories(adminDataCache.memories);
|
|
4085
|
+
updateAdminTabsVisibility();
|
|
4017
4086
|
}catch(e){
|
|
4018
4087
|
var statsEl=document.getElementById('adminStats');
|
|
4019
4088
|
if(statsEl) statsEl.innerHTML='<div class="admin-empty">'+t('admin.loadFailed')+esc(String(e))+'</div>';
|
|
4020
4089
|
}
|
|
4021
4090
|
}
|
|
4091
|
+
function updateAdminTabsVisibility(){
|
|
4092
|
+
var bar=document.getElementById('adminTabsBar');
|
|
4093
|
+
if(!bar) return;
|
|
4094
|
+
var tabs=bar.querySelectorAll('.admin-tab');
|
|
4095
|
+
var isAdmin=!!window._isHubAdmin;
|
|
4096
|
+
tabs.forEach(function(tab){
|
|
4097
|
+
var onclick=tab.getAttribute('onclick')||'';
|
|
4098
|
+
if(onclick.indexOf("'users'")!==-1){
|
|
4099
|
+
tab.style.display=isAdmin?'':'none';
|
|
4100
|
+
}
|
|
4101
|
+
});
|
|
4102
|
+
if(!isAdmin){
|
|
4103
|
+
var usersPanel=document.getElementById('adminUsersPanel');
|
|
4104
|
+
if(usersPanel&&usersPanel.classList.contains('active')){
|
|
4105
|
+
usersPanel.classList.remove('active');
|
|
4106
|
+
var memPanel=document.getElementById('adminMemoriesPanel');
|
|
4107
|
+
if(memPanel) memPanel.classList.add('active');
|
|
4108
|
+
tabs.forEach(function(tab){
|
|
4109
|
+
tab.classList.remove('active');
|
|
4110
|
+
var onclick=tab.getAttribute('onclick')||'';
|
|
4111
|
+
if(onclick.indexOf("'memories'")!==-1) tab.classList.add('active');
|
|
4112
|
+
});
|
|
4113
|
+
}
|
|
4114
|
+
}
|
|
4115
|
+
var subEl=document.querySelector('.admin-header-sub');
|
|
4116
|
+
if(subEl) subEl.textContent=isAdmin?t('admin.subtitle'):t('admin.subtitle.member');
|
|
4117
|
+
}
|
|
4022
4118
|
|
|
4023
4119
|
function renderAdminStats(pendingCount){
|
|
4024
4120
|
var el=document.getElementById('adminStats');
|
|
4025
4121
|
if(!el) return;
|
|
4122
|
+
var isAdmin=!!window._isHubAdmin;
|
|
4123
|
+
var onlineCount=adminDataCache.users.filter(function(u){return !!u.isOnline;}).length;
|
|
4026
4124
|
el.innerHTML=
|
|
4027
|
-
'<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>'+
|
|
4028
|
-
'<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>'+
|
|
4125
|
+
(isAdmin?'<div class="admin-stat-box"><span class="as-icon">\u{1F465}</span><div class="val">'+onlineCount+' / '+adminDataCache.users.length+'</div><div class="lbl">'+t('admin.stat.activeUsers')+'</div></div>'+
|
|
4126
|
+
'<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>':'')+
|
|
4029
4127
|
'<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>'+
|
|
4030
4128
|
'<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>'+
|
|
4031
4129
|
'<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>';
|
|
@@ -4035,9 +4133,81 @@ function renderAdminStats(pendingCount){
|
|
|
4035
4133
|
tc=document.getElementById('adminTabCountSkills');if(tc)tc.textContent=adminDataCache.skills.length;
|
|
4036
4134
|
}
|
|
4037
4135
|
|
|
4136
|
+
function auRelativeTime(ts){
|
|
4137
|
+
if(!ts) return t('admin.neverActive');
|
|
4138
|
+
var diff=Date.now()-ts;
|
|
4139
|
+
if(diff<60000) return t('notif.timeAgo.just');
|
|
4140
|
+
if(diff<3600000) return t('notif.timeAgo.min').replace('{n}',Math.floor(diff/60000));
|
|
4141
|
+
if(diff<86400000) return t('notif.timeAgo.hour').replace('{n}',Math.floor(diff/3600000));
|
|
4142
|
+
return t('notif.timeAgo.day').replace('{n}',Math.floor(diff/86400000));
|
|
4143
|
+
}
|
|
4144
|
+
|
|
4145
|
+
function renderAdminUserCard(u,adminCount){
|
|
4146
|
+
var uid=escAttr(u.id);
|
|
4147
|
+
var uname=escAttr(u.username||'');
|
|
4148
|
+
var online=!!u.isOnline;
|
|
4149
|
+
var statusCls=online?'online':'offline';
|
|
4150
|
+
|
|
4151
|
+
var statusIndicator='<span class="au-status-dot '+statusCls+'"></span>';
|
|
4152
|
+
var statusLabel=online
|
|
4153
|
+
?'<span class="au-status-text online">'+t('admin.onlineNow')+'</span>'
|
|
4154
|
+
:'<span class="au-status-text offline">'+auRelativeTime(u.lastActiveAt)+'</span>';
|
|
4155
|
+
|
|
4156
|
+
var titleDisplay='<span class="admin-card-title" id="au_name_'+uid+'">'+statusIndicator+esc(u.username||u.id)+
|
|
4157
|
+
' <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>';
|
|
4158
|
+
|
|
4159
|
+
var editRow='<div id="au_edit_'+uid+'" style="display:none;align-items:center;gap:6px">'+
|
|
4160
|
+
'<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+'")">'+
|
|
4161
|
+
'<button onclick="adminSaveEditName("'+uid+'")" class="btn btn-sm btn-primary" style="padding:4px 12px;font-size:11px;white-space:nowrap">\u2713</button>'+
|
|
4162
|
+
'<button onclick="adminCancelEditName("'+uid+'")" class="btn btn-sm btn-ghost" style="padding:4px 8px;font-size:11px;color:var(--text-muted)">\u2717</button></div>';
|
|
4163
|
+
|
|
4164
|
+
var mc=u.memoryCount||0, tc=u.taskCount||0, sc=u.skillCount||0;
|
|
4165
|
+
var contribHtml='<div class="au-contrib">'+
|
|
4166
|
+
'<span class="au-contrib-item"><span class="au-contrib-num" style="color:var(--pri)">'+mc+'</span> '+t('admin.contrib.memories')+'</span>'+
|
|
4167
|
+
'<span class="au-contrib-item"><span class="au-contrib-num" style="color:var(--green)">'+tc+'</span> '+t('admin.contrib.tasks')+'</span>'+
|
|
4168
|
+
'<span class="au-contrib-item"><span class="au-contrib-num" style="color:var(--amber)">'+sc+'</span> '+t('admin.contrib.skills')+'</span>'+
|
|
4169
|
+
'</div>';
|
|
4170
|
+
|
|
4171
|
+
var infoRows=[];
|
|
4172
|
+
if(u.deviceName) infoRows.push('<span class="au-info-item">\u{1F4BB} '+t('admin.device')+esc(u.deviceName)+'</span>');
|
|
4173
|
+
if(u.lastIp) infoRows.push('<span class="au-info-item">\u{1F310} '+t('admin.ip')+esc(u.lastIp)+'</span>');
|
|
4174
|
+
if(u.createdAt) infoRows.push('<span class="au-info-item">\u{1F4C5} '+t('admin.joined')+formatDateTimeSeconds(u.createdAt)+'</span>');
|
|
4175
|
+
if(u.approvedAt) infoRows.push('<span class="au-info-item">\u2705 '+t('admin.approved')+formatDateTimeSeconds(u.approvedAt)+'</span>');
|
|
4176
|
+
var lastAct=u.lastActiveAt||u.approvedAt||u.createdAt;
|
|
4177
|
+
infoRows.push('<span class="au-info-item">\u{1F552} '+t('admin.lastActive')+(lastAct?formatDateTimeSeconds(lastAct):t('admin.neverActive'))+'</span>');
|
|
4178
|
+
var infoHtml='<div class="au-info">'+infoRows.join('')+'</div>';
|
|
4179
|
+
|
|
4180
|
+
var actions='';
|
|
4181
|
+
if(u.isOwner){
|
|
4182
|
+
actions+='<span style="font-size:11px;color:var(--text-muted);padding:4px 0">'+t('admin.ownerHint')+'</span>';
|
|
4183
|
+
}else if(u.role!=='admin'){
|
|
4184
|
+
actions+='<button class="btn btn-sm btn-ghost" onclick="adminToggleRole("'+uid+'","admin")" style="color:var(--accent)">'+t('admin.promoteAdmin')+'</button>';
|
|
4185
|
+
actions+='<button class="btn btn-sm btn-ghost" onclick="adminRemoveUser("'+uid+'","'+uname+'")" style="color:var(--rose)">'+t('admin.remove')+'</button>';
|
|
4186
|
+
}else if(adminCount>1){
|
|
4187
|
+
actions+='<button class="btn btn-sm btn-ghost" onclick="adminToggleRole("'+uid+'","member")">'+t('admin.demoteMember')+'</button>';
|
|
4188
|
+
actions+='<button class="btn btn-sm btn-ghost" onclick="adminRemoveUser("'+uid+'","'+uname+'")" style="color:var(--rose)">'+t('admin.remove')+'</button>';
|
|
4189
|
+
}else{
|
|
4190
|
+
actions+='<span style="font-size:11px;color:var(--text-muted);padding:4px 0">'+t('admin.lastAdminHint')+'</span>';
|
|
4191
|
+
}
|
|
4192
|
+
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>':'';
|
|
4193
|
+
|
|
4194
|
+
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">'+
|
|
4195
|
+
'<div style="flex:1;min-width:0">'+titleDisplay+editRow+'</div>'+statusLabel+
|
|
4196
|
+
'</div>'+
|
|
4197
|
+
'<span class="admin-badge '+(u.role==='admin'?'admin':'member')+'">'+esc(u.role||'member')+'</span>'+ownerBadge+'</div>'+
|
|
4198
|
+
contribHtml+infoHtml+
|
|
4199
|
+
(actions?'<div class="admin-card-actions" style="border-top:1px dashed var(--border);padding-top:10px;margin-top:4px">'+actions+'</div>':'')+
|
|
4200
|
+
'</div>';
|
|
4201
|
+
}
|
|
4202
|
+
|
|
4038
4203
|
function renderAdminUsers(users,pending){
|
|
4039
4204
|
var el=document.getElementById('adminUsersPanel');
|
|
4040
4205
|
if(!el) return;
|
|
4206
|
+
var isAdmin=!!window._isHubAdmin;
|
|
4207
|
+
if(!isAdmin){
|
|
4208
|
+
el.innerHTML='<div class="admin-empty" style="padding:32px;text-align:center;color:var(--text-sec)">'+t('admin.noPermission')+'</div>';
|
|
4209
|
+
return;
|
|
4210
|
+
}
|
|
4041
4211
|
var html='';
|
|
4042
4212
|
if(pending&&pending.length>0){
|
|
4043
4213
|
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>';
|
|
@@ -4052,65 +4222,32 @@ function renderAdminUsers(users,pending){
|
|
|
4052
4222
|
}
|
|
4053
4223
|
html+='</div>';
|
|
4054
4224
|
}
|
|
4055
|
-
|
|
4056
|
-
|
|
4225
|
+
|
|
4226
|
+
var onlineUsers=users.filter(function(u){return !!u.isOnline;});
|
|
4227
|
+
var offlineUsers=users.filter(function(u){return !u.isOnline;});
|
|
4228
|
+
offlineUsers.sort(function(a,b){return (b.lastActiveAt||0)-(a.lastActiveAt||0);});
|
|
4229
|
+
var sorted=onlineUsers.concat(offlineUsers);
|
|
4230
|
+
var adminCount=users.filter(function(x){return x.role==='admin';}).length;
|
|
4231
|
+
|
|
4232
|
+
if(sorted.length===0){
|
|
4057
4233
|
html+='<div class="admin-empty"><span class="ae-icon">\u{1F465}</span>'+t('admin.noActiveUsers')+'</div>';
|
|
4058
4234
|
}else{
|
|
4059
|
-
|
|
4060
|
-
|
|
4061
|
-
|
|
4062
|
-
|
|
4063
|
-
|
|
4064
|
-
|
|
4065
|
-
|
|
4066
|
-
|
|
4067
|
-
|
|
4068
|
-
|
|
4069
|
-
|
|
4070
|
-
var titleDisplay='<span class="admin-card-title" id="au_name_'+uid+'">'+esc(u.username||u.id)+
|
|
4071
|
-
' <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>';
|
|
4072
|
-
|
|
4073
|
-
var editRow='<div id="au_edit_'+uid+'" style="display:none;align-items:center;gap:6px">'+
|
|
4074
|
-
'<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+'")">'+
|
|
4075
|
-
'<button onclick="adminSaveEditName("'+uid+'")" class="btn btn-sm btn-primary" style="padding:4px 12px;font-size:11px;white-space:nowrap">\u2713</button>'+
|
|
4076
|
-
'<button onclick="adminCancelEditName("'+uid+'")" class="btn btn-sm btn-ghost" style="padding:4px 8px;font-size:11px;color:var(--text-muted)">\u2717</button></div>';
|
|
4077
|
-
|
|
4078
|
-
var mc=u.memoryCount||0, tc=u.taskCount||0, sc=u.skillCount||0;
|
|
4079
|
-
var contribHtml='<div class="au-contrib">'+
|
|
4080
|
-
'<span class="au-contrib-item"><span class="au-contrib-num" style="color:var(--pri)">'+mc+'</span> '+t('admin.contrib.memories')+'</span>'+
|
|
4081
|
-
'<span class="au-contrib-item"><span class="au-contrib-num" style="color:var(--green)">'+tc+'</span> '+t('admin.contrib.tasks')+'</span>'+
|
|
4082
|
-
'<span class="au-contrib-item"><span class="au-contrib-num" style="color:var(--amber)">'+sc+'</span> '+t('admin.contrib.skills')+'</span>'+
|
|
4083
|
-
'</div>';
|
|
4084
|
-
|
|
4085
|
-
var infoRows=[];
|
|
4086
|
-
if(u.deviceName) infoRows.push('<span class="au-info-item">\u{1F4BB} '+t('admin.device')+esc(u.deviceName)+'</span>');
|
|
4087
|
-
if(u.lastIp) infoRows.push('<span class="au-info-item">\u{1F310} '+t('admin.ip')+esc(u.lastIp)+'</span>');
|
|
4088
|
-
if(u.createdAt) infoRows.push('<span class="au-info-item">\u{1F4C5} '+t('admin.joined')+formatDateTimeSeconds(u.createdAt)+'</span>');
|
|
4089
|
-
if(u.approvedAt) infoRows.push('<span class="au-info-item">\u2705 '+t('admin.approved')+formatDateTimeSeconds(u.approvedAt)+'</span>');
|
|
4090
|
-
infoRows.push('<span class="au-info-item">\u{1F552} '+t('admin.lastActive')+(u.lastActiveAt?formatDateTimeSeconds(u.lastActiveAt):t('admin.neverActive'))+'</span>');
|
|
4091
|
-
var infoHtml='<div class="au-info">'+infoRows.join('')+'</div>';
|
|
4092
|
-
|
|
4093
|
-
var actions='';
|
|
4094
|
-
if(u.role!=='admin'){
|
|
4095
|
-
actions+='<button class="btn btn-sm btn-ghost" onclick="adminToggleRole("'+uid+'","admin")" style="color:var(--accent)">'+t('admin.promoteAdmin')+'</button>';
|
|
4096
|
-
actions+='<button class="btn btn-sm btn-ghost" onclick="adminRemoveUser("'+uid+'","'+uname+'")" style="color:var(--rose)">'+t('admin.remove')+'</button>';
|
|
4097
|
-
}else if(adminCount>1){
|
|
4098
|
-
actions+='<button class="btn btn-sm btn-ghost" onclick="adminToggleRole("'+uid+'","member")">'+t('admin.demoteMember')+'</button>';
|
|
4099
|
-
actions+='<button class="btn btn-sm btn-ghost" onclick="adminRemoveUser("'+uid+'","'+uname+'")" style="color:var(--rose)">'+t('admin.remove')+'</button>';
|
|
4100
|
-
}else{
|
|
4101
|
-
actions+='<span style="font-size:11px;color:var(--text-muted);padding:4px 0">'+t('admin.lastAdminHint')+'</span>';
|
|
4102
|
-
}
|
|
4103
|
-
html+='<div class="admin-card au-card"><div class="admin-card-header"><div style="flex:1;min-width:0">'+titleDisplay+editRow+'</div>'+
|
|
4104
|
-
'<span class="admin-badge '+(u.role==='admin'?'admin':'member')+'">'+esc(u.role||'member')+'</span></div>'+
|
|
4105
|
-
contribHtml+infoHtml+
|
|
4106
|
-
(actions?'<div class="admin-card-actions" style="border-top:1px dashed var(--border);padding-top:10px;margin-top:4px">'+actions+'</div>':'')+
|
|
4107
|
-
'</div>';
|
|
4235
|
+
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>';
|
|
4236
|
+
if(onlineUsers.length===0){
|
|
4237
|
+
html+='<div style="font-size:12px;color:var(--text-muted);padding:8px 0 12px">\u2014</div>';
|
|
4238
|
+
}else{
|
|
4239
|
+
for(var i=0;i<onlineUsers.length;i++) html+=renderAdminUserCard(onlineUsers[i],adminCount);
|
|
4240
|
+
}
|
|
4241
|
+
html+='<div class="au-group-header"><span class="au-group-dot offline"></span>'+t('admin.offlineUsers')+' <span class="au-group-count">('+offlineUsers.length+')</span></div>';
|
|
4242
|
+
if(offlineUsers.length===0){
|
|
4243
|
+
html+='<div style="font-size:12px;color:var(--text-muted);padding:8px 0 12px">\u2014</div>';
|
|
4244
|
+
}else{
|
|
4245
|
+
for(var j=0;j<offlineUsers.length;j++) html+=renderAdminUserCard(offlineUsers[j],adminCount);
|
|
4108
4246
|
}
|
|
4109
|
-
html+=adminPaginateHtml(totalUsers,adminPage.users,'adminUsers');
|
|
4110
4247
|
}
|
|
4111
4248
|
el.innerHTML=html;
|
|
4112
4249
|
}
|
|
4113
|
-
function adminUsersPage(p){
|
|
4250
|
+
function adminUsersPage(p){renderAdminUsers(adminDataCache.users,adminDataCache._pending||[]);}
|
|
4114
4251
|
|
|
4115
4252
|
async function adminApproveUser(userId,username){
|
|
4116
4253
|
try{
|
|
@@ -4133,7 +4270,9 @@ async function adminToggleRole(userId,newRole){
|
|
|
4133
4270
|
try{
|
|
4134
4271
|
var r=await fetch('/api/sharing/change-role',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:userId,role:newRole})});
|
|
4135
4272
|
var d=await r.json();
|
|
4136
|
-
if(d.ok){toast(t('toast.roleChanged'),'success');loadAdminData();}
|
|
4273
|
+
if(d.ok){toast(t('toast.roleChanged'),'success');loadAdminData();}
|
|
4274
|
+
else if(d.error==='cannot_demote_owner'){toast(t('admin.ownerHint'),'error');}
|
|
4275
|
+
else{toast(d.error||t('toast.roleChangeFail'),'error');}
|
|
4137
4276
|
}catch(e){toast(t('toast.roleChangeFail')+': '+e.message,'error');}
|
|
4138
4277
|
}
|
|
4139
4278
|
function adminStartEditName(btn,userId,currentName){
|
|
@@ -4172,7 +4311,9 @@ async function adminRemoveUser(userId,username){
|
|
|
4172
4311
|
try{
|
|
4173
4312
|
var r=await fetch('/api/sharing/remove-user',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({userId:userId,cleanResources:clean})});
|
|
4174
4313
|
var d=await r.json();
|
|
4175
|
-
if(d.ok){toast(t('toast.userRemoved'),'success');loadAdminData();}
|
|
4314
|
+
if(d.ok){toast(t('toast.userRemoved'),'success');loadAdminData();}
|
|
4315
|
+
else if(d.error==='cannot_remove_owner'){toast(t('admin.ownerHint'),'error');}
|
|
4316
|
+
else{toast(d.error||t('toast.removeFail'),'error');}
|
|
4176
4317
|
}catch(e){toast(t('toast.removeFail')+': '+e.message,'error');}
|
|
4177
4318
|
}
|
|
4178
4319
|
|
|
@@ -4244,7 +4385,7 @@ function renderAdminTasks(tasks){
|
|
|
4244
4385
|
(tk.chunkCount!=null?'<span class="admin-card-tag tag-kind">\u{1F4DD} '+tk.chunkCount+' '+t('admin.chunks')+'</span>':'')+
|
|
4245
4386
|
'</div>'+
|
|
4246
4387
|
'<span class="admin-card-actions" onclick="event.stopPropagation()">'+
|
|
4247
|
-
'<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>'+
|
|
4388
|
+
(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>':'')+
|
|
4248
4389
|
'<button class="btn btn-sm btn-ghost admin-card-expand-btn" onclick="toggleAdminTaskCard("'+cardId+'",'+i+')">'+t('admin.expand')+'</button>'+
|
|
4249
4390
|
'<span class="admin-card-time">'+(timeRange||formatDateTimeSeconds(tk.updatedAt||tk.createdAt))+'</span>'+
|
|
4250
4391
|
'</span>'+
|
|
@@ -4307,7 +4448,7 @@ function renderAdminSkills(skills){
|
|
|
4307
4448
|
(qs!=null?'<span class="admin-card-tag tag-kind">\u2605 '+Number(qs).toFixed(1)+'</span>':'')+
|
|
4308
4449
|
'</div>'+
|
|
4309
4450
|
'<span class="admin-card-actions" onclick="event.stopPropagation()">'+
|
|
4310
|
-
'<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>'+
|
|
4451
|
+
(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>':'')+
|
|
4311
4452
|
'<button class="btn btn-sm btn-ghost admin-card-expand-btn" onclick="toggleAdminSkillCard("'+cardId+'",'+i+')">'+t('admin.expand')+'</button>'+
|
|
4312
4453
|
(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>':'')+
|
|
4313
4454
|
'<span class="admin-card-time">'+formatDateTimeSeconds(s.updatedAt||s.createdAt)+'</span>'+
|
|
@@ -4371,7 +4512,7 @@ function renderAdminMemories(memories){
|
|
|
4371
4512
|
(m.kind?'<span class="admin-card-tag tag-kind">'+esc(m.kind)+'</span>':'')+
|
|
4372
4513
|
'</div>'+
|
|
4373
4514
|
'<span class="admin-card-actions">'+
|
|
4374
|
-
'<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>'+
|
|
4515
|
+
(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>':'')+
|
|
4375
4516
|
'<button class="btn btn-sm btn-ghost admin-card-expand-btn" onclick="event.stopPropagation();toggleAdminMemoryCard("'+cardId+'",'+i+')">'+t('admin.expand')+'</button>'+
|
|
4376
4517
|
'<span class="admin-card-time">'+formatDateTimeSeconds(m.updatedAt||m.createdAt)+'</span>'+
|
|
4377
4518
|
'</span>'+
|
|
@@ -4449,12 +4590,19 @@ async function toggleAdminTaskCard(cardId,idx){
|
|
|
4449
4590
|
var tk=(adminTasksCache||[])[idx];
|
|
4450
4591
|
if(!tk){detail.innerHTML='<div style="color:var(--text-muted);font-size:14px;padding:12px">'+t('admin.noContent')+'</div>';return;}
|
|
4451
4592
|
var localTaskId=tk.sourceTaskId||tk.id;
|
|
4593
|
+
var hubTaskId=tk.id;
|
|
4452
4594
|
detail.innerHTML='<div class="spinner"></div>';
|
|
4453
4595
|
var task=null;
|
|
4454
4596
|
try{
|
|
4455
4597
|
var r=await fetch('/api/task/'+encodeURIComponent(localTaskId));
|
|
4456
4598
|
if(r.ok) task=await r.json();
|
|
4457
4599
|
}catch(e){}
|
|
4600
|
+
if(!task){
|
|
4601
|
+
try{
|
|
4602
|
+
var r2=await fetch('/api/admin/shared-tasks/'+encodeURIComponent(hubTaskId)+'/detail');
|
|
4603
|
+
if(r2.ok) task=await r2.json();
|
|
4604
|
+
}catch(e2){}
|
|
4605
|
+
}
|
|
4458
4606
|
if(!task){detail.innerHTML='<div style="color:var(--text-muted);font-size:14px;padding:12px">'+t('admin.noContent')+'</div>';return;}
|
|
4459
4607
|
var metaHtml='<div class="admin-card-detail-meta admin-task-meta">'+
|
|
4460
4608
|
(tk.status?'<span class="meta-item"><span class="task-status-badge '+tk.status+'">'+esc(tk.status)+'</span></span>':'')+
|
|
@@ -4525,11 +4673,18 @@ async function toggleAdminSkillCard(cardId,idx){
|
|
|
4525
4673
|
if(!sk){detail.innerHTML='<div style="color:var(--text-muted);font-size:13px">'+t('admin.noContent')+'</div>';return;}
|
|
4526
4674
|
detail.innerHTML='<div class="spinner"></div>';
|
|
4527
4675
|
var localSkillId=sk.sourceSkillId||sk.id;
|
|
4676
|
+
var hubSkillId=sk.id;
|
|
4528
4677
|
var localData=null;
|
|
4529
4678
|
try{
|
|
4530
4679
|
var lr=await fetch('/api/skill/'+encodeURIComponent(localSkillId));
|
|
4531
4680
|
if(lr.ok) localData=await lr.json();
|
|
4532
4681
|
}catch(e){}
|
|
4682
|
+
if(!localData){
|
|
4683
|
+
try{
|
|
4684
|
+
var hr=await fetch('/api/admin/shared-skills/'+encodeURIComponent(hubSkillId)+'/detail');
|
|
4685
|
+
if(hr.ok) localData=await hr.json();
|
|
4686
|
+
}catch(e2){}
|
|
4687
|
+
}
|
|
4533
4688
|
var localSkill=localData&&localData.skill?localData.skill:sk;
|
|
4534
4689
|
var files=localData&&localData.files?localData.files:[];
|
|
4535
4690
|
var versions=localData&&localData.versions?localData.versions:[];
|
|
@@ -5359,18 +5514,21 @@ function setTaskStatusFilter(btn,status){
|
|
|
5359
5514
|
async function loadTasks(){
|
|
5360
5515
|
const scope=document.getElementById('taskSearchScope')?document.getElementById('taskSearchScope').value:taskSearchScope;
|
|
5361
5516
|
taskSearchScope=scope||'local';
|
|
5362
|
-
if(taskSearchScope
|
|
5517
|
+
if(taskSearchScope==='hub'){ return loadHubTasks(); }
|
|
5363
5518
|
const list=document.getElementById('tasksList');
|
|
5364
5519
|
list.innerHTML='<div class="spinner"></div>';
|
|
5365
5520
|
try{
|
|
5366
5521
|
const params=new URLSearchParams({limit:String(TASKS_PER_PAGE),offset:String(tasksPage*TASKS_PER_PAGE)});
|
|
5367
5522
|
if(tasksStatusFilter) params.set('status',tasksStatusFilter);
|
|
5523
|
+
if(taskSearchScope==='local') params.set('owner','agent:main');
|
|
5524
|
+
var baseP=new URLSearchParams();
|
|
5525
|
+
if(taskSearchScope==='local') baseP.set('owner','agent:main');
|
|
5368
5526
|
const [data,allD,activeD,compD,skipD]=await Promise.all([
|
|
5369
5527
|
fetch('/api/tasks?'+params).then(r=>r.json()),
|
|
5370
|
-
fetch('/api/tasks?limit=1&offset=0').then(r=>r.json()),
|
|
5371
|
-
fetch('/api/tasks?status=active&limit=1&offset=0').then(r=>r.json()),
|
|
5372
|
-
fetch('/api/tasks?status=completed&limit=1&offset=0').then(r=>r.json()),
|
|
5373
|
-
fetch('/api/tasks?status=skipped&limit=1&offset=0').then(r=>r.json())
|
|
5528
|
+
fetch('/api/tasks?limit=1&offset=0&'+baseP).then(r=>r.json()),
|
|
5529
|
+
fetch('/api/tasks?status=active&limit=1&offset=0&'+baseP).then(r=>r.json()),
|
|
5530
|
+
fetch('/api/tasks?status=completed&limit=1&offset=0&'+baseP).then(r=>r.json()),
|
|
5531
|
+
fetch('/api/tasks?status=skipped&limit=1&offset=0&'+baseP).then(r=>r.json())
|
|
5374
5532
|
]);
|
|
5375
5533
|
document.getElementById('tasksTotalCount').textContent=formatNum(allD.total);
|
|
5376
5534
|
document.getElementById('tasksActiveCount').textContent=formatNum(activeD.total);
|
|
@@ -5663,7 +5821,7 @@ async function loadSkills(){
|
|
|
5663
5821
|
list.innerHTML='<div class="spinner"></div>';
|
|
5664
5822
|
var hubSection=document.getElementById('hubSkillsSection');
|
|
5665
5823
|
if(hubList){
|
|
5666
|
-
if(skillSearchScope==='local'){
|
|
5824
|
+
if(skillSearchScope==='local'||skillSearchScope==='allLocal'){
|
|
5667
5825
|
if(hubSection) hubSection.style.display='none';
|
|
5668
5826
|
}else{
|
|
5669
5827
|
if(hubSection) hubSection.style.display='block';
|
|
@@ -5736,7 +5894,7 @@ async function loadSkills(){
|
|
|
5736
5894
|
|
|
5737
5895
|
list.innerHTML=renderLocalCards(localSkills);
|
|
5738
5896
|
|
|
5739
|
-
if(skillSearchScope==='local'){
|
|
5897
|
+
if(skillSearchScope==='local'||skillSearchScope==='allLocal'){
|
|
5740
5898
|
if(hubSection) hubSection.style.display='none';
|
|
5741
5899
|
document.getElementById('skillSearchMeta').textContent=query?(t('skills.search.local')+' '+localSkills.length):'';
|
|
5742
5900
|
document.getElementById('skillsTotalCount').textContent=formatNum(localSkills.length);
|
|
@@ -5807,6 +5965,46 @@ async function loadSkills(){
|
|
|
5807
5965
|
}
|
|
5808
5966
|
}
|
|
5809
5967
|
|
|
5968
|
+
async function loadHubTasks(){
|
|
5969
|
+
var list=document.getElementById('tasksList');
|
|
5970
|
+
if(!list) return;
|
|
5971
|
+
list.innerHTML='<div class="spinner"></div>';
|
|
5972
|
+
try{
|
|
5973
|
+
var r=await fetch('/api/sharing/tasks/list?limit=40');
|
|
5974
|
+
var d=await r.json();
|
|
5975
|
+
var tasks=Array.isArray(d.tasks)?d.tasks:[];
|
|
5976
|
+
hubTasksCache=tasks;
|
|
5977
|
+
document.getElementById('tasksTotalCount').textContent=formatNum(tasks.length);
|
|
5978
|
+
document.getElementById('tasksActiveCount').textContent='-';
|
|
5979
|
+
document.getElementById('tasksCompletedCount').textContent='-';
|
|
5980
|
+
document.getElementById('tasksSkippedCount').textContent='-';
|
|
5981
|
+
if(!tasks.length){
|
|
5982
|
+
list.innerHTML='<div style="text-align:center;padding:48px;color:var(--text-muted);font-size:14px">'+t('tasks.empty')+'</div>';
|
|
5983
|
+
document.getElementById('tasksPagination').innerHTML='';
|
|
5984
|
+
return;
|
|
5985
|
+
}
|
|
5986
|
+
list.innerHTML=tasks.map(function(task,idx){
|
|
5987
|
+
var timeStr=task.updatedAt?formatTime(task.updatedAt):(task.createdAt?formatTime(task.createdAt):'');
|
|
5988
|
+
return '<div class="task-card" onclick="openHubTaskDetailFromCache(\\x27hub\\x27,'+idx+')" style="cursor:pointer">'+
|
|
5989
|
+
'<div class="task-card-top">'+
|
|
5990
|
+
'<div class="task-card-title">'+esc(task.title||'(no title)')+'</div>'+
|
|
5991
|
+
'<div class="task-card-badges"><span class="scope-badge team">\\u{1F310} '+t('scope.hub')+'</span></div>'+
|
|
5992
|
+
'</div>'+
|
|
5993
|
+
(task.summary?'<div class="task-card-summary">'+esc(task.summary)+'</div>':'')+
|
|
5994
|
+
'<div class="task-card-bottom">'+
|
|
5995
|
+
(timeStr?'<span class="tag"><span class="icon">\\u{1F4C5}</span> '+timeStr+'</span>':'')+
|
|
5996
|
+
'<span class="tag"><span class="icon">\\u{1F464}</span> '+esc(task.ownerName||'unknown')+'</span>'+
|
|
5997
|
+
(task.chunkCount!=null?'<span class="tag"><span class="icon">\\u{1F4DD}</span> '+task.chunkCount+' '+t('tasks.chunks.label')+'</span>':'')+
|
|
5998
|
+
'</div>'+
|
|
5999
|
+
'</div>';
|
|
6000
|
+
}).join('');
|
|
6001
|
+
document.getElementById('tasksPagination').innerHTML='';
|
|
6002
|
+
}catch(e){
|
|
6003
|
+
list.innerHTML='<div style="text-align:center;padding:48px;color:var(--text-muted);font-size:14px">'+t('tasks.empty')+'</div>';
|
|
6004
|
+
document.getElementById('tasksPagination').innerHTML='';
|
|
6005
|
+
}
|
|
6006
|
+
}
|
|
6007
|
+
|
|
5810
6008
|
async function loadHubSkills(hubList){
|
|
5811
6009
|
if(!hubList) hubList=document.getElementById('hubSkillsList');
|
|
5812
6010
|
if(!hubList) return;
|
|
@@ -6167,6 +6365,7 @@ async function loadConfig(){
|
|
|
6167
6365
|
document.getElementById('cfgHubTeamToken').value=hub.teamToken||'';
|
|
6168
6366
|
document.getElementById('cfgClientHubAddress').value=client.hubAddress||'';
|
|
6169
6367
|
document.getElementById('cfgClientTeamToken').value=client.teamToken||'';
|
|
6368
|
+
document.getElementById('cfgClientNickname').value=client.nickname||'';
|
|
6170
6369
|
document.getElementById('cfgClientUserToken').value=client.userToken||'';
|
|
6171
6370
|
onSharingToggle();
|
|
6172
6371
|
updateHubShareInfo();
|
|
@@ -6335,6 +6534,7 @@ async function saveHubConfig(){
|
|
|
6335
6534
|
var hubPort=document.getElementById('cfgHubPort').value.trim();
|
|
6336
6535
|
var hubTeamName=document.getElementById('cfgHubTeamName').value.trim();
|
|
6337
6536
|
var hubTeamToken=document.getElementById('cfgHubTeamToken').value.trim();
|
|
6537
|
+
var hubAdminName=document.getElementById('cfgHubAdminName').value.trim();
|
|
6338
6538
|
cfg.sharing.hub={port:hubPort?Number(hubPort):18800};
|
|
6339
6539
|
if(hubTeamName) cfg.sharing.hub.teamName=hubTeamName;
|
|
6340
6540
|
if(hubTeamToken) cfg.sharing.hub.teamToken=hubTeamToken;
|
|
@@ -6344,8 +6544,10 @@ async function saveHubConfig(){
|
|
|
6344
6544
|
var clientAddr=document.getElementById('cfgClientHubAddress').value.trim();
|
|
6345
6545
|
var clientTeamToken=document.getElementById('cfgClientTeamToken').value.trim();
|
|
6346
6546
|
var clientUserToken=document.getElementById('cfgClientUserToken').value.trim();
|
|
6547
|
+
var clientNickname=document.getElementById('cfgClientNickname').value.trim();
|
|
6347
6548
|
cfg.sharing.client={};
|
|
6348
6549
|
if(clientAddr) cfg.sharing.client.hubAddress=clientAddr;
|
|
6550
|
+
if(clientNickname) cfg.sharing.client.nickname=clientNickname;
|
|
6349
6551
|
if(clientTeamToken) cfg.sharing.client.teamToken=clientTeamToken;
|
|
6350
6552
|
if(clientUserToken) cfg.sharing.client.userToken=clientUserToken;
|
|
6351
6553
|
cfg.sharing.hub={port:18800,teamName:'',teamToken:''};
|
|
@@ -6370,6 +6572,12 @@ async function saveHubConfig(){
|
|
|
6370
6572
|
|
|
6371
6573
|
var ok=await doSaveConfig(cfg, saveBtn, 'hubSaved');
|
|
6372
6574
|
if(ok){
|
|
6575
|
+
if(sharingEnabled&&_sharingRole==='hub'){
|
|
6576
|
+
var adminNameEl=document.getElementById('cfgHubAdminName');
|
|
6577
|
+
if(adminNameEl&&adminNameEl.value.trim()){
|
|
6578
|
+
try{await fetch('/api/sharing/update-username',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify({username:adminNameEl.value.trim()})});}catch(e){}
|
|
6579
|
+
}
|
|
6580
|
+
}
|
|
6373
6581
|
loadSharingStatus(false);
|
|
6374
6582
|
var needsRestart=sharingEnabled||(prevSharingEnabled&&!sharingEnabled);
|
|
6375
6583
|
if(sharingEnabled) updateHubShareInfo();
|
|
@@ -6791,23 +6999,83 @@ function renderToolAgg(data){
|
|
|
6791
6999
|
'</tbody></table>';
|
|
6792
7000
|
}
|
|
6793
7001
|
|
|
6794
|
-
/* ───
|
|
6795
|
-
var
|
|
6796
|
-
|
|
6797
|
-
|
|
6798
|
-
|
|
7002
|
+
/* ─── Unified live-data poller ─── */
|
|
7003
|
+
var _livePoller=null;
|
|
7004
|
+
var _LIVE_POLL_MS=15000;
|
|
7005
|
+
var _livePollBusy=false;
|
|
7006
|
+
|
|
7007
|
+
async function _livePollTick(){
|
|
7008
|
+
if(_livePollBusy||document.hidden) return;
|
|
7009
|
+
_livePollBusy=true;
|
|
7010
|
+
try{
|
|
6799
7011
|
if(sharingStatusCache&&sharingStatusCache.enabled) loadSharingStatus(false);
|
|
6800
|
-
|
|
7012
|
+
if(!_notifSSEConnected) pollNotifCount();
|
|
7013
|
+
pollAdminPending();
|
|
7014
|
+
if(_activeView==='admin') loadAdminData();
|
|
7015
|
+
else if(_activeView==='memories'){loadStats();loadMemories();}
|
|
7016
|
+
else if(_activeView==='tasks') loadTasks();
|
|
7017
|
+
else if(_activeView==='skills') loadSkills();
|
|
7018
|
+
else if(_activeView==='analytics') loadMetrics();
|
|
7019
|
+
}catch(e){}
|
|
7020
|
+
_livePollBusy=false;
|
|
7021
|
+
}
|
|
7022
|
+
|
|
7023
|
+
function startLivePoller(){
|
|
7024
|
+
stopLivePoller();
|
|
7025
|
+
_livePoller=setInterval(_livePollTick,_LIVE_POLL_MS);
|
|
6801
7026
|
}
|
|
6802
|
-
function
|
|
6803
|
-
if(
|
|
7027
|
+
function stopLivePoller(){
|
|
7028
|
+
if(_livePoller){clearInterval(_livePoller);_livePoller=null;}
|
|
6804
7029
|
}
|
|
6805
7030
|
|
|
6806
|
-
|
|
7031
|
+
document.addEventListener('visibilitychange',function(){
|
|
7032
|
+
if(document.hidden){
|
|
7033
|
+
stopLivePoller();
|
|
7034
|
+
}else{
|
|
7035
|
+
_livePollTick();
|
|
7036
|
+
startLivePoller();
|
|
7037
|
+
if(!_notifSSE||!_notifSSEConnected) connectNotifSSE();
|
|
7038
|
+
}
|
|
7039
|
+
});
|
|
7040
|
+
|
|
7041
|
+
/* ─── Notifications (SSE push + fallback poll) ─── */
|
|
6807
7042
|
var _notifCache=[];
|
|
6808
7043
|
var _notifUnread=0;
|
|
6809
7044
|
var _notifPollTimer=null;
|
|
6810
7045
|
var _notifPanelOpen=false;
|
|
7046
|
+
var _notifSSE=null;
|
|
7047
|
+
var _notifSSEConnected=false;
|
|
7048
|
+
var _notifSSERetryMs=1000;
|
|
7049
|
+
|
|
7050
|
+
function connectNotifSSE(){
|
|
7051
|
+
if(_notifSSE) return;
|
|
7052
|
+
try{
|
|
7053
|
+
_notifSSE=new EventSource('/api/notifications/stream');
|
|
7054
|
+
_notifSSE.onmessage=function(ev){
|
|
7055
|
+
try{
|
|
7056
|
+
var d=JSON.parse(ev.data);
|
|
7057
|
+
if(d.type==='connected'){_notifSSEConnected=true;_notifSSERetryMs=1000;return;}
|
|
7058
|
+
if(d.type==='update'){
|
|
7059
|
+
var prev=_notifUnread;
|
|
7060
|
+
_notifUnread=d.unreadCount||0;
|
|
7061
|
+
renderNotifBadge();
|
|
7062
|
+
if(_notifUnread>prev&&_notifPanelOpen) loadNotifications();
|
|
7063
|
+
}
|
|
7064
|
+
if(d.type==='cleared'){
|
|
7065
|
+
_notifUnread=0;_notifCache=[];
|
|
7066
|
+
renderNotifBadge();renderNotifPanel();
|
|
7067
|
+
}
|
|
7068
|
+
}catch(e){}
|
|
7069
|
+
};
|
|
7070
|
+
_notifSSE.onerror=function(){
|
|
7071
|
+
_notifSSEConnected=false;
|
|
7072
|
+
if(_notifSSE){_notifSSE.close();_notifSSE=null;}
|
|
7073
|
+
setTimeout(connectNotifSSE,Math.min(_notifSSERetryMs,30000));
|
|
7074
|
+
_notifSSERetryMs=Math.min(_notifSSERetryMs*2,30000);
|
|
7075
|
+
};
|
|
7076
|
+
}catch(e){}
|
|
7077
|
+
}
|
|
7078
|
+
connectNotifSSE();
|
|
6811
7079
|
|
|
6812
7080
|
function toggleNotifPanel(e){
|
|
6813
7081
|
if(e)e.stopPropagation();
|
|
@@ -6838,7 +7106,10 @@ function notifTimeAgo(ts){
|
|
|
6838
7106
|
return t('notif.timeAgo.day').replace('{n}',Math.floor(diff/86400000));
|
|
6839
7107
|
}
|
|
6840
7108
|
|
|
6841
|
-
function notifIcon(resource){
|
|
7109
|
+
function notifIcon(resource,type){
|
|
7110
|
+
if(type==='user_online') return '\\u{1F7E2}';
|
|
7111
|
+
if(type==='user_offline') return '\\u{1F534}';
|
|
7112
|
+
if(type==='user_join_request') return '\\u{1F464}';
|
|
6842
7113
|
if(resource==='memory') return '\\u{1F4DD}';
|
|
6843
7114
|
if(resource==='task') return '\\u{1F4CB}';
|
|
6844
7115
|
if(resource==='skill') return '\\u{1F9E0}';
|
|
@@ -6849,6 +7120,21 @@ function notifTypeText(n){
|
|
|
6849
7120
|
if(n.type==='resource_removed'){
|
|
6850
7121
|
return t('notif.removed.'+n.resource)||t('notif.removed.memory');
|
|
6851
7122
|
}
|
|
7123
|
+
if(n.type==='resource_shared'){
|
|
7124
|
+
return t('notif.shared.'+n.resource)||t('notif.shared.memory');
|
|
7125
|
+
}
|
|
7126
|
+
if(n.type==='resource_unshared'){
|
|
7127
|
+
return t('notif.unshared.'+n.resource)||t('notif.unshared.memory');
|
|
7128
|
+
}
|
|
7129
|
+
if(n.type==='user_join_request'){
|
|
7130
|
+
return t('notif.userJoin');
|
|
7131
|
+
}
|
|
7132
|
+
if(n.type==='user_online'){
|
|
7133
|
+
return t('notif.userOnline');
|
|
7134
|
+
}
|
|
7135
|
+
if(n.type==='user_offline'){
|
|
7136
|
+
return t('notif.userOffline');
|
|
7137
|
+
}
|
|
6852
7138
|
return n.message||n.type;
|
|
6853
7139
|
}
|
|
6854
7140
|
|
|
@@ -6893,7 +7179,7 @@ function renderNotifPanel(){
|
|
|
6893
7179
|
body.innerHTML=_notifCache.map(function(n){
|
|
6894
7180
|
var cls='notif-item'+(n.read?'':' unread');
|
|
6895
7181
|
return '<div class="'+cls+'" onclick="markNotifRead("'+esc(n.id)+'")">'+
|
|
6896
|
-
'<div class="notif-item-icon">'+notifIcon(n.resource)+'</div>'+
|
|
7182
|
+
'<div class="notif-item-icon">'+notifIcon(n.resource,n.type)+'</div>'+
|
|
6897
7183
|
'<div class="notif-item-body">'+
|
|
6898
7184
|
'<div class="notif-item-title">'+esc(notifTypeText(n))+'</div>'+
|
|
6899
7185
|
'<div class="notif-item-name">'+esc(n.title)+'</div>'+
|
|
@@ -6934,15 +7220,8 @@ async function clearAllNotifs(){
|
|
|
6934
7220
|
}catch(e){}
|
|
6935
7221
|
}
|
|
6936
7222
|
|
|
6937
|
-
function startNotifPoll(){
|
|
6938
|
-
|
|
6939
|
-
pollNotifCount();
|
|
6940
|
-
_notifPollTimer=setInterval(pollNotifCount,15000);
|
|
6941
|
-
}
|
|
6942
|
-
|
|
6943
|
-
function stopNotifPoll(){
|
|
6944
|
-
if(_notifPollTimer){clearInterval(_notifPollTimer);_notifPollTimer=null;}
|
|
6945
|
-
}
|
|
7223
|
+
function startNotifPoll(){ startLivePoller(); }
|
|
7224
|
+
function stopNotifPoll(){ }
|
|
6946
7225
|
|
|
6947
7226
|
/* ─── Data loading ─── */
|
|
6948
7227
|
async function loadAll(){
|
|
@@ -6950,8 +7229,8 @@ async function loadAll(){
|
|
|
6950
7229
|
checkMigrateStatus();
|
|
6951
7230
|
connectPPSSE();
|
|
6952
7231
|
checkForUpdate();
|
|
6953
|
-
|
|
6954
|
-
|
|
7232
|
+
pollNotifCount();
|
|
7233
|
+
startLivePoller();
|
|
6955
7234
|
}
|
|
6956
7235
|
|
|
6957
7236
|
async function loadStats(ownerFilter){
|
|
@@ -7029,11 +7308,14 @@ async function loadStats(ownerFilter){
|
|
|
7029
7308
|
const ownerSel=document.getElementById('filterOwner');
|
|
7030
7309
|
if(ownerSel && d.owners && d.owners.length>0){
|
|
7031
7310
|
const curVal=ownerSel.value;
|
|
7032
|
-
|
|
7033
|
-
|
|
7034
|
-
|
|
7311
|
+
var agents=d.owners.filter(function(o){return o && o.indexOf('agent:')===0;});
|
|
7312
|
+
ownerSel.innerHTML='<option value="">'+t('filter.allagents')+'</option>';
|
|
7313
|
+
agents.forEach(function(o){
|
|
7314
|
+
var label=o.replace('agent:','');
|
|
7315
|
+
ownerSel.innerHTML+='<option value="'+o+'"'+(o===curVal?' selected':'')+'>'+label+'</option>';
|
|
7035
7316
|
});
|
|
7036
|
-
ownerSel.
|
|
7317
|
+
if(agents.length<=1) ownerSel.style.display='none';
|
|
7318
|
+
else ownerSel.style.display='';
|
|
7037
7319
|
}
|
|
7038
7320
|
}
|
|
7039
7321
|
|
|
@@ -7125,7 +7407,7 @@ async function doSearch(query){
|
|
|
7125
7407
|
var scope=document.getElementById('memorySearchScope')?.value||memorySearchScope||'local';
|
|
7126
7408
|
var list=document.getElementById('memoryList');
|
|
7127
7409
|
list.innerHTML='<div class="spinner"></div>';
|
|
7128
|
-
if(scope
|
|
7410
|
+
if(scope==='hub'){
|
|
7129
7411
|
try{
|
|
7130
7412
|
var r=await fetch('/api/sharing/search/memories',{
|
|
7131
7413
|
method:'POST',
|
|
@@ -8223,7 +8505,7 @@ async function checkForUpdate(){
|
|
|
8223
8505
|
const pkgSpec=d.installCommand?d.installCommand.replace(/^(?:npx\s+)?openclaw\s+plugins\s+install\s+/,''):(d.packageName+'@'+d.latest);
|
|
8224
8506
|
var banner=document.createElement('div');
|
|
8225
8507
|
banner.id='updateBanner';
|
|
8226
|
-
banner.style.cssText='display:flex;align-items:center;gap:12px;padding:10px max
|
|
8508
|
+
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)';
|
|
8227
8509
|
var textNode=document.createElement('div');
|
|
8228
8510
|
textNode.style.cssText='display:flex;align-items:center;gap:8px;flex-shrink:0;font-size:13px';
|
|
8229
8511
|
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>';
|