3d958d0411
- Home Assistant administrators are admins: Dashboard, Builder and Admin screens - Everyone else only sees the dashboards an admin chose, always in kiosk mode; the server enforces it (saving, people, devices, history are admin-only, and the websocket only allows reading states and controlling devices) - Admin screen: dashboards, people and what each sees (with preview), devices, messages to the screens, the Haven app, activity, about - Haven: new Android app (haven/) that only shows dashboards; replaces the Dashboard Studio Android app and signs in through Home Assistant's page - Screens pick up dashboard and access changes within a minute - Version history records who made each change; panel visible to all users Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
34 lines
1.6 KiB
JavaScript
34 lines
1.6 KiB
JavaScript
/* Dashboard Studio service worker: always the network first, so updates show straight away.
|
|
* When the network fails (or Home Assistant's ingress session has run out), it answers with
|
|
* the last good copy, so the app can start, show the last known states and reconnect. */
|
|
const CACHE = "ds-__VERSION__";
|
|
const SKIP = /\/(ws|api\/camera|api\/immich|api\/history)/;
|
|
|
|
self.addEventListener("install", () => self.skipWaiting());
|
|
self.addEventListener("activate", (e) => {
|
|
e.waitUntil(caches.keys().then((keys) => Promise.all(keys.filter((k) => k.startsWith("ds-") && k !== CACHE).map((k) => caches.delete(k)))).then(() => self.clients.claim()));
|
|
});
|
|
self.addEventListener("fetch", (e) => {
|
|
const req = e.request, url = new URL(req.url);
|
|
if (req.method !== "GET" || url.origin !== location.origin || SKIP.test(url.pathname)) return;
|
|
const page = req.mode === "navigate";
|
|
e.respondWith((async () => {
|
|
const cache = await caches.open(CACHE);
|
|
try {
|
|
const res = await fetch(req);
|
|
if (res.ok) {
|
|
cache.put(page ? new Request(new URL("./", self.registration.scope)) : req, res.clone());
|
|
return res;
|
|
}
|
|
if (!page) return res;
|
|
// Signed out of Home Assistant: the last good copy renews the session itself. Without one, pass
|
|
// the refusal on, so Haven knows to sign in again.
|
|
return (await cache.match(new URL("./", self.registration.scope).href)) || res;
|
|
} catch (err) {
|
|
const hit = page ? await cache.match(new URL("./", self.registration.scope).href) : await cache.match(req);
|
|
if (hit) return hit;
|
|
throw err;
|
|
}
|
|
})());
|
|
});
|