diff --git a/client/ui/frontend/src/components/empty-state/DaemonOutdatedOverlay.tsx b/client/ui/frontend/src/components/empty-state/DaemonOutdatedOverlay.tsx
new file mode 100644
index 000000000..b18f83d52
--- /dev/null
+++ b/client/ui/frontend/src/components/empty-state/DaemonOutdatedOverlay.tsx
@@ -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 (
+
+
+
+
+
+
+ {t("daemon.outdated.title")}
+
+
+ {t("daemon.outdated.description")}
+
+
+
+
+
+
+
+
+ );
+};
diff --git a/client/ui/frontend/src/contexts/StatusContext.tsx b/client/ui/frontend/src/contexts/StatusContext.tsx
index 0164d892e..0ad9c7875 100644
--- a/client/ui/frontend/src/contexts/StatusContext.tsx
+++ b/client/ui/frontend/src/contexts/StatusContext.tsx
@@ -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(null);
@@ -36,6 +39,7 @@ export const useStatus = () => {
export const StatusProvider = ({ children }: { children: ReactNode }) => {
const [status, setStatus] = useState(null);
const [error, setError] = useState(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(
() => ({
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 (
- {isDaemonAvailable && children}
+ {isDaemonAvailable && !isDaemonOutdated && children}
+
);
};
diff --git a/client/ui/i18n/locales/de/common.json b/client/ui/i18n/locales/de/common.json
index 66249250e..c1751acd8 100644
--- a/client/ui/i18n/locales/de/common.json
+++ b/client/ui/i18n/locales/de/common.json
@@ -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."
},
diff --git a/client/ui/i18n/locales/en/common.json b/client/ui/i18n/locales/en/common.json
index 0d64b2657..a8dff2e29 100644
--- a/client/ui/i18n/locales/en/common.json
+++ b/client/ui/i18n/locales/en/common.json
@@ -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."
diff --git a/client/ui/i18n/locales/es/common.json b/client/ui/i18n/locales/es/common.json
index bafddb096..87ae60460 100644
--- a/client/ui/i18n/locales/es/common.json
+++ b/client/ui/i18n/locales/es/common.json
@@ -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."
},
diff --git a/client/ui/i18n/locales/fr/common.json b/client/ui/i18n/locales/fr/common.json
index 2b76863df..1ec0f9356 100644
--- a/client/ui/i18n/locales/fr/common.json
+++ b/client/ui/i18n/locales/fr/common.json
@@ -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 : l’horloge de cet appareil n’est pas synchronisée avec le serveur. Veuillez synchroniser l’horloge de votre système et réessayer."
},
diff --git a/client/ui/i18n/locales/hu/common.json b/client/ui/i18n/locales/hu/common.json
index 20d596453..7cab54828 100644
--- a/client/ui/i18n/locales/hu/common.json
+++ b/client/ui/i18n/locales/hu/common.json
@@ -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."
},
diff --git a/client/ui/i18n/locales/it/common.json b/client/ui/i18n/locales/it/common.json
index b75b85eef..bff7c4ce6 100644
--- a/client/ui/i18n/locales/it/common.json
+++ b/client/ui/i18n/locales/it/common.json
@@ -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."
},
diff --git a/client/ui/i18n/locales/pt/common.json b/client/ui/i18n/locales/pt/common.json
index f2ce6471c..aa95540b2 100644
--- a/client/ui/i18n/locales/pt/common.json
+++ b/client/ui/i18n/locales/pt/common.json
@@ -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."
},
diff --git a/client/ui/i18n/locales/ru/common.json b/client/ui/i18n/locales/ru/common.json
index 866e1e495..8c548818f 100644
--- a/client/ui/i18n/locales/ru/common.json
+++ b/client/ui/i18n/locales/ru/common.json
@@ -1250,6 +1250,12 @@
"daemon.unavailable.docsLink": {
"message": "Документация"
},
+ "daemon.outdated.title": {
+ "message": "Служба NetBird устарела"
+ },
+ "daemon.outdated.description": {
+ "message": "Обновите службу NetBird, чтобы использовать это приложение."
+ },
"error.jwt_clock_skew": {
"message": "Не удалось войти: часы этого устройства рассинхронизированы с сервером. Синхронизируйте системные часы и повторите попытку."
},
diff --git a/client/ui/i18n/locales/zh-CN/common.json b/client/ui/i18n/locales/zh-CN/common.json
index 848e497b5..9e68efef0 100644
--- a/client/ui/i18n/locales/zh-CN/common.json
+++ b/client/ui/i18n/locales/zh-CN/common.json
@@ -1250,6 +1250,12 @@
"daemon.unavailable.docsLink": {
"message": "文档"
},
+ "daemon.outdated.title": {
+ "message": "NetBird 服务版本过旧"
+ },
+ "daemon.outdated.description": {
+ "message": "请更新 NetBird 服务以使用此应用。"
+ },
"error.jwt_clock_skew": {
"message": "登录失败:此设备的时钟与服务器不同步。请同步您的系统时钟后重试。"
},