@wenbin_wb/dsh-bridge 2.7.1 → 2.8.1
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/CHANGELOG.md +36 -0
- package/README.en.md +31 -8
- package/README.md +31 -8
- package/client/client.js +1024 -6
- package/client/index.js +1121 -8
- package/docs/feishu-usage.md +1 -0
- package/docs/qq-usage.md +1 -0
- package/docs/screenshots/mobile-chat.jpg +0 -0
- package/docs/screenshots/mobile-drawer.jpg +0 -0
- package/docs/screenshots/mobile-remote-settings.jpg +0 -0
- package/docs/screenshots/mobile-settings-im.jpg +0 -0
- package/docs/screenshots/mobile-settings-lan.jpg +0 -0
- package/docs/screenshots/mobile-settings-security.jpg +0 -0
- package/docs/screenshots/mobile-settings-tunnel.jpg +0 -0
- package/docs/screenshots/mobile-workspace-picker.jpg +0 -0
- package/docs/screenshots/remote-web-mobile.jpg +0 -0
- package/docs/telegram-usage.md +1 -0
- package/docs/wechat-usage.md +2 -0
- package/lib/bridge-rpc-constants.js +4 -0
- package/lib/bridge-rpc.js +41 -0
- package/lib/feishu/index.js +4 -1
- package/lib/index.js +252 -4
- package/lib/platform/conversation-bridge.js +42 -2
- package/lib/qq/index.js +4 -1
- package/lib/security/path-validator.js +195 -0
- package/lib/security/rate-limiter.js +93 -0
- package/lib/telegram/index.js +4 -1
- package/lib/wechat/index.js +4 -1
- package/package.json +2 -2
package/client/client.js
CHANGED
|
@@ -50,6 +50,10 @@ var BRIDGE_ENDPOINTS = {
|
|
|
50
50
|
importBackup: "importBackup",
|
|
51
51
|
diagnoseNetwork: "diagnoseNetwork",
|
|
52
52
|
getSystemMetrics: "getSystemMetrics",
|
|
53
|
+
// 远程工作区管理与目录浏览
|
|
54
|
+
listRemoteDirectories: "listRemoteDirectories",
|
|
55
|
+
addRemoteWorkspace: "addRemoteWorkspace",
|
|
56
|
+
listWorkspaces: "listWorkspaces",
|
|
53
57
|
// 访问安全认证(密码保护 / 扫码免密 Token)
|
|
54
58
|
authGetStatus: "authGetStatus",
|
|
55
59
|
authUpdateConfig: "authUpdateConfig",
|
|
@@ -94,6 +98,37 @@ if (typeof window !== "undefined") {
|
|
|
94
98
|
};
|
|
95
99
|
}
|
|
96
100
|
}
|
|
101
|
+
var _globalAdminToken = "";
|
|
102
|
+
function setGlobalAdminToken(t) {
|
|
103
|
+
_globalAdminToken = t || "";
|
|
104
|
+
if (typeof window !== "undefined") {
|
|
105
|
+
try {
|
|
106
|
+
if (t) sessionStorage.setItem("dsh_admin_token", t);
|
|
107
|
+
else sessionStorage.removeItem("dsh_admin_token");
|
|
108
|
+
} catch {
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
function getGlobalAdminToken() {
|
|
113
|
+
if (_globalAdminToken) return _globalAdminToken;
|
|
114
|
+
if (typeof window !== "undefined") {
|
|
115
|
+
try {
|
|
116
|
+
const saved = sessionStorage.getItem("dsh_admin_token");
|
|
117
|
+
if (saved) {
|
|
118
|
+
_globalAdminToken = saved;
|
|
119
|
+
return saved;
|
|
120
|
+
}
|
|
121
|
+
} catch {
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return "";
|
|
125
|
+
}
|
|
126
|
+
function isLocalEnvironment() {
|
|
127
|
+
if (typeof window === "undefined") return true;
|
|
128
|
+
const host = window.location.hostname || "";
|
|
129
|
+
const proto = window.location.protocol || "";
|
|
130
|
+
return host === "127.0.0.1" || host === "localhost" || host === "::1" || host === "" || proto === "file:" || proto === "vscode-webview:" || proto === "app:" || typeof window.__DSH_ELECTRON__ !== "undefined" || typeof navigator !== "undefined" && navigator.userAgent && navigator.userAgent.includes("Electron");
|
|
131
|
+
}
|
|
97
132
|
var GITHUB_URL = "https://github.com/wenbin-wb/dsh-bridge";
|
|
98
133
|
var RELEASES_URL = "https://github.com/wenbin-wb/dsh-bridge/releases";
|
|
99
134
|
var ISSUES_URL = "https://github.com/wenbin-wb/dsh-bridge/issues/new";
|
|
@@ -106,7 +141,7 @@ function upgradeCommands(latest) {
|
|
|
106
141
|
];
|
|
107
142
|
}
|
|
108
143
|
var name = "dsh-bridge";
|
|
109
|
-
var inject = ["slots", "connection"];
|
|
144
|
+
var inject = ["slots", "connection", "workspaces", "sessions"];
|
|
110
145
|
function semverGt(a, b) {
|
|
111
146
|
const parse = (v) => {
|
|
112
147
|
const [main = "", pre = ""] = String(v).split("-");
|
|
@@ -1138,7 +1173,7 @@ function PlatformCard({ platformId, platformName, platformDesc, rpcCall, onStatu
|
|
|
1138
1173
|
setCfgDraft({
|
|
1139
1174
|
digestIntervalSec: String(platform.config.digestIntervalSec ?? 300),
|
|
1140
1175
|
approvalTimeoutSec: String(platform.config.approvalTimeoutSec ?? 600),
|
|
1141
|
-
maxMessageChars: String(platform.config.maxMessageChars ?? (platformId === "telegram" ? 4096 : 2e3)),
|
|
1176
|
+
maxMessageChars: String((platform.config.maxMessageChars >= 500 ? platform.config.maxMessageChars : null) ?? (platformId === "telegram" ? 4096 : 2e3)),
|
|
1142
1177
|
sendChunkDelayMs: String(platform.config.sendChunkDelayMs ?? 1500),
|
|
1143
1178
|
appId: platform.config.appId ?? "",
|
|
1144
1179
|
// Secret 不由后端回传;空值表示沿用已保存密钥
|
|
@@ -2085,6 +2120,91 @@ function RestartDshCard({ rpcCall }) {
|
|
|
2085
2120
|
)
|
|
2086
2121
|
);
|
|
2087
2122
|
}
|
|
2123
|
+
function RemoteWorkspaceCard({ rpcCall }) {
|
|
2124
|
+
const [workspaces, setWorkspaces] = React.useState([]);
|
|
2125
|
+
const [loading, setLoading] = React.useState(false);
|
|
2126
|
+
const load = React.useCallback(async () => {
|
|
2127
|
+
if (!rpcCall) return;
|
|
2128
|
+
setLoading(true);
|
|
2129
|
+
try {
|
|
2130
|
+
const res = await rpcCall(BRIDGE_ENDPOINTS.listWorkspaces, {});
|
|
2131
|
+
const list = res?.value || res;
|
|
2132
|
+
if (Array.isArray(list)) setWorkspaces(list);
|
|
2133
|
+
else if (list?.workspaces && Array.isArray(list.workspaces)) setWorkspaces(list.workspaces);
|
|
2134
|
+
} catch {
|
|
2135
|
+
} finally {
|
|
2136
|
+
setLoading(false);
|
|
2137
|
+
}
|
|
2138
|
+
}, [rpcCall]);
|
|
2139
|
+
React.useEffect(() => {
|
|
2140
|
+
load();
|
|
2141
|
+
}, [load]);
|
|
2142
|
+
return React.createElement(
|
|
2143
|
+
"div",
|
|
2144
|
+
{ style: { ...s.card, marginBottom: 16 } },
|
|
2145
|
+
React.createElement(
|
|
2146
|
+
"div",
|
|
2147
|
+
{
|
|
2148
|
+
style: { display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 10, flexWrap: "wrap", gap: 8 }
|
|
2149
|
+
},
|
|
2150
|
+
React.createElement(
|
|
2151
|
+
"div",
|
|
2152
|
+
null,
|
|
2153
|
+
React.createElement(
|
|
2154
|
+
"div",
|
|
2155
|
+
{ style: { ...s.label, fontSize: 13, display: "flex", alignItems: "center", gap: 6 } },
|
|
2156
|
+
"\u{1F5C2}\uFE0F \u8FDC\u7A0B\u5DE5\u4F5C\u533A\u7BA1\u7406 (\u76EE\u5F55\u6D4F\u89C8\u5668)"
|
|
2157
|
+
),
|
|
2158
|
+
React.createElement(
|
|
2159
|
+
"div",
|
|
2160
|
+
{ style: { ...s.muted, marginTop: 3 } },
|
|
2161
|
+
"\u5728\u79FB\u52A8\u7AEF\u6216\u8FDC\u7A0B\u8BBE\u5907\u4E0A\u53EF\u89C6\u70B9\u9009\u7535\u8111\u4E0A\u7684\u6587\u4EF6\u5939\u6216\u76F4\u63A5\u8F93\u5165\u8DEF\u5F84\u6DFB\u52A0\u81F3 DSH\u3002"
|
|
2162
|
+
)
|
|
2163
|
+
),
|
|
2164
|
+
React.createElement("button", {
|
|
2165
|
+
type: "button",
|
|
2166
|
+
style: { ...s.btnPri, height: 32, fontSize: 12, padding: "0 14px" },
|
|
2167
|
+
onClick: () => {
|
|
2168
|
+
if (typeof window.__dshOpenRemoteWorkspaceModal === "function") {
|
|
2169
|
+
window.__dshOpenRemoteWorkspaceModal();
|
|
2170
|
+
} else if (typeof showRemoteWorkspaceDialog === "function") {
|
|
2171
|
+
showRemoteWorkspaceDialog(rpcCall, () => load());
|
|
2172
|
+
}
|
|
2173
|
+
}
|
|
2174
|
+
}, "+ \u8FDC\u7A0B\u6DFB\u52A0\u5DE5\u4F5C\u533A")
|
|
2175
|
+
),
|
|
2176
|
+
workspaces.length > 0 ? React.createElement(
|
|
2177
|
+
"div",
|
|
2178
|
+
{
|
|
2179
|
+
style: { display: "flex", flexDirection: "column", gap: 6, marginTop: 8 }
|
|
2180
|
+
},
|
|
2181
|
+
workspaces.map((ws, i) => React.createElement(
|
|
2182
|
+
"div",
|
|
2183
|
+
{
|
|
2184
|
+
key: ws.path || i,
|
|
2185
|
+
style: {
|
|
2186
|
+
display: "flex",
|
|
2187
|
+
alignItems: "center",
|
|
2188
|
+
justifyContent: "space-between",
|
|
2189
|
+
padding: "7px 12px",
|
|
2190
|
+
background: "var(--dsw-alias-bg-layer-1,#ffffff)",
|
|
2191
|
+
border: "1px solid var(--dsw-alias-border-l2,#e5e7eb)",
|
|
2192
|
+
borderRadius: 8,
|
|
2193
|
+
fontSize: 12
|
|
2194
|
+
}
|
|
2195
|
+
},
|
|
2196
|
+
React.createElement(
|
|
2197
|
+
"div",
|
|
2198
|
+
{ style: { display: "flex", alignItems: "center", gap: 8, overflow: "hidden" } },
|
|
2199
|
+
React.createElement("span", { style: { fontWeight: 600, color: "var(--dsw-alias-brand-primary,#4f6ef7)", flexShrink: 0 } }, `@${i + 1} ${ws.title || ""}`),
|
|
2200
|
+
React.createElement("span", { style: { ...s.code, color: "var(--dsw-alias-label-tertiary,#6b7280)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" } }, ws.path)
|
|
2201
|
+
)
|
|
2202
|
+
))
|
|
2203
|
+
) : React.createElement("div", {
|
|
2204
|
+
style: { ...s.muted, marginTop: 6, padding: "10px 14px", background: "var(--dsw-alias-bg-layer-1,#ffffff)", border: "1px solid var(--dsw-alias-border-l2,#e5e7eb)", borderRadius: 8, textAlign: "center" }
|
|
2205
|
+
}, loading ? "\u6B63\u5728\u8BFB\u53D6\u5DE5\u4F5C\u533A\u5217\u8868\u2026" : "\u6682\u65E0\u5DF2\u6CE8\u518C\u5DE5\u4F5C\u533A\uFF0C\u70B9\u51FB\u53F3\u4E0A\u89D2\u300C+ \u8FDC\u7A0B\u6DFB\u52A0\u5DE5\u4F5C\u533A\u300D\u5373\u53EF\u6D4F\u89C8\u6DFB\u52A0\u3002")
|
|
2206
|
+
);
|
|
2207
|
+
}
|
|
2088
2208
|
function VersionBanner({ rpcCall }) {
|
|
2089
2209
|
const [info, setInfo] = React.useState(null);
|
|
2090
2210
|
const [loading, setLoading] = React.useState(false);
|
|
@@ -2522,6 +2642,7 @@ function BridgePanel({ rpcCall }) {
|
|
|
2522
2642
|
const data = await res.json();
|
|
2523
2643
|
if (data?.ok && data.adminToken) {
|
|
2524
2644
|
setAdminToken(data.adminToken);
|
|
2645
|
+
setGlobalAdminToken(data.adminToken);
|
|
2525
2646
|
setAdminUnlocked(true);
|
|
2526
2647
|
return data.adminToken;
|
|
2527
2648
|
}
|
|
@@ -2537,7 +2658,7 @@ function BridgePanel({ rpcCall }) {
|
|
|
2537
2658
|
}
|
|
2538
2659
|
}, [isLocalhost, adminUnlocked, fetchLoopbackToken]);
|
|
2539
2660
|
const authRpcCall = React.useCallback(async (endpoint, payload = {}, signal) => {
|
|
2540
|
-
let token = adminToken;
|
|
2661
|
+
let token = adminToken || getGlobalAdminToken();
|
|
2541
2662
|
if (isLocalhost && !token) {
|
|
2542
2663
|
token = await fetchLoopbackToken();
|
|
2543
2664
|
}
|
|
@@ -2563,7 +2684,9 @@ function BridgePanel({ rpcCall }) {
|
|
|
2563
2684
|
try {
|
|
2564
2685
|
const res = await rpcCall(BRIDGE_ENDPOINTS.authAdminUnlock, { password: unlockPassword });
|
|
2565
2686
|
if (res?.ok) {
|
|
2566
|
-
|
|
2687
|
+
const token = res.value?.adminToken || "";
|
|
2688
|
+
setAdminToken(token);
|
|
2689
|
+
setGlobalAdminToken(token);
|
|
2567
2690
|
setAdminUnlocked(true);
|
|
2568
2691
|
setUnlockPassword("");
|
|
2569
2692
|
setShowUnlockModal(false);
|
|
@@ -2585,6 +2708,7 @@ function BridgePanel({ rpcCall }) {
|
|
|
2585
2708
|
} catch {
|
|
2586
2709
|
}
|
|
2587
2710
|
setAdminToken("");
|
|
2711
|
+
setGlobalAdminToken("");
|
|
2588
2712
|
setAdminUnlocked(false);
|
|
2589
2713
|
}, [rpcCall, adminToken]);
|
|
2590
2714
|
const loadInFlightRef = React.useRef(false);
|
|
@@ -2761,6 +2885,7 @@ function BridgePanel({ rpcCall }) {
|
|
|
2761
2885
|
React.Fragment,
|
|
2762
2886
|
null,
|
|
2763
2887
|
React.createElement(SystemMetricsWidget, { metrics: status?.system }),
|
|
2888
|
+
React.createElement(RemoteWorkspaceCard, { rpcCall: authRpcCall }),
|
|
2764
2889
|
React.createElement(NetworkDiagnosticWidget, { rpcCall: authRpcCall }),
|
|
2765
2890
|
React.createElement(BackupRestoreWidget, {
|
|
2766
2891
|
rpcCall: authRpcCall,
|
|
@@ -3188,6 +3313,7 @@ function injectMobileStyles() {
|
|
|
3188
3313
|
z-index: 9998 !important;
|
|
3189
3314
|
box-sizing: border-box !important;
|
|
3190
3315
|
user-select: none !important;
|
|
3316
|
+
pointer-events: none !important;
|
|
3191
3317
|
}
|
|
3192
3318
|
|
|
3193
3319
|
/* \u5DE6\u4FA7\u53CC\u6A2A\u7EBF\u6309\u94AE (DeepSeek App \u539F\u751F\u56FE\u6807) */
|
|
@@ -3204,6 +3330,7 @@ function injectMobileStyles() {
|
|
|
3204
3330
|
cursor: pointer;
|
|
3205
3331
|
padding: 0;
|
|
3206
3332
|
transition: opacity 0.15s;
|
|
3333
|
+
pointer-events: auto !important;
|
|
3207
3334
|
}
|
|
3208
3335
|
.dsh-header-menu-btn:active {
|
|
3209
3336
|
opacity: 0.6;
|
|
@@ -3223,11 +3350,29 @@ function injectMobileStyles() {
|
|
|
3223
3350
|
cursor: pointer;
|
|
3224
3351
|
padding: 0;
|
|
3225
3352
|
transition: opacity 0.15s;
|
|
3353
|
+
pointer-events: auto !important;
|
|
3226
3354
|
}
|
|
3227
3355
|
.dsh-header-new-btn:active {
|
|
3228
3356
|
opacity: 0.6;
|
|
3229
3357
|
}
|
|
3230
3358
|
|
|
3359
|
+
/* \u4E2D\u95F4\u52A8\u6001\u4F1A\u8BDD\u6807\u9898 (\u5355\u884C\u5C45\u4E2D\u6253\u70B9\u622A\u65AD\uFF0C100% \u8FD8\u539F\u539F\u751F App \u5BFC\u822A\u4F53\u9A8C) */
|
|
3360
|
+
.dsh-mobile-header-title {
|
|
3361
|
+
flex: 1 1 auto !important;
|
|
3362
|
+
min-width: 0 !important;
|
|
3363
|
+
text-align: center !important;
|
|
3364
|
+
font-size: 15px !important;
|
|
3365
|
+
font-weight: 600 !important;
|
|
3366
|
+
color: var(--dsw-alias-label-primary, #111827) !important;
|
|
3367
|
+
overflow: hidden !important;
|
|
3368
|
+
text-overflow: ellipsis !important;
|
|
3369
|
+
white-space: nowrap !important;
|
|
3370
|
+
padding: 0 10px !important;
|
|
3371
|
+
user-select: none !important;
|
|
3372
|
+
pointer-events: none !important;
|
|
3373
|
+
letter-spacing: -0.2px !important;
|
|
3374
|
+
}
|
|
3375
|
+
|
|
3231
3376
|
/* 3. \u4E2D\u95F4\u4E3B\u5185\u5BB9\u533A\u4E0E\u8F93\u5165\u6846 */
|
|
3232
3377
|
div[class*="_centerCol"] {
|
|
3233
3378
|
flex: 1 1 100% !important;
|
|
@@ -3244,6 +3389,110 @@ function injectMobileStyles() {
|
|
|
3244
3389
|
display: none !important;
|
|
3245
3390
|
}
|
|
3246
3391
|
|
|
3392
|
+
/* 3.1 \u4F1A\u8BDD\u5BF9\u8BDD\u5934\u90E8\u9876\u680F\uFF1A\u79FB\u52A8\u7AEF\u9632\u6324\u538B\u4E0E\u7A7A\u95F4\u91CA\u653E\u4F18\u5316\uFF08\u4E25\u683C\u6392\u9664 .dsh-mobile-app-header\uFF09 */
|
|
3393
|
+
div[class*="_centerCol"] header,
|
|
3394
|
+
header[class*="wSkVaW_header"] {
|
|
3395
|
+
padding: 4px 16px 2px 16px !important;
|
|
3396
|
+
position: relative !important;
|
|
3397
|
+
overflow: visible !important;
|
|
3398
|
+
}
|
|
3399
|
+
|
|
3400
|
+
div[class*="wSkVaW_titleRow"],
|
|
3401
|
+
div[class*="titleRow"] {
|
|
3402
|
+
display: flex !important;
|
|
3403
|
+
flex-direction: row !important;
|
|
3404
|
+
align-items: center !important;
|
|
3405
|
+
justify-content: space-between !important;
|
|
3406
|
+
gap: 8px !important;
|
|
3407
|
+
min-height: 32px !important;
|
|
3408
|
+
width: 100% !important;
|
|
3409
|
+
box-sizing: border-box !important;
|
|
3410
|
+
}
|
|
3411
|
+
|
|
3412
|
+
/* \u79FB\u52A8\u7AEF\u5C06\u539F\u6709\u5D4C\u5165\u5728\u5185\u5BB9\u533A\u7684\u957F\u9762\u5305\u5C51\u6807\u9898\u9690\u85CF\uFF08\u5DF2\u7EDF\u4E00\u63D0\u5347\u81F3\u9876\u90E8\u5BFC\u822A\u680F\u6B63\u4E2D\uFF09\uFF0C\u5F7B\u5E95\u91CA\u653E\u7B2C\u4E8C\u884C\u7A7A\u95F4 */
|
|
3413
|
+
nav[class*="wSkVaW_crumbs"],
|
|
3414
|
+
nav[class*="crumbs"],
|
|
3415
|
+
div[class*="wSkVaW_crumbs"],
|
|
3416
|
+
div[class*="crumbs"],
|
|
3417
|
+
[class*="wSkVaW_crumbs"] {
|
|
3418
|
+
display: none !important;
|
|
3419
|
+
}
|
|
3420
|
+
|
|
3421
|
+
/* \u5B50\u4EE3\u7406/\u667A\u80FD\u4F53\u6A21\u5F0F\u80F6\u56CA (Actions)\uFF1A\u7D27\u51D1\u5706\u89D2\u80F6\u56CA */
|
|
3422
|
+
div[class*="wSkVaW_headerActions"],
|
|
3423
|
+
div[class*="headerActions"] {
|
|
3424
|
+
flex: 0 0 auto !important;
|
|
3425
|
+
display: inline-flex !important;
|
|
3426
|
+
align-items: center !important;
|
|
3427
|
+
gap: 4px !important;
|
|
3428
|
+
margin-left: 0 !important;
|
|
3429
|
+
}
|
|
3430
|
+
|
|
3431
|
+
button[class*="h8S2Va_trigger"],
|
|
3432
|
+
button[class*="subagent"] {
|
|
3433
|
+
min-height: 26px !important;
|
|
3434
|
+
height: 26px !important;
|
|
3435
|
+
padding: 2px 8px !important;
|
|
3436
|
+
font-size: 11.5px !important;
|
|
3437
|
+
line-height: 16px !important;
|
|
3438
|
+
border-radius: 13px !important;
|
|
3439
|
+
background: var(--dsw-alias-bg-layer-2, rgba(0, 0, 0, 0.04)) !important;
|
|
3440
|
+
white-space: nowrap !important;
|
|
3441
|
+
flex-shrink: 0 !important;
|
|
3442
|
+
}
|
|
3443
|
+
|
|
3444
|
+
/* Session Log \u5BFC\u51FA\u4E0B\u8F7D\u6309\u94AE (Utilities)\uFF1A\u5728\u79FB\u52A8\u7AEF\u6781\u7B80\u4E3A 28px \u5706\u5F62\u7EAF\u56FE\u6807\u6309\u94AE\uFF0C\u9690\u85CF\u957F\u6587\u672C\uFF0C\u6781\u5927\u91CA\u653E\u9876\u90E8\u7A7A\u95F4 */
|
|
3445
|
+
div[class*="wSkVaW_headerUtilities"],
|
|
3446
|
+
div[class*="headerUtilities"] {
|
|
3447
|
+
flex: 0 0 auto !important;
|
|
3448
|
+
margin-left: 4px !important;
|
|
3449
|
+
display: inline-flex !important;
|
|
3450
|
+
align-items: center !important;
|
|
3451
|
+
}
|
|
3452
|
+
|
|
3453
|
+
button[class*="nL4_yW_sessionLogButton"],
|
|
3454
|
+
button[class*="sessionLogButton"] {
|
|
3455
|
+
min-width: 28px !important;
|
|
3456
|
+
width: 28px !important;
|
|
3457
|
+
height: 28px !important;
|
|
3458
|
+
padding: 0 !important;
|
|
3459
|
+
border-radius: 50% !important;
|
|
3460
|
+
display: inline-flex !important;
|
|
3461
|
+
align-items: center !important;
|
|
3462
|
+
justify-content: center !important;
|
|
3463
|
+
flex-shrink: 0 !important;
|
|
3464
|
+
border: 1px solid var(--dsw-alias-border-l2, rgba(0, 0, 0, 0.1)) !important;
|
|
3465
|
+
background: var(--dsw-alias-bg-layer-2, rgba(0, 0, 0, 0.03)) !important;
|
|
3466
|
+
color: var(--dsw-alias-label-secondary, #6b7280) !important;
|
|
3467
|
+
margin-left: 0 !important;
|
|
3468
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.03) !important;
|
|
3469
|
+
}
|
|
3470
|
+
|
|
3471
|
+
button[class*="nL4_yW_sessionLogButton"]:hover:not(:disabled),
|
|
3472
|
+
button[class*="sessionLogButton"]:hover:not(:disabled) {
|
|
3473
|
+
background: var(--dsw-alias-interactive-bg-hover, rgba(0, 0, 0, 0.06)) !important;
|
|
3474
|
+
color: var(--dsw-alias-label-primary, #111827) !important;
|
|
3475
|
+
}
|
|
3476
|
+
|
|
3477
|
+
button[class*="nL4_yW_sessionLogButton"] span,
|
|
3478
|
+
button[class*="sessionLogButton"] span {
|
|
3479
|
+
display: none !important;
|
|
3480
|
+
}
|
|
3481
|
+
|
|
3482
|
+
button[class*="nL4_yW_sessionLogButton"] svg,
|
|
3483
|
+
button[class*="sessionLogButton"] svg {
|
|
3484
|
+
width: 13px !important;
|
|
3485
|
+
height: 13px !important;
|
|
3486
|
+
margin: 0 !important;
|
|
3487
|
+
}
|
|
3488
|
+
|
|
3489
|
+
/* \u5B50\u4EE3\u7406\u5C55\u5F00\u83DC\u5355\u5728\u79FB\u52A8\u7AEF\u53F3\u5BF9\u9F50\u4E0E\u5BBD\u5EA6\u81EA\u9002\u5E94 */
|
|
3490
|
+
div[class*="h8S2Va_menu"] {
|
|
3491
|
+
max-width: calc(100vw - 32px) !important;
|
|
3492
|
+
left: auto !important;
|
|
3493
|
+
right: 0 !important;
|
|
3494
|
+
}
|
|
3495
|
+
|
|
3247
3496
|
/* \u8F93\u5165\u6846\u5E95\u5EA7\uFF1ADeepSeek App \u5C45\u4E2D\u53CA\u5E95\u90E8\u56FA\u5B9A */
|
|
3248
3497
|
div[class*="wSkVaW_scrollBody"] {
|
|
3249
3498
|
padding-bottom: max(16px, env(safe-area-inset-bottom)) !important;
|
|
@@ -3258,6 +3507,67 @@ function injectMobileStyles() {
|
|
|
3258
3507
|
background: var(--dsw-alias-bg-layer-2, #f4f4f7) !important;
|
|
3259
3508
|
}
|
|
3260
3509
|
|
|
3510
|
+
/* \u8F93\u5165\u6846\u5E95\u90E8\u5DE5\u5177\u680F\uFF1A\u5F39\u6027\u81EA\u9002\u5E94\uFF0C\u5F7B\u5E95\u675C\u7EDD\u6743\u9650\u9009\u62E9\u5668(Full access)\u4E0E\u6A21\u578B\u9009\u62E9\u5668\u91CD\u53E0\u78B0\u649E */
|
|
3511
|
+
div[class*="uV2eYG_row"] {
|
|
3512
|
+
display: flex !important;
|
|
3513
|
+
align-items: center !important;
|
|
3514
|
+
justify-content: space-between !important;
|
|
3515
|
+
gap: 6px !important;
|
|
3516
|
+
width: 100% !important;
|
|
3517
|
+
padding: 2px 2px 4px !important;
|
|
3518
|
+
box-sizing: border-box !important;
|
|
3519
|
+
}
|
|
3520
|
+
|
|
3521
|
+
div[class*="uV2eYG_tools"] {
|
|
3522
|
+
display: flex !important;
|
|
3523
|
+
align-items: center !important;
|
|
3524
|
+
gap: 6px !important;
|
|
3525
|
+
flex: 0 0 auto !important;
|
|
3526
|
+
min-width: 0 !important;
|
|
3527
|
+
}
|
|
3528
|
+
|
|
3529
|
+
div[class*="uV2eYG_modes"] {
|
|
3530
|
+
display: flex !important;
|
|
3531
|
+
align-items: center !important;
|
|
3532
|
+
gap: 4px !important;
|
|
3533
|
+
flex: 0 0 auto !important;
|
|
3534
|
+
min-width: 0 !important;
|
|
3535
|
+
}
|
|
3536
|
+
|
|
3537
|
+
button[class*="Sh0Q9G_trigger"] {
|
|
3538
|
+
flex: 0 0 auto !important;
|
|
3539
|
+
min-width: 0 !important;
|
|
3540
|
+
}
|
|
3541
|
+
|
|
3542
|
+
div[class*="uV2eYG_trailing"] {
|
|
3543
|
+
display: flex !important;
|
|
3544
|
+
align-items: center !important;
|
|
3545
|
+
justify-content: flex-end !important;
|
|
3546
|
+
gap: 6px !important;
|
|
3547
|
+
flex: 1 1 auto !important;
|
|
3548
|
+
min-width: 0 !important;
|
|
3549
|
+
}
|
|
3550
|
+
|
|
3551
|
+
div[class*="_7KE1Ra_root"] {
|
|
3552
|
+
flex: 0 1 auto !important;
|
|
3553
|
+
min-width: 0 !important;
|
|
3554
|
+
max-width: 180px !important;
|
|
3555
|
+
}
|
|
3556
|
+
|
|
3557
|
+
button[class*="_7KE1Ra_trigger"] {
|
|
3558
|
+
max-width: 100% !important;
|
|
3559
|
+
min-width: 0 !important;
|
|
3560
|
+
flex: 1 1 auto !important;
|
|
3561
|
+
padding: 0 4px 0 6px !important;
|
|
3562
|
+
}
|
|
3563
|
+
|
|
3564
|
+
span[class*="_7KE1Ra_triggerLabel"] {
|
|
3565
|
+
overflow: hidden !important;
|
|
3566
|
+
text-overflow: ellipsis !important;
|
|
3567
|
+
white-space: nowrap !important;
|
|
3568
|
+
min-width: 0 !important;
|
|
3569
|
+
}
|
|
3570
|
+
|
|
3261
3571
|
/* 4. \u539F\u751F\u4FA7\u8FB9\u680F\u62BD\u5C49\u5316 (Drawer) */
|
|
3262
3572
|
div[class*="_sidebarCol"] {
|
|
3263
3573
|
position: fixed !important;
|
|
@@ -3474,6 +3784,86 @@ function injectMobileStyles() {
|
|
|
3474
3784
|
}
|
|
3475
3785
|
}
|
|
3476
3786
|
|
|
3787
|
+
/* \u8FDC\u7A0B\u5DE5\u4F5C\u533A\u9009\u62E9\u5F39\u7A97\u79FB\u52A8\u7AEF/\u684C\u9762\u7AEF\u81EA\u9002\u5E94\u6837\u5F0F */
|
|
3788
|
+
#dsh-remote-workspace-modal {
|
|
3789
|
+
position: fixed !important;
|
|
3790
|
+
inset: 0 !important;
|
|
3791
|
+
z-index: 100000 !important;
|
|
3792
|
+
background: rgba(0, 0, 0, 0.65) !important;
|
|
3793
|
+
backdrop-filter: blur(5px) !important;
|
|
3794
|
+
display: flex !important;
|
|
3795
|
+
align-items: center !important;
|
|
3796
|
+
justify-content: center !important;
|
|
3797
|
+
padding: 16px !important;
|
|
3798
|
+
box-sizing: border-box !important;
|
|
3799
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important;
|
|
3800
|
+
color: var(--dsw-alias-label-primary, #111827) !important;
|
|
3801
|
+
}
|
|
3802
|
+
|
|
3803
|
+
.dsh-ws-dialog-card {
|
|
3804
|
+
background: var(--dsw-alias-bg-layer-1, #ffffff) !important;
|
|
3805
|
+
border: 1px solid var(--dsw-alias-border-l1, #e5e7eb) !important;
|
|
3806
|
+
border-radius: 16px !important;
|
|
3807
|
+
width: 100% !important;
|
|
3808
|
+
max-width: 620px !important;
|
|
3809
|
+
max-height: 88vh !important;
|
|
3810
|
+
display: flex !important;
|
|
3811
|
+
flex-direction: column !important;
|
|
3812
|
+
box-shadow: 0 25px 35px -5px rgba(0,0,0,0.3), 0 12px 16px -5px rgba(0,0,0,0.2) !important;
|
|
3813
|
+
overflow: hidden !important;
|
|
3814
|
+
animation: dshModalFadeIn 0.2s ease-out !important;
|
|
3815
|
+
}
|
|
3816
|
+
|
|
3817
|
+
.dsh-ws-chips-scroll {
|
|
3818
|
+
display: flex !important;
|
|
3819
|
+
align-items: center !important;
|
|
3820
|
+
gap: 6px !important;
|
|
3821
|
+
overflow-x: auto !important;
|
|
3822
|
+
white-space: nowrap !important;
|
|
3823
|
+
scrollbar-width: none !important;
|
|
3824
|
+
-ms-overflow-style: none !important;
|
|
3825
|
+
-webkit-overflow-scrolling: touch !important;
|
|
3826
|
+
padding: 2px 0 !important;
|
|
3827
|
+
}
|
|
3828
|
+
.dsh-ws-chips-scroll::-webkit-scrollbar {
|
|
3829
|
+
display: none !important;
|
|
3830
|
+
}
|
|
3831
|
+
|
|
3832
|
+
@media (max-width: 640px) {
|
|
3833
|
+
#dsh-remote-workspace-modal {
|
|
3834
|
+
align-items: flex-end !important;
|
|
3835
|
+
padding: 0 !important;
|
|
3836
|
+
}
|
|
3837
|
+
|
|
3838
|
+
.dsh-ws-dialog-card {
|
|
3839
|
+
max-height: 92dvh !important;
|
|
3840
|
+
height: 92dvh !important;
|
|
3841
|
+
border-bottom-left-radius: 0 !important;
|
|
3842
|
+
border-bottom-right-radius: 0 !important;
|
|
3843
|
+
border-left: none !important;
|
|
3844
|
+
border-right: none !important;
|
|
3845
|
+
border-bottom: none !important;
|
|
3846
|
+
max-width: 100vw !important;
|
|
3847
|
+
width: 100vw !important;
|
|
3848
|
+
margin: 0 !important;
|
|
3849
|
+
animation: dshBottomSheetUp 0.25s cubic-bezier(0.16, 1, 0.3, 1) !important;
|
|
3850
|
+
}
|
|
3851
|
+
|
|
3852
|
+
.dsh-ws-drag-handle {
|
|
3853
|
+
display: block !important;
|
|
3854
|
+
}
|
|
3855
|
+
}
|
|
3856
|
+
|
|
3857
|
+
@keyframes dshModalFadeIn {
|
|
3858
|
+
from { opacity: 0; transform: scale(0.96); }
|
|
3859
|
+
to { opacity: 1; transform: scale(1); }
|
|
3860
|
+
}
|
|
3861
|
+
|
|
3862
|
+
@keyframes dshBottomSheetUp {
|
|
3863
|
+
from { transform: translateY(100%); }
|
|
3864
|
+
to { transform: translateY(0); }
|
|
3865
|
+
}
|
|
3866
|
+
|
|
3477
3867
|
@media (min-width: 769px) {
|
|
3478
3868
|
.dsh-mobile-app-header,
|
|
3479
3869
|
.dsh-mobile-backdrop {
|
|
@@ -3483,10 +3873,11 @@ function injectMobileStyles() {
|
|
|
3483
3873
|
`;
|
|
3484
3874
|
document.head.appendChild(style);
|
|
3485
3875
|
}
|
|
3486
|
-
function setupMobileExperience() {
|
|
3876
|
+
function setupMobileExperience(rpcCall, ctx) {
|
|
3487
3877
|
if (typeof document === "undefined" || typeof window === "undefined") return;
|
|
3488
3878
|
injectMobileStyles();
|
|
3489
3879
|
let header = document.querySelector(".dsh-mobile-app-header");
|
|
3880
|
+
let titleEl = document.querySelector(".dsh-mobile-header-title");
|
|
3490
3881
|
if (!header) {
|
|
3491
3882
|
header = document.createElement("header");
|
|
3492
3883
|
header.className = "dsh-mobile-app-header";
|
|
@@ -3506,6 +3897,9 @@ function setupMobileExperience() {
|
|
|
3506
3897
|
if (collapsedToggle) collapsedToggle.click();
|
|
3507
3898
|
}
|
|
3508
3899
|
};
|
|
3900
|
+
titleEl = document.createElement("div");
|
|
3901
|
+
titleEl.className = "dsh-mobile-header-title";
|
|
3902
|
+
titleEl.innerText = "\u65B0\u4F1A\u8BDD";
|
|
3509
3903
|
const rightBtn = document.createElement("button");
|
|
3510
3904
|
rightBtn.className = "dsh-header-new-btn";
|
|
3511
3905
|
rightBtn.title = "\u65B0\u5EFA\u4F1A\u8BDD";
|
|
@@ -3521,9 +3915,26 @@ function setupMobileExperience() {
|
|
|
3521
3915
|
if (dshNewBtn) dshNewBtn.click();
|
|
3522
3916
|
};
|
|
3523
3917
|
header.appendChild(leftBtn);
|
|
3918
|
+
header.appendChild(titleEl);
|
|
3524
3919
|
header.appendChild(rightBtn);
|
|
3525
3920
|
document.body.appendChild(header);
|
|
3526
3921
|
}
|
|
3922
|
+
const syncMobileTitle = () => {
|
|
3923
|
+
if (!titleEl) titleEl = document.querySelector(".dsh-mobile-header-title");
|
|
3924
|
+
if (!titleEl) return;
|
|
3925
|
+
const snap = ctx?.sessions?.list?.getSnapshot?.();
|
|
3926
|
+
if (!snap) return;
|
|
3927
|
+
const cur = snap.current ? snap.byId?.[snap.current] : null;
|
|
3928
|
+
if (!cur || cur.blank) {
|
|
3929
|
+
titleEl.innerText = "\u65B0\u4F1A\u8BDD";
|
|
3930
|
+
} else {
|
|
3931
|
+
titleEl.innerText = cur.displayTitle || cur.title || "\u4F1A\u8BDD";
|
|
3932
|
+
}
|
|
3933
|
+
};
|
|
3934
|
+
syncMobileTitle();
|
|
3935
|
+
if (typeof ctx?.sessions?.list?.subscribe === "function") {
|
|
3936
|
+
ctx.sessions.list.subscribe(syncMobileTitle);
|
|
3937
|
+
}
|
|
3527
3938
|
let backdrop = document.querySelector(".dsh-mobile-backdrop");
|
|
3528
3939
|
if (!backdrop) {
|
|
3529
3940
|
backdrop = document.createElement("div");
|
|
@@ -3619,10 +4030,617 @@ function setupMobileExperience() {
|
|
|
3619
4030
|
}
|
|
3620
4031
|
}
|
|
3621
4032
|
}, { passive: true });
|
|
4033
|
+
document.addEventListener("click", (e) => {
|
|
4034
|
+
if (isLocalEnvironment()) return;
|
|
4035
|
+
const btn = e.target.closest('button, [role="button"], a');
|
|
4036
|
+
if (!btn) return;
|
|
4037
|
+
if (btn.closest("#dsh-remote-workspace-modal")) return;
|
|
4038
|
+
const label = (btn.getAttribute("aria-label") || btn.innerText || btn.title || "").trim();
|
|
4039
|
+
const isAddWorkspace = label === "\u6DFB\u52A0\u5DE5\u4F5C\u533A" || label === "\u65B0\u5EFA\u5DE5\u4F5C\u533A" || label === "\u6253\u5F00\u5DE5\u4F5C\u533A" || label === "\u6253\u5F00\u6587\u4EF6\u5939" || label === "Add Workspace" || label === "Open Folder" || label.includes("\u6DFB\u52A0\u5DE5\u4F5C\u533A") || label.includes("\u6253\u5F00\u5DE5\u4F5C\u533A") || label.includes("\u6253\u5F00\u6587\u4EF6\u5939") || btn.matches('button[aria-label*="\u5DE5\u4F5C\u533A"][aria-label*="\u6DFB\u52A0"], button[aria-label*="\u5DE5\u4F5C\u533A"][aria-label*="\u6253\u5F00"]');
|
|
4040
|
+
if (isAddWorkspace) {
|
|
4041
|
+
e.preventDefault();
|
|
4042
|
+
e.stopPropagation();
|
|
4043
|
+
e.stopImmediatePropagation();
|
|
4044
|
+
if (typeof window.__dshOpenRemoteWorkspaceModal === "function") {
|
|
4045
|
+
window.__dshOpenRemoteWorkspaceModal();
|
|
4046
|
+
}
|
|
4047
|
+
}
|
|
4048
|
+
}, true);
|
|
4049
|
+
}
|
|
4050
|
+
function escapeHtml(str) {
|
|
4051
|
+
if (!str) return "";
|
|
4052
|
+
return String(str).replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """).replace(/'/g, "'");
|
|
4053
|
+
}
|
|
4054
|
+
function showRemoteWorkspaceDialog(rpcCall, onWorkspaceAdded, clientCtx, onPicked, onCancel) {
|
|
4055
|
+
if (typeof document === "undefined" || typeof window === "undefined") return;
|
|
4056
|
+
const existing = document.getElementById("dsh-remote-workspace-modal");
|
|
4057
|
+
if (existing) existing.remove();
|
|
4058
|
+
const overlay = document.createElement("div");
|
|
4059
|
+
overlay.id = "dsh-remote-workspace-modal";
|
|
4060
|
+
overlay.style.cssText = `
|
|
4061
|
+
position: fixed;
|
|
4062
|
+
inset: 0;
|
|
4063
|
+
z-index: 100000;
|
|
4064
|
+
background: rgba(0, 0, 0, 0.65);
|
|
4065
|
+
backdrop-filter: blur(5px);
|
|
4066
|
+
display: flex;
|
|
4067
|
+
align-items: center;
|
|
4068
|
+
justify-content: center;
|
|
4069
|
+
padding: 16px;
|
|
4070
|
+
box-sizing: border-box;
|
|
4071
|
+
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
4072
|
+
color: var(--dsw-alias-label-primary, #111827);
|
|
4073
|
+
`;
|
|
4074
|
+
const modal = document.createElement("div");
|
|
4075
|
+
modal.className = "dsh-ws-dialog-card";
|
|
4076
|
+
let currentPath = "";
|
|
4077
|
+
let parentPath = null;
|
|
4078
|
+
let breadcrumbs = [];
|
|
4079
|
+
let entries = [];
|
|
4080
|
+
let roots = [];
|
|
4081
|
+
let drives = [];
|
|
4082
|
+
let workspaces = [];
|
|
4083
|
+
let filterQuery = "";
|
|
4084
|
+
let showManualInput = false;
|
|
4085
|
+
let isLoading = false;
|
|
4086
|
+
let isSubmitting = false;
|
|
4087
|
+
let statusMessage = null;
|
|
4088
|
+
let isErrorMessage = false;
|
|
4089
|
+
function closeModal() {
|
|
4090
|
+
document.removeEventListener("keydown", handleKeydown);
|
|
4091
|
+
overlay.style.opacity = "0";
|
|
4092
|
+
overlay.style.transition = "opacity 0.15s ease";
|
|
4093
|
+
setTimeout(() => overlay.remove(), 150);
|
|
4094
|
+
if (typeof onCancel === "function") {
|
|
4095
|
+
try {
|
|
4096
|
+
onCancel();
|
|
4097
|
+
} catch (e) {
|
|
4098
|
+
}
|
|
4099
|
+
}
|
|
4100
|
+
}
|
|
4101
|
+
overlay.addEventListener("click", (e) => {
|
|
4102
|
+
if (e.target === overlay) closeModal();
|
|
4103
|
+
});
|
|
4104
|
+
const handleKeydown = (e) => {
|
|
4105
|
+
if (e.key === "Escape") {
|
|
4106
|
+
closeModal();
|
|
4107
|
+
}
|
|
4108
|
+
};
|
|
4109
|
+
document.addEventListener("keydown", handleKeydown);
|
|
4110
|
+
function render() {
|
|
4111
|
+
const filteredEntries = (entries || []).filter((e) => {
|
|
4112
|
+
if (!filterQuery.trim()) return true;
|
|
4113
|
+
return e.name.toLowerCase().includes(filterQuery.trim().toLowerCase());
|
|
4114
|
+
});
|
|
4115
|
+
modal.innerHTML = `
|
|
4116
|
+
<!-- \u79FB\u52A8\u7AEF\u9876\u90E8\u4E0B\u62C9\u6307\u793A\u6761 -->
|
|
4117
|
+
<div class="dsh-ws-drag-handle" style="width: 36px; height: 4px; background: var(--dsw-alias-border-l2, #d1d5db); border-radius: 2px; margin: 8px auto 0 auto; display: none;"></div>
|
|
4118
|
+
|
|
4119
|
+
<!-- \u5F39\u7A97\u9876\u90E8\u6807\u9898\u680F -->
|
|
4120
|
+
<div style="padding: 12px 16px; border-bottom: 1px solid var(--dsw-alias-border-l2, #e5e7eb); display: flex; align-items: center; justify-content: space-between; flex-shrink: 0; background: var(--dsw-alias-bg-layer-2, #f9fafb);">
|
|
4121
|
+
<div style="display: flex; align-items: center; gap: 8px; overflow: hidden;">
|
|
4122
|
+
<span style="font-size: 20px; flex-shrink: 0;">\u{1F5C2}\uFE0F</span>
|
|
4123
|
+
<div style="overflow: hidden;">
|
|
4124
|
+
<div style="font-size: 15px; font-weight: 600; color: var(--dsw-alias-label-primary, #111827); white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">\u9009\u62E9\u7535\u8111\u5DE5\u4F5C\u533A</div>
|
|
4125
|
+
<div style="font-size: 11px; color: var(--dsw-alias-label-tertiary, #6b7280); margin-top: 1px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;">\u70B9\u51FB\u8FDB\u5165\u6587\u4EF6\u5939\uFF0C\u6216\u70B9\u51FB\u300C+ \u9009\u4E3A\u5DE5\u4F5C\u533A\u300D\u76F4\u63A5\u6DFB\u52A0\u5E76\u5207\u6362</div>
|
|
4126
|
+
</div>
|
|
4127
|
+
</div>
|
|
4128
|
+
<button id="dsh-ws-close-btn" style="border: none; background: none; font-size: 18px; cursor: pointer; color: var(--dsw-alias-label-tertiary, #9ca3af); padding: 4px 8px; border-radius: 6px; line-height: 1; flex-shrink: 0;">\u2715</button>
|
|
4129
|
+
</div>
|
|
4130
|
+
|
|
4131
|
+
<div style="padding: 12px 16px; overflow-y: auto; flex: 1; display: flex; flex-direction: column; gap: 10px;">
|
|
4132
|
+
<!-- \u63D0\u793A\u4FE1\u606F\u6A2A\u5E45 -->
|
|
4133
|
+
${statusMessage ? `
|
|
4134
|
+
<div style="padding: 8px 12px; border-radius: 8px; font-size: 12px; line-height: 1.5; font-weight: 500; display: flex; align-items: center; gap: 8px; ${isErrorMessage ? "background: var(--dsw-alias-state-error-bg, #fef2f2); border: 1px solid var(--dsw-alias-state-error-border, #fecaca); color: var(--dsw-alias-state-error-primary, #dc2626);" : "background: var(--dsw-alias-state-success-bg, #ecfdf5); border: 1px solid var(--dsw-alias-state-success-border, #a7f3d0); color: var(--dsw-alias-state-success-primary, #059669);"}">
|
|
4135
|
+
<span>${isErrorMessage ? "\u26A0\uFE0F" : "\u{1F389}"}</span>
|
|
4136
|
+
<span>${escapeHtml(statusMessage)}</span>
|
|
4137
|
+
</div>
|
|
4138
|
+
` : ""}
|
|
4139
|
+
|
|
4140
|
+
<!-- \u5FEB\u901F\u76F4\u8FBE\u4E0E\u78C1\u76D8\u6A2A\u5411\u6ED1\u52A8\u680F (\u6781\u7B80\u7701\u7A7A\u95F4) -->
|
|
4141
|
+
<div class="dsh-ws-chips-scroll">
|
|
4142
|
+
${(drives || []).map((d) => {
|
|
4143
|
+
const isActive = currentPath.startsWith(d.path) || currentPath === d.path;
|
|
4144
|
+
return `
|
|
4145
|
+
<button class="dsh-ws-quick-btn" data-path="${escapeHtml(d.path)}" style="border: 1px solid ${isActive ? "var(--dsw-alias-brand-primary, #4f6ef7)" : "var(--dsw-alias-border-l2, #d1d5db)"}; background: ${isActive ? "var(--dsw-alias-brand-primary, #4f6ef7)" : "var(--dsw-alias-bg-layer-2, #f9fafb)"}; color: ${isActive ? "#fff" : "var(--dsw-alias-label-primary, #111827)"}; border-radius: 14px; padding: 4px 10px; font-size: 11px; cursor: pointer; font-weight: 500; flex-shrink: 0; transition: all 0.1s;">
|
|
4146
|
+
\u{1F4BE} ${escapeHtml(d.name)}
|
|
4147
|
+
</button>
|
|
4148
|
+
`;
|
|
4149
|
+
}).join("")}
|
|
4150
|
+
<span style="color: var(--dsw-alias-border-l2, #d1d5db); margin: 0 1px; flex-shrink: 0;">|</span>
|
|
4151
|
+
${(roots || []).map((r) => {
|
|
4152
|
+
const isActive = currentPath === r.path;
|
|
4153
|
+
return `
|
|
4154
|
+
<button class="dsh-ws-quick-btn" data-path="${escapeHtml(r.path)}" style="border: 1px solid ${isActive ? "var(--dsw-alias-brand-primary, #4f6ef7)" : "var(--dsw-alias-border-l2, #d1d5db)"}; background: ${isActive ? "var(--dsw-alias-state-info-bg, #eff6ff)" : "var(--dsw-alias-bg-layer-2, #f9fafb)"}; color: ${isActive ? "var(--dsw-alias-brand-primary, #4f6ef7)" : "var(--dsw-alias-label-secondary, #374151)"}; border-radius: 14px; padding: 4px 10px; font-size: 11px; cursor: pointer; font-weight: 500; flex-shrink: 0;">
|
|
4155
|
+
${escapeHtml(r.name)}
|
|
4156
|
+
</button>
|
|
4157
|
+
`;
|
|
4158
|
+
}).join("")}
|
|
4159
|
+
</div>
|
|
4160
|
+
|
|
4161
|
+
<!-- \u4EA4\u4E92\u5F0F\u9762\u5305\u5C51\u8DEF\u5F84\u5BFC\u822A\u6761 (Breadcrumbs Bar) -->
|
|
4162
|
+
<div style="background: var(--dsw-alias-bg-layer-3, #f3f4f6); border: 1px solid var(--dsw-alias-border-l2, #e5e7eb); border-radius: 10px; padding: 6px 10px; display: flex; align-items: center; justify-content: space-between; gap: 6px;">
|
|
4163
|
+
<div class="dsh-ws-chips-scroll" style="flex: 1;">
|
|
4164
|
+
<span style="font-size: 12px; margin-right: 2px; flex-shrink: 0;">\u{1F4C2}</span>
|
|
4165
|
+
${(breadcrumbs || []).map((crumb, idx) => {
|
|
4166
|
+
const isLast = idx === breadcrumbs.length - 1;
|
|
4167
|
+
return `
|
|
4168
|
+
<button class="dsh-ws-crumb-btn" data-path="${escapeHtml(crumb.path)}" style="border: none; background: ${isLast ? "var(--dsw-alias-bg-layer-1, #fff)" : "transparent"}; color: ${isLast ? "var(--dsw-alias-brand-primary, #4f6ef7)" : "var(--dsw-alias-label-secondary, #4b5563)"}; font-family: ui-monospace, Menlo, monospace; font-size: 11px; font-weight: ${isLast ? "700" : "500"}; padding: 3px 6px; border-radius: 4px; cursor: pointer; text-decoration: ${isLast ? "none" : "underline"}; text-underline-offset: 2px; flex-shrink: 0; box-shadow: ${isLast ? "0 1px 2px rgba(0,0,0,0.06)" : "none"};">
|
|
4169
|
+
${escapeHtml(crumb.name)}
|
|
4170
|
+
</button>
|
|
4171
|
+
${!isLast ? `<span style="color: var(--dsw-alias-label-tertiary, #9ca3af); font-size: 11px; font-weight: 600; flex-shrink: 0;">/</span>` : ""}
|
|
4172
|
+
`;
|
|
4173
|
+
}).join("")}
|
|
4174
|
+
</div>
|
|
4175
|
+
|
|
4176
|
+
<div style="display: flex; align-items: center; gap: 4px; flex-shrink: 0;">
|
|
4177
|
+
${parentPath ? `
|
|
4178
|
+
<button id="dsh-ws-up-btn" data-path="${escapeHtml(parentPath)}" title="\u8FD4\u56DE\u4E0A\u4E00\u7EA7" style="border: 1px solid var(--dsw-alias-border-l2, #d1d5db); background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #111827); padding: 3px 8px; border-radius: 6px; font-size: 11px; font-weight: 600; cursor: pointer; display: inline-flex; align-items: center; gap: 2px;">
|
|
4179
|
+
\u2B06\uFE0F \u4E0A\u7EA7
|
|
4180
|
+
</button>
|
|
4181
|
+
` : ""}
|
|
4182
|
+
<button id="dsh-ws-refresh-btn" title="\u5237\u65B0\u76EE\u5F55" style="border: 1px solid var(--dsw-alias-border-l2, #d1d5db); background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #111827); padding: 3px 6px; border-radius: 6px; font-size: 11px; cursor: pointer;">
|
|
4183
|
+
\u{1F504}
|
|
4184
|
+
</button>
|
|
4185
|
+
</div>
|
|
4186
|
+
</div>
|
|
4187
|
+
|
|
4188
|
+
<!-- \u5F53\u524D\u6240\u5728\u76EE\u5F55\u786E\u8BA4\u5361\u7247 (Primary Action Card) -->
|
|
4189
|
+
<div style="background: var(--dsw-alias-state-info-bg, #eff6ff); border: 1px solid var(--dsw-alias-state-info-border, #bfdbfe); border-radius: 10px; padding: 10px 12px; display: flex; flex-direction: column; gap: 6px;">
|
|
4190
|
+
<div style="display: flex; align-items: center; justify-content: space-between; gap: 6px;">
|
|
4191
|
+
<span style="font-size: 11px; font-weight: 600; color: var(--dsw-alias-brand-primary, #2563eb); flex-shrink: 0;">\u5F53\u524D\u76EE\u5F55:</span>
|
|
4192
|
+
<span style="font-family: ui-monospace, Menlo, monospace; font-size: 11px; color: var(--dsw-alias-label-primary, #1e3a8a); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; text-align: right; font-weight: 600;">${escapeHtml(currentPath)}</span>
|
|
4193
|
+
</div>
|
|
4194
|
+
<button id="dsh-ws-add-current-btn" style="border: none; background: var(--dsw-alias-brand-primary, #2563eb); color: #fff; height: 36px; border-radius: 8px; font-size: 13px; font-weight: 600; cursor: pointer; display: flex; align-items: center; justify-content: center; gap: 6px; width: 100%; box-shadow: 0 2px 4px rgba(37,99,235,0.25); transition: opacity 0.1s;" ${isSubmitting ? "disabled" : ""}>
|
|
4195
|
+
${isSubmitting ? "\u6B63\u5728\u6DFB\u52A0\u5E76\u5207\u6362\u2026" : "\u{1F449} \u8BBE\u4E3A\u5F53\u524D\u5DE5\u4F5C\u533A\u5E76\u8FDB\u5165"}
|
|
4196
|
+
</button>
|
|
4197
|
+
</div>
|
|
4198
|
+
|
|
4199
|
+
<!-- \u5B50\u76EE\u5F55\u5217\u8868\u4E0E\u8FC7\u6EE4\u680F -->
|
|
4200
|
+
<div style="border: 1px solid var(--dsw-alias-border-l2, #e5e7eb); border-radius: 10px; overflow: hidden; display: flex; flex-direction: column; background: var(--dsw-alias-bg-layer-1, #fff);">
|
|
4201
|
+
<!-- \u5B9E\u65F6\u8FC7\u6EE4\u641C\u7D22\u6846 -->
|
|
4202
|
+
<div style="padding: 7px 10px; background: var(--dsw-alias-bg-layer-2, #f9fafb); border-bottom: 1px solid var(--dsw-alias-border-l2, #e5e7eb); display: flex; align-items: center; justify-content: space-between; gap: 6px;">
|
|
4203
|
+
<div style="display: flex; align-items: center; gap: 6px; flex: 1;">
|
|
4204
|
+
<span style="font-size: 11px; color: var(--dsw-alias-label-tertiary, #9ca3af);">\u{1F50D}</span>
|
|
4205
|
+
<input id="dsh-ws-filter-input" type="text" value="${escapeHtml(filterQuery)}" placeholder="\u8FC7\u6EE4\u5B50\u6587\u4EF6\u5939\u2026" style="border: none; background: transparent; font-size: 12px; width: 100%; color: var(--dsw-alias-label-primary, #111827); outline: none;" />
|
|
4206
|
+
</div>
|
|
4207
|
+
<span style="font-size: 10px; color: var(--dsw-alias-label-tertiary, #6b7280); flex-shrink: 0;">
|
|
4208
|
+
${filteredEntries.length} \u4E2A\u6587\u4EF6\u5939
|
|
4209
|
+
</span>
|
|
4210
|
+
</div>
|
|
4211
|
+
|
|
4212
|
+
<!-- \u5B50\u6587\u4EF6\u5939\u6EDA\u52A8\u5217\u8868 (\u79FB\u52A8\u7AEF\u8212\u9002\u5927\u70B9\u6309\u533A\u57DF) -->
|
|
4213
|
+
<div style="max-height: 240px; min-height: 120px; overflow-y: auto; padding: 2px 0;">
|
|
4214
|
+
${isLoading ? `
|
|
4215
|
+
<div style="padding: 32px; text-align: center; font-size: 12px; color: var(--dsw-alias-label-tertiary, #6b7280); display: flex; flex-direction: column; align-items: center; gap: 6px;">
|
|
4216
|
+
<span style="font-size: 20px;">\u23F3</span>
|
|
4217
|
+
<span>\u6B63\u5728\u8BFB\u53D6\u76EE\u5F55\u5185\u5BB9\u2026</span>
|
|
4218
|
+
</div>
|
|
4219
|
+
` : filteredEntries.length === 0 ? `
|
|
4220
|
+
<div style="padding: 26px 16px; text-align: center; font-size: 12px; color: var(--dsw-alias-label-tertiary, #6b7280); display: flex; flex-direction: column; align-items: center; gap: 4px;">
|
|
4221
|
+
<span style="font-size: 22px;">\u{1F4C1}</span>
|
|
4222
|
+
<span>${filterQuery ? "\u672A\u627E\u5230\u5339\u914D\u7684\u5B50\u6587\u4EF6\u5939" : "\u5F53\u524D\u6587\u4EF6\u5939\u4E0B\u6CA1\u6709\u66F4\u591A\u5B50\u6587\u4EF6\u5939"}</span>
|
|
4223
|
+
<span style="font-size: 11px; color: var(--dsw-alias-label-tertiary, #9ca3af);">\uFF08\u76F4\u63A5\u70B9\u51FB\u4E0A\u65B9\u84DD\u8272\u6309\u94AE\u5373\u53EF\u8FDB\u5165\u5F53\u524D\u76EE\u5F55\uFF09</span>
|
|
4224
|
+
</div>
|
|
4225
|
+
` : filteredEntries.map((e) => `
|
|
4226
|
+
<div class="dsh-ws-entry-row" data-path="${escapeHtml(e.path)}" style="display: flex; align-items: center; justify-content: space-between; padding: 9px 12px; border-bottom: 1px solid var(--dsw-alias-border-l2, #f3f4f6); cursor: pointer; font-size: 12px; transition: background 0.1s; min-height: 40px;">
|
|
4227
|
+
<div class="dsh-ws-drill-btn" data-path="${escapeHtml(e.path)}" style="display: flex; align-items: center; gap: 8px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1; padding: 2px 0;">
|
|
4228
|
+
<span style="font-size: 16px; flex-shrink: 0;">\u{1F4C1}</span>
|
|
4229
|
+
<span style="font-family: ui-monospace, Menlo, monospace; font-weight: 500; color: var(--dsw-alias-label-primary, #111827); overflow: hidden; text-overflow: ellipsis;">${escapeHtml(e.name)}</span>
|
|
4230
|
+
<span style="color: var(--dsw-alias-label-tertiary, #9ca3af); font-size: 12px; margin-left: 2px; flex-shrink: 0;">\u203A</span>
|
|
4231
|
+
</div>
|
|
4232
|
+
<button class="dsh-ws-pick-entry-btn" data-path="${escapeHtml(e.path)}" title="\u76F4\u63A5\u6DFB\u52A0\u6B64\u5B50\u6587\u4EF6\u5939\u4E3A\u5DE5\u4F5C\u533A\u5E76\u8FDB\u5165" style="border: 1px solid var(--dsw-alias-state-success-border, #a7f3d0); background: var(--dsw-alias-state-success-bg, #ecfdf5); color: var(--dsw-alias-state-success-primary, #059669); padding: 4px 10px; border-radius: 12px; font-size: 11px; font-weight: 600; cursor: pointer; display: inline-flex; align-items: center; gap: 2px; flex-shrink: 0; margin-left: 8px; white-space: nowrap; transition: all 0.1s;">
|
|
4233
|
+
+ \u9009\u4E3A\u5DE5\u4F5C\u533A
|
|
4234
|
+
</button>
|
|
4235
|
+
</div>
|
|
4236
|
+
`).join("")}
|
|
4237
|
+
</div>
|
|
4238
|
+
</div>
|
|
4239
|
+
|
|
4240
|
+
<!-- \u624B\u52A8\u8F93\u5165\u8DEF\u5F84\u6298\u53E0\u533A -->
|
|
4241
|
+
<div>
|
|
4242
|
+
<div style="display: flex; align-items: center; justify-content: space-between;">
|
|
4243
|
+
<button id="dsh-ws-toggle-manual" style="border: none; background: none; color: var(--dsw-alias-label-tertiary, #6b7280); font-size: 11px; cursor: pointer; padding: 2px 0; text-decoration: underline;">
|
|
4244
|
+
${showManualInput ? "\u25BC \u6536\u8D77\u7EDD\u5BF9\u8DEF\u5F84\u624B\u52A8\u8F93\u5165" : "\u25B6 \u624B\u52A8\u7C98\u8D34/\u8F93\u5165\u7EDD\u5BF9\u8DEF\u5F84"}
|
|
4245
|
+
</button>
|
|
4246
|
+
</div>
|
|
4247
|
+
${showManualInput ? `
|
|
4248
|
+
<div style="margin-top: 6px; display: flex; gap: 6px;">
|
|
4249
|
+
<input id="dsh-ws-manual-input" type="text" value="${escapeHtml(currentPath)}" placeholder="\u8F93\u5165\u7535\u8111\u7EDD\u5BF9\u8DEF\u5F84\uFF0C\u4F8B\u5982 C:\\Projects\\my-app" style="flex: 1; font-family: ui-monospace, Menlo, monospace; font-size: 11px; padding: 6px 8px; border-radius: 8px; border: 1px solid var(--dsw-alias-border-l2, #d1d5db); background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #111827); outline: none;" />
|
|
4250
|
+
<button id="dsh-ws-manual-jump-btn" style="border: 1px solid var(--dsw-alias-border-l2, #d1d5db); background: var(--dsw-alias-bg-layer-2, #f9fafb); color: var(--dsw-alias-label-primary, #111827); padding: 0 10px; border-radius: 8px; font-size: 11px; cursor: pointer; white-space: nowrap;">
|
|
4251
|
+
\u524D\u5F80
|
|
4252
|
+
</button>
|
|
4253
|
+
<button id="dsh-ws-manual-add-btn" style="border: none; background: var(--dsw-alias-brand-primary, #4f6ef7); color: #fff; padding: 0 12px; border-radius: 8px; font-size: 11px; font-weight: 500; cursor: pointer; white-space: nowrap;">
|
|
4254
|
+
\u6DFB\u52A0\u5E76\u8FDB\u5165
|
|
4255
|
+
</button>
|
|
4256
|
+
</div>
|
|
4257
|
+
` : ""}
|
|
4258
|
+
</div>
|
|
4259
|
+
|
|
4260
|
+
<!-- \u5DF2\u5728 DSH \u6CE8\u518C\u7684\u5DE5\u4F5C\u533A\u5C55\u793A (\u652F\u6301\u4E00\u952E\u5207\u6362) -->
|
|
4261
|
+
${workspaces && workspaces.length > 0 ? `
|
|
4262
|
+
<div style="padding-top: 2px;">
|
|
4263
|
+
<div style="font-size: 11px; font-weight: 600; color: var(--dsw-alias-label-tertiary, #6b7280); margin-bottom: 4px;">\u5DF2\u6CE8\u518C\u5DE5\u4F5C\u533A (${workspaces.length} \u4E2A\uFF0C\u70B9\u51FB\u76F4\u63A5\u5207\u6362)\uFF1A</div>
|
|
4264
|
+
<div style="display: flex; flex-direction: column; gap: 4px; max-height: 80px; overflow-y: auto;">
|
|
4265
|
+
${workspaces.map((w, i) => `
|
|
4266
|
+
<div class="dsh-ws-registered-row" data-ws-id="${escapeHtml(w.id || "")}" data-ws-path="${escapeHtml(w.path)}" style="display: flex; align-items: center; justify-content: space-between; background: var(--dsw-alias-bg-layer-2, #f9fafb); border: 1px solid var(--dsw-alias-border-l2, #e5e7eb); border-radius: 6px; padding: 4px 8px; font-size: 11px; cursor: pointer; transition: background 0.1s;">
|
|
4267
|
+
<div style="overflow: hidden; text-overflow: ellipsis; white-space: nowrap; flex: 1;">
|
|
4268
|
+
<span style="font-weight: 600; color: var(--dsw-alias-brand-primary, #4f6ef7);">@${i + 1} ${escapeHtml(w.title || "")}</span>
|
|
4269
|
+
<span style="color: var(--dsw-alias-label-tertiary, #6b7280); margin-left: 6px; font-family: ui-monospace, Menlo, monospace; font-size: 10px;">${escapeHtml(w.path)}</span>
|
|
4270
|
+
</div>
|
|
4271
|
+
<button class="dsh-ws-switch-btn" data-ws-id="${escapeHtml(w.id || "")}" data-ws-path="${escapeHtml(w.path)}" style="border: 1px solid var(--dsw-alias-brand-primary, #4f6ef7); background: var(--dsw-alias-state-info-bg, #eff6ff); color: var(--dsw-alias-brand-primary, #4f6ef7); padding: 2px 8px; border-radius: 6px; font-size: 10px; font-weight: 600; cursor: pointer; flex-shrink: 0; margin-left: 6px; white-space: nowrap;">
|
|
4272
|
+
\u8FDB\u5165 \u2794
|
|
4273
|
+
</button>
|
|
4274
|
+
</div>
|
|
4275
|
+
`).join("")}
|
|
4276
|
+
</div>
|
|
4277
|
+
</div>
|
|
4278
|
+
` : ""}
|
|
4279
|
+
</div>
|
|
4280
|
+
|
|
4281
|
+
<!-- \u5F39\u7A97\u5E95\u90E8\u64CD\u4F5C\u6761 -->
|
|
4282
|
+
<div style="padding: 8px 16px; border-top: 1px solid var(--dsw-alias-border-l2, #e5e7eb); display: flex; align-items: center; justify-content: space-between; background: var(--dsw-alias-bg-layer-2, #f9fafb); flex-shrink: 0;">
|
|
4283
|
+
<span style="font-size: 10px; color: var(--dsw-alias-label-tertiary, #6b7280);">
|
|
4284
|
+
\u{1F4A1} \u70B9\u51FB\u6587\u4EF6\u5939\u53EF\u9010\u7EA7\u8FDB\u5165
|
|
4285
|
+
</span>
|
|
4286
|
+
<button id="dsh-ws-cancel-btn" style="border: 1px solid var(--dsw-alias-border-l2, #d1d5db); background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #111827); padding: 5px 14px; border-radius: 8px; font-size: 12px; cursor: pointer; font-weight: 500;">\u5173\u95ED</button>
|
|
4287
|
+
</div>
|
|
4288
|
+
`;
|
|
4289
|
+
modal.querySelector("#dsh-ws-close-btn")?.addEventListener("click", closeModal);
|
|
4290
|
+
modal.querySelector("#dsh-ws-cancel-btn")?.addEventListener("click", closeModal);
|
|
4291
|
+
modal.querySelectorAll(".dsh-ws-crumb-btn").forEach((btn) => {
|
|
4292
|
+
btn.addEventListener("click", () => {
|
|
4293
|
+
const p = btn.getAttribute("data-path");
|
|
4294
|
+
if (p) loadDirectory(p);
|
|
4295
|
+
});
|
|
4296
|
+
});
|
|
4297
|
+
modal.querySelectorAll(".dsh-ws-quick-btn").forEach((btn) => {
|
|
4298
|
+
btn.addEventListener("click", () => {
|
|
4299
|
+
const p = btn.getAttribute("data-path");
|
|
4300
|
+
if (p) loadDirectory(p);
|
|
4301
|
+
});
|
|
4302
|
+
});
|
|
4303
|
+
modal.querySelector("#dsh-ws-up-btn")?.addEventListener("click", (e) => {
|
|
4304
|
+
const p = e.currentTarget.getAttribute("data-path");
|
|
4305
|
+
if (p) loadDirectory(p);
|
|
4306
|
+
});
|
|
4307
|
+
modal.querySelector("#dsh-ws-refresh-btn")?.addEventListener("click", () => {
|
|
4308
|
+
loadDirectory(currentPath);
|
|
4309
|
+
});
|
|
4310
|
+
modal.querySelector("#dsh-ws-add-current-btn")?.addEventListener("click", () => {
|
|
4311
|
+
doSubmit(currentPath);
|
|
4312
|
+
});
|
|
4313
|
+
const filterInput = modal.querySelector("#dsh-ws-filter-input");
|
|
4314
|
+
if (filterInput) {
|
|
4315
|
+
filterInput.addEventListener("input", (e) => {
|
|
4316
|
+
filterQuery = e.target.value;
|
|
4317
|
+
render();
|
|
4318
|
+
const nextInput = modal.querySelector("#dsh-ws-filter-input");
|
|
4319
|
+
if (nextInput) {
|
|
4320
|
+
nextInput.focus();
|
|
4321
|
+
nextInput.selectionStart = nextInput.selectionEnd = nextInput.value.length;
|
|
4322
|
+
}
|
|
4323
|
+
});
|
|
4324
|
+
}
|
|
4325
|
+
modal.querySelectorAll(".dsh-ws-drill-btn").forEach((btn) => {
|
|
4326
|
+
btn.addEventListener("click", (e) => {
|
|
4327
|
+
e.stopPropagation();
|
|
4328
|
+
const p = btn.getAttribute("data-path");
|
|
4329
|
+
if (p) loadDirectory(p);
|
|
4330
|
+
});
|
|
4331
|
+
});
|
|
4332
|
+
modal.querySelectorAll(".dsh-ws-entry-row").forEach((row) => {
|
|
4333
|
+
row.addEventListener("click", (e) => {
|
|
4334
|
+
if (e.target.closest(".dsh-ws-pick-entry-btn")) return;
|
|
4335
|
+
const p = row.getAttribute("data-path");
|
|
4336
|
+
if (p) loadDirectory(p);
|
|
4337
|
+
});
|
|
4338
|
+
});
|
|
4339
|
+
modal.querySelectorAll(".dsh-ws-pick-entry-btn").forEach((btn) => {
|
|
4340
|
+
btn.addEventListener("click", (e) => {
|
|
4341
|
+
e.stopPropagation();
|
|
4342
|
+
const p = btn.getAttribute("data-path");
|
|
4343
|
+
if (p) doSubmit(p);
|
|
4344
|
+
});
|
|
4345
|
+
});
|
|
4346
|
+
modal.querySelectorAll(".dsh-ws-registered-row, .dsh-ws-switch-btn").forEach((el) => {
|
|
4347
|
+
el.addEventListener("click", (e) => {
|
|
4348
|
+
e.stopPropagation();
|
|
4349
|
+
const wsId = el.getAttribute("data-ws-id");
|
|
4350
|
+
const wsPath = el.getAttribute("data-ws-path");
|
|
4351
|
+
if (wsId || wsPath) {
|
|
4352
|
+
switchToWorkspace(wsId, wsPath);
|
|
4353
|
+
}
|
|
4354
|
+
});
|
|
4355
|
+
});
|
|
4356
|
+
modal.querySelector("#dsh-ws-toggle-manual")?.addEventListener("click", () => {
|
|
4357
|
+
showManualInput = !showManualInput;
|
|
4358
|
+
render();
|
|
4359
|
+
});
|
|
4360
|
+
const manualInput = modal.querySelector("#dsh-ws-manual-input");
|
|
4361
|
+
modal.querySelector("#dsh-ws-manual-jump-btn")?.addEventListener("click", () => {
|
|
4362
|
+
if (manualInput && manualInput.value.trim()) {
|
|
4363
|
+
loadDirectory(manualInput.value.trim());
|
|
4364
|
+
}
|
|
4365
|
+
});
|
|
4366
|
+
modal.querySelector("#dsh-ws-manual-add-btn")?.addEventListener("click", () => {
|
|
4367
|
+
if (manualInput && manualInput.value.trim()) {
|
|
4368
|
+
doSubmit(manualInput.value.trim());
|
|
4369
|
+
}
|
|
4370
|
+
});
|
|
4371
|
+
if (manualInput) {
|
|
4372
|
+
manualInput.addEventListener("keydown", (e) => {
|
|
4373
|
+
if (e.key === "Enter") {
|
|
4374
|
+
doSubmit(manualInput.value.trim());
|
|
4375
|
+
}
|
|
4376
|
+
});
|
|
4377
|
+
}
|
|
4378
|
+
}
|
|
4379
|
+
async function authRpc(endpoint, payload = {}) {
|
|
4380
|
+
let token = getGlobalAdminToken();
|
|
4381
|
+
if (!token && isLocalEnvironment()) {
|
|
4382
|
+
try {
|
|
4383
|
+
const res = await fetch("/__dsh_bridge__/loopback-token", { method: "POST" });
|
|
4384
|
+
if (res.ok) {
|
|
4385
|
+
const data = await res.json();
|
|
4386
|
+
if (data?.adminToken) {
|
|
4387
|
+
token = data.adminToken;
|
|
4388
|
+
setGlobalAdminToken(token);
|
|
4389
|
+
}
|
|
4390
|
+
}
|
|
4391
|
+
} catch {
|
|
4392
|
+
}
|
|
4393
|
+
}
|
|
4394
|
+
return rpcCall(endpoint, {
|
|
4395
|
+
...payload,
|
|
4396
|
+
...token ? { adminToken: token } : {},
|
|
4397
|
+
...isLocalEnvironment() ? { isLocalhost: true } : {}
|
|
4398
|
+
});
|
|
4399
|
+
}
|
|
4400
|
+
async function switchToWorkspace(wsId, wsPath) {
|
|
4401
|
+
if (isSubmitting) return;
|
|
4402
|
+
isSubmitting = true;
|
|
4403
|
+
statusMessage = `\u6B63\u5728\u5207\u6362\u5DE5\u4F5C\u533A\u2026`;
|
|
4404
|
+
isErrorMessage = false;
|
|
4405
|
+
render();
|
|
4406
|
+
if (typeof onPicked === "function" && wsPath) {
|
|
4407
|
+
try {
|
|
4408
|
+
onPicked(wsPath);
|
|
4409
|
+
} catch (e) {
|
|
4410
|
+
}
|
|
4411
|
+
}
|
|
4412
|
+
let switched = false;
|
|
4413
|
+
if (clientCtx?.workspaces?.startSession && wsId) {
|
|
4414
|
+
try {
|
|
4415
|
+
clientCtx.workspaces.startSession(wsId);
|
|
4416
|
+
switched = true;
|
|
4417
|
+
} catch (e) {
|
|
4418
|
+
console.warn("[dsh-bridge] startSession failed:", e);
|
|
4419
|
+
}
|
|
4420
|
+
}
|
|
4421
|
+
if (!switched && wsPath) {
|
|
4422
|
+
try {
|
|
4423
|
+
if (clientCtx?.workspaces?.create) {
|
|
4424
|
+
const ws = await clientCtx.workspaces.create({ path: wsPath });
|
|
4425
|
+
if (ws?.workspaceId && clientCtx?.workspaces?.startSession) {
|
|
4426
|
+
clientCtx.workspaces.startSession(ws.workspaceId);
|
|
4427
|
+
switched = true;
|
|
4428
|
+
}
|
|
4429
|
+
}
|
|
4430
|
+
if (!switched) {
|
|
4431
|
+
const raw = await authRpc(BRIDGE_ENDPOINTS.addRemoteWorkspace, { path: wsPath });
|
|
4432
|
+
const res = raw?.value || raw;
|
|
4433
|
+
if (res?.workspaceId && clientCtx?.workspaces?.startSession) {
|
|
4434
|
+
try {
|
|
4435
|
+
clientCtx.workspaces.startSession(res.workspaceId);
|
|
4436
|
+
switched = true;
|
|
4437
|
+
} catch (e) {
|
|
4438
|
+
}
|
|
4439
|
+
}
|
|
4440
|
+
if (!switched && res?.sessionId && clientCtx?.sessions?.open) {
|
|
4441
|
+
try {
|
|
4442
|
+
clientCtx.sessions.open(res.sessionId);
|
|
4443
|
+
switched = true;
|
|
4444
|
+
} catch (e) {
|
|
4445
|
+
}
|
|
4446
|
+
}
|
|
4447
|
+
}
|
|
4448
|
+
} catch (e) {
|
|
4449
|
+
}
|
|
4450
|
+
}
|
|
4451
|
+
statusMessage = `\u2713 \u5DF2\u5207\u6362\u81F3\u5DE5\u4F5C\u533A\uFF01`;
|
|
4452
|
+
render();
|
|
4453
|
+
setTimeout(() => {
|
|
4454
|
+
closeModal();
|
|
4455
|
+
document.body.classList.remove("dsh-drawer-open");
|
|
4456
|
+
}, 400);
|
|
4457
|
+
}
|
|
4458
|
+
async function loadDirectory(targetPath) {
|
|
4459
|
+
if (isSubmitting) return;
|
|
4460
|
+
if (!rpcCall) return;
|
|
4461
|
+
isLoading = true;
|
|
4462
|
+
filterQuery = "";
|
|
4463
|
+
statusMessage = null;
|
|
4464
|
+
isErrorMessage = false;
|
|
4465
|
+
render();
|
|
4466
|
+
try {
|
|
4467
|
+
const raw = await authRpc(BRIDGE_ENDPOINTS.listRemoteDirectories, { path: targetPath });
|
|
4468
|
+
const res = raw?.value || raw;
|
|
4469
|
+
if (res) {
|
|
4470
|
+
currentPath = res.currentPath || targetPath || "";
|
|
4471
|
+
parentPath = res.parentPath || null;
|
|
4472
|
+
breadcrumbs = res.breadcrumbs || [];
|
|
4473
|
+
entries = res.entries || [];
|
|
4474
|
+
roots = res.roots || [];
|
|
4475
|
+
drives = res.drives || [];
|
|
4476
|
+
workspaces = res.workspaces || [];
|
|
4477
|
+
if (res.error) {
|
|
4478
|
+
statusMessage = res.error;
|
|
4479
|
+
isErrorMessage = true;
|
|
4480
|
+
}
|
|
4481
|
+
}
|
|
4482
|
+
} catch (err) {
|
|
4483
|
+
statusMessage = err.message || "\u8BFB\u53D6\u76EE\u5F55\u5931\u8D25";
|
|
4484
|
+
isErrorMessage = true;
|
|
4485
|
+
} finally {
|
|
4486
|
+
isLoading = false;
|
|
4487
|
+
render();
|
|
4488
|
+
}
|
|
4489
|
+
}
|
|
4490
|
+
async function doSubmit(pathToRegister) {
|
|
4491
|
+
if (isSubmitting) return;
|
|
4492
|
+
const p = (pathToRegister || currentPath || "").trim();
|
|
4493
|
+
if (!p) {
|
|
4494
|
+
statusMessage = "\u8BF7\u8F93\u5165\u6216\u9009\u62E9\u5DE5\u4F5C\u533A\u8DEF\u5F84";
|
|
4495
|
+
isErrorMessage = true;
|
|
4496
|
+
render();
|
|
4497
|
+
return;
|
|
4498
|
+
}
|
|
4499
|
+
if (!rpcCall) return;
|
|
4500
|
+
isSubmitting = true;
|
|
4501
|
+
statusMessage = null;
|
|
4502
|
+
isErrorMessage = false;
|
|
4503
|
+
render();
|
|
4504
|
+
try {
|
|
4505
|
+
let clientWs = null;
|
|
4506
|
+
if (clientCtx?.workspaces?.create) {
|
|
4507
|
+
try {
|
|
4508
|
+
clientWs = await clientCtx.workspaces.create({ path: p });
|
|
4509
|
+
} catch (e) {
|
|
4510
|
+
console.warn("[dsh-bridge] clientCtx.workspaces.create failed:", e);
|
|
4511
|
+
}
|
|
4512
|
+
}
|
|
4513
|
+
const raw = await authRpc(BRIDGE_ENDPOINTS.addRemoteWorkspace, { path: p });
|
|
4514
|
+
const res = raw?.value || raw;
|
|
4515
|
+
if (res && res.ok) {
|
|
4516
|
+
statusMessage = `\u2713 \u5DE5\u4F5C\u533A\u300C${res.title || p}\u300D\u5DF2\u9009\u5B9A\uFF0C\u6B63\u5728\u5207\u6362\u2026`;
|
|
4517
|
+
isErrorMessage = false;
|
|
4518
|
+
workspaces = res.workspaces || [];
|
|
4519
|
+
render();
|
|
4520
|
+
const targetWorkspaceId = clientWs?.workspaceId || res.workspaceId;
|
|
4521
|
+
if (typeof onPicked === "function") {
|
|
4522
|
+
try {
|
|
4523
|
+
onPicked(p);
|
|
4524
|
+
} catch (e) {
|
|
4525
|
+
}
|
|
4526
|
+
}
|
|
4527
|
+
let switched = false;
|
|
4528
|
+
if (clientCtx?.workspaces?.startSession && targetWorkspaceId) {
|
|
4529
|
+
try {
|
|
4530
|
+
clientCtx.workspaces.startSession(targetWorkspaceId);
|
|
4531
|
+
switched = true;
|
|
4532
|
+
} catch (e) {
|
|
4533
|
+
console.warn("[dsh-bridge] startSession failed:", e);
|
|
4534
|
+
}
|
|
4535
|
+
}
|
|
4536
|
+
if (!switched && clientCtx?.sessions?.open && res.sessionId) {
|
|
4537
|
+
try {
|
|
4538
|
+
clientCtx.sessions.open(res.sessionId);
|
|
4539
|
+
switched = true;
|
|
4540
|
+
} catch (e) {
|
|
4541
|
+
console.warn("[dsh-bridge] sessions.open failed:", e);
|
|
4542
|
+
}
|
|
4543
|
+
}
|
|
4544
|
+
if (typeof onWorkspaceAdded === "function") {
|
|
4545
|
+
onWorkspaceAdded(res);
|
|
4546
|
+
}
|
|
4547
|
+
setTimeout(() => {
|
|
4548
|
+
closeModal();
|
|
4549
|
+
document.body.classList.remove("dsh-drawer-open");
|
|
4550
|
+
}, 500);
|
|
4551
|
+
} else {
|
|
4552
|
+
statusMessage = res?.error || raw?.error || "\u6DFB\u52A0\u5DE5\u4F5C\u533A\u5931\u8D25";
|
|
4553
|
+
isErrorMessage = true;
|
|
4554
|
+
render();
|
|
4555
|
+
}
|
|
4556
|
+
} catch (err) {
|
|
4557
|
+
statusMessage = err.message || "\u6DFB\u52A0\u5DE5\u4F5C\u533A\u5F02\u5E38";
|
|
4558
|
+
isErrorMessage = true;
|
|
4559
|
+
render();
|
|
4560
|
+
} finally {
|
|
4561
|
+
isSubmitting = false;
|
|
4562
|
+
}
|
|
4563
|
+
}
|
|
4564
|
+
overlay.appendChild(modal);
|
|
4565
|
+
document.body.appendChild(overlay);
|
|
4566
|
+
loadDirectory("");
|
|
4567
|
+
}
|
|
4568
|
+
function RemoteDirectoryFlow(props) {
|
|
4569
|
+
const { open, pick } = props;
|
|
4570
|
+
const outcome = React.useRef(props);
|
|
4571
|
+
outcome.current = props;
|
|
4572
|
+
const armed = React.useRef(false);
|
|
4573
|
+
React.useEffect(() => {
|
|
4574
|
+
if (!open) {
|
|
4575
|
+
armed.current = false;
|
|
4576
|
+
return;
|
|
4577
|
+
}
|
|
4578
|
+
if (armed.current) return;
|
|
4579
|
+
armed.current = true;
|
|
4580
|
+
if (isLocalEnvironment()) {
|
|
4581
|
+
const pickFn = typeof pick === "function" ? pick : typeof window.__dshClientCtx?.workspaces?.pickDirectory === "function" ? () => window.__dshClientCtx.workspaces.pickDirectory() : null;
|
|
4582
|
+
if (pickFn) {
|
|
4583
|
+
pickFn().then((chosenPath) => {
|
|
4584
|
+
if (chosenPath === null) {
|
|
4585
|
+
if (outcome.current?.onCancel) outcome.current.onCancel();
|
|
4586
|
+
} else if (chosenPath) {
|
|
4587
|
+
if (outcome.current?.onPicked) outcome.current.onPicked(chosenPath);
|
|
4588
|
+
}
|
|
4589
|
+
}, (err) => {
|
|
4590
|
+
if (outcome.current?.onError) outcome.current.onError(err instanceof Error ? err.message : String(err));
|
|
4591
|
+
});
|
|
4592
|
+
return;
|
|
4593
|
+
}
|
|
4594
|
+
}
|
|
4595
|
+
if (typeof window.__dshOpenRemoteWorkspaceModal === "function") {
|
|
4596
|
+
window.__dshOpenRemoteWorkspaceModal(
|
|
4597
|
+
(res) => {
|
|
4598
|
+
if (res?.path && outcome.current?.onPicked) {
|
|
4599
|
+
outcome.current.onPicked(res.path);
|
|
4600
|
+
}
|
|
4601
|
+
},
|
|
4602
|
+
(chosenPath) => {
|
|
4603
|
+
if (chosenPath && outcome.current?.onPicked) {
|
|
4604
|
+
outcome.current.onPicked(chosenPath);
|
|
4605
|
+
}
|
|
4606
|
+
},
|
|
4607
|
+
() => {
|
|
4608
|
+
if (outcome.current?.onCancel) {
|
|
4609
|
+
outcome.current.onCancel();
|
|
4610
|
+
}
|
|
4611
|
+
}
|
|
4612
|
+
);
|
|
4613
|
+
}
|
|
4614
|
+
}, [open, pick]);
|
|
4615
|
+
return null;
|
|
3622
4616
|
}
|
|
3623
4617
|
function apply(ctx) {
|
|
3624
|
-
|
|
4618
|
+
window.__dshClientCtx = ctx;
|
|
3625
4619
|
const rpcCall = (endpoint, payload, signal) => ctx.connection.rpc.call(BRIDGE_RPC_CHANNEL, endpoint, payload, signal);
|
|
4620
|
+
window.__dshOpenRemoteWorkspaceModal = (onAdded, onPickDirect, onCancel) => showRemoteWorkspaceDialog(rpcCall, onAdded, ctx, onPickDirect, onCancel);
|
|
4621
|
+
setupMobileExperience(rpcCall, ctx);
|
|
4622
|
+
const injected = () => ({ pick: () => ctx.workspaces?.pickDirectory?.() });
|
|
4623
|
+
ctx.slots.inject(
|
|
4624
|
+
"conversation.hero.workspace.directoryFlow",
|
|
4625
|
+
() => ctx.slots.inject("sidebar.workspaces.directoryFlow", function* () {
|
|
4626
|
+
yield ctx.slots.register(
|
|
4627
|
+
{
|
|
4628
|
+
name: "conversation.hero.workspace.directoryFlow",
|
|
4629
|
+
priority: -10,
|
|
4630
|
+
inject: injected
|
|
4631
|
+
},
|
|
4632
|
+
RemoteDirectoryFlow
|
|
4633
|
+
);
|
|
4634
|
+
yield ctx.slots.register(
|
|
4635
|
+
{
|
|
4636
|
+
name: "sidebar.workspaces.directoryFlow",
|
|
4637
|
+
priority: -10,
|
|
4638
|
+
inject: injected
|
|
4639
|
+
},
|
|
4640
|
+
RemoteDirectoryFlow
|
|
4641
|
+
);
|
|
4642
|
+
})
|
|
4643
|
+
);
|
|
3626
4644
|
ctx.slots.inject(
|
|
3627
4645
|
"settings.section",
|
|
3628
4646
|
() => ctx.slots.register(
|