diff --git a/js/src/App.vue b/js/src/App.vue index 218a48cdc..f0ef0bfe6 100644 --- a/js/src/App.vue +++ b/js/src/App.vue @@ -117,11 +117,38 @@ export default class App extends Vue { window.addEventListener("offline", () => { this.online = false; this.showOfflineNetworkWarning(); - console.log("offline"); + console.debug("offline"); }); window.addEventListener("online", () => { this.online = true; - console.log("online"); + console.debug("online"); + }); + document.addEventListener("refreshApp", (event: Event) => { + this.$buefy.snackbar.open({ + queue: false, + indefinite: true, + type: "is-primary", + actionText: this.$t("Update app") as string, + cancelText: this.$t("Ignore") as string, + message: this.$t("A new version is available.") as string, + onAction: async () => { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + const detail = event.detail; + const registration = detail as ServiceWorkerRegistration; + try { + await this.refreshApp(registration); + window.location.reload(); + } catch (err) { + console.error(err); + this.$notifier.error( + this.$t( + "An error has occured while refreshing the page." + ) as string + ); + } + }, + }); }); this.interval = setInterval(async () => { @@ -138,6 +165,30 @@ export default class App extends Vue { }, 60000); } + private async refreshApp( + registration: ServiceWorkerRegistration + ): Promise { + const worker = registration.waiting; + if (!worker) { + return Promise.resolve(); + } + console.debug("Doing worker.skipWaiting()."); + return new Promise((resolve, reject) => { + const channel = new MessageChannel(); + + channel.port1.onmessage = (event) => { + console.debug("Done worker.skipWaiting()."); + if (event.data.error) { + reject(event.data); + } else { + resolve(event.data); + } + }; + console.debug("calling skip waiting"); + worker?.postMessage({ type: "skip-waiting" }, [channel.port2]); + }); + } + showOfflineNetworkWarning(): void { this.$notifier.error(this.$t("You are offline") as string); } diff --git a/js/src/i18n/en_US.json b/js/src/i18n/en_US.json index 3cf0514d1..787d95548 100644 --- a/js/src/i18n/en_US.json +++ b/js/src/i18n/en_US.json @@ -1047,5 +1047,11 @@ "Share this group": "Share this group", "This group is accessible only through it's link. Be careful where you post this link.": "This group is accessible only through it's link. Be careful where you post this link.", "{count} members": "No members|One member|{count} members", - "Share": "Share" + "Share": "Share", + "Update app": "Update app", + "Ignore": "Ignore", + "A new version is available.": "A new version is available.", + "An error has occured while refreshing the page.": "An error has occured while refreshing the page.", + "Join group {group}": "Join group {group}", + "Public preview": "Public preview" } diff --git a/js/src/i18n/fr_FR.json b/js/src/i18n/fr_FR.json index 2215a30c7..f5b8257f4 100644 --- a/js/src/i18n/fr_FR.json +++ b/js/src/i18n/fr_FR.json @@ -1138,5 +1138,11 @@ "Share this group": "Partager ce groupe", "This group is accessible only through it's link. Be careful where you post this link.": "Ce groupe est accessible uniquement à travers son lien. Faites attention où vous le diffusez.", "{count} members": "Aucun membre|Un⋅e membre|{count} membres", - "Share": "Partager" + "Share": "Partager", + "Update app": "Mettre à jour", + "Ignore": "Ignorer", + "A new version is available.": "Une nouvelle version est disponible.", + "An error has occured while refreshing the page.": "Une erreur est survenue lors du rafraîchissement de la page.", + "Join group {group}": "Rejoindre le groupe {group}", + "Public preview": "Aperçu public" } diff --git a/js/src/registerServiceWorker.ts b/js/src/registerServiceWorker.ts index 141c1daa4..ee0de1d9b 100644 --- a/js/src/registerServiceWorker.ts +++ b/js/src/registerServiceWorker.ts @@ -5,25 +5,27 @@ import { register } from "register-service-worker"; if ("serviceWorker" in navigator && isProduction()) { register(`${process.env.BASE_URL}service-worker.js`, { ready() { - console.log( + console.debug( "App is being served from cache by a service worker.\n" + "For more details, visit https://goo.gl/AFskqB" ); }, registered() { - console.log("Service worker has been registered."); + console.debug("Service worker has been registered."); }, cached() { - console.log("Content has been cached for offline use."); + console.debug("Content has been cached for offline use."); }, updatefound() { - console.log("New content is downloading."); + console.debug("New content is downloading."); }, - updated() { - console.log("New content is available; please refresh."); + updated(registration: ServiceWorkerRegistration) { + const event = new CustomEvent("refreshApp", { detail: registration }); + document.dispatchEvent(event); + console.debug("New content is available; please refresh."); }, offline() { - console.log( + console.debug( "No internet connection found. App is running in offline mode." ); }, @@ -34,6 +36,5 @@ if ("serviceWorker" in navigator && isProduction()) { } function isProduction(): boolean { - return true; - // return process.env.NODE_ENV === "production"; + return process.env.NODE_ENV === "production"; } diff --git a/js/src/service-worker.ts b/js/src/service-worker.ts index 7ff855658..e87c5cce7 100644 --- a/js/src/service-worker.ts +++ b/js/src/service-worker.ts @@ -124,3 +124,17 @@ self.addEventListener("notificationclick", function (event: NotificationEvent) { })() ); }); + +self.addEventListener("message", (event: ExtendableMessageEvent) => { + const replyPort = event.ports[0]; + const message = event.data; + if (replyPort && message && message.type === "skip-waiting") { + console.log("doing skip waiting"); + event.waitUntil( + self.skipWaiting().then( + () => replyPort.postMessage({ error: null }), + (error) => replyPort.postMessage({ error }) + ) + ); + } +});