@memtensor/memos-local-openclaw-plugin 1.0.4-beta.15 → 1.0.4-beta.17
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 +94 -27
- package/dist/hub/server.d.ts +1 -0
- package/dist/hub/server.d.ts.map +1 -1
- package/dist/hub/server.js +74 -7
- package/dist/hub/server.js.map +1 -1
- package/dist/ingest/providers/index.js +2 -2
- package/dist/ingest/providers/index.js.map +1 -1
- package/dist/shared/llm-call.d.ts.map +1 -1
- package/dist/shared/llm-call.js +2 -1
- package/dist/shared/llm-call.js.map +1 -1
- package/dist/viewer/html.d.ts.map +1 -1
- package/dist/viewer/html.js +214 -67
- package/dist/viewer/html.js.map +1 -1
- package/dist/viewer/server.d.ts +6 -0
- package/dist/viewer/server.d.ts.map +1 -1
- package/dist/viewer/server.js +152 -42
- package/dist/viewer/server.js.map +1 -1
- package/index.ts +7 -4
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
- package/src/hub/server.ts +70 -8
- package/src/ingest/providers/index.ts +2 -2
- package/src/shared/llm-call.ts +2 -1
- package/src/viewer/html.ts +214 -67
- package/src/viewer/server.ts +145 -41
package/src/viewer/html.ts
CHANGED
|
@@ -1654,7 +1654,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1654
1654
|
<li><span data-i18n="guide.join.s1">Ask your team admin for the Server Address and Team Token</span></li>
|
|
1655
1655
|
<li><span data-i18n="guide.join.s2">Enable sharing above, select "Client" mode</span></li>
|
|
1656
1656
|
<li><span data-i18n="guide.join.s3">Fill in Server Address and Team Token, click "Test Connection"</span></li>
|
|
1657
|
-
<li><span data-i18n="guide.join.s4">Save
|
|
1657
|
+
<li><span data-i18n="guide.join.s4">Click "Save & Apply" — the service restarts automatically (page refreshes)</span></li>
|
|
1658
1658
|
</ol>
|
|
1659
1659
|
<button class="btn-guide" onclick="guideGoToHub('client')" data-i18n="guide.join.btn">\u2192 Configure Client Mode</button>
|
|
1660
1660
|
</div>
|
|
@@ -1666,7 +1666,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1666
1666
|
<div class="team-guide-opt-desc" data-i18n="guide.hub.desc">Be the team server. Run it on this device so others can connect and share memories with you.</div>
|
|
1667
1667
|
<ol class="team-guide-steps">
|
|
1668
1668
|
<li><span data-i18n="guide.hub.s1">Enable sharing above, select "Server" mode</span></li>
|
|
1669
|
-
<li><span data-i18n="guide.hub.s2">Set a team name,
|
|
1669
|
+
<li><span data-i18n="guide.hub.s2">Set a team name, click "Save & Apply" — the service restarts automatically</span></li>
|
|
1670
1670
|
<li><span data-i18n="guide.hub.s3">Share the Server Address and Team Token with your team members</span></li>
|
|
1671
1671
|
<li><span data-i18n="guide.hub.s4">Approve join requests in the Admin Panel</span></li>
|
|
1672
1672
|
</ol>
|
|
@@ -1727,7 +1727,7 @@ input,textarea,select{font-family:inherit;font-size:inherit}
|
|
|
1727
1727
|
<div style="font-weight:700;color:var(--text);margin-bottom:4px" data-i18n="settings.hub.clientSteps.title">Quick Setup (3 steps)</div>
|
|
1728
1728
|
<div><span style="color:var(--accent)">1.</span> <span data-i18n="settings.hub.clientSteps.s1">Ask your team admin for the Server Address and Team Token</span></div>
|
|
1729
1729
|
<div><span style="color:var(--accent)">2.</span> <span data-i18n="settings.hub.clientSteps.s2">Fill them in below, click "Test Connection" to verify</span></div>
|
|
1730
|
-
<div><span style="color:var(--accent)">3.</span> <span data-i18n="settings.hub.clientSteps.s3">Click "Save
|
|
1730
|
+
<div><span style="color:var(--accent)">3.</span> <span data-i18n="settings.hub.clientSteps.s3">Click "Save & Apply" — the service will restart and page refreshes automatically</span></div>
|
|
1731
1731
|
</div>
|
|
1732
1732
|
<div class="settings-grid">
|
|
1733
1733
|
<div class="settings-field full-width">
|
|
@@ -2123,8 +2123,13 @@ const I18N={
|
|
|
2123
2123
|
'notif.userJoin':'New user requests to join the team',
|
|
2124
2124
|
'notif.userOnline':'User came online',
|
|
2125
2125
|
'notif.userOffline':'User went offline',
|
|
2126
|
+
'notif.userLeft':'User has left the team',
|
|
2126
2127
|
'notif.membershipApproved':'Your team join request has been approved',
|
|
2127
2128
|
'notif.membershipRejected':'Your team join request has been declined',
|
|
2129
|
+
'notif.membershipRemoved':'You have been removed from the team by the admin',
|
|
2130
|
+
'notif.hubShutdown':'The team server has been shut down',
|
|
2131
|
+
'notif.rolePromoted':'You have been promoted to admin',
|
|
2132
|
+
'notif.roleDemoted':'You have been changed to member',
|
|
2128
2133
|
'notif.clearAll':'Clear all',
|
|
2129
2134
|
'notif.timeAgo.just':'just now',
|
|
2130
2135
|
'notif.timeAgo.min':'{n}m ago',
|
|
@@ -2275,12 +2280,12 @@ const I18N={
|
|
|
2275
2280
|
'settings.test.ok':'Connected',
|
|
2276
2281
|
'settings.test.fail':'Failed',
|
|
2277
2282
|
'settings.session.expired':'Session expired, please refresh the page to log in again',
|
|
2278
|
-
'settings.save':'Save
|
|
2283
|
+
'settings.save':'Save & Apply',
|
|
2279
2284
|
'settings.reset':'Reset',
|
|
2280
2285
|
'settings.saved':'Saved',
|
|
2281
|
-
'settings.restart.hint':'
|
|
2282
|
-
'settings.restart.autoRefresh':'
|
|
2283
|
-
'settings.restart.waiting':'Configuration saved.
|
|
2286
|
+
'settings.restart.hint':'Changes will take effect after the service restarts automatically.',
|
|
2287
|
+
'settings.restart.autoRefresh':'Service restarting, page will refresh automatically...',
|
|
2288
|
+
'settings.restart.waiting':'Configuration saved. Service is restarting...',
|
|
2284
2289
|
'settings.save.fail':'Failed to save settings',
|
|
2285
2290
|
'settings.save.emb.required':'Embedding model is required. Please configure an embedding model before saving.',
|
|
2286
2291
|
'settings.save.emb.fail':'Embedding model test failed, cannot save',
|
|
@@ -2407,16 +2412,16 @@ const I18N={
|
|
|
2407
2412
|
'settings.hub.tokenCopied':'Team Token copied!',
|
|
2408
2413
|
'settings.hub.hubSteps.title':'Quick Setup (3 steps)',
|
|
2409
2414
|
'settings.hub.hubSteps.s1':'Fill in Team Name below (or keep default)',
|
|
2410
|
-
'settings.hub.hubSteps.s2':'Click "Save
|
|
2415
|
+
'settings.hub.hubSteps.s2':'Click "Save & Apply" — the service will restart automatically',
|
|
2411
2416
|
'settings.hub.hubSteps.s3':'Share the Server Address and Team Token below with your team members',
|
|
2412
2417
|
'settings.hub.clientSteps.title':'Quick Setup (3 steps)',
|
|
2413
2418
|
'settings.hub.clientSteps.s1':'Ask your team admin for the Server Address and Team Token',
|
|
2414
2419
|
'settings.hub.clientSteps.s2':'Fill them in below, click "Test Connection" to verify',
|
|
2415
|
-
'settings.hub.clientSteps.s3':'Click "Save
|
|
2420
|
+
'settings.hub.clientSteps.s3':'Click "Save & Apply" — the service will restart and page refreshes automatically',
|
|
2416
2421
|
'settings.hub.shareInfo.title':'Share this info with your team members:',
|
|
2417
2422
|
'settings.hub.shareInfo.yourIP':'your-IP',
|
|
2418
2423
|
'settings.hub.shareInfo.clickCopy':'Click to copy',
|
|
2419
|
-
'settings.hub.restartAlert':'Team sharing config saved!
|
|
2424
|
+
'settings.hub.restartAlert':'Team sharing config saved! The service will restart automatically to apply changes.',
|
|
2420
2425
|
'settings.hub.hubAddress':'Server Address',
|
|
2421
2426
|
'settings.hub.hubAddress.hint':'Team server address, e.g. 192.168.1.100:18800',
|
|
2422
2427
|
'settings.hub.teamTokenClient':'Team Token',
|
|
@@ -2437,6 +2442,10 @@ const I18N={
|
|
|
2437
2442
|
'sidebar.hub':'\u{1F310} Team Sharing',
|
|
2438
2443
|
'sharing.sidebar.connected':'Connected',
|
|
2439
2444
|
'sharing.sidebar.disconnected':'Disconnected',
|
|
2445
|
+
'sharing.sidebar.hubRunning':'Hub Running',
|
|
2446
|
+
'sharing.sidebar.teamName':'Team',
|
|
2447
|
+
'sharing.sidebar.members':'Members',
|
|
2448
|
+
'sharing.sidebar.online':'online',
|
|
2440
2449
|
'sharing.sidebar.pending':'Pending Approval',
|
|
2441
2450
|
'sharing.sidebar.rejected':'Rejected',
|
|
2442
2451
|
'sharing.sidebar.starting':'Starting...',
|
|
@@ -2453,6 +2462,11 @@ const I18N={
|
|
|
2453
2462
|
'sharing.retryJoin':'Retry Join',
|
|
2454
2463
|
'sharing.retryJoin.hint':'Clears local data and re-submits the join request',
|
|
2455
2464
|
'sharing.retryJoin.confirm':'This will clear your current connection and re-submit a join request. Continue?',
|
|
2465
|
+
'sharing.leaveTeam':'Leave Team',
|
|
2466
|
+
'sharing.leaveTeam.confirm':'You are about to leave team "{team}".\\n\\nWhat will happen:\\n\\u2022 You will disconnect from the team server\\n\\u2022 The team admin will be notified that you left\\n\\u2022 You will no longer receive shared memories, tasks, or skills\\n\\u2022 Your local data is preserved and not affected\\n\\u2022 You can rejoin later if the admin approves\\n\\nAre you sure?',
|
|
2467
|
+
'sharing.leaveTeam.success':'You have left the team. Sharing has been disabled.',
|
|
2468
|
+
'sharing.leaveTeam.fail':'Failed to leave team',
|
|
2469
|
+
'sharing.team.default':'the team',
|
|
2456
2470
|
'sharing.retryJoin.success':'Join request re-submitted. Waiting for admin approval.',
|
|
2457
2471
|
'sharing.retryJoin.fail':'Failed to retry join',
|
|
2458
2472
|
'sharing.ownerRemoved':'(removed)',
|
|
@@ -2506,6 +2520,7 @@ const I18N={
|
|
|
2506
2520
|
'admin.editName':'Edit Name',
|
|
2507
2521
|
'admin.lastAdminHint':'Last admin — cannot remove or demote',
|
|
2508
2522
|
'admin.ownerHint':'Hub owner — cannot be demoted or removed',
|
|
2523
|
+
'admin.selfHint':'This is you',
|
|
2509
2524
|
'admin.editNamePrompt':'Enter new username:',
|
|
2510
2525
|
'confirm.promoteAdmin':'Promote this user to admin? They will be able to manage all team members and resources.',
|
|
2511
2526
|
'confirm.demoteMember':'Demote this admin to member?',
|
|
@@ -2567,6 +2582,8 @@ const I18N={
|
|
|
2567
2582
|
'toast.userApproved':'User approved',
|
|
2568
2583
|
'sharing.approved.toast':'Your join request has been approved!',
|
|
2569
2584
|
'sharing.rejected.toast':'Your join request was rejected by the admin.',
|
|
2585
|
+
'sharing.hubOffline.toast':'Team server is offline. Will reconnect automatically when it comes back.',
|
|
2586
|
+
'sharing.hubReconnected.toast':'Team server is back online! Connection restored.',
|
|
2570
2587
|
'toast.userRejected':'User rejected',
|
|
2571
2588
|
'toast.approveFail':'Approve failed',
|
|
2572
2589
|
'toast.rejectFail':'Reject failed',
|
|
@@ -2726,9 +2743,10 @@ const I18N={
|
|
|
2726
2743
|
'update.dismiss':'Dismiss',
|
|
2727
2744
|
'sharing.disable.confirm.hub':'You are about to shut down the team server.\\n\\nWhat will happen:\\n\\u2022 All connected team members will be disconnected\\n\\u2022 They will no longer be able to sync memories, tasks, or skills\\n\\u2022 Shared data is preserved and will be available when you re-enable\\n\\nAre you sure?',
|
|
2728
2745
|
'sharing.disable.confirm.client':'You are about to disconnect from the team.\\n\\nWhat will happen:\\n\\u2022 You will no longer receive shared memories, tasks, or skills from the team\\n\\u2022 Your local data is preserved and will not be affected\\n\\u2022 You can reconnect later by re-enabling sharing\\n\\nAre you sure?',
|
|
2729
|
-
'sharing.disable.restartAlert':'Sharing has been disabled.
|
|
2730
|
-
'sharing.switch.hubToClient':'You are about to switch from Server to Client mode.\\n\\nWhat will happen:\\n\\u2022 The Hub server will shut down after
|
|
2731
|
-
'sharing.switch.clientToHub':'You are about to switch from Client to Server mode.\\n\\nWhat will happen:\\n\\u2022 You will disconnect from the current team\\n\\u2022 A new Hub server will start after
|
|
2746
|
+
'sharing.disable.restartAlert':'Sharing has been disabled. The service will restart automatically to apply the change.',
|
|
2747
|
+
'sharing.switch.hubToClient':'You are about to switch from Server to Client mode.\\n\\nWhat will happen:\\n\\u2022 The Hub server will shut down after the service restarts\\n\\u2022 All connected team members will be disconnected\\n\\u2022 Shared data on the Hub is preserved for future use\\n\\u2022 You will join the specified remote team as a client\\n\\nAre you sure?',
|
|
2748
|
+
'sharing.switch.clientToHub':'You are about to switch from Client to Server mode.\\n\\nWhat will happen:\\n\\u2022 You will disconnect from the current team\\n\\u2022 A new Hub server will start after the service restarts\\n\\u2022 Your local data is not affected\\n\\nAre you sure?',
|
|
2749
|
+
'sharing.switch.hubAddress':'You are about to leave the current team and join a different one.\\n\\nWhat will happen:\\n\\u2022 You will disconnect from the current team server\\n\\u2022 The current team admin will be notified that you left\\n\\u2022 You will join the new team server as a new member\\n\\u2022 Your local data is not affected\\n\\nAre you sure?',
|
|
2732
2750
|
'admin.notEnabled.title':'Team sharing is not enabled',
|
|
2733
2751
|
'admin.notEnabled.desc':'The Admin Panel is used to manage team members, shared memories, tasks, and skills. To use this feature, you need to enable team sharing first.',
|
|
2734
2752
|
'admin.notEnabled.setupHub':'Set Up as Team Server',
|
|
@@ -2746,12 +2764,12 @@ const I18N={
|
|
|
2746
2764
|
'guide.join.s1':'Ask your team admin for the Server Address and Team Token',
|
|
2747
2765
|
'guide.join.s2':'Go to Settings \u2192 Team Sharing, enable sharing, select "Client" mode',
|
|
2748
2766
|
'guide.join.s3':'Fill in Server Address and Team Token, click "Test Connection"',
|
|
2749
|
-
'guide.join.s4':'Save
|
|
2767
|
+
'guide.join.s4':'Click "Save & Apply" — the service restarts automatically (page refreshes)',
|
|
2750
2768
|
'guide.join.btn':'\u2192 Configure Client Mode',
|
|
2751
2769
|
'guide.hub.title':'Start Your Own Team Server',
|
|
2752
2770
|
'guide.hub.desc':'Be the team server. Run it on this device so others can connect and share memories with you.',
|
|
2753
2771
|
'guide.hub.s1':'Go to Settings \u2192 Team Sharing, enable sharing, select "Server" mode',
|
|
2754
|
-
'guide.hub.s2':'Set a team name,
|
|
2772
|
+
'guide.hub.s2':'Set a team name, click "Save & Apply" — the service restarts automatically',
|
|
2755
2773
|
'guide.hub.s3':'Share the Server Address and Team Token with your team members',
|
|
2756
2774
|
'guide.hub.s4':'Approve join requests in the Admin Panel',
|
|
2757
2775
|
'guide.hub.btn':'\u2192 Configure Server Mode'
|
|
@@ -2842,8 +2860,13 @@ const I18N={
|
|
|
2842
2860
|
'notif.userJoin':'有新用户申请加入团队',
|
|
2843
2861
|
'notif.userOnline':'用户上线了',
|
|
2844
2862
|
'notif.userOffline':'用户下线了',
|
|
2863
|
+
'notif.userLeft':'用户已退出团队',
|
|
2845
2864
|
'notif.membershipApproved':'你的团队加入申请已通过',
|
|
2846
2865
|
'notif.membershipRejected':'你的团队加入申请已被拒绝',
|
|
2866
|
+
'notif.membershipRemoved':'你已被管理员移出团队',
|
|
2867
|
+
'notif.hubShutdown':'团队服务已关闭',
|
|
2868
|
+
'notif.rolePromoted':'你已被提升为管理员',
|
|
2869
|
+
'notif.roleDemoted':'你已被设为普通成员',
|
|
2847
2870
|
'notif.clearAll':'清除全部',
|
|
2848
2871
|
'notif.timeAgo.just':'刚刚',
|
|
2849
2872
|
'notif.timeAgo.min':'{n}分钟前',
|
|
@@ -2994,12 +3017,12 @@ const I18N={
|
|
|
2994
3017
|
'settings.test.ok':'连接成功',
|
|
2995
3018
|
'settings.test.fail':'连接失败',
|
|
2996
3019
|
'settings.session.expired':'登录已过期,请刷新页面重新登录',
|
|
2997
|
-
'settings.save':'
|
|
3020
|
+
'settings.save':'保存并应用',
|
|
2998
3021
|
'settings.reset':'重置',
|
|
2999
3022
|
'settings.saved':'已保存',
|
|
3000
|
-
'settings.restart.hint':'
|
|
3001
|
-
'settings.restart.autoRefresh':'
|
|
3002
|
-
'settings.restart.waiting':'
|
|
3023
|
+
'settings.restart.hint':'修改将在服务自动重启后生效。',
|
|
3024
|
+
'settings.restart.autoRefresh':'服务重启中,页面将自动刷新...',
|
|
3025
|
+
'settings.restart.waiting':'配置已保存,服务正在重启...',
|
|
3003
3026
|
'settings.save.fail':'保存设置失败',
|
|
3004
3027
|
'settings.save.emb.required':'嵌入模型为必填项,请先配置嵌入模型再保存。',
|
|
3005
3028
|
'settings.save.emb.fail':'嵌入模型测试失败,无法保存',
|
|
@@ -3126,16 +3149,16 @@ const I18N={
|
|
|
3126
3149
|
'settings.hub.tokenCopied':'团队令牌已复制!',
|
|
3127
3150
|
'settings.hub.hubSteps.title':'快速配置(3 步)',
|
|
3128
3151
|
'settings.hub.hubSteps.s1':'填写下方团队名称(或保持默认)',
|
|
3129
|
-
'settings.hub.hubSteps.s2':'
|
|
3152
|
+
'settings.hub.hubSteps.s2':'点击「保存并应用」,服务将自动重启',
|
|
3130
3153
|
'settings.hub.hubSteps.s3':'将下方的服务器地址和团队令牌分享给团队成员',
|
|
3131
3154
|
'settings.hub.clientSteps.title':'快速配置(3 步)',
|
|
3132
3155
|
'settings.hub.clientSteps.s1':'向团队管理员获取服务器地址和团队令牌',
|
|
3133
3156
|
'settings.hub.clientSteps.s2':'填入下方,点击"测试连接"验证连通性',
|
|
3134
|
-
'settings.hub.clientSteps.s3':'
|
|
3157
|
+
'settings.hub.clientSteps.s3':'点击「保存并应用」,服务将自动重启(页面会自动刷新)',
|
|
3135
3158
|
'settings.hub.shareInfo.title':'请将以下信息分享给团队成员:',
|
|
3136
3159
|
'settings.hub.shareInfo.yourIP':'你的IP',
|
|
3137
3160
|
'settings.hub.shareInfo.clickCopy':'点击复制',
|
|
3138
|
-
'settings.hub.restartAlert':'
|
|
3161
|
+
'settings.hub.restartAlert':'团队共享配置已保存!服务将自动重启以应用更改。',
|
|
3139
3162
|
'settings.hub.hubAddress':'服务器地址',
|
|
3140
3163
|
'settings.hub.hubAddress.hint':'团队服务器地址,如 192.168.1.100:18800',
|
|
3141
3164
|
'settings.hub.teamTokenClient':'团队令牌',
|
|
@@ -3156,6 +3179,10 @@ const I18N={
|
|
|
3156
3179
|
'sidebar.hub':'\u{1F310} 团队共享',
|
|
3157
3180
|
'sharing.sidebar.connected':'已连接',
|
|
3158
3181
|
'sharing.sidebar.disconnected':'已断开',
|
|
3182
|
+
'sharing.sidebar.hubRunning':'服务运行中',
|
|
3183
|
+
'sharing.sidebar.teamName':'团队',
|
|
3184
|
+
'sharing.sidebar.members':'成员',
|
|
3185
|
+
'sharing.sidebar.online':'在线',
|
|
3159
3186
|
'sharing.sidebar.pending':'等待审核',
|
|
3160
3187
|
'sharing.sidebar.rejected':'已拒绝',
|
|
3161
3188
|
'sharing.sidebar.starting':'启动中...',
|
|
@@ -3172,6 +3199,11 @@ const I18N={
|
|
|
3172
3199
|
'sharing.retryJoin':'重新申请',
|
|
3173
3200
|
'sharing.retryJoin.hint':'清除本地连接数据并重新提交加入申请',
|
|
3174
3201
|
'sharing.retryJoin.confirm':'这将清除当前连接数据并重新提交加入申请,是否继续?',
|
|
3202
|
+
'sharing.leaveTeam':'退出团队',
|
|
3203
|
+
'sharing.leaveTeam.confirm':'你即将退出团队「{team}」。\\n\\n退出后将会:\\n\\u2022 断开与团队服务器的连接\\n\\u2022 团队管理员会收到你退出的通知\\n\\u2022 你将无法再接收团队共享的记忆、任务和技能\\n\\u2022 你的本地数据不受影响,会完整保留\\n\\u2022 之后可以重新申请加入(需管理员审批)\\n\\n确定要退出吗?',
|
|
3204
|
+
'sharing.leaveTeam.success':'你已退出团队,团队共享已关闭。',
|
|
3205
|
+
'sharing.leaveTeam.fail':'退出团队失败',
|
|
3206
|
+
'sharing.team.default':'该团队',
|
|
3175
3207
|
'sharing.retryJoin.success':'加入申请已重新提交,请等待管理员审核。',
|
|
3176
3208
|
'sharing.retryJoin.fail':'重新申请失败',
|
|
3177
3209
|
'sharing.ownerRemoved':'(已移除)',
|
|
@@ -3225,6 +3257,7 @@ const I18N={
|
|
|
3225
3257
|
'admin.editName':'编辑名称',
|
|
3226
3258
|
'admin.lastAdminHint':'唯一管理员 — 无法删除或降级',
|
|
3227
3259
|
'admin.ownerHint':'Hub 创建者 — 不可降级或移除',
|
|
3260
|
+
'admin.selfHint':'这是你自己',
|
|
3228
3261
|
'admin.editNamePrompt':'请输入新用户名:',
|
|
3229
3262
|
'confirm.promoteAdmin':'确定要将此用户提升为管理员吗?管理员可以管理所有团队成员和资源。',
|
|
3230
3263
|
'confirm.demoteMember':'确定要将此管理员降为普通成员吗?',
|
|
@@ -3286,6 +3319,8 @@ const I18N={
|
|
|
3286
3319
|
'toast.userApproved':'用户已批准',
|
|
3287
3320
|
'sharing.approved.toast':'您的加入申请已通过审核!',
|
|
3288
3321
|
'sharing.rejected.toast':'您的加入申请已被管理员拒绝。',
|
|
3322
|
+
'sharing.hubOffline.toast':'团队服务已离线,恢复后将自动重新连接。',
|
|
3323
|
+
'sharing.hubReconnected.toast':'团队服务已恢复上线,连接已自动恢复!',
|
|
3289
3324
|
'toast.userRejected':'用户已拒绝',
|
|
3290
3325
|
'toast.approveFail':'批准失败',
|
|
3291
3326
|
'toast.rejectFail':'拒绝失败',
|
|
@@ -3445,9 +3480,10 @@ const I18N={
|
|
|
3445
3480
|
'update.dismiss':'关闭',
|
|
3446
3481
|
'sharing.disable.confirm.hub':'你即将关闭团队服务。\\n\\n关闭后将会:\\n\\u2022 所有已连接的团队成员将断开连接\\n\\u2022 他们将无法继续同步记忆、任务和技能\\n\\u2022 已共享的数据会保留,重新开启后仍可使用\\n\\n确定要关闭吗?',
|
|
3447
3482
|
'sharing.disable.confirm.client':'你即将断开与团队的连接。\\n\\n断开后将会:\\n\\u2022 你将无法再接收团队共享的记忆、任务和技能\\n\\u2022 你的本地数据不受影响,会完整保留\\n\\u2022 之后可以随时重新开启共享来恢复连接\\n\\n确定要断开吗?',
|
|
3448
|
-
'sharing.disable.restartAlert':'
|
|
3449
|
-
'sharing.switch.hubToClient':'你即将从服务端模式切换为客户端模式。\\n\\n切换后将会:\\n\\u2022 Hub
|
|
3450
|
-
'sharing.switch.clientToHub':'你即将从客户端模式切换为服务端模式。\\n\\n切换后将会:\\n\\u2022 你将断开与当前团队的连接\\n\\u2022
|
|
3483
|
+
'sharing.disable.restartAlert':'共享已关闭,服务将自动重启以应用更改。',
|
|
3484
|
+
'sharing.switch.hubToClient':'你即将从服务端模式切换为客户端模式。\\n\\n切换后将会:\\n\\u2022 Hub 服务将在服务重启后关闭\\n\\u2022 所有已连接的团队成员将断开连接\\n\\u2022 Hub 上的共享数据会保留,以后可恢复使用\\n\\u2022 你将作为客户端加入指定的远程团队\\n\\n确定要切换吗?',
|
|
3485
|
+
'sharing.switch.clientToHub':'你即将从客户端模式切换为服务端模式。\\n\\n切换后将会:\\n\\u2022 你将断开与当前团队的连接\\n\\u2022 服务重启后将启动新的 Hub 服务\\n\\u2022 你的本地数据不受影响\\n\\n确定要切换吗?',
|
|
3486
|
+
'sharing.switch.hubAddress':'你即将离开当前团队并加入新的团队。\\n\\n操作后将会:\\n\\u2022 你将断开与当前团队服务器的连接\\n\\u2022 当前团队管理员会收到你离开的通知\\n\\u2022 你将作为新成员加入新的团队服务器\\n\\u2022 你的本地数据不受影响\\n\\n确定要切换吗?',
|
|
3451
3487
|
'admin.notEnabled.title':'团队共享尚未开启',
|
|
3452
3488
|
'admin.notEnabled.desc':'管理面板用于管理团队成员、共享的记忆、任务和技能。使用此功能前,需要先开启团队共享。',
|
|
3453
3489
|
'admin.notEnabled.setupHub':'配置为团队服务端',
|
|
@@ -3465,12 +3501,12 @@ const I18N={
|
|
|
3465
3501
|
'guide.join.s1':'向团队管理员索取服务器地址和团队令牌',
|
|
3466
3502
|
'guide.join.s2':'前往「设置 → 团队共享」,开启共享,选择「客户端」模式',
|
|
3467
3503
|
'guide.join.s3':'填写服务器地址和团队令牌,点击「测试连接」',
|
|
3468
|
-
'guide.join.s4':'
|
|
3504
|
+
'guide.join.s4':'点击「保存并应用」,服务将自动重启(页面会自动刷新)',
|
|
3469
3505
|
'guide.join.btn':'\u2192 配置客户端模式',
|
|
3470
3506
|
'guide.hub.title':'自建团队服务',
|
|
3471
3507
|
'guide.hub.desc':'将本机作为团队服务端,让其他成员连接过来共享记忆。',
|
|
3472
3508
|
'guide.hub.s1':'前往「设置 → 团队共享」,开启共享,选择「服务端」模式',
|
|
3473
|
-
'guide.hub.s2':'
|
|
3509
|
+
'guide.hub.s2':'设置团队名称,点击「保存并应用」,服务将自动重启',
|
|
3474
3510
|
'guide.hub.s3':'将服务器地址和团队令牌分享给团队成员',
|
|
3475
3511
|
'guide.hub.s4':'在管理面板中审批加入请求',
|
|
3476
3512
|
'guide.hub.btn':'\u2192 配置服务端模式'
|
|
@@ -3576,12 +3612,28 @@ async function doReset(){
|
|
|
3576
3612
|
}
|
|
3577
3613
|
|
|
3578
3614
|
var _sharingRole='client';
|
|
3615
|
+
var _loadedClientHubAddress='';
|
|
3579
3616
|
function _genToken(len){
|
|
3580
3617
|
var a=new Uint8Array(len||18);crypto.getRandomValues(a);
|
|
3581
3618
|
return btoa(String.fromCharCode.apply(null,a)).replace(/\\+/g,'-').replace(/\\//g,'_').replace(/=+$/,'');
|
|
3582
3619
|
}
|
|
3583
|
-
function onSharingToggle(){
|
|
3584
|
-
var
|
|
3620
|
+
async function onSharingToggle(){
|
|
3621
|
+
var chk=document.getElementById('cfgSharingEnabled');
|
|
3622
|
+
var on=chk.checked;
|
|
3623
|
+
if(!on && sharingStatusCache && sharingStatusCache.enabled){
|
|
3624
|
+
var prevRole=sharingStatusCache.role;
|
|
3625
|
+
var confirmMsg=prevRole==='hub'?t('sharing.disable.confirm.hub'):t('sharing.disable.confirm.client');
|
|
3626
|
+
if(!(await confirmModal(confirmMsg,{danger:true}))){
|
|
3627
|
+
chk.checked=true;
|
|
3628
|
+
return;
|
|
3629
|
+
}
|
|
3630
|
+
var cfg={sharing:{enabled:false,role:prevRole}};
|
|
3631
|
+
chk.disabled=true;
|
|
3632
|
+
var result=await doSaveConfig(cfg, null, 'hubSaved');
|
|
3633
|
+
chk.disabled=false;
|
|
3634
|
+
if(!result){chk.checked=true;return;}
|
|
3635
|
+
return;
|
|
3636
|
+
}
|
|
3585
3637
|
document.getElementById('sharingConfigPanel').style.display=on?'block':'none';
|
|
3586
3638
|
var pw=document.getElementById('sharingPanelsWrap');
|
|
3587
3639
|
if(pw) pw.style.display=on?'':'none';
|
|
@@ -3652,13 +3704,6 @@ async function testHubConnection(){
|
|
|
3652
3704
|
if(!addr){result.innerHTML='<span style="color:var(--rose)">\u274C '+t('settings.hub.test.noAddr')+'</span>';return;}
|
|
3653
3705
|
btn.disabled=true;result.innerHTML=t('settings.hub.test.testing');
|
|
3654
3706
|
try{
|
|
3655
|
-
var ipsData=await fetch('/api/local-ips').then(function(r){return r.json();});
|
|
3656
|
-
var localAddrs=['127.0.0.1','localhost','0.0.0.0'].concat(ipsData.ips||[]);
|
|
3657
|
-
var parsed=new URL(addr.indexOf('://')>-1?addr:'http://'+addr);
|
|
3658
|
-
if(localAddrs.indexOf(parsed.hostname)>=0){
|
|
3659
|
-
result.innerHTML='<span style="color:var(--rose)">\u274C '+t('sharing.cannotJoinSelf')+'</span>';
|
|
3660
|
-
btn.disabled=false;return;
|
|
3661
|
-
}
|
|
3662
3707
|
}catch(e){}
|
|
3663
3708
|
try{
|
|
3664
3709
|
var url=addr.match(/^https?:\\/\\//)?addr:'http://'+addr;
|
|
@@ -3781,16 +3826,26 @@ async function loadSharingStatus(forcePending){
|
|
|
3781
3826
|
var curStatus=conn.rejected?'rejected':conn.pendingApproval?'pending':conn.connected?'connected':'none';
|
|
3782
3827
|
var hubActive=d.role==='hub'||curStatus==='connected';
|
|
3783
3828
|
_updateScopeSelectorsVisibility(hubActive);
|
|
3784
|
-
if(_lastSharingConnStatus==='pending'&&curStatus==='rejected'){
|
|
3829
|
+
if(_lastSharingConnStatus==='pending'&&curStatus==='rejected'&&d.role==='client'){
|
|
3785
3830
|
toast(t('sharing.rejected.toast'),'error');
|
|
3786
3831
|
}
|
|
3787
|
-
if(_lastSharingConnStatus==='pending'&&curStatus==='connected'){
|
|
3832
|
+
if(_lastSharingConnStatus==='pending'&&curStatus==='connected'&&d.role==='client'){
|
|
3788
3833
|
toast(t('sharing.approved.toast'),'success');
|
|
3789
3834
|
loadMemories();loadTasks();loadSkills();
|
|
3790
3835
|
if(_notifSSE){_notifSSE.close();_notifSSE=null;_notifSSEConnected=false;}
|
|
3791
3836
|
connectNotifSSE();
|
|
3792
3837
|
loadNotifications();
|
|
3793
3838
|
}
|
|
3839
|
+
if(_lastSharingConnStatus==='connected'&&curStatus==='none'&&d.role==='client'){
|
|
3840
|
+
toast(t('sharing.hubOffline.toast'),'error');
|
|
3841
|
+
}
|
|
3842
|
+
if(_lastSharingConnStatus==='none'&&curStatus==='connected'&&d.role==='client'){
|
|
3843
|
+
toast(t('sharing.hubReconnected.toast'),'success');
|
|
3844
|
+
loadMemories();loadTasks();loadSkills();
|
|
3845
|
+
if(_notifSSE){_notifSSE.close();_notifSSE=null;_notifSSEConnected=false;}
|
|
3846
|
+
connectNotifSSE();
|
|
3847
|
+
loadNotifications();
|
|
3848
|
+
}
|
|
3794
3849
|
_lastSharingConnStatus=curStatus;
|
|
3795
3850
|
if(curStatus==='pending'&&!_clientPendingPollTimer){
|
|
3796
3851
|
_clientPendingPollTimer=setInterval(function(){loadSharingStatus(false);},5000);
|
|
@@ -3815,7 +3870,8 @@ function renderSharingSidebar(data){
|
|
|
3815
3870
|
var badgeEl=document.getElementById('sharingSidebarConnBadge');
|
|
3816
3871
|
if(!statusEl||!hintEl) return;
|
|
3817
3872
|
var conn=data&&data.connection||{};
|
|
3818
|
-
var
|
|
3873
|
+
var hs=data&&data.hubStats||{};
|
|
3874
|
+
var fp=JSON.stringify({e:!!data&&!!data.enabled,r:data&&data.role,pa:!!conn.pendingApproval,rj:!!conn.rejected,c:!!conn.connected,u:conn.user&&conn.user.username,tn:conn.teamName,cc:!!data&&!!data.clientConfigured,hu:data&&data.hubUrl,tm:hs.totalMembers,om:hs.onlineMembers,pm:hs.pendingMembers});
|
|
3819
3875
|
if(fp===_lastSidebarFingerprint) return;
|
|
3820
3876
|
_lastSidebarFingerprint=fp;
|
|
3821
3877
|
if(!data||!data.enabled){
|
|
@@ -3830,8 +3886,16 @@ function renderSharingSidebar(data){
|
|
|
3830
3886
|
badgeEl.innerHTML='<span style="display:inline-flex;align-items:center;gap:4px;font-size:10px;font-weight:600;padding:2px 8px;border-radius:9999px;background:'+color+'15;color:'+color+'"><span style="display:inline-block;width:6px;height:6px;border-radius:50%;background:'+color+(glow?';box-shadow:0 0 4px '+color:'')+'"></span>'+esc(text)+'</span>';
|
|
3831
3887
|
}
|
|
3832
3888
|
if(data.role==='hub'){
|
|
3833
|
-
setBadge('#34d399',t('sharing.sidebar.
|
|
3834
|
-
|
|
3889
|
+
setBadge('#34d399',t('sharing.sidebar.hubRunning'),true);
|
|
3890
|
+
var hs=data.hubStats||{};
|
|
3891
|
+
var html='<div class="info-grid">';
|
|
3892
|
+
if(conn.teamName) html+='<span class="label">'+t('sharing.sidebar.teamName')+'</span><span class="value" style="font-weight:600">'+esc(conn.teamName)+'</span>';
|
|
3893
|
+
html+='<span class="label">'+t('sharing.sidebar.members')+'</span><span class="value">'+(hs.totalMembers||0)+' <span style="opacity:.5;font-size:10px">/ '+t('sharing.sidebar.online')+' '+(hs.onlineMembers||0)+'</span></span>';
|
|
3894
|
+
if(hs.pendingMembers>0){
|
|
3895
|
+
html+='<span class="label">'+t('sharing.sidebar.pending')+'</span><span class="value" style="color:var(--yellow,#fbbf24);font-weight:600">'+hs.pendingMembers+'</span>';
|
|
3896
|
+
}
|
|
3897
|
+
html+='</div>';
|
|
3898
|
+
statusEl.innerHTML=html;
|
|
3835
3899
|
hintEl.textContent='';
|
|
3836
3900
|
}else if(conn.pendingApproval&&conn.user){
|
|
3837
3901
|
setBadge('#fbbf24',t('sharing.sidebar.pending'),false);
|
|
@@ -3902,7 +3966,6 @@ function renderSharingSettings(data){
|
|
|
3902
3966
|
var conn=data.connection||{};
|
|
3903
3967
|
var user=conn.user||{};
|
|
3904
3968
|
var actualRole=data.role||_sharingRole||'client';
|
|
3905
|
-
if(data.role) _sharingRole=data.role;
|
|
3906
3969
|
var prevIsAdmin=!!window._isHubAdmin;
|
|
3907
3970
|
var isAdmin=(data.admin&&data.admin.canManageUsers)||(conn.connected&&user.role==='admin')||(actualRole==='hub');
|
|
3908
3971
|
window._isHubAdmin=isAdmin;
|
|
@@ -3966,7 +4029,10 @@ function renderSharingSettings(data){
|
|
|
3966
4029
|
'<button class="btn btn-sm" onclick="updateHubUsername()" style="padding:2px 10px;font-size:11px">'+t('sharing.saveUsername')+'</button>'+
|
|
3967
4030
|
'</span>';
|
|
3968
4031
|
sh+='<span class="hic-label">'+t('sharing.team')+'</span><span class="hic-value">'+esc(conn.teamName||'-')+'</span>';
|
|
3969
|
-
sh+='</div
|
|
4032
|
+
sh+='</div>'+
|
|
4033
|
+
'<div style="border-top:1px solid var(--border);margin-top:10px;padding:10px 16px 6px;display:flex;align-items:center;justify-content:flex-end">'+
|
|
4034
|
+
'<button class="btn btn-sm" onclick="leaveTeam()" style="color:#ef4444;border-color:rgba(239,68,68,.3);font-size:11px;padding:4px 12px">'+t('sharing.leaveTeam')+'</button>'+
|
|
4035
|
+
'</div></div>';
|
|
3970
4036
|
}else{
|
|
3971
4037
|
sh+='</div><div class="hic-empty" style="color:var(--text-muted)">'+t('sharing.disconnected.hint')+'</div>'+
|
|
3972
4038
|
'<div style="margin-top:10px;padding:0 16px 14px"><button class="btn btn-sm btn-primary" id="btnRetryConn" onclick="retryConnection()">'+t('sharing.retryConnection')+'</button>'+
|
|
@@ -4018,6 +4084,22 @@ async function retryHubJoin(){
|
|
|
4018
4084
|
}catch(e){toast(t('sharing.retryJoin.fail')+': '+e.message,'error');}
|
|
4019
4085
|
}
|
|
4020
4086
|
|
|
4087
|
+
async function leaveTeam(){
|
|
4088
|
+
var teamName=(sharingStatusCache&&sharingStatusCache.connection&&sharingStatusCache.connection.teamName)||'';
|
|
4089
|
+
var msg=t('sharing.leaveTeam.confirm').replace('{team}',teamName||t('sharing.team.default'));
|
|
4090
|
+
if(!(await confirmModal(msg,{danger:true}))) return;
|
|
4091
|
+
try{
|
|
4092
|
+
var r=await fetch('/api/sharing/leave',{method:'POST',headers:{'Content-Type':'application/json'},body:'{}'});
|
|
4093
|
+
var d=await r.json();
|
|
4094
|
+
if(d.ok){
|
|
4095
|
+
toast(t('sharing.leaveTeam.success'),'success');
|
|
4096
|
+
showRestartOverlay(t('settings.restart.waiting'));
|
|
4097
|
+
}else{
|
|
4098
|
+
toast(d.error||t('sharing.leaveTeam.fail'),'error');
|
|
4099
|
+
}
|
|
4100
|
+
}catch(e){toast(t('sharing.leaveTeam.fail')+': '+e.message,'error');}
|
|
4101
|
+
}
|
|
4102
|
+
|
|
4021
4103
|
async function updateHubUsername(){
|
|
4022
4104
|
var input=document.getElementById('hubUsernameInput');
|
|
4023
4105
|
if(!input) return;
|
|
@@ -4106,8 +4188,7 @@ async function rejectSharingUser(userId,username){
|
|
|
4106
4188
|
function updateTeamGuide(sharingData){
|
|
4107
4189
|
var el=document.getElementById('teamSetupGuide');
|
|
4108
4190
|
if(!el) return;
|
|
4109
|
-
|
|
4110
|
-
el.style.display=isConfigured?'none':'block';
|
|
4191
|
+
el.style.display='block';
|
|
4111
4192
|
}
|
|
4112
4193
|
function guideGoToHub(role){
|
|
4113
4194
|
switchSettingsTab('hub',document.querySelector('.settings-tab-btn[data-tab="hub"]'));
|
|
@@ -4307,9 +4388,10 @@ function auRelativeTime(ts){
|
|
|
4307
4388
|
return t('notif.timeAgo.day').replace('{n}',Math.floor(diff/86400000));
|
|
4308
4389
|
}
|
|
4309
4390
|
|
|
4310
|
-
function renderAdminUserCard(u,adminCount){
|
|
4391
|
+
function renderAdminUserCard(u,adminCount,myUserId){
|
|
4311
4392
|
var uid=escAttr(u.id);
|
|
4312
4393
|
var uname=escAttr(u.username||'');
|
|
4394
|
+
var isSelf=!!(myUserId&&u.id===myUserId);
|
|
4313
4395
|
var online=!!u.isOnline;
|
|
4314
4396
|
var statusCls=online?'online':'offline';
|
|
4315
4397
|
|
|
@@ -4343,7 +4425,9 @@ function renderAdminUserCard(u,adminCount){
|
|
|
4343
4425
|
var infoHtml='<div class="au-info">'+infoRows.join('')+'</div>';
|
|
4344
4426
|
|
|
4345
4427
|
var actions='';
|
|
4346
|
-
if(
|
|
4428
|
+
if(isSelf){
|
|
4429
|
+
actions+='<span style="font-size:11px;color:var(--text-muted);padding:4px 0">'+t('admin.selfHint')+'</span>';
|
|
4430
|
+
}else if(u.isOwner){
|
|
4347
4431
|
actions+='<span style="font-size:11px;color:var(--text-muted);padding:4px 0">'+t('admin.ownerHint')+'</span>';
|
|
4348
4432
|
}else if(u.role!=='admin'){
|
|
4349
4433
|
actions+='<button class="btn btn-sm btn-ghost" onclick="adminToggleRole("'+uid+'","admin")" style="color:var(--accent)">'+t('admin.promoteAdmin')+'</button>';
|
|
@@ -4395,6 +4479,7 @@ function renderAdminUsers(users,pending){
|
|
|
4395
4479
|
offlineUsers.sort(function(a,b){return (b.lastActiveAt||0)-(a.lastActiveAt||0);});
|
|
4396
4480
|
var sorted=onlineUsers.concat(offlineUsers);
|
|
4397
4481
|
var adminCount=users.filter(function(x){return x.role==='admin';}).length;
|
|
4482
|
+
var myUserId=sharingStatusCache&&sharingStatusCache.connection&&sharingStatusCache.connection.user?sharingStatusCache.connection.user.id:null;
|
|
4398
4483
|
|
|
4399
4484
|
if(sorted.length===0){
|
|
4400
4485
|
html+='<div class="admin-empty"><span class="ae-icon">\u{1F465}</span>'+t('admin.noActiveUsers')+'</div>';
|
|
@@ -4403,13 +4488,13 @@ function renderAdminUsers(users,pending){
|
|
|
4403
4488
|
if(onlineUsers.length===0){
|
|
4404
4489
|
html+='<div style="font-size:12px;color:var(--text-muted);padding:8px 0 12px">\u2014</div>';
|
|
4405
4490
|
}else{
|
|
4406
|
-
for(var i=0;i<onlineUsers.length;i++) html+=renderAdminUserCard(onlineUsers[i],adminCount);
|
|
4491
|
+
for(var i=0;i<onlineUsers.length;i++) html+=renderAdminUserCard(onlineUsers[i],adminCount,myUserId);
|
|
4407
4492
|
}
|
|
4408
4493
|
html+='<div class="au-group-header"><span class="au-group-dot offline"></span>'+t('admin.offlineUsers')+' <span class="au-group-count">('+offlineUsers.length+')</span></div>';
|
|
4409
4494
|
if(offlineUsers.length===0){
|
|
4410
4495
|
html+='<div style="font-size:12px;color:var(--text-muted);padding:8px 0 12px">\u2014</div>';
|
|
4411
4496
|
}else{
|
|
4412
|
-
for(var j=0;j<offlineUsers.length;j++) html+=renderAdminUserCard(offlineUsers[j],adminCount);
|
|
4497
|
+
for(var j=0;j<offlineUsers.length;j++) html+=renderAdminUserCard(offlineUsers[j],adminCount,myUserId);
|
|
4413
4498
|
}
|
|
4414
4499
|
}
|
|
4415
4500
|
el.innerHTML=html;
|
|
@@ -6579,6 +6664,7 @@ async function loadConfig(){
|
|
|
6579
6664
|
document.getElementById('cfgHubTeamName').value=hub.teamName||'';
|
|
6580
6665
|
document.getElementById('cfgHubTeamToken').value=hub.teamToken||'';
|
|
6581
6666
|
document.getElementById('cfgClientHubAddress').value=client.hubAddress||'';
|
|
6667
|
+
_loadedClientHubAddress=client.hubAddress||'';
|
|
6582
6668
|
document.getElementById('cfgClientTeamToken').value=client.teamToken||'';
|
|
6583
6669
|
document.getElementById('cfgClientNickname').value=client.nickname||'';
|
|
6584
6670
|
document.getElementById('cfgClientUserToken').value=client.userToken||'';
|
|
@@ -6624,15 +6710,19 @@ function flashSaved(id){
|
|
|
6624
6710
|
}
|
|
6625
6711
|
|
|
6626
6712
|
async function doSaveConfig(cfg, btnEl, savedId){
|
|
6627
|
-
btnEl.disabled=true;btnEl.textContent=t('settings.test.loading');
|
|
6628
|
-
function done(){btnEl.disabled=false;btnEl.textContent=t('settings.save');}
|
|
6713
|
+
if(btnEl){btnEl.disabled=true;btnEl.textContent=t('settings.test.loading');}
|
|
6714
|
+
function done(){if(btnEl){btnEl.disabled=false;btnEl.textContent=t('settings.save');}}
|
|
6629
6715
|
try{
|
|
6630
6716
|
const r=await fetch('/api/config',{method:'PUT',headers:{'Content-Type':'application/json'},body:JSON.stringify(cfg)});
|
|
6631
6717
|
if(r.status===401){done();toast(t('settings.session.expired'),'error');return null;}
|
|
6632
6718
|
if(!r.ok) throw new Error(await r.text());
|
|
6633
6719
|
var data=await r.json().catch(function(){return {ok:true};});
|
|
6634
6720
|
flashSaved(savedId);
|
|
6635
|
-
|
|
6721
|
+
if(data&&data.restart){
|
|
6722
|
+
showRestartOverlay(t('settings.restart.waiting'));
|
|
6723
|
+
}else{
|
|
6724
|
+
done();
|
|
6725
|
+
}
|
|
6636
6726
|
return data;
|
|
6637
6727
|
}catch(e){
|
|
6638
6728
|
toast(t('settings.save.fail')+': '+e.message,'error');
|
|
@@ -6758,7 +6848,7 @@ async function saveHubConfig(){
|
|
|
6758
6848
|
var hubTeamName=document.getElementById('cfgHubTeamName').value.trim();
|
|
6759
6849
|
var hubTeamToken=document.getElementById('cfgHubTeamToken').value.trim();
|
|
6760
6850
|
var hubAdminName=document.getElementById('cfgHubAdminName').value.trim();
|
|
6761
|
-
cfg.sharing.hub={port:
|
|
6851
|
+
if(hubPort) cfg.sharing.hub={port:Number(hubPort)}; else cfg.sharing.hub={};
|
|
6762
6852
|
if(hubTeamName) cfg.sharing.hub.teamName=hubTeamName;
|
|
6763
6853
|
if(hubTeamToken) cfg.sharing.hub.teamToken=hubTeamToken;
|
|
6764
6854
|
cfg.sharing.client={hubAddress:'',userToken:'',teamToken:''};
|
|
@@ -6775,15 +6865,9 @@ async function saveHubConfig(){
|
|
|
6775
6865
|
if(clientNickname) cfg.sharing.client.nickname=clientNickname;
|
|
6776
6866
|
if(clientTeamToken) cfg.sharing.client.teamToken=clientTeamToken;
|
|
6777
6867
|
if(clientUserToken) cfg.sharing.client.userToken=clientUserToken;
|
|
6778
|
-
cfg.sharing.hub={
|
|
6868
|
+
cfg.sharing.hub={teamName:'',teamToken:''};
|
|
6779
6869
|
if(clientAddr){
|
|
6780
6870
|
try{
|
|
6781
|
-
var ips=await fetch('/api/local-ips').then(function(r){return r.json();});
|
|
6782
|
-
var localAddrs=['127.0.0.1','localhost','0.0.0.0'].concat(ips.ips||[]);
|
|
6783
|
-
var parsed=new URL(clientAddr.indexOf('://')>-1?clientAddr:'http://'+clientAddr);
|
|
6784
|
-
if(localAddrs.indexOf(parsed.hostname)>=0){
|
|
6785
|
-
done();toast(t('sharing.cannotJoinSelf'),'error');return;
|
|
6786
|
-
}
|
|
6787
6871
|
}catch(e){}
|
|
6788
6872
|
try{
|
|
6789
6873
|
var testUrl=clientAddr.indexOf('://')>-1?clientAddr:'http://'+clientAddr;
|
|
@@ -6810,6 +6894,12 @@ async function saveHubConfig(){
|
|
|
6810
6894
|
var switchMsg=prevRole==='hub'?t('sharing.switch.hubToClient'):t('sharing.switch.clientToHub');
|
|
6811
6895
|
if(!(await confirmModal(switchMsg,{danger:true}))){done();return;}
|
|
6812
6896
|
}
|
|
6897
|
+
if(prevSharingEnabled&&sharingEnabled&&prevRole==='client'&&_sharingRole==='client'){
|
|
6898
|
+
var newAddr=(document.getElementById('cfgClientHubAddress').value||'').trim();
|
|
6899
|
+
if(_loadedClientHubAddress&&newAddr&&newAddr!==_loadedClientHubAddress){
|
|
6900
|
+
if(!(await confirmModal(t('sharing.switch.hubAddress'),{danger:true}))){done();return;}
|
|
6901
|
+
}
|
|
6902
|
+
}
|
|
6813
6903
|
|
|
6814
6904
|
var result=await doSaveConfig(cfg, saveBtn, 'hubSaved');
|
|
6815
6905
|
if(result){
|
|
@@ -7378,7 +7468,12 @@ function notifTimeAgo(ts){
|
|
|
7378
7468
|
function notifIcon(resource,type){
|
|
7379
7469
|
if(type==='user_online') return '\\u{1F7E2}';
|
|
7380
7470
|
if(type==='user_offline') return '\\u{1F534}';
|
|
7471
|
+
if(type==='user_left') return '\\u{1F6AA}';
|
|
7381
7472
|
if(type==='user_join_request') return '\\u{1F464}';
|
|
7473
|
+
if(type==='membership_removed') return '\\u{26D4}';
|
|
7474
|
+
if(type==='hub_shutdown') return '\\u{1F6D1}';
|
|
7475
|
+
if(type==='role_promoted') return '\\u{2B06}';
|
|
7476
|
+
if(type==='role_demoted') return '\\u{2B07}';
|
|
7382
7477
|
if(resource==='memory') return '\\u{1F4DD}';
|
|
7383
7478
|
if(resource==='task') return '\\u{1F4CB}';
|
|
7384
7479
|
if(resource==='skill') return '\\u{1F9E0}';
|
|
@@ -7404,12 +7499,27 @@ function notifTypeText(n){
|
|
|
7404
7499
|
if(n.type==='user_offline'){
|
|
7405
7500
|
return t('notif.userOffline');
|
|
7406
7501
|
}
|
|
7502
|
+
if(n.type==='user_left'){
|
|
7503
|
+
return t('notif.userLeft');
|
|
7504
|
+
}
|
|
7407
7505
|
if(n.type==='membership_approved'){
|
|
7408
7506
|
return t('notif.membershipApproved');
|
|
7409
7507
|
}
|
|
7410
7508
|
if(n.type==='membership_rejected'){
|
|
7411
7509
|
return t('notif.membershipRejected');
|
|
7412
7510
|
}
|
|
7511
|
+
if(n.type==='membership_removed'){
|
|
7512
|
+
return t('notif.membershipRemoved');
|
|
7513
|
+
}
|
|
7514
|
+
if(n.type==='hub_shutdown'){
|
|
7515
|
+
return t('notif.hubShutdown');
|
|
7516
|
+
}
|
|
7517
|
+
if(n.type==='role_promoted'){
|
|
7518
|
+
return t('notif.rolePromoted');
|
|
7519
|
+
}
|
|
7520
|
+
if(n.type==='role_demoted'){
|
|
7521
|
+
return t('notif.roleDemoted');
|
|
7522
|
+
}
|
|
7413
7523
|
return n.message||n.type;
|
|
7414
7524
|
}
|
|
7415
7525
|
|
|
@@ -7444,6 +7554,21 @@ function renderNotifBadge(){
|
|
|
7444
7554
|
}
|
|
7445
7555
|
}
|
|
7446
7556
|
|
|
7557
|
+
var _notifKnownTypes={membership_approved:1,membership_rejected:1,membership_removed:1,hub_shutdown:1,user_left:1,user_online:1,user_offline:1,user_join_request:1,role_promoted:1,role_demoted:1,resource_removed:1,resource_shared:1,resource_unshared:1};
|
|
7558
|
+
function notifDisplayTitle(n){
|
|
7559
|
+
if(_notifKnownTypes[n.type]) return notifTypeText(n);
|
|
7560
|
+
return n.title||notifTypeText(n);
|
|
7561
|
+
}
|
|
7562
|
+
function notifDisplayDetail(n){
|
|
7563
|
+
if(_notifKnownTypes[n.type]){
|
|
7564
|
+
if(n.type==='resource_removed'||n.type==='resource_shared'||n.type==='resource_unshared') return n.title||'';
|
|
7565
|
+
var m=n.title&&n.title.match(/["\u201C]([^"\u201D]+)["\u201D]/);
|
|
7566
|
+
if(m) return m[1];
|
|
7567
|
+
if(n.type==='user_left'||n.type==='user_online'||n.type==='user_offline'||n.type==='user_join_request') return n.title||'';
|
|
7568
|
+
return '';
|
|
7569
|
+
}
|
|
7570
|
+
return n.title||'';
|
|
7571
|
+
}
|
|
7447
7572
|
function renderNotifPanel(){
|
|
7448
7573
|
var body=document.getElementById('notifPanelBody');
|
|
7449
7574
|
if(!body) return;
|
|
@@ -7453,11 +7578,12 @@ function renderNotifPanel(){
|
|
|
7453
7578
|
}
|
|
7454
7579
|
body.innerHTML=_notifCache.map(function(n){
|
|
7455
7580
|
var cls='notif-item'+(n.read?'':' unread');
|
|
7581
|
+
var detail=notifDisplayDetail(n);
|
|
7456
7582
|
return '<div class="'+cls+'" onclick="markNotifRead("'+esc(n.id)+'")">'+
|
|
7457
7583
|
'<div class="notif-item-icon">'+notifIcon(n.resource,n.type)+'</div>'+
|
|
7458
7584
|
'<div class="notif-item-body">'+
|
|
7459
|
-
'<div class="notif-item-title">'+esc(
|
|
7460
|
-
'<div class="notif-item-name">'+esc(
|
|
7585
|
+
'<div class="notif-item-title">'+esc(notifDisplayTitle(n))+'</div>'+
|
|
7586
|
+
(detail?'<div class="notif-item-name">'+esc(detail)+'</div>':'')+
|
|
7461
7587
|
'<div class="notif-item-time">'+notifTimeAgo(n.createdAt)+'</div>'+
|
|
7462
7588
|
'</div>'+
|
|
7463
7589
|
'<div class="notif-item-dot"></div>'+
|
|
@@ -8743,7 +8869,7 @@ function confirmModal(message,opts){
|
|
|
8743
8869
|
_confirmResolve=resolve;
|
|
8744
8870
|
var overlay=document.getElementById('confirmOverlay');
|
|
8745
8871
|
document.getElementById('confirmTitle').textContent=opts.title||t('confirm.title')||'\u786E\u8BA4';
|
|
8746
|
-
document.getElementById('confirmBody').
|
|
8872
|
+
document.getElementById('confirmBody').innerText=message||'';
|
|
8747
8873
|
var okBtn=document.getElementById('confirmOkBtn');
|
|
8748
8874
|
okBtn.textContent=opts.okText||t('confirm.ok')||'\u786E\u5B9A';
|
|
8749
8875
|
okBtn.className='btn-confirm-ok'+(opts.danger?' danger':'');
|
|
@@ -8784,14 +8910,35 @@ function showRestartOverlay(msg){
|
|
|
8784
8910
|
/* ─── Update check ─── */
|
|
8785
8911
|
function waitForGatewayAndReload(maxAttempts,attempt){
|
|
8786
8912
|
attempt=attempt||0;
|
|
8913
|
+
var phase=arguments.length>2?arguments[2]:'waitDown';
|
|
8914
|
+
var MAX_WAIT_DOWN=8;
|
|
8787
8915
|
function forceReload(){window.location.href=window.location.pathname+'?_t='+Date.now();}
|
|
8788
8916
|
if(attempt>=maxAttempts){forceReload();return;}
|
|
8917
|
+
var delay=phase==='waitDown'?1500:2500;
|
|
8789
8918
|
setTimeout(function(){
|
|
8790
8919
|
fetch('/api/auth/status').then(function(r){
|
|
8791
|
-
if(
|
|
8792
|
-
|
|
8793
|
-
|
|
8794
|
-
|
|
8920
|
+
if(phase==='waitDown'){
|
|
8921
|
+
if(r.ok||r.status===401||r.status===403){
|
|
8922
|
+
if(attempt>=MAX_WAIT_DOWN){
|
|
8923
|
+
forceReload();
|
|
8924
|
+
}else{
|
|
8925
|
+
waitForGatewayAndReload(maxAttempts,attempt+1,'waitDown');
|
|
8926
|
+
}
|
|
8927
|
+
}else{
|
|
8928
|
+
waitForGatewayAndReload(maxAttempts,0,'waitUp');
|
|
8929
|
+
}
|
|
8930
|
+
}else{
|
|
8931
|
+
if(r.ok||r.status===401||r.status===403) forceReload();
|
|
8932
|
+
else waitForGatewayAndReload(maxAttempts,attempt+1,'waitUp');
|
|
8933
|
+
}
|
|
8934
|
+
}).catch(function(){
|
|
8935
|
+
if(phase==='waitDown'){
|
|
8936
|
+
waitForGatewayAndReload(maxAttempts,0,'waitUp');
|
|
8937
|
+
}else{
|
|
8938
|
+
waitForGatewayAndReload(maxAttempts,attempt+1,'waitUp');
|
|
8939
|
+
}
|
|
8940
|
+
});
|
|
8941
|
+
},delay);
|
|
8795
8942
|
}
|
|
8796
8943
|
function doUpdateInstall(packageSpec,btnEl,statusEl){
|
|
8797
8944
|
btnEl.disabled=true;
|