feat: Add service worker with offline support and route caching to web dashboard

- Add offline.html fallback page with gradient background, centered container, and retry button
- Add sw.js service worker with telecom-dashboard-v1 cache for dashboard routes
- Add install event handler caching /, /login, /dashboard, /services, /monitoring, /deploy, /plugins, /automation, /chaos, /billing, and /config routes
- Add fetch event handler with cache-first strategy and offline.html fallback
- Add activate event
This commit is contained in:
nutcas3
2026-04-25 05:58:10 +03:00
parent 131f9a0d69
commit 0e11bf49dc
4 changed files with 134 additions and 0 deletions
+59
View File
@@ -0,0 +1,59 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Offline - Telecom Dashboard</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, sans-serif;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
color: white;
}
.container {
text-align: center;
padding: 2rem;
background: rgba(255, 255, 255, 0.1);
border-radius: 1rem;
backdrop-filter: blur(10px);
max-width: 500px;
}
h1 {
font-size: 2rem;
margin-bottom: 1rem;
}
p {
font-size: 1.1rem;
margin-bottom: 1.5rem;
opacity: 0.9;
}
button {
background: white;
color: #667eea;
border: none;
padding: 0.75rem 1.5rem;
border-radius: 0.5rem;
font-size: 1rem;
cursor: pointer;
font-weight: 600;
transition: transform 0.2s, box-shadow 0.2s;
}
button:hover {
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
}
</style>
</head>
<body>
<div class="container">
<h1>You're Offline</h1>
<p>Check your internet connection and try again.</p>
<button onclick="window.location.reload()">Retry</button>
</div>
</body>
</html>
+51
View File
@@ -0,0 +1,51 @@
const CACHE_NAME = 'telecom-dashboard-v1';
const urlsToCache = [
'/',
'/login',
'/dashboard',
'/services',
'/monitoring',
'/deploy',
'/plugins',
'/automation',
'/chaos',
'/billing',
'/config',
];
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME)
.then((cache) => {
return cache.addAll(urlsToCache);
})
);
});
self.addEventListener('fetch', (event) => {
event.respondWith(
caches.match(event.request)
.then((response) => {
if (response) {
return response;
}
return fetch(event.request).catch(() => {
return caches.match('/offline.html');
});
})
);
});
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys().then((cacheNames) => {
return Promise.all(
cacheNames.map((cacheName) => {
if (cacheName !== CACHE_NAME) {
return caches.delete(cacheName);
}
})
);
})
);
});
+2
View File
@@ -4,6 +4,7 @@ import "./globals.css";
import { cn } from "@/lib/utils";
import { Sidebar } from "@/components/sidebar";
import { Providers } from "./providers";
import { ServiceWorkerRegistration } from "@/components/service-worker-registration";
const inter = Inter({ subsets: ["latin"], variable: "--font-sans" });
@@ -34,6 +35,7 @@ export default function RootLayout({
>
<body className="min-h-full flex">
<Providers>
<ServiceWorkerRegistration />
<Sidebar />
<main className="flex-1 overflow-auto">{children}</main>
</Providers>
@@ -0,0 +1,22 @@
"use client";
import { useEffect } from "react";
export function ServiceWorkerRegistration() {
useEffect(() => {
if ("serviceWorker" in navigator && process.env.NEXT_PUBLIC_ENABLE_SW === "true") {
window.addEventListener("load", () => {
navigator.serviceWorker
.register("/sw.js")
.then((registration) => {
console.log("Service Worker registered: ", registration);
})
.catch((registrationError) => {
console.log("Service Worker registration failed: ", registrationError);
});
});
}
}, []);
return null;
}