Files
wled-screen-controller-mixed/server/src/wled_controller/static/sw.js
alexei.dolgolyov 5b4813368b Add visual selectors to automation and KC target editors
Automation editor:
- IconSelect grid for condition logic (OR/AND) with descriptions

KC target editor:
- IconSelect for color mode (average/median/dominant) with SVG previews
- EntitySelect palette for picture source, pattern template, brightness source

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 10:12:57 +03:00

95 lines
3.2 KiB
JavaScript

/**
* Service Worker for LED Grab PWA.
*
* Strategy:
* - Static assets (/static/): stale-while-revalidate
* - API / config requests: network-only (device control must be live)
* - Navigation: network-first with offline fallback
*/
const CACHE_NAME = 'ledgrab-v23';
// Only pre-cache static assets (no auth required).
// Do NOT pre-cache '/' — it requires API key auth and would cache an error page.
const PRECACHE_URLS = [
'/static/css/base.css',
'/static/css/layout.css',
'/static/css/components.css',
'/static/css/cards.css',
'/static/css/modal.css',
'/static/css/calibration.css',
'/static/css/dashboard.css',
'/static/css/streams.css',
'/static/css/patterns.css',
'/static/css/automations.css',
'/static/css/tutorials.css',
'/static/css/mobile.css',
'/static/icons/icon-192.png',
'/static/icons/icon-512.png',
];
// Install: pre-cache core shell
self.addEventListener('install', (event) => {
event.waitUntil(
caches.open(CACHE_NAME)
.then((cache) => cache.addAll(PRECACHE_URLS))
.then(() => self.skipWaiting())
);
});
// Activate: clean old caches
self.addEventListener('activate', (event) => {
event.waitUntil(
caches.keys()
.then((keys) => Promise.all(
keys.filter((k) => k !== CACHE_NAME).map((k) => caches.delete(k))
))
.then(() => self.clients.claim())
);
});
// Fetch handler
self.addEventListener('fetch', (event) => {
const url = new URL(event.request.url);
// API and config: always network (device control must be live)
if (url.pathname.startsWith('/api/') || url.pathname.startsWith('/config/')) {
return; // fall through to default network fetch
}
// Static assets: stale-while-revalidate
if (url.pathname.startsWith('/static/')) {
event.respondWith(
caches.open(CACHE_NAME).then((cache) =>
cache.match(event.request).then((cached) => {
const fetchPromise = fetch(event.request).then((response) => {
if (response.ok) {
cache.put(event.request, response.clone());
}
return response;
}).catch(() => cached);
return cached || fetchPromise;
})
)
);
return;
}
// Navigation: network-only (page requires auth, no useful offline fallback)
if (event.request.mode === 'navigate') {
event.respondWith(
fetch(event.request).catch(() =>
new Response(
'<html><body style="font-family:system-ui;text-align:center;padding:60px 20px;background:#1a1a1a;color:#ccc">' +
'<h2>LED Grab</h2><p>Cannot reach the server. Check that it is running and you are on the same network.</p>' +
'<button onclick="location.reload()" style="margin-top:20px;padding:10px 24px;border-radius:8px;border:none;background:#4CAF50;color:#fff;font-size:1rem;cursor:pointer">Retry</button>' +
'</body></html>',
{ status: 503, headers: { 'Content-Type': 'text/html' } }
)
)
);
return;
}
});