Skip to content
Snippets Groups Projects
Commit d951ced8 authored by Hugo SUBTIL's avatar Hugo SUBTIL
Browse files

feat: add pwa handling

BREAKING CHANGE: app is now working with PWA handling
parent 14aa777a
No related branches found
No related tags found
2 merge requests!1981.13,!172feat/US7-PWA
Showing
with 13256 additions and 16878 deletions
......@@ -32,6 +32,7 @@ speed-measure-plugin*.json
.history/*
# misc
/.angular/cache
/.sass-cache
/connect.lock
/coverage
......
......@@ -28,18 +28,6 @@ build_dev:
- docker build --pull -t "$CI_REGISTRY_IMAGE:dev" --build-arg conf=dev .
- docker push "$CI_REGISTRY_IMAGE:dev"
build_mobile:
image: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/docker:18.09
services:
- docker:18.09-dind
stage: build
only:
- mobile
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build --pull -t "$CI_REGISTRY_IMAGE:mobile" --build-arg conf=dev .
- docker push "$CI_REGISTRY_IMAGE:mobile"
build_json_server:
image: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/docker:18.09
services:
......@@ -123,3 +111,17 @@ mr:
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build --pull -t "$CI_REGISTRY_IMAGE:dev" --build-arg conf=dev .
# Job for auto building pwa in case of issue
# Juste create a new branche 'pwa'
pwa-build:
image: ${CI_DEPENDENCY_PROXY_DIRECT_GROUP_IMAGE_PREFIX}/docker:18.09
services:
- docker:18.09-dind
stage: build
only:
- feat/poc-pwa
script:
- docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY
- docker build --pull -t "$CI_REGISTRY_IMAGE:pwa" --build-arg conf=dev .
- docker push "$CI_REGISTRY_IMAGE:pwa"
# Stage 0, based on Node.js, to build and compile Angular
FROM node:12.16-slim as build
FROM node:14.18-slim as build
WORKDIR /app
......@@ -14,6 +14,7 @@ RUN npm install --silent
COPY angular.json .
COPY tsconfig.json .
COPY tsconfig.app.json .
COPY ngsw-config.json .
COPY /nginx/nginx.conf .
COPY /src ./src
......
......@@ -35,13 +35,15 @@
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.app.json",
"localize": true,
"aot": true,
"allowedCommonJsDependencies": ["lodash", "leaflet.locatecontrol"],
"assets": [
"src/favicon.ico",
"src/assets",
"src/sitemap.xml",
"src/robots.txt",
"src/ngsw-worker.js",
"src/ngsw.json",
"src/manifest.webmanifest",
{
"glob": "**/*",
"input": "./node_modules/leaflet/dist/images",
......@@ -53,7 +55,15 @@
"./node_modules/leaflet/dist/leaflet.css",
"./node_modules/leaflet.locatecontrol/dist/L.Control.Locate.css"
],
"scripts": []
"scripts": [],
"serviceWorker": true,
"ngswConfigPath": "ngsw-config.json",
"vendorChunk": true,
"extractLicenses": false,
"buildOptimizer": false,
"sourceMap": true,
"optimization": false,
"namedChunks": true
},
"configurations": {
"production": {
......@@ -63,15 +73,12 @@
"with": "src/environments/environment.prod.ts"
}
],
"aot": true,
"optimization": true,
"outputHashing": "all",
"sourceMap": false,
"extractCss": true,
"namedChunks": false,
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": false,
"budgets": [
{
"type": "initial",
......@@ -83,7 +90,9 @@
"maximumWarning": "10kb",
"maximumError": "15kb"
}
]
],
"serviceWorker": true,
"ngswConfigPath": "ngsw-config.json"
},
"fr": {
"localize": ["fr"]
......@@ -91,7 +100,8 @@
"en": {
"localize": ["en"]
}
}
},
"defaultConfiguration": ""
},
"serve": {
"builder": "@angular-devkit/build-angular:dev-server",
......@@ -124,18 +134,11 @@
"polyfills": "src/polyfills.ts",
"tsConfig": "tsconfig.spec.json",
"karmaConfig": "karma.conf.js",
"assets": ["src/favicon.ico", "src/assets"],
"assets": ["src/favicon.ico", "src/assets", "src/manifest.webmanifest"],
"styles": ["src/styles.scss"],
"scripts": []
}
},
"lint": {
"builder": "@angular-devkit/build-angular:tslint",
"options": {
"tsConfig": ["tsconfig.app.json", "tsconfig.spec.json", "e2e/tsconfig.json"],
"exclude": ["**/node_modules/**"]
}
},
"e2e": {
"builder": "@angular-devkit/build-angular:protractor",
"options": {
......
upstream api_node_js {
server service-ram:3000;
}
map $http_user_agent $outdated {
default 0;
"~MSIE [1-10]\." 1;
......
{
"$schema": "./node_modules/@angular/service-worker/config/schema.json",
"index": "/index.html",
"assetGroups": [
{
"name": "app",
"installMode": "prefetch",
"resources": {
"files": [
"/favicon.ico",
"/index.html",
"/manifest.webmanifest",
"/*.css",
"/*.js"
]
}
},
{
"name": "assets",
"installMode": "lazy",
"updateMode": "prefetch",
"resources": {
"files": [
"/assets/**",
"/*.(svg|cur|jpg|jpeg|png|apng|webp|avif|gif|otf|ttf|woff|woff2)"
]
}
}
]
}
This diff is collapsed.
......@@ -4,10 +4,11 @@
"scripts": {
"ng": "ng",
"start": "ng serve --configuration=fr --proxy-config proxy.conf.json",
"build:prod": "ng build --prod --configuration=production,fr --output-path=dist --subresource-integrity",
"build:dev": "ng build --prod --configuration=fr --output-path=dist --subresource-integrity",
"doc": "npx @compodoc/compodoc -p tsconfig.doc.json",
"doc:serve": "npm run doc && npx compodoc -s",
"start-pwa": "npm run build:prod && http-server -p 8080 -c-1 dist/fr --proxy http://localhost:3000",
"build:prod": "ng build --configuration=production,fr --output-path=dist --subresource-integrity",
"build:dev": "ng build --configuration=production,fr --output-path=dist --subresource-integrity",
"doc": "./node_modules/.bin/compodoc -p tsconfig.doc.json",
"doc:serve": "./node_modules/.bin/compodoc compodoc -s",
"test": "ng test",
"lint": "ng lint",
"e2e": "ng e2e",
......@@ -17,48 +18,49 @@
},
"private": true,
"dependencies": {
"@angular/animations": "~11.2.12",
"@angular/cdk": "^10.2.3",
"@angular/common": "~11.2.12",
"@angular/compiler": "~11.2.12",
"@angular/core": "~11.2.12",
"@angular/animations": "~13.1.1",
"@angular/cdk": "^13.1.1",
"@angular/common": "~13.1.1",
"@angular/compiler": "~13.1.1",
"@angular/core": "~13.1.1",
"@angular/flex-layout": "^10.0.0-beta.32",
"@angular/forms": "~11.2.12",
"@angular/platform-browser": "~11.2.12",
"@angular/platform-browser-dynamic": "~11.2.12",
"@angular/router": "~11.2.12",
"@angular/forms": "~13.1.1",
"@angular/platform-browser": "~13.1.1",
"@angular/platform-browser-dynamic": "~13.1.1",
"@angular/router": "~13.1.1",
"@angular/service-worker": "~13.1.1",
"@asymmetrik/ngx-leaflet": "^8.1.0",
"@ngx-translate/core": "^13.0.0",
"ag-grid-angular": "^26.2.0",
"ag-grid-community": "^26.2.1",
"ag-grid-enterprise": "^26.2.1",
"json-server": "^0.16.2",
"json-server": "^0.17.0",
"jwt-decode": "^3.1.2",
"leaflet": "^1.7.1",
"leaflet.locatecontrol": "^0.72.0",
"lodash": "^4.17.20",
"lodash": "^4.17.21",
"luxon": "^1.25.0",
"ngx-toastr": "^13.2.1",
"npx": "^10.2.2",
"rxjs": "~6.6.0",
"tslib": "^2.0.0",
"zone.js": "~0.10.2"
"zone.js": "~0.11.4"
},
"devDependencies": {
"@angular-devkit/build-angular": "^0.1100.6",
"@angular/cli": "^11.2.11",
"@angular/compiler-cli": "~11.2.12",
"@angular/localize": "^11.2.12",
"@compodoc/compodoc": "^1.1.11",
"@angular-devkit/build-angular": "^13.2.1",
"@angular/cli": "^13.1.2",
"@angular/compiler-cli": "~13.1.1",
"@angular/localize": "^13.1.1",
"@compodoc/compodoc": "^1.1.16",
"@types/jasmine": "~3.5.0",
"@types/jasminewd2": "~2.0.3",
"@types/leaflet": "^1.5.17",
"@types/leaflet.locatecontrol": "^0.60.7",
"@types/node": "^12.12.67",
"codelyzer": "^6.0.0",
"http-server": "^14.1.0",
"jasmine-core": "~3.6.0",
"jasmine-spec-reporter": "~5.0.0",
"karma": "~5.0.0",
"karma": "^6.3.9",
"karma-browserify": "^7.0.0",
"karma-chrome-launcher": "~3.1.0",
"karma-coverage-istanbul-reporter": "~3.0.2",
......@@ -66,9 +68,9 @@
"karma-jasmine-html-reporter": "^1.5.0",
"prettier": "^2.1.2",
"protractor": "~7.0.0",
"standard-version": "^9.0.0",
"standard-version": "^9.3.2",
"ts-node": "~8.3.0",
"tslint": "~6.1.0",
"typescript": "~4.0.2"
"typescript": "~4.5.4"
}
}
......@@ -3,10 +3,7 @@
"target": "http://localhost:3000",
"secure": false,
"changeOrigin": true,
"logLevel": "debug",
"pathRewrite": {
"^/api": ""
}
"logLevel": "debug"
},
"/base-adresse/base-adresse-nationale/streets": {
"target": "https://passerelle.formulaireextranet.grandlyon.com",
......
......@@ -3,6 +3,7 @@ import { NavigationEnd, Router } from '@angular/router';
import { ProfileService } from './profile/services/profile.service';
import { AuthService } from './services/auth.service';
import { RouterListenerService } from './services/routerListener.service';
import { UpdateService } from './services/update.service';
import { PrintService } from './shared/service/print.service';
import { WindowScrollService } from './shared/service/windowScroll.service';
......@@ -20,6 +21,7 @@ export class AppComponent implements OnInit {
private profilService: ProfileService,
private windowScrollService: WindowScrollService,
private routerListener: RouterListenerService,
private updateService: UpdateService,
private router: Router
) {
if (this.authService.isLoggedIn()) {
......@@ -30,6 +32,8 @@ export class AppComponent implements OnInit {
this.setHeightApp();
});
this.routerListener.loadRouting();
// handle pwa update
this.updateService.subscribeUpdate();
}
ngOnInit(): void {
......
......@@ -39,8 +39,11 @@ import { OrientationFormComponent } from './form/orientation-form/orientation-fo
import { StructureDetailPrintComponent } from './form/orientation-form/component/structure-detail-print/structure-detail-print.component';
import { StructureListPrintComponent } from './form/orientation-form/component/structure-list-print/structure-list-print.component';
import { StructurePrintHeaderComponent } from './form/orientation-form/component/structure-print-header/structure-print-header.component';
import { ServiceWorkerModule } from '@angular/service-worker';
import { environment } from '../environments/environment';
import { StructureResolver } from './resolvers/structure.resolver';
import { RoleGuard } from './guards/role.guard';
import { UpdateService } from './services/update.service';
@NgModule({
declarations: [
......@@ -77,6 +80,9 @@ import { RoleGuard } from './guards/role.guard';
MapModule,
BrowserAnimationsModule,
ToastrModule.forRoot(),
ServiceWorkerModule.register('ngsw-worker.js', {
enabled: environment.production,
}),
],
providers: [
{ provide: LOCALE_ID, useValue: 'fr' },
......@@ -89,6 +95,7 @@ import { RoleGuard } from './guards/role.guard';
TempUserResolver,
StructureResolver,
RouterListenerService,
UpdateService,
],
bootstrap: [AppComponent],
})
......
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { DomSanitizer } from '@angular/platform-browser';
import { version } from '../../../package.json';
import packageJson from '../../../package.json';
import { Page } from './models/page.model';
import { PageService } from './services/page.service';
import { PageEnum } from './enum/page.enum';
......@@ -27,7 +27,7 @@ export class PageComponent implements OnInit {
this.page.safeHtml = this.sanitizer.bypassSecurityTrustHtml(this.page.html);
});
// Display version number in 'About' page only
this.slugPage == this.quiSommesNous ? (this.version = version) : (this.version = '');
this.slugPage == this.quiSommesNous ? (this.version = packageJson.version) : (this.version = '');
});
}
}
......@@ -7,17 +7,32 @@ import { ToastrService } from 'ngx-toastr';
export class NotificationService {
constructor(private toastr: ToastrService) {}
showSuccess(message: string, title: string, timespan: number = 10000): void {
public showSuccess(message: string, title: string, timespan: number = 10000): void {
this.toastr.success(message, title, {
timeOut: timespan,
});
}
// Par defaut, l'erreur reste affichée jusqu'à ce qu'on clique dessus
showError(message: string, title: string, timespan: number = 0): void {
public showError(message: string, title: string, timespan: number = 0): void {
this.toastr.error(message, title, {
timeOut: timespan,
disableTimeOut: timespan ? false : true,
});
}
// Par defaut, l'erreur reste affichée jusqu'à ce qu'on clique dessus
public showAppNewVersion(): void {
const update = this.toastr.info(
'Une nouvelle version est disponible, cliquer ici pour mettre a jour.',
'Nouvelle version',
{
disableTimeOut: true,
}
);
update.onTap.subscribe((action) => {
window.location.reload();
});
}
}
import { Injectable } from '@angular/core';
import { SwUpdate } from '@angular/service-worker';
import { NotificationService } from './notification.service';
@Injectable({
providedIn: 'root',
})
export class UpdateService {
// Ref: https://angular.io/api/service-worker/SwUpdate
// Ref: https://alligator.io/angular/service-worker-updates/
constructor(private swUpdate: SwUpdate, private notificationService: NotificationService) {}
subscribeUpdate() {
if (this.swUpdate.isEnabled) {
this.swUpdate.available.subscribe(() => {
this.showUpdateToast();
});
}
}
private async showUpdateToast() {
this.notificationService.showAppNewVersion();
}
}
src/assets/icons/icon-128x128.png

2.84 KiB

src/assets/icons/icon-144x144.png

3.05 KiB

src/assets/icons/icon-152x152.png

2.88 KiB

src/assets/icons/icon-192x192.png

2.19 KiB

src/assets/icons/icon-384x384.png

6.51 KiB

src/assets/icons/icon-512x512.png

3.23 KiB

0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment