PWA update available notification (#42)

This commit is contained in:
konrad 2019-12-18 21:30:20 +00:00
parent 81e9eef154
commit ff0f078ee6
5 changed files with 79 additions and 4 deletions

View file

@ -11,6 +11,10 @@
</router-link> </router-link>
</div> </div>
<div class="navbar-end"> <div class="navbar-end">
<div v-if="updateAvailable" class="update-notification">
<p>There is an update for Vikunja available!</p>
<a @click="refreshApp()" class="button is-primary noshadow">Update Now</a>
</div>
<div class="user"> <div class="user">
<img :src="gravatar()" class="avatar" alt=""/> <img :src="gravatar()" class="avatar" alt=""/>
<div class="dropdown is-right is-active"> <div class="dropdown is-right is-active">
@ -187,6 +191,8 @@
import NamespaceService from './services/namespace' import NamespaceService from './services/namespace'
import authTypes from './models/authTypes' import authTypes from './models/authTypes'
import swEvents from './ServiceWorker/events'
export default { export default {
name: 'app', name: 'app',
@ -201,6 +207,11 @@
userMenuActive: false, userMenuActive: false,
authTypes: authTypes, authTypes: authTypes,
isOnline: true, isOnline: true,
// Service Worker stuff
updateAvailable: false,
registration: null,
refreshing: false,
} }
}, },
beforeMount() { beforeMount() {
@ -226,6 +237,17 @@
if (auth.user.authenticated && auth.user.infos.type === authTypes.USER && (this.$route.params.name === 'home' || this.namespaces.length === 0)) { if (auth.user.authenticated && auth.user.infos.type === authTypes.USER && (this.$route.params.name === 'home' || this.namespaces.length === 0)) {
this.loadNamespaces() this.loadNamespaces()
} }
// Service worker communication
document.addEventListener(swEvents.SW_UPDATED, this.showRefreshUI, { once: true })
navigator.serviceWorker.addEventListener(
'controllerchange', () => {
if (this.refreshing) return;
this.refreshing = true;
window.location.reload();
}
);
}, },
watch: { watch: {
// call the method again if the route changes // call the method again if the route changes
@ -261,6 +283,17 @@
setFullPage() { setFullPage() {
this.fullpage = true; this.fullpage = true;
}, },
showRefreshUI (e) {
console.log('recieved refresh event', e)
this.registration = e.detail;
this.updateAvailable = true;
},
refreshApp () {
this.updateExists = false;
if (!this.registration || !this.registration.waiting) { return; }
// Notify the service worker to actually do the update
this.registration.waiting.postMessage('skipWaiting');
},
}, },
} }
</script> </script>

View file

@ -0,0 +1,3 @@
{
"SW_UPDATED": "swUpdated"
}

View file

@ -19,3 +19,24 @@ workbox.routing.registerRoute(
new RegExp('.*'), new RegExp('.*'),
new workbox.strategies.StaleWhileRevalidate() new workbox.strategies.StaleWhileRevalidate()
); );
// This code listens for the user's confirmation to update the app.
self.addEventListener('message', (e) => {
if (!e.data) {
return;
}
switch (e.data) {
case 'skipWaiting':
self.skipWaiting();
break;
default:
// NOOP
break;
}
});
workbox.core.clientsClaim();
// The precaching code provided by Workbox.
self.__precacheManifest = [].concat(self.__precacheManifest || []);
workbox.precaching.precacheAndRoute(self.__precacheManifest, {});

View file

@ -1,13 +1,12 @@
/* eslint-disable no-console */ /* eslint-disable no-console */
import { register } from 'register-service-worker' import { register } from 'register-service-worker'
import swEvents from './ServiceWorker/events'
if (process.env.NODE_ENV === 'production') { if (process.env.NODE_ENV === 'production') {
register(`${process.env.BASE_URL}sw.js`, { register(`${process.env.BASE_URL}sw.js`, {
ready () { ready () {
console.log( console.log('App is being served from cache by a service worker.')
'App is being served from cache by a service worker.'
)
}, },
registered () { registered () {
console.log('Service worker has been registered.') console.log('Service worker has been registered.')
@ -18,8 +17,12 @@ if (process.env.NODE_ENV === 'production') {
updatefound () { updatefound () {
console.log('New content is downloading.') console.log('New content is downloading.')
}, },
updated () { updated (registration) {
console.log('New content is available; please refresh.') console.log('New content is available; please refresh.')
// Send an event with the updated info
document.dispatchEvent(
new CustomEvent(swEvents.SW_UPDATED, { detail:registration })
)
}, },
offline () { offline () {
console.log('No internet connection found. App is running in offline mode.') console.log('No internet connection found. App is running in offline mode.')

View file

@ -288,3 +288,18 @@ h1,h2,h3,h4,h5,h6{
height: 18px; height: 18px;
} }
} }
.update-notification {
margin: 1em;
display: flex;
align-items: center;
background: $warning;
padding: 0 0 0 .5em;
border-radius: $radius;
font-size: .9em;
color: darken($dark, 5);
.button {
margin-left: .5em;
}
}