Improve PWA support
|
@ -51,6 +51,7 @@
|
|||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/assets",
|
||||
"src/manifest.webmanifest",
|
||||
"src/manifest.webmanifest"
|
||||
],
|
||||
"styles": [
|
||||
|
@ -126,6 +127,7 @@
|
|||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/assets",
|
||||
"src/manifest.webmanifest",
|
||||
"src/manifest.webmanifest"
|
||||
],
|
||||
"styles": [
|
||||
|
|
|
@ -0,0 +1,51 @@
|
|||
import { ApplicationRef, Injectable } from '@angular/core';
|
||||
import { SwUpdate } from '@angular/service-worker';
|
||||
import { TranslateService } from '@ngx-translate/core';
|
||||
import { concat, interval } from 'rxjs';
|
||||
import { first } from 'rxjs/operators';
|
||||
import Swal from 'sweetalert2';
|
||||
|
||||
@Injectable({providedIn: 'root'})
|
||||
export class UpdaterService {
|
||||
//https://angular.io/guide/service-worker-communications
|
||||
constructor(
|
||||
appRef: ApplicationRef,
|
||||
updates: SwUpdate,
|
||||
translate: TranslateService
|
||||
) {
|
||||
// Allow the app to stabilize first, before starting
|
||||
// polling for updates with `interval()`.
|
||||
const appIsStable$ = appRef.isStable.pipe(first(isStable => isStable === true));
|
||||
const everySixHours$ = interval(6 * 60 * 60 * 1000);
|
||||
const everySixHoursOnceAppIsStable$ = concat(appIsStable$, everySixHours$);
|
||||
|
||||
everySixHoursOnceAppIsStable$.subscribe(async () => {
|
||||
try {
|
||||
const updateFound = await updates.checkForUpdate();
|
||||
console.log(updateFound ? 'A new version is available.' : 'Already on the latest version.');
|
||||
} catch (err) {
|
||||
console.error('Failed to check for updates:', err);
|
||||
}
|
||||
});
|
||||
|
||||
updates.unrecoverable.subscribe(event => {
|
||||
console.error(event);
|
||||
location.reload();
|
||||
});
|
||||
|
||||
updates.versionUpdates.subscribe(evt => {
|
||||
switch (evt.type) {
|
||||
case 'VERSION_DETECTED':
|
||||
console.log(`Downloading new app version: ${evt.version.hash}`);
|
||||
break;
|
||||
case 'VERSION_READY':
|
||||
console.log(`Current app version: ${evt.currentVersion.hash}`);
|
||||
console.log(`New app version ready for use: ${evt.latestVersion.hash}`);
|
||||
break;
|
||||
case 'VERSION_INSTALLATION_FAILED':
|
||||
console.log(`Failed to install app version '${evt.version.hash}': ${evt.error}`);
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
|
@ -5,6 +5,7 @@ import { GuardLoaderIconService } from 'src/app/_services/guard-loader-icon.serv
|
|||
import { versions } from 'src/environments/versions';
|
||||
import { Router, RouteConfigLoadStart, RouteConfigLoadEnd } from '@angular/router';
|
||||
import { ApiClientService } from './_services/api-client.service';
|
||||
import { UpdaterService } from './_services/updater.service';
|
||||
import { ModalAlertComponent } from 'src/app/_components/modal-alert/modal-alert.component';
|
||||
import { BsModalService } from 'ngx-bootstrap/modal';
|
||||
import { AuthorizeGuard } from './_guards/authorize.guard';
|
||||
|
@ -30,7 +31,8 @@ export class AppComponent {
|
|||
private router: Router,
|
||||
public api: ApiClientService,
|
||||
private modalService: BsModalService,
|
||||
public guard: AuthorizeGuard
|
||||
public guard: AuthorizeGuard,
|
||||
private updater: UpdaterService
|
||||
) {
|
||||
this.revision_datetime_string = new Date(versions.revision_timestamp).toLocaleString(undefined, { day: '2-digit', month: '2-digit', year: 'numeric', hour: 'numeric', minute: 'numeric', second: 'numeric' });
|
||||
this.locationBackService.initialize();
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { NgModule, ErrorHandler, APP_INITIALIZER } from '@angular/core';
|
||||
import { NgModule, ErrorHandler, APP_INITIALIZER, isDevMode } from '@angular/core';
|
||||
import { BrowserModule } from '@angular/platform-browser';
|
||||
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
|
||||
import { HttpClient, HttpClientModule, HttpClientXsrfModule, HTTP_INTERCEPTORS } from '@angular/common/http';
|
||||
|
@ -77,8 +77,8 @@ import { FirstLetterUppercasePipe } from './_pipes/first-letter-uppercase.pipe';
|
|||
DaterangePickerModule,
|
||||
PaginationModule.forRoot(),
|
||||
ServiceWorkerModule.register('ngsw-worker.js', {
|
||||
enabled: false && environment.production,
|
||||
// Register the ServiceWorker as soon as the app is stable
|
||||
enabled: !isDevMode(),
|
||||
// Register the ServiceWorker as soon as the application is stable
|
||||
// or after 30 seconds (whichever comes first).
|
||||
registrationStrategy: 'registerWhenStable:30000'
|
||||
}),
|
||||
|
|
After Width: | Height: | Size: 14 KiB |
After Width: | Height: | Size: 17 KiB |
After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 59 KiB After Width: | Height: | Size: 60 KiB |
After Width: | Height: | Size: 102 KiB |
After Width: | Height: | Size: 7.2 KiB |
After Width: | Height: | Size: 10 KiB |
After Width: | Height: | Size: 59 KiB |
|
@ -7,15 +7,53 @@
|
|||
"scope": "./",
|
||||
"start_url": "./",
|
||||
"icons": [
|
||||
{
|
||||
"src": "assets/icons/icon-72x72.png",
|
||||
"sizes": "72x72",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable any"
|
||||
},
|
||||
{
|
||||
"src": "assets/icons/icon-96x96.png",
|
||||
"sizes": "96x96",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable any"
|
||||
},
|
||||
{
|
||||
"src": "assets/icons/icon-128x128.png",
|
||||
"sizes": "128x128",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable any"
|
||||
},
|
||||
{
|
||||
"src": "assets/icons/icon-144x144.png",
|
||||
"sizes": "144x144",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable any"
|
||||
},
|
||||
{
|
||||
"src": "assets/icons/icon-152x152.png",
|
||||
"sizes": "152x152",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable any"
|
||||
},
|
||||
{
|
||||
"src": "assets/icons/icon-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
"type": "image/png",
|
||||
"purpose": "maskable any"
|
||||
},
|
||||
{
|
||||
"src": "assets/icons/icon-384x384.png",
|
||||
"sizes": "384x384",
|
||||
"type": "image/png"
|
||||
"type": "image/png",
|
||||
"purpose": "maskable any"
|
||||
},
|
||||
{
|
||||
"src": "assets/icons/icon-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png",
|
||||
"purpose": "maskable any"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|