update about gui version, add mock data, truncate some strings

This commit is contained in:
Eduard Gert
2026-06-01 17:14:30 +02:00
parent a4ad93008b
commit 3f989f69cb
14 changed files with 844 additions and 66 deletions
@@ -32,6 +32,10 @@ const EVENT_TRIGGER_LOGIN = "trigger-login";
const NEEDS_LOGIN_STATES = new Set(["NeedsLogin", "SessionExpired", "LoginFailed"]);
// Re-enable the switch after this long in a transitioning state so the user
// can force a Connection.Down on a stuck Connecting/Disconnecting flow.
const FORCE_TOGGLE_DELAY_MS = 7000;
const errorMessage = formatErrorMessage;
// startLogin drives the daemon's SSO login end-to-end. The BrowserLogin
@@ -280,7 +284,12 @@ export const MainConnectionStatusSwitch = () => {
}, [driveLogin]);
const handleSwitch = (next: boolean) => {
if (unreachable || action !== null) return;
if (unreachable) return;
if (isTransitioning) {
if (canForceCancel) void forceCancel();
return;
}
if (action !== null) return;
if (needsLogin) {
driveLogin();
return;
@@ -296,6 +305,38 @@ export const MainConnectionStatusSwitch = () => {
connState === ConnectionState.Connecting || connState === ConnectionState.Disconnecting;
const isOn =
connState === ConnectionState.Connected || connState === ConnectionState.Connecting;
// When the daemon hangs in Connecting/Disconnecting, give the user an
// escape hatch: after the delay, the switch becomes clickable again so a
// tap fires Connection.Down (plus cancels any in-flight SSO flow).
const [canForceCancel, setCanForceCancel] = useState(false);
useEffect(() => {
if (!isTransitioning) {
setCanForceCancel(false);
return;
}
const id = setTimeout(() => setCanForceCancel(true), FORCE_TOGGLE_DELAY_MS);
return () => clearTimeout(id);
}, [isTransitioning]);
const forceCancel = async () => {
if (action === "logging-in") {
void Events.Emit(EVENT_BROWSER_LOGIN_CANCEL);
}
WindowManager.CloseBrowserLogin().catch(() => {});
setAction("disconnect");
try {
await Connection.Down();
await refresh();
} catch (e) {
setAction(null);
await refresh();
await Dialogs.Error({
Title: t("connect.error.disconnectTitle"),
Message: errorMessage(e),
});
}
};
const showLocal = connState === ConnectionState.Connected;
const fqdn = status?.local.fqdn || "";
const ip = status?.local.ip || "";
@@ -313,7 +354,7 @@ export const MainConnectionStatusSwitch = () => {
size={"large"}
checked={isOn}
onCheckedChange={handleSwitch}
disabled={isTransitioning || unreachable}
disabled={(isTransitioning && !canForceCancel) || unreachable}
className={cn(unreachable && "opacity-80", isTransitioning && "animate-pulse")}
/>