Merge remote-tracking branch 'origin/ui-refactor' into ui-refactor

# Conflicts:
#	client/ui/frontend/src/screens/Update.tsx
This commit is contained in:
Eduard Gert
2026-05-21 09:34:45 +02:00
59 changed files with 6967 additions and 2714 deletions
@@ -7,6 +7,7 @@ import { ToggleSwitch } from "@/components/ToggleSwitch.tsx";
import { useStatus } from "@/modules/daemon-status/StatusContext.tsx";
import { useProfile } from "@/modules/profile/ProfileContext.tsx";
import { cn } from "@/lib/cn.ts";
import { formatErrorMessage } from "@/lib/errors.ts";
import netbirdFullLogo from "@/assets/logos/netbird-full.svg";
enum ConnectionState {
@@ -38,8 +39,7 @@ const NEEDS_LOGIN_STATES = new Set([
"LoginFailed",
]);
const errorMessage = (e: unknown) =>
e instanceof Error ? e.message : String(e);
const errorMessage = formatErrorMessage;
// startLogin drives the daemon's SSO login end-to-end. The BrowserLogin
// popup window is the only login UI; errors surface as a native
@@ -230,6 +230,14 @@ export const ConnectionStatusSwitch = () => {
// See connect() above — clear via the effect, not eagerly.
};
// Tracks whether the daemon has entered Connecting during the
// current "connect" action. Lets us distinguish "still waiting for
// the daemon to start" (Idle → Idle) from "the connect flow was
// cancelled externally" (Connecting → Idle, e.g. tray Disconnect
// while the UI was Connecting). Reset whenever action returns to
// null.
const sawConnectingRef = useRef(false);
// Release the action latch when the daemon settles on a terminal
// state for the user's intent — and, in the connect → NeedsLogin
// case, hand off to driveLogin so the user doesn't have to click
@@ -237,6 +245,13 @@ export const ConnectionStatusSwitch = () => {
// .finally, not here: Login's internal Down makes the daemon flap
// through Idle, which would otherwise look like a terminal state.
useEffect(() => {
if (action === null) {
sawConnectingRef.current = false;
return;
}
if (daemonState === "Connecting") {
sawConnectingRef.current = true;
}
if (action === "connect") {
if (needsLogin) {
driveLogin();
@@ -244,6 +259,14 @@ export const ConnectionStatusSwitch = () => {
}
if (daemonState === "Connected" || unreachable) {
setAction(null);
return;
}
// Cancelled externally (e.g. tray Disconnect during our
// Connecting): the daemon went back to Idle after we'd
// observed Connecting. Clear the latch so the UI stops
// showing Connecting forever.
if (sawConnectingRef.current && daemonState === "Idle") {
setAction(null);
}
return;
}