ds-harness-remote 0.3.22 → 0.3.23

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.
@@ -1771,6 +1771,20 @@ Minimum version required to store current data is: ` + bestVersion + `.
1771
1771
  openWorkspace: "Open workspace",
1772
1772
  openingWorkspace: "Opening\u2026",
1773
1773
  loadingDirectory: "Loading directories\u2026",
1774
+ remoteProgressCheckingHost: "Checking Host",
1775
+ remoteProgressCheckingHostDetail: "Finding the selected device and checking whether it is online.",
1776
+ remoteProgressAuthorizingPeer: "Verifying authorization",
1777
+ remoteProgressAuthorizingPeerDetail: "Confirming account membership and pinned Host identity.",
1778
+ remoteProgressOpeningChannel: "Opening encrypted channel",
1779
+ remoteProgressOpeningChannelDetail: "Trying LAN, P2P, TURN, then Relay if needed.",
1780
+ remoteProgressLoadingWorkspaces: "Loading workspaces",
1781
+ remoteProgressLoadingWorkspacesDetail: "Reading the remote Harness workspace list through the tunnel.",
1782
+ remoteProgressOpeningWorkspace: "Opening workspace",
1783
+ remoteProgressOpeningWorkspaceDetail: "Asking the Host to prepare the selected working directory.",
1784
+ remoteProgressSwitchingWorkspace: "Switching interface",
1785
+ remoteProgressSwitchingWorkspaceDetail: "Handing the remote workspace to the local Harness UI.",
1786
+ remoteProgressReady: "Ready",
1787
+ remoteProgressReadyDetail: "The remote Host is connected and encrypted.",
1774
1788
  backToHosts: "Choose another Host",
1775
1789
  currentDirectory: "Selected directory",
1776
1790
  directoryTruncated: "Only part of this directory could be shown.",
@@ -1941,6 +1955,20 @@ Minimum version required to store current data is: ` + bestVersion + `.
1941
1955
  openWorkspace: "\u6253\u5F00\u5DE5\u4F5C\u533A",
1942
1956
  openingWorkspace: "\u6B63\u5728\u6253\u5F00\u2026",
1943
1957
  loadingDirectory: "\u6B63\u5728\u52A0\u8F7D\u76EE\u5F55\u2026",
1958
+ remoteProgressCheckingHost: "\u6B63\u5728\u68C0\u67E5 Host",
1959
+ remoteProgressCheckingHostDetail: "\u6B63\u5728\u67E5\u627E\u6240\u9009\u8BBE\u5907\u5E76\u786E\u8BA4\u662F\u5426\u5728\u7EBF\u3002",
1960
+ remoteProgressAuthorizingPeer: "\u6B63\u5728\u9A8C\u8BC1\u6388\u6743",
1961
+ remoteProgressAuthorizingPeerDetail: "\u6B63\u5728\u786E\u8BA4\u8D26\u53F7\u6210\u5458\u5173\u7CFB\u548C\u5DF2\u56FA\u5B9A\u7684 Host \u8EAB\u4EFD\u3002",
1962
+ remoteProgressOpeningChannel: "\u6B63\u5728\u5EFA\u7ACB\u52A0\u5BC6\u901A\u9053",
1963
+ remoteProgressOpeningChannelDetail: "\u4F9D\u6B21\u5C1D\u8BD5\u5C40\u57DF\u7F51\u3001P2P\u3001TURN\uFF0C\u5FC5\u8981\u65F6\u56DE\u843D\u5230 Relay\u3002",
1964
+ remoteProgressLoadingWorkspaces: "\u6B63\u5728\u52A0\u8F7D\u5DE5\u4F5C\u533A",
1965
+ remoteProgressLoadingWorkspacesDetail: "\u901A\u8FC7\u96A7\u9053\u8BFB\u53D6\u8FDC\u7AEF Harness \u5DE5\u4F5C\u533A\u5217\u8868\u3002",
1966
+ remoteProgressOpeningWorkspace: "\u6B63\u5728\u6253\u5F00\u5DE5\u4F5C\u533A",
1967
+ remoteProgressOpeningWorkspaceDetail: "\u6B63\u5728\u8BF7\u6C42 Host \u51C6\u5907\u6240\u9009\u5DE5\u4F5C\u76EE\u5F55\u3002",
1968
+ remoteProgressSwitchingWorkspace: "\u6B63\u5728\u5207\u6362\u754C\u9762",
1969
+ remoteProgressSwitchingWorkspaceDetail: "\u6B63\u5728\u628A\u8FDC\u7AEF\u5DE5\u4F5C\u533A\u4EA4\u7ED9\u672C\u5730 Harness UI\u3002",
1970
+ remoteProgressReady: "\u5DF2\u5C31\u7EEA",
1971
+ remoteProgressReadyDetail: "\u8FDC\u7AEF Host \u5DF2\u8FDE\u63A5\uFF0C\u7AEF\u5230\u7AEF\u52A0\u5BC6\u5DF2\u5EFA\u7ACB\u3002",
1944
1972
  backToHosts: "\u9009\u62E9\u5176\u4ED6\u4E3B\u673A",
1945
1973
  currentDirectory: "\u5DF2\u9009\u76EE\u5F55",
1946
1974
  directoryTruncated: "\u76EE\u5F55\u5185\u5BB9\u8F83\u591A\uFF0C\u76EE\u524D\u53EA\u663E\u793A\u4E86\u4E00\u90E8\u5206\u3002",
@@ -2054,6 +2082,58 @@ Minimum version required to store current data is: ` + bestVersion + `.
2054
2082
  id: clientModuleId,
2055
2083
  factory: (require2) => {
2056
2084
  let module = { exports: {} }, React = require2("react"), inject = ["connection", "slots", "locale", "workspaces", "sessions"];
2085
+ function RemoteProgressView(props) {
2086
+ let progress = props.progress;
2087
+ if (progress === void 0) return null;
2088
+ let percent = Math.max(0, Math.min(100, Math.round(progress.percent)));
2089
+ return React.createElement(
2090
+ "div",
2091
+ {
2092
+ className: "dshRemoteProgress",
2093
+ role: "status",
2094
+ "aria-live": "polite"
2095
+ },
2096
+ React.createElement(
2097
+ "div",
2098
+ { className: "dshRemoteProgressHeader" },
2099
+ React.createElement("strong", null, props.t(progress.label)),
2100
+ React.createElement("span", null, `${percent}%`)
2101
+ ),
2102
+ React.createElement("div", {
2103
+ className: "dshRemoteProgressBar",
2104
+ role: "progressbar",
2105
+ "aria-valuemin": 0,
2106
+ "aria-valuemax": 100,
2107
+ "aria-valuenow": percent,
2108
+ "aria-label": props.t(progress.label)
2109
+ }, React.createElement("span", { style: { width: `${percent}%` } })),
2110
+ React.createElement("p", null, props.t(progress.detail))
2111
+ );
2112
+ }
2113
+ async function runRemoteProgress(steps, setProgress, progressRun, action) {
2114
+ let runId = progressRun.current + 1;
2115
+ progressRun.current = runId;
2116
+ let apply2 = (next) => {
2117
+ progressRun.current === runId && setProgress(next);
2118
+ }, [first, ...rest] = steps;
2119
+ first !== void 0 && apply2(first);
2120
+ let timers = rest.map((step) => window.setTimeout(() => apply2(step), step.delayMs ?? 0));
2121
+ try {
2122
+ let result = await action();
2123
+ return apply2({ label: "remoteProgressReady", detail: "remoteProgressReadyDetail", percent: 100 }), await new Promise((resolve) => window.setTimeout(resolve, 220)), result;
2124
+ } finally {
2125
+ timers.forEach((timer) => window.clearTimeout(timer)), progressRun.current === runId && setProgress(void 0);
2126
+ }
2127
+ }
2128
+ let connectHostProgressSteps = [
2129
+ { label: "remoteProgressCheckingHost", detail: "remoteProgressCheckingHostDetail", percent: 12 },
2130
+ { label: "remoteProgressAuthorizingPeer", detail: "remoteProgressAuthorizingPeerDetail", percent: 32, delayMs: 280 },
2131
+ { label: "remoteProgressOpeningChannel", detail: "remoteProgressOpeningChannelDetail", percent: 58, delayMs: 760 },
2132
+ { label: "remoteProgressLoadingWorkspaces", detail: "remoteProgressLoadingWorkspacesDetail", percent: 82, delayMs: 1350 }
2133
+ ], openWorkspaceProgressSteps = [
2134
+ { label: "remoteProgressOpeningWorkspace", detail: "remoteProgressOpeningWorkspaceDetail", percent: 30 },
2135
+ { label: "remoteProgressSwitchingWorkspace", detail: "remoteProgressSwitchingWorkspaceDetail", percent: 74, delayMs: 520 }
2136
+ ];
2057
2137
  function RemotePluginOptions(props) {
2058
2138
  let { t } = props, [open, setOpen] = React.useState(!1), [serverUrl, setServerUrl] = React.useState(""), role = "host", [registrationCode, setRegistrationCode] = React.useState(""), [associations, setAssociations] = React.useState({}), [loaded, setLoaded] = React.useState(!1), [writable, setWritable] = React.useState(!1), [busy, setBusy] = React.useState(!1), [reconnectBusy, setReconnectBusy] = React.useState(!1), [hostStatus, setHostStatus] = React.useState(void 0), [notice, setNotice] = React.useState(void 0), [error, setError] = React.useState(void 0), [settingsView, setSettingsView] = React.useState(void 0), persistedServerUrl = settingsView?.config.serverUrl ?? "https://dsh.r2049.cn", association = associations.client ?? associations.host, serverDirty = settingsView !== void 0 && serverUrl !== persistedServerUrl, draftDirty = serverDirty, applyView = (view) => {
2059
2139
  setSettingsView(view), setServerUrl(view.config.serverUrl ?? "https://dsh.r2049.cn"), setAssociations(view.associations ?? (view.association === void 0 ? {} : { host: view.association })), setWritable(view.writable), setLoaded(!0);
@@ -2282,7 +2362,7 @@ Minimum version required to store current data is: ` + bestVersion + `.
2282
2362
  );
2283
2363
  }
2284
2364
  function RemoteWorkspaceAction(props) {
2285
- let { t } = props, [open, setOpen] = React.useState(!1), [status, setStatus] = React.useState(void 0), [devices, setDevices] = React.useState([]), [selectedHost, setSelectedHost] = React.useState(void 0), [workspaces, setWorkspaces] = React.useState([]), [directory, setDirectory] = React.useState(void 0), [path, setPath] = React.useState(""), [addingWorkspace, setAddingWorkspace] = React.useState(!1), [busy, setBusy] = React.useState(!1), [needsAuthorization, setNeedsAuthorization] = React.useState(!1), [email, setEmail] = React.useState(""), [password, setPassword] = React.useState(""), [loginMethod, setLoginMethod] = React.useState(props.preferredQrProvider), [loginMethodManuallySelected, setLoginMethodManuallySelected] = React.useState(!1), [qrSession, setQrSession] = React.useState(void 0), [qrImage, setQrImage] = React.useState(void 0), [qrExpired, setQrExpired] = React.useState(!1), [notice, setNotice] = React.useState(void 0), [error, setError] = React.useState(void 0);
2365
+ let { t } = props, [open, setOpen] = React.useState(!1), [status, setStatus] = React.useState(void 0), [devices, setDevices] = React.useState([]), [selectedHost, setSelectedHost] = React.useState(void 0), [workspaces, setWorkspaces] = React.useState([]), [directory, setDirectory] = React.useState(void 0), [path, setPath] = React.useState(""), [addingWorkspace, setAddingWorkspace] = React.useState(!1), [busy, setBusy] = React.useState(!1), [needsAuthorization, setNeedsAuthorization] = React.useState(!1), [email, setEmail] = React.useState(""), [password, setPassword] = React.useState(""), [loginMethod, setLoginMethod] = React.useState(props.preferredQrProvider), [loginMethodManuallySelected, setLoginMethodManuallySelected] = React.useState(!1), [qrSession, setQrSession] = React.useState(void 0), [qrImage, setQrImage] = React.useState(void 0), [qrExpired, setQrExpired] = React.useState(!1), [progress, setProgress] = React.useState(void 0), progressRun = React.useRef(0), [notice, setNotice] = React.useState(void 0), [error, setError] = React.useState(void 0);
2286
2366
  React.useEffect(() => {
2287
2367
  if (!open) return;
2288
2368
  let closeOnEscape = (event) => {
@@ -2347,7 +2427,12 @@ Minimum version required to store current data is: ` + bestVersion + `.
2347
2427
  }, t(provider === "github" ? "githubLogin" : "zhihuLogin")), selectHost = async (host) => {
2348
2428
  setBusy(!0), setError(void 0);
2349
2429
  try {
2350
- setWorkspaces(await props.control("workspaces.list", { targetDeviceId: host.deviceId })), setSelectedHost(host), setPath(""), setAddingWorkspace(!1), setDirectory(void 0);
2430
+ setWorkspaces(await runRemoteProgress(
2431
+ connectHostProgressSteps,
2432
+ setProgress,
2433
+ progressRun,
2434
+ () => props.control("workspaces.list", { targetDeviceId: host.deviceId })
2435
+ )), setSelectedHost(host), setPath(""), setAddingWorkspace(!1), setDirectory(void 0);
2351
2436
  } catch (reason) {
2352
2437
  setError(messageOf(reason));
2353
2438
  } finally {
@@ -2423,10 +2508,15 @@ Minimum version required to store current data is: ` + bestVersion + `.
2423
2508
  if (!(selectedHost === void 0 || path.trim() === "")) {
2424
2509
  setBusy(!0), setError(void 0);
2425
2510
  try {
2426
- await props.control("workspace.open", {
2427
- targetDeviceId: selectedHost.deviceId,
2428
- path: path.trim()
2429
- }), window.location.reload();
2511
+ await runRemoteProgress(
2512
+ openWorkspaceProgressSteps,
2513
+ setProgress,
2514
+ progressRun,
2515
+ () => props.control("workspace.open", {
2516
+ targetDeviceId: selectedHost.deviceId,
2517
+ path: path.trim()
2518
+ })
2519
+ ), window.location.reload();
2430
2520
  } catch (reason) {
2431
2521
  setError(messageOf(reason)), setBusy(!1);
2432
2522
  }
@@ -2663,6 +2753,7 @@ Minimum version required to store current data is: ` + bestVersion + `.
2663
2753
  React.createElement("small", null, [formatPlatform(selectedHost.platform), t("online")].join(" \xB7 "))
2664
2754
  )
2665
2755
  ),
2756
+ React.createElement(RemoteProgressView, { progress, t }),
2666
2757
  selectedHost === void 0 ? React.createElement("p", { className: "dshRemoteHint" }, t("selectHostHint")) : React.createElement(
2667
2758
  "section",
2668
2759
  { className: "dshRemoteBrowser", "aria-label": t("chooseDirectory") },
@@ -2742,7 +2833,7 @@ Minimum version required to store current data is: ` + bestVersion + `.
2742
2833
  );
2743
2834
  }
2744
2835
  function RemoteModeAction(props) {
2745
- let { t } = props, [open, setOpen] = React.useState(!1), [status, setStatus] = React.useState(void 0), [devices, setDevices] = React.useState([]), [hostRegistrationCode, setHostRegistrationCode] = React.useState(""), [email, setEmail] = React.useState(""), [password, setPassword] = React.useState(""), [busy, setBusy] = React.useState(!1), [error, setError] = React.useState(void 0), [supported, setSupported] = React.useState(!0), refresh = async () => {
2836
+ let { t } = props, [open, setOpen] = React.useState(!1), [status, setStatus] = React.useState(void 0), [devices, setDevices] = React.useState([]), [hostRegistrationCode, setHostRegistrationCode] = React.useState(""), [email, setEmail] = React.useState(""), [password, setPassword] = React.useState(""), [busy, setBusy] = React.useState(!1), [progress, setProgress] = React.useState(void 0), progressRun = React.useRef(0), [error, setError] = React.useState(void 0), [supported, setSupported] = React.useState(!0), refresh = async () => {
2746
2837
  let [nextStatus, nextDevices] = await Promise.all([
2747
2838
  props.control("status"),
2748
2839
  props.control("devices").catch(() => [])
@@ -2766,7 +2857,8 @@ Minimum version required to store current data is: ` + bestVersion + `.
2766
2857
  let switchMode = async (mode, targetDeviceId) => {
2767
2858
  setBusy(!0), setError(void 0);
2768
2859
  try {
2769
- await props.control("mode.set", { mode, ...targetDeviceId === void 0 ? {} : { targetDeviceId } }), window.location.reload();
2860
+ let action = () => props.control("mode.set", { mode, ...targetDeviceId === void 0 ? {} : { targetDeviceId } });
2861
+ mode === "remote" ? await runRemoteProgress(connectHostProgressSteps, setProgress, progressRun, action) : await action(), window.location.reload();
2770
2862
  } catch (reason) {
2771
2863
  setError(messageOf(reason)), setBusy(!1);
2772
2864
  }
@@ -2831,6 +2923,7 @@ Minimum version required to store current data is: ` + bestVersion + `.
2831
2923
  disabled: busy || !device.online || status?.target?.deviceId === device.deviceId,
2832
2924
  onClick: () => void switchMode("remote", device.deviceId)
2833
2925
  }, `${device.name} \xB7 ${t(device.online ? "online" : "offline")}`))),
2926
+ React.createElement(RemoteProgressView, { progress, t }),
2834
2927
  status?.hostAuthorizationAvailable && status.host !== void 0 ? React.createElement(
2835
2928
  "div",
2836
2929
  { className: "dshRemoteHostAccount" },
@@ -3076,6 +3169,7 @@ Minimum version required to store current data is: ` + bestVersion + `.
3076
3169
  ".dshRemoteSectionHeading>.dshRemoteAddWorkspace{width:30px;height:30px;display:inline-flex;align-items:center;justify-content:center;padding:0;border-radius:50%;font-size:20px;line-height:1}.dshRemoteSectionHeading>.dshRemoteAddWorkspace:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}",
3077
3170
  ".dshRemoteHostList{display:flex;flex-direction:column;border-top:1px solid var(--dsw-alias-border-l2)}.dshRemoteHostList>button{min-height:58px;display:flex;align-items:center;justify-content:space-between;gap:16px;text-align:left;border:0;border-bottom:1px solid var(--dsw-alias-border-l2);background:transparent;padding:10px 4px;cursor:pointer}.dshRemoteHostList>button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.dshRemoteHostList>button:disabled{opacity:.5;cursor:default}.dshRemoteHostList>button>span{min-width:0;display:flex;flex-direction:column;gap:3px}.dshRemoteHostList>button strong{font-size:14px;font-weight:500}.dshRemoteHostList small,.dshRemoteSelectedHost small{color:var(--dsw-alias-label-secondary);font-size:12px}",
3078
3171
  ".dshRemoteSelectedHost{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:12px 14px;border-radius:10px;background:var(--dsw-alias-bg-layer-2)}",
3172
+ ".dshRemoteProgress{display:flex;flex-direction:column;gap:8px;margin:12px 0;padding:12px 14px;border:1px solid var(--dsw-alias-border-l2);border-radius:10px;background:var(--dsw-alias-bg-layer-2)}.dshRemoteProgressHeader{display:flex;align-items:center;justify-content:space-between;gap:12px}.dshRemoteProgressHeader strong{font-size:13px;font-weight:600}.dshRemoteProgressHeader span{color:var(--dsw-alias-label-secondary);font-size:12px}.dshRemoteProgressBar{height:6px;overflow:hidden;border-radius:999px;background:var(--dsw-alias-bg-layer-3)}.dshRemoteProgressBar>span{display:block;height:100%;border-radius:inherit;background:var(--dsw-alias-brand-primary);transition:width .22s ease-out}.dshRemoteProgress p{margin:0;color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.45}@media(prefers-reduced-motion:reduce){.dshRemoteProgressBar>span{transition:none}}",
3079
3173
  '.dshRemoteBrowser{display:flex;flex-direction:column}.dshRemoteCrumbs{display:flex;align-items:center;gap:4px;overflow:auto;padding:2px 0 10px}.dshRemoteCrumbs>button{flex:0 0 auto;border:0;background:transparent;color:var(--dsw-alias-label-secondary);padding:5px 7px;border-radius:6px;cursor:pointer}.dshRemoteCrumbs>button:not(:last-child)::after{content:" /";color:var(--dsw-alias-label-tertiary)}.dshRemoteCrumbs>button:disabled{color:var(--dsw-alias-label-primary);font-weight:600}',
3080
3174
  ".dshRemoteDirectoryList{min-height:72px;display:flex;flex-direction:column;border-top:1px solid var(--dsw-alias-border-l2)}.dshRemoteDirectoryList>button{min-height:52px;display:grid;grid-template-columns:auto 1fr;column-gap:10px;text-align:left;border:0;border-bottom:1px solid var(--dsw-alias-border-l2);background:transparent;padding:8px 4px;cursor:pointer}.dshRemoteDirectoryList>button:hover,.dshRemoteDirectoryList>button.isSelected{background:var(--dsw-alias-interactive-bg-hover)}.dshRemoteDirectoryList>button.isSelected{color:var(--dsw-alias-label-primary)}.dshRemoteDirectoryList>button>span:first-child{grid-row:1/3}.dshRemoteDirectoryList>button>small{grid-column:2;color:var(--dsw-alias-label-secondary);overflow:hidden;text-overflow:ellipsis}.dshRemoteDirectoryList>p,.dshRemoteHint{margin:12px 0;color:var(--dsw-alias-label-secondary);font-size:13px}",
3081
3175
  ".dshRemoteFolderBrowser{margin-top:14px}.dshRemoteFolderBrowser>p,.dshRemoteFolderList>p{margin:12px 0;color:var(--dsw-alias-label-secondary);font-size:13px}.dshRemoteFolderList{max-height:260px;overflow:auto;border-block:1px solid var(--dsw-alias-border-l2)}.dshRemoteFolderList>button{width:100%;min-height:42px;display:flex;align-items:center;gap:9px;border:0;border-bottom:1px solid var(--dsw-alias-border-l2);background:transparent;padding:7px 6px;text-align:left;cursor:pointer}.dshRemoteFolderList>button:hover{background:var(--dsw-alias-interactive-bg-hover)}.dshRemoteFolderBrowser>small{display:block;margin-top:8px;color:var(--dsw-alias-state-warn-label)}",
package/dist/client.js CHANGED
@@ -1771,6 +1771,20 @@ Minimum version required to store current data is: ` + bestVersion + `.
1771
1771
  openWorkspace: "Open workspace",
1772
1772
  openingWorkspace: "Opening\u2026",
1773
1773
  loadingDirectory: "Loading directories\u2026",
1774
+ remoteProgressCheckingHost: "Checking Host",
1775
+ remoteProgressCheckingHostDetail: "Finding the selected device and checking whether it is online.",
1776
+ remoteProgressAuthorizingPeer: "Verifying authorization",
1777
+ remoteProgressAuthorizingPeerDetail: "Confirming account membership and pinned Host identity.",
1778
+ remoteProgressOpeningChannel: "Opening encrypted channel",
1779
+ remoteProgressOpeningChannelDetail: "Trying LAN, P2P, TURN, then Relay if needed.",
1780
+ remoteProgressLoadingWorkspaces: "Loading workspaces",
1781
+ remoteProgressLoadingWorkspacesDetail: "Reading the remote Harness workspace list through the tunnel.",
1782
+ remoteProgressOpeningWorkspace: "Opening workspace",
1783
+ remoteProgressOpeningWorkspaceDetail: "Asking the Host to prepare the selected working directory.",
1784
+ remoteProgressSwitchingWorkspace: "Switching interface",
1785
+ remoteProgressSwitchingWorkspaceDetail: "Handing the remote workspace to the local Harness UI.",
1786
+ remoteProgressReady: "Ready",
1787
+ remoteProgressReadyDetail: "The remote Host is connected and encrypted.",
1774
1788
  backToHosts: "Choose another Host",
1775
1789
  currentDirectory: "Selected directory",
1776
1790
  directoryTruncated: "Only part of this directory could be shown.",
@@ -1941,6 +1955,20 @@ Minimum version required to store current data is: ` + bestVersion + `.
1941
1955
  openWorkspace: "\u6253\u5F00\u5DE5\u4F5C\u533A",
1942
1956
  openingWorkspace: "\u6B63\u5728\u6253\u5F00\u2026",
1943
1957
  loadingDirectory: "\u6B63\u5728\u52A0\u8F7D\u76EE\u5F55\u2026",
1958
+ remoteProgressCheckingHost: "\u6B63\u5728\u68C0\u67E5 Host",
1959
+ remoteProgressCheckingHostDetail: "\u6B63\u5728\u67E5\u627E\u6240\u9009\u8BBE\u5907\u5E76\u786E\u8BA4\u662F\u5426\u5728\u7EBF\u3002",
1960
+ remoteProgressAuthorizingPeer: "\u6B63\u5728\u9A8C\u8BC1\u6388\u6743",
1961
+ remoteProgressAuthorizingPeerDetail: "\u6B63\u5728\u786E\u8BA4\u8D26\u53F7\u6210\u5458\u5173\u7CFB\u548C\u5DF2\u56FA\u5B9A\u7684 Host \u8EAB\u4EFD\u3002",
1962
+ remoteProgressOpeningChannel: "\u6B63\u5728\u5EFA\u7ACB\u52A0\u5BC6\u901A\u9053",
1963
+ remoteProgressOpeningChannelDetail: "\u4F9D\u6B21\u5C1D\u8BD5\u5C40\u57DF\u7F51\u3001P2P\u3001TURN\uFF0C\u5FC5\u8981\u65F6\u56DE\u843D\u5230 Relay\u3002",
1964
+ remoteProgressLoadingWorkspaces: "\u6B63\u5728\u52A0\u8F7D\u5DE5\u4F5C\u533A",
1965
+ remoteProgressLoadingWorkspacesDetail: "\u901A\u8FC7\u96A7\u9053\u8BFB\u53D6\u8FDC\u7AEF Harness \u5DE5\u4F5C\u533A\u5217\u8868\u3002",
1966
+ remoteProgressOpeningWorkspace: "\u6B63\u5728\u6253\u5F00\u5DE5\u4F5C\u533A",
1967
+ remoteProgressOpeningWorkspaceDetail: "\u6B63\u5728\u8BF7\u6C42 Host \u51C6\u5907\u6240\u9009\u5DE5\u4F5C\u76EE\u5F55\u3002",
1968
+ remoteProgressSwitchingWorkspace: "\u6B63\u5728\u5207\u6362\u754C\u9762",
1969
+ remoteProgressSwitchingWorkspaceDetail: "\u6B63\u5728\u628A\u8FDC\u7AEF\u5DE5\u4F5C\u533A\u4EA4\u7ED9\u672C\u5730 Harness UI\u3002",
1970
+ remoteProgressReady: "\u5DF2\u5C31\u7EEA",
1971
+ remoteProgressReadyDetail: "\u8FDC\u7AEF Host \u5DF2\u8FDE\u63A5\uFF0C\u7AEF\u5230\u7AEF\u52A0\u5BC6\u5DF2\u5EFA\u7ACB\u3002",
1944
1972
  backToHosts: "\u9009\u62E9\u5176\u4ED6\u4E3B\u673A",
1945
1973
  currentDirectory: "\u5DF2\u9009\u76EE\u5F55",
1946
1974
  directoryTruncated: "\u76EE\u5F55\u5185\u5BB9\u8F83\u591A\uFF0C\u76EE\u524D\u53EA\u663E\u793A\u4E86\u4E00\u90E8\u5206\u3002",
@@ -2054,6 +2082,58 @@ Minimum version required to store current data is: ` + bestVersion + `.
2054
2082
  id: clientModuleId,
2055
2083
  factory: (require2) => {
2056
2084
  let module = { exports: {} }, React = require2("react"), inject = ["connection", "slots", "locale", "workspaces", "sessions"];
2085
+ function RemoteProgressView(props) {
2086
+ let progress = props.progress;
2087
+ if (progress === void 0) return null;
2088
+ let percent = Math.max(0, Math.min(100, Math.round(progress.percent)));
2089
+ return React.createElement(
2090
+ "div",
2091
+ {
2092
+ className: "dshRemoteProgress",
2093
+ role: "status",
2094
+ "aria-live": "polite"
2095
+ },
2096
+ React.createElement(
2097
+ "div",
2098
+ { className: "dshRemoteProgressHeader" },
2099
+ React.createElement("strong", null, props.t(progress.label)),
2100
+ React.createElement("span", null, `${percent}%`)
2101
+ ),
2102
+ React.createElement("div", {
2103
+ className: "dshRemoteProgressBar",
2104
+ role: "progressbar",
2105
+ "aria-valuemin": 0,
2106
+ "aria-valuemax": 100,
2107
+ "aria-valuenow": percent,
2108
+ "aria-label": props.t(progress.label)
2109
+ }, React.createElement("span", { style: { width: `${percent}%` } })),
2110
+ React.createElement("p", null, props.t(progress.detail))
2111
+ );
2112
+ }
2113
+ async function runRemoteProgress(steps, setProgress, progressRun, action) {
2114
+ let runId = progressRun.current + 1;
2115
+ progressRun.current = runId;
2116
+ let apply2 = (next) => {
2117
+ progressRun.current === runId && setProgress(next);
2118
+ }, [first, ...rest] = steps;
2119
+ first !== void 0 && apply2(first);
2120
+ let timers = rest.map((step) => window.setTimeout(() => apply2(step), step.delayMs ?? 0));
2121
+ try {
2122
+ let result = await action();
2123
+ return apply2({ label: "remoteProgressReady", detail: "remoteProgressReadyDetail", percent: 100 }), await new Promise((resolve) => window.setTimeout(resolve, 220)), result;
2124
+ } finally {
2125
+ timers.forEach((timer) => window.clearTimeout(timer)), progressRun.current === runId && setProgress(void 0);
2126
+ }
2127
+ }
2128
+ let connectHostProgressSteps = [
2129
+ { label: "remoteProgressCheckingHost", detail: "remoteProgressCheckingHostDetail", percent: 12 },
2130
+ { label: "remoteProgressAuthorizingPeer", detail: "remoteProgressAuthorizingPeerDetail", percent: 32, delayMs: 280 },
2131
+ { label: "remoteProgressOpeningChannel", detail: "remoteProgressOpeningChannelDetail", percent: 58, delayMs: 760 },
2132
+ { label: "remoteProgressLoadingWorkspaces", detail: "remoteProgressLoadingWorkspacesDetail", percent: 82, delayMs: 1350 }
2133
+ ], openWorkspaceProgressSteps = [
2134
+ { label: "remoteProgressOpeningWorkspace", detail: "remoteProgressOpeningWorkspaceDetail", percent: 30 },
2135
+ { label: "remoteProgressSwitchingWorkspace", detail: "remoteProgressSwitchingWorkspaceDetail", percent: 74, delayMs: 520 }
2136
+ ];
2057
2137
  function RemotePluginOptions(props) {
2058
2138
  let { t } = props, [open, setOpen] = React.useState(!1), [serverUrl, setServerUrl] = React.useState(""), role = "host", [registrationCode, setRegistrationCode] = React.useState(""), [associations, setAssociations] = React.useState({}), [loaded, setLoaded] = React.useState(!1), [writable, setWritable] = React.useState(!1), [busy, setBusy] = React.useState(!1), [reconnectBusy, setReconnectBusy] = React.useState(!1), [hostStatus, setHostStatus] = React.useState(void 0), [notice, setNotice] = React.useState(void 0), [error, setError] = React.useState(void 0), [settingsView, setSettingsView] = React.useState(void 0), persistedServerUrl = settingsView?.config.serverUrl ?? "https://dsh.r2049.cn", association = associations.client ?? associations.host, serverDirty = settingsView !== void 0 && serverUrl !== persistedServerUrl, draftDirty = serverDirty, applyView = (view) => {
2059
2139
  setSettingsView(view), setServerUrl(view.config.serverUrl ?? "https://dsh.r2049.cn"), setAssociations(view.associations ?? (view.association === void 0 ? {} : { host: view.association })), setWritable(view.writable), setLoaded(!0);
@@ -2282,7 +2362,7 @@ Minimum version required to store current data is: ` + bestVersion + `.
2282
2362
  );
2283
2363
  }
2284
2364
  function RemoteWorkspaceAction(props) {
2285
- let { t } = props, [open, setOpen] = React.useState(!1), [status, setStatus] = React.useState(void 0), [devices, setDevices] = React.useState([]), [selectedHost, setSelectedHost] = React.useState(void 0), [workspaces, setWorkspaces] = React.useState([]), [directory, setDirectory] = React.useState(void 0), [path, setPath] = React.useState(""), [addingWorkspace, setAddingWorkspace] = React.useState(!1), [busy, setBusy] = React.useState(!1), [needsAuthorization, setNeedsAuthorization] = React.useState(!1), [email, setEmail] = React.useState(""), [password, setPassword] = React.useState(""), [loginMethod, setLoginMethod] = React.useState(props.preferredQrProvider), [loginMethodManuallySelected, setLoginMethodManuallySelected] = React.useState(!1), [qrSession, setQrSession] = React.useState(void 0), [qrImage, setQrImage] = React.useState(void 0), [qrExpired, setQrExpired] = React.useState(!1), [notice, setNotice] = React.useState(void 0), [error, setError] = React.useState(void 0);
2365
+ let { t } = props, [open, setOpen] = React.useState(!1), [status, setStatus] = React.useState(void 0), [devices, setDevices] = React.useState([]), [selectedHost, setSelectedHost] = React.useState(void 0), [workspaces, setWorkspaces] = React.useState([]), [directory, setDirectory] = React.useState(void 0), [path, setPath] = React.useState(""), [addingWorkspace, setAddingWorkspace] = React.useState(!1), [busy, setBusy] = React.useState(!1), [needsAuthorization, setNeedsAuthorization] = React.useState(!1), [email, setEmail] = React.useState(""), [password, setPassword] = React.useState(""), [loginMethod, setLoginMethod] = React.useState(props.preferredQrProvider), [loginMethodManuallySelected, setLoginMethodManuallySelected] = React.useState(!1), [qrSession, setQrSession] = React.useState(void 0), [qrImage, setQrImage] = React.useState(void 0), [qrExpired, setQrExpired] = React.useState(!1), [progress, setProgress] = React.useState(void 0), progressRun = React.useRef(0), [notice, setNotice] = React.useState(void 0), [error, setError] = React.useState(void 0);
2286
2366
  React.useEffect(() => {
2287
2367
  if (!open) return;
2288
2368
  let closeOnEscape = (event) => {
@@ -2347,7 +2427,12 @@ Minimum version required to store current data is: ` + bestVersion + `.
2347
2427
  }, t(provider === "github" ? "githubLogin" : "zhihuLogin")), selectHost = async (host) => {
2348
2428
  setBusy(!0), setError(void 0);
2349
2429
  try {
2350
- setWorkspaces(await props.control("workspaces.list", { targetDeviceId: host.deviceId })), setSelectedHost(host), setPath(""), setAddingWorkspace(!1), setDirectory(void 0);
2430
+ setWorkspaces(await runRemoteProgress(
2431
+ connectHostProgressSteps,
2432
+ setProgress,
2433
+ progressRun,
2434
+ () => props.control("workspaces.list", { targetDeviceId: host.deviceId })
2435
+ )), setSelectedHost(host), setPath(""), setAddingWorkspace(!1), setDirectory(void 0);
2351
2436
  } catch (reason) {
2352
2437
  setError(messageOf(reason));
2353
2438
  } finally {
@@ -2423,10 +2508,15 @@ Minimum version required to store current data is: ` + bestVersion + `.
2423
2508
  if (!(selectedHost === void 0 || path.trim() === "")) {
2424
2509
  setBusy(!0), setError(void 0);
2425
2510
  try {
2426
- await props.control("workspace.open", {
2427
- targetDeviceId: selectedHost.deviceId,
2428
- path: path.trim()
2429
- }), window.location.reload();
2511
+ await runRemoteProgress(
2512
+ openWorkspaceProgressSteps,
2513
+ setProgress,
2514
+ progressRun,
2515
+ () => props.control("workspace.open", {
2516
+ targetDeviceId: selectedHost.deviceId,
2517
+ path: path.trim()
2518
+ })
2519
+ ), window.location.reload();
2430
2520
  } catch (reason) {
2431
2521
  setError(messageOf(reason)), setBusy(!1);
2432
2522
  }
@@ -2663,6 +2753,7 @@ Minimum version required to store current data is: ` + bestVersion + `.
2663
2753
  React.createElement("small", null, [formatPlatform(selectedHost.platform), t("online")].join(" \xB7 "))
2664
2754
  )
2665
2755
  ),
2756
+ React.createElement(RemoteProgressView, { progress, t }),
2666
2757
  selectedHost === void 0 ? React.createElement("p", { className: "dshRemoteHint" }, t("selectHostHint")) : React.createElement(
2667
2758
  "section",
2668
2759
  { className: "dshRemoteBrowser", "aria-label": t("chooseDirectory") },
@@ -2742,7 +2833,7 @@ Minimum version required to store current data is: ` + bestVersion + `.
2742
2833
  );
2743
2834
  }
2744
2835
  function RemoteModeAction(props) {
2745
- let { t } = props, [open, setOpen] = React.useState(!1), [status, setStatus] = React.useState(void 0), [devices, setDevices] = React.useState([]), [hostRegistrationCode, setHostRegistrationCode] = React.useState(""), [email, setEmail] = React.useState(""), [password, setPassword] = React.useState(""), [busy, setBusy] = React.useState(!1), [error, setError] = React.useState(void 0), [supported, setSupported] = React.useState(!0), refresh = async () => {
2836
+ let { t } = props, [open, setOpen] = React.useState(!1), [status, setStatus] = React.useState(void 0), [devices, setDevices] = React.useState([]), [hostRegistrationCode, setHostRegistrationCode] = React.useState(""), [email, setEmail] = React.useState(""), [password, setPassword] = React.useState(""), [busy, setBusy] = React.useState(!1), [progress, setProgress] = React.useState(void 0), progressRun = React.useRef(0), [error, setError] = React.useState(void 0), [supported, setSupported] = React.useState(!0), refresh = async () => {
2746
2837
  let [nextStatus, nextDevices] = await Promise.all([
2747
2838
  props.control("status"),
2748
2839
  props.control("devices").catch(() => [])
@@ -2766,7 +2857,8 @@ Minimum version required to store current data is: ` + bestVersion + `.
2766
2857
  let switchMode = async (mode, targetDeviceId) => {
2767
2858
  setBusy(!0), setError(void 0);
2768
2859
  try {
2769
- await props.control("mode.set", { mode, ...targetDeviceId === void 0 ? {} : { targetDeviceId } }), window.location.reload();
2860
+ let action = () => props.control("mode.set", { mode, ...targetDeviceId === void 0 ? {} : { targetDeviceId } });
2861
+ mode === "remote" ? await runRemoteProgress(connectHostProgressSteps, setProgress, progressRun, action) : await action(), window.location.reload();
2770
2862
  } catch (reason) {
2771
2863
  setError(messageOf(reason)), setBusy(!1);
2772
2864
  }
@@ -2831,6 +2923,7 @@ Minimum version required to store current data is: ` + bestVersion + `.
2831
2923
  disabled: busy || !device.online || status?.target?.deviceId === device.deviceId,
2832
2924
  onClick: () => void switchMode("remote", device.deviceId)
2833
2925
  }, `${device.name} \xB7 ${t(device.online ? "online" : "offline")}`))),
2926
+ React.createElement(RemoteProgressView, { progress, t }),
2834
2927
  status?.hostAuthorizationAvailable && status.host !== void 0 ? React.createElement(
2835
2928
  "div",
2836
2929
  { className: "dshRemoteHostAccount" },
@@ -3076,6 +3169,7 @@ Minimum version required to store current data is: ` + bestVersion + `.
3076
3169
  ".dshRemoteSectionHeading>.dshRemoteAddWorkspace{width:30px;height:30px;display:inline-flex;align-items:center;justify-content:center;padding:0;border-radius:50%;font-size:20px;line-height:1}.dshRemoteSectionHeading>.dshRemoteAddWorkspace:hover{color:var(--dsw-alias-label-primary);background:var(--dsw-alias-interactive-bg-hover)}",
3077
3170
  ".dshRemoteHostList{display:flex;flex-direction:column;border-top:1px solid var(--dsw-alias-border-l2)}.dshRemoteHostList>button{min-height:58px;display:flex;align-items:center;justify-content:space-between;gap:16px;text-align:left;border:0;border-bottom:1px solid var(--dsw-alias-border-l2);background:transparent;padding:10px 4px;cursor:pointer}.dshRemoteHostList>button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}.dshRemoteHostList>button:disabled{opacity:.5;cursor:default}.dshRemoteHostList>button>span{min-width:0;display:flex;flex-direction:column;gap:3px}.dshRemoteHostList>button strong{font-size:14px;font-weight:500}.dshRemoteHostList small,.dshRemoteSelectedHost small{color:var(--dsw-alias-label-secondary);font-size:12px}",
3078
3171
  ".dshRemoteSelectedHost{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:12px 14px;border-radius:10px;background:var(--dsw-alias-bg-layer-2)}",
3172
+ ".dshRemoteProgress{display:flex;flex-direction:column;gap:8px;margin:12px 0;padding:12px 14px;border:1px solid var(--dsw-alias-border-l2);border-radius:10px;background:var(--dsw-alias-bg-layer-2)}.dshRemoteProgressHeader{display:flex;align-items:center;justify-content:space-between;gap:12px}.dshRemoteProgressHeader strong{font-size:13px;font-weight:600}.dshRemoteProgressHeader span{color:var(--dsw-alias-label-secondary);font-size:12px}.dshRemoteProgressBar{height:6px;overflow:hidden;border-radius:999px;background:var(--dsw-alias-bg-layer-3)}.dshRemoteProgressBar>span{display:block;height:100%;border-radius:inherit;background:var(--dsw-alias-brand-primary);transition:width .22s ease-out}.dshRemoteProgress p{margin:0;color:var(--dsw-alias-label-secondary);font-size:12px;line-height:1.45}@media(prefers-reduced-motion:reduce){.dshRemoteProgressBar>span{transition:none}}",
3079
3173
  '.dshRemoteBrowser{display:flex;flex-direction:column}.dshRemoteCrumbs{display:flex;align-items:center;gap:4px;overflow:auto;padding:2px 0 10px}.dshRemoteCrumbs>button{flex:0 0 auto;border:0;background:transparent;color:var(--dsw-alias-label-secondary);padding:5px 7px;border-radius:6px;cursor:pointer}.dshRemoteCrumbs>button:not(:last-child)::after{content:" /";color:var(--dsw-alias-label-tertiary)}.dshRemoteCrumbs>button:disabled{color:var(--dsw-alias-label-primary);font-weight:600}',
3080
3174
  ".dshRemoteDirectoryList{min-height:72px;display:flex;flex-direction:column;border-top:1px solid var(--dsw-alias-border-l2)}.dshRemoteDirectoryList>button{min-height:52px;display:grid;grid-template-columns:auto 1fr;column-gap:10px;text-align:left;border:0;border-bottom:1px solid var(--dsw-alias-border-l2);background:transparent;padding:8px 4px;cursor:pointer}.dshRemoteDirectoryList>button:hover,.dshRemoteDirectoryList>button.isSelected{background:var(--dsw-alias-interactive-bg-hover)}.dshRemoteDirectoryList>button.isSelected{color:var(--dsw-alias-label-primary)}.dshRemoteDirectoryList>button>span:first-child{grid-row:1/3}.dshRemoteDirectoryList>button>small{grid-column:2;color:var(--dsw-alias-label-secondary);overflow:hidden;text-overflow:ellipsis}.dshRemoteDirectoryList>p,.dshRemoteHint{margin:12px 0;color:var(--dsw-alias-label-secondary);font-size:13px}",
3081
3175
  ".dshRemoteFolderBrowser{margin-top:14px}.dshRemoteFolderBrowser>p,.dshRemoteFolderList>p{margin:12px 0;color:var(--dsw-alias-label-secondary);font-size:13px}.dshRemoteFolderList{max-height:260px;overflow:auto;border-block:1px solid var(--dsw-alias-border-l2)}.dshRemoteFolderList>button{width:100%;min-height:42px;display:flex;align-items:center;gap:9px;border:0;border-bottom:1px solid var(--dsw-alias-border-l2);background:transparent;padding:7px 6px;text-align:left;cursor:pointer}.dshRemoteFolderList>button:hover{background:var(--dsw-alias-interactive-bg-hover)}.dshRemoteFolderBrowser>small{display:block;margin-top:8px;color:var(--dsw-alias-state-warn-label)}",