add overlay if daemon not compatible

This commit is contained in:
Eduard Gert
2026-06-17 14:06:38 +02:00
parent 6e696719c8
commit 622e5e140f
11 changed files with 131 additions and 2 deletions

View File

@@ -0,0 +1,52 @@
import { useTranslation } from "react-i18next";
import { AlertTriangleIcon, DownloadIcon } from "lucide-react";
import { Browser } from "@wailsio/runtime";
import { Button } from "@/components/buttons/Button";
import { useStatus } from "@/contexts/StatusContext.tsx";
const RELEASES_URL = "https://github.com/netbirdio/netbird/releases/latest";
function openUrl(url: string) {
Browser.OpenURL(url).catch(() => globalThis.open(url, "_blank"));
}
export const DaemonOutdatedOverlay = () => {
const { t } = useTranslation();
const { isDaemonOutdated } = useStatus();
if (!isDaemonOutdated) return null;
return (
<div
className={
"fixed inset-0 z-[100] flex items-center justify-center bg-nb-gray-950 backdrop-blur-sm cursor-default select-none wails-draggable"
}
>
<div className={"flex flex-col items-center gap-5 px-8 max-w-lg text-center"}>
<div
className={
"h-11 w-11 rounded-xl flex items-center justify-center bg-nb-gray-920 border border-nb-gray-900 text-amber-500"
}
>
<AlertTriangleIcon size={20} />
</div>
<div className={"flex flex-col items-center gap-1"}>
<p className={"text-base font-medium text-nb-gray-50"}>
{t("daemon.outdated.title")}
</p>
<p className={"text-sm text-nb-gray-300"}>
{t("daemon.outdated.description")}
</p>
</div>
<div className={"wails-no-draggable"}>
<Button variant={"primary"} size={"xs"} onClick={() => openUrl(RELEASES_URL)}>
<DownloadIcon size={14} />
{t("update.card.getInstaller")}
</Button>
</div>
</div>
</div>
);
};

View File

@@ -10,7 +10,9 @@ import {
import { Events } from "@wailsio/runtime";
import { DaemonFeed } from "@bindings/services";
import { Status } from "@bindings/services/models.js";
import { DaemonOutdatedOverlay } from "@/components/empty-state/DaemonOutdatedOverlay.tsx";
import { DaemonUnavailableOverlay } from "@/components/empty-state/DaemonUnavailableOverlay.tsx";
import { isDaemonCompatible } from "@/lib/compat";
const EVENT_STATUS = "netbird:status";
@@ -21,6 +23,7 @@ type StatusContextValue = {
isReady: boolean;
isDaemonUnavailable: boolean;
isDaemonAvailable: boolean;
isDaemonOutdated: boolean;
};
const StatusContext = createContext<StatusContextValue | null>(null);
@@ -36,6 +39,7 @@ export const useStatus = () => {
export const StatusProvider = ({ children }: { children: ReactNode }) => {
const [status, setStatus] = useState<Status | null>(null);
const [error, setError] = useState<string | null>(null);
const [isDaemonOutdated, setIsDaemonOutdated] = useState(false);
const refresh = useCallback(async () => {
try {
@@ -64,6 +68,21 @@ export const StatusProvider = ({ children }: { children: ReactNode }) => {
const isDaemonUnavailable = isReady && status.status === "DaemonUnavailable";
const isDaemonAvailable = isReady && !isDaemonUnavailable;
useEffect(() => {
if (!isDaemonAvailable) return;
let cancelled = false;
isDaemonCompatible()
.then((ok) => {
if (!cancelled) setIsDaemonOutdated(!ok);
})
.catch((err) => {
console.error("[StatusContext] daemon compatible error", err);
});
return () => {
cancelled = true;
};
}, [isDaemonAvailable]);
const value = useMemo<StatusContextValue>(
() => ({
status,
@@ -72,14 +91,16 @@ export const StatusProvider = ({ children }: { children: ReactNode }) => {
isReady,
isDaemonUnavailable,
isDaemonAvailable,
isDaemonOutdated,
}),
[status, error, refresh, isReady, isDaemonUnavailable, isDaemonAvailable],
[status, error, refresh, isReady, isDaemonUnavailable, isDaemonAvailable, isDaemonOutdated],
);
return (
<StatusContext.Provider value={value}>
{isDaemonAvailable && children}
{isDaemonAvailable && !isDaemonOutdated && children}
<DaemonUnavailableOverlay />
<DaemonOutdatedOverlay />
</StatusContext.Provider>
);
};

View File

@@ -1250,6 +1250,12 @@
"daemon.unavailable.docsLink": {
"message": "Dokumentation"
},
"daemon.outdated.title": {
"message": "NetBird-Dienst ist veraltet"
},
"daemon.outdated.description": {
"message": "Aktualisieren Sie den NetBird-Dienst, um diese App zu verwenden."
},
"error.jwt_clock_skew": {
"message": "Anmeldung fehlgeschlagen: Die Uhr dieses Geräts ist nicht mit dem Server synchron. Bitte synchronisieren Sie die Systemuhr und versuchen Sie es erneut."
},

View File

@@ -1667,6 +1667,14 @@
"message": "Documentation",
"description": "Documentation link on the daemon-unavailable overlay."
},
"daemon.outdated.title": {
"message": "NetBird Service Is Outdated",
"description": "Title of the overlay shown when the NetBird background service is too old to drive this UI."
},
"daemon.outdated.description": {
"message": "Update the NetBird service to use this app.",
"description": "Body of the daemon-outdated overlay telling the user to upgrade the service."
},
"error.jwt_clock_skew": {
"message": "Sign-in failed: this device's clock is out of sync with the server. Please sync your system clock and try again.",
"description": "Sign-in error shown to the user: the device clock is out of sync with the server."

View File

@@ -1250,6 +1250,12 @@
"daemon.unavailable.docsLink": {
"message": "Documentación"
},
"daemon.outdated.title": {
"message": "El servicio de NetBird está desactualizado"
},
"daemon.outdated.description": {
"message": "Actualice el servicio de NetBird para usar esta aplicación."
},
"error.jwt_clock_skew": {
"message": "Error al iniciar sesión: el reloj de este dispositivo no está sincronizado con el servidor. Sincronice el reloj del sistema e inténtelo de nuevo."
},

View File

@@ -1250,6 +1250,12 @@
"daemon.unavailable.docsLink": {
"message": "Documentation"
},
"daemon.outdated.title": {
"message": "Le service NetBird est obsolète"
},
"daemon.outdated.description": {
"message": "Mettez à jour le service NetBird pour utiliser cette application."
},
"error.jwt_clock_skew": {
"message": "Échec de la connexion : lhorloge de cet appareil nest pas synchronisée avec le serveur. Veuillez synchroniser lhorloge de votre système et réessayer."
},

View File

@@ -1250,6 +1250,12 @@
"daemon.unavailable.docsLink": {
"message": "Dokumentáció"
},
"daemon.outdated.title": {
"message": "A NetBird szolgáltatás elavult"
},
"daemon.outdated.description": {
"message": "Frissítsd a NetBird szolgáltatást az alkalmazás használatához."
},
"error.jwt_clock_skew": {
"message": "A bejelentkezés sikertelen: az eszköz órája eltér a szerverétől. Kérjük, szinkronizálja a rendszer óráját, majd próbálja újra."
},

View File

@@ -1250,6 +1250,12 @@
"daemon.unavailable.docsLink": {
"message": "Documentazione"
},
"daemon.outdated.title": {
"message": "Il servizio NetBird è obsoleto"
},
"daemon.outdated.description": {
"message": "Aggiorna il servizio NetBird per usare questa app."
},
"error.jwt_clock_skew": {
"message": "Accesso non riuscito: l'orologio di questo dispositivo non è sincronizzato con il server. Sincronizzi l'orologio di sistema e riprovi."
},

View File

@@ -1250,6 +1250,12 @@
"daemon.unavailable.docsLink": {
"message": "Documentação"
},
"daemon.outdated.title": {
"message": "O serviço NetBird está desatualizado"
},
"daemon.outdated.description": {
"message": "Atualize o serviço NetBird para usar este aplicativo."
},
"error.jwt_clock_skew": {
"message": "Falha no login: o relógio deste dispositivo está fora de sincronia com o servidor. Sincronize o relógio do sistema e tente novamente."
},

View File

@@ -1250,6 +1250,12 @@
"daemon.unavailable.docsLink": {
"message": "Документация"
},
"daemon.outdated.title": {
"message": "Служба NetBird устарела"
},
"daemon.outdated.description": {
"message": "Обновите службу NetBird, чтобы использовать это приложение."
},
"error.jwt_clock_skew": {
"message": "Не удалось войти: часы этого устройства рассинхронизированы с сервером. Синхронизируйте системные часы и повторите попытку."
},

View File

@@ -1250,6 +1250,12 @@
"daemon.unavailable.docsLink": {
"message": "文档"
},
"daemon.outdated.title": {
"message": "NetBird 服务版本过旧"
},
"daemon.outdated.description": {
"message": "请更新 NetBird 服务以使用此应用。"
},
"error.jwt_clock_skew": {
"message": "登录失败:此设备的时钟与服务器不同步。请同步您的系统时钟后重试。"
},