From 8a2ad9912f9fc1e17873a1c71ef263b2926057b0 Mon Sep 17 00:00:00 2001 From: Max Burri Date: Tue, 2 Jul 2024 16:59:54 +0200 Subject: [PATCH 01/13] feat: add new global toast service --- AMW_angular/io/src/app/app.component.html | 1 + AMW_angular/io/src/app/app.component.ts | 3 +- .../src/app/settings/tags/tags.component.ts | 17 +++-- .../shared/elements/toast/toast-service.ts | 28 ++++++++ .../toast/toasts-container.component.ts | 67 ++++++++++++++++++ .../io/src/assets/images/toast_alert.png | Bin 0 -> 1156 bytes AMW_angular/io/src/styles.scss | 3 + 7 files changed, 111 insertions(+), 8 deletions(-) create mode 100644 AMW_angular/io/src/app/shared/elements/toast/toast-service.ts create mode 100644 AMW_angular/io/src/app/shared/elements/toast/toasts-container.component.ts create mode 100644 AMW_angular/io/src/assets/images/toast_alert.png diff --git a/AMW_angular/io/src/app/app.component.html b/AMW_angular/io/src/app/app.component.html index 880892c62..c8cfe52a7 100644 --- a/AMW_angular/io/src/app/app.component.html +++ b/AMW_angular/io/src/app/app.component.html @@ -3,5 +3,6 @@
+
diff --git a/AMW_angular/io/src/app/app.component.ts b/AMW_angular/io/src/app/app.component.ts index ae024dd93..1800d3a6a 100644 --- a/AMW_angular/io/src/app/app.component.ts +++ b/AMW_angular/io/src/app/app.component.ts @@ -5,6 +5,7 @@ import { AppConfiguration } from './setting/app-configuration'; import { AMW_LOGOUT_URL } from './core/amw-constants'; import { AsyncPipe } from '@angular/common'; import { NavigationComponent } from './navigation/navigation.component'; +import { ToastsContainerComponent } from './shared/elements/toast/toasts-container.component'; @Component({ selector: 'app', @@ -12,7 +13,7 @@ import { NavigationComponent } from './navigation/navigation.component'; styleUrls: ['./app.component.scss'], templateUrl: './app.component.html', standalone: true, - imports: [RouterOutlet, AsyncPipe, NavigationComponent], + imports: [RouterOutlet, AsyncPipe, NavigationComponent, ToastsContainerComponent], }) export class AppComponent implements OnInit { logoutUrl: string; diff --git a/AMW_angular/io/src/app/settings/tags/tags.component.ts b/AMW_angular/io/src/app/settings/tags/tags.component.ts index 81da430d9..6cc409159 100644 --- a/AMW_angular/io/src/app/settings/tags/tags.component.ts +++ b/AMW_angular/io/src/app/settings/tags/tags.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, ViewChild } from '@angular/core'; +import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { ToastComponent } from 'src/app/shared/elements/toast/toast.component'; import { ToastComponent as ToastComponent_1 } from '../../shared/elements/toast/toast.component'; @@ -7,6 +7,7 @@ import { IconComponent } from '../../shared/icon/icon.component'; import { Subject } from 'rxjs'; import { AuthService } from '../../auth/auth.service'; import { takeUntil } from 'rxjs/operators'; +import { ToastService } from '../../shared/elements/toast/toast-service'; type Tag = { id: number; name: string }; @@ -17,7 +18,7 @@ type Tag = { id: number; name: string }; standalone: true, imports: [FormsModule, ToastComponent_1, IconComponent], }) -export class TagsComponent implements OnInit { +export class TagsComponent implements OnInit, OnDestroy { tagName = ''; tags: Tag[] = []; canCreate: boolean = false; @@ -29,6 +30,7 @@ export class TagsComponent implements OnInit { constructor( private http: HttpClient, private authService: AuthService, + private toastService: ToastService, ) {} ngOnInit(): void { @@ -62,12 +64,12 @@ export class TagsComponent implements OnInit { if (this.tagName.trim().length > 0) { this.http.post('/AMW_rest/resources/settings/tags', { name: this.tagName }).subscribe({ next: (newTag) => { + this.toastService.success('Tag added.'); this.tags.push(newTag); - this.toast.display('Tag added.'); this.tagName = ''; }, error: (error) => { - this.toast.display(error.error.message, 'error', 5000); + this.toastService.error(error.error.message); }, }); } @@ -75,12 +77,13 @@ export class TagsComponent implements OnInit { deleteTag(tagId: number): void { this.http.delete(`/AMW_rest/resources/settings/tags/${tagId}`).subscribe({ - next: (response) => { + next: () => { this.tags = this.tags.filter((tag) => tag.id !== tagId); - this.toast.display('Tag deleted.'); + this.toastService.success('Tag deleted.'); }, + error: (error) => { - this.toast.display(error.error.message, 'error', 5000); + this.toastService.error(error.error.message); }, }); } diff --git a/AMW_angular/io/src/app/shared/elements/toast/toast-service.ts b/AMW_angular/io/src/app/shared/elements/toast/toast-service.ts new file mode 100644 index 000000000..81b2716f3 --- /dev/null +++ b/AMW_angular/io/src/app/shared/elements/toast/toast-service.ts @@ -0,0 +1,28 @@ +import { Injectable } from '@angular/core'; + +export interface Toast { + type: 'light' | 'danger'; + body: string; + delay?: number; +} + +@Injectable({ providedIn: 'root' }) +export class ToastService { + toasts: Toast[] = []; + + success(message: string) { + this.show({ type: 'light', body: message }); + } + + error(message: string) { + this.show({ type: 'danger', body: message, delay: 15000 }); + } + + show(toast: Toast) { + this.toasts.push(toast); + } + + remove(toast: Toast) { + this.toasts = this.toasts.filter((t) => t !== toast); + } +} diff --git a/AMW_angular/io/src/app/shared/elements/toast/toasts-container.component.ts b/AMW_angular/io/src/app/shared/elements/toast/toasts-container.component.ts new file mode 100644 index 000000000..f03d4104c --- /dev/null +++ b/AMW_angular/io/src/app/shared/elements/toast/toasts-container.component.ts @@ -0,0 +1,67 @@ +import { Component } from '@angular/core'; +import { NgbToastModule } from '@ng-bootstrap/ng-bootstrap'; +import { NgTemplateOutlet } from '@angular/common'; +import { ToastService } from './toast-service'; + +@Component({ + selector: 'app-toasts', + standalone: true, + imports: [NgbToastModule, NgTemplateOutlet], + template: `@for (toast of toastService.toasts; track toast) { + +
+
+
{{ toast.body }}
+
+
+ }`, + styles: ` + :host { + position: fixed; + top: 3rem; + right: 0; + z-index: 1200; + margin: 0.5rem; + } + + .toast { + margin-bottom: 0.25rem; + } + + .toast-content { + display: flex; + flex-direction: row; + } + + .toast-image { + background-image: url('toast_alert.png'); + background-repeat: no-repeat; + height: 50px; + width: 50px; + border-radius: var(--bs-border-radius) 0 0 var(--bs-border-radius); + } + + .light .toast-image { + background-color: var(--bs-primary); + } + .danger .toast-image { + background-color: var(--bs-danger); + } + + .light .toast-content { + color: steelblue; + } + + .danger .toast-content { + color: darkred; + } + `, +}) +export class ToastsContainerComponent { + constructor(public toastService: ToastService) {} +} diff --git a/AMW_angular/io/src/assets/images/toast_alert.png b/AMW_angular/io/src/assets/images/toast_alert.png new file mode 100644 index 0000000000000000000000000000000000000000..9bce0727bd2c20ee0ffea7dc7ff241ee58da8a49 GIT binary patch literal 1156 zcmV-~1bh35P)Kjs{jB19&|-mbW?9;ba!ELWdK2BZ(?O2Mrm?o zcW-iQb09-gH7+r$A4ux}000(rMObu0a%Ew3X>V>IRB3Hx05&c+E;2ANGL>N5$^ZZZ z+DSw~RCt`_oy~dMFc3r^^W`3Q5SO45Sb|DGI&djTM@k3oAnqVa1)D=8TcZ9*Vis5+ zbFw6RvEz9lDFU*g1DVB0j++pGBc~)N0yFQ^?+7i zST&8-DORncb%xcTtZZgaz~*d#Vc03hI2mgXeDSD#5w{n+W;Ra8QKPk)JpL)Jf7Hd% z%6pFNoa(w887Gfl#q}|>4e)jPe2a-BhnnY_%)d9MG2W&V-TOSUQy0926$sHf405WS zs`iP}trwJuJWU?UCpvd75|u`tPrm*$41?6jJ*>dbh({Xf-iuyFcEY+x-F@%Tgpo&B z0elvY_rk}7SEDtG>(!B&ymML%jkKQf^-vY*tQo*Z*(zsxa` zJ=x7{B?X7+UD7bGz<7b{63!!YcDA161i9BW_51+CIpfnOrU_ak;=M2?nX&3uhK5~;GywHqTIpJy+Q73dSG zwtKo8BQmsVVg=ens&2~f#)t&1+E{@uk?NoI=*EZ&Ex$juGE<7rAq1k9f z#tLR85*;g;k5=+*LZMk`MaK$eByw0Y4{ZYGp%w0u{hH<&N#0E;ba#%_*ov`Mj}mDD zD|l=qm1shtn`pI!72Hpx8LZ&GkyNS)g|4F28dh*Sk*2VM+eT8!CKS3rE5e%j8eL1I zIjo=~BWGx}iWOWY(qtOYk&$<_TE+^_6KOUL=*Y+b?PCQWi8P%CbY$d+R=fZ7?V!I9 W0nQI14nRHt0000 Date: Tue, 2 Jul 2024 17:02:20 +0200 Subject: [PATCH 02/13] fix: es-lint warnings --- AMW_angular/io/src/app/settings/tags/tags.component.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/AMW_angular/io/src/app/settings/tags/tags.component.ts b/AMW_angular/io/src/app/settings/tags/tags.component.ts index 6cc409159..499f82226 100644 --- a/AMW_angular/io/src/app/settings/tags/tags.component.ts +++ b/AMW_angular/io/src/app/settings/tags/tags.component.ts @@ -12,7 +12,7 @@ import { ToastService } from '../../shared/elements/toast/toast-service'; type Tag = { id: number; name: string }; @Component({ - selector: 'amw-tags', + selector: 'app-tags', templateUrl: './tags.component.html', styleUrl: './tags.component.scss', standalone: true, @@ -21,8 +21,8 @@ type Tag = { id: number; name: string }; export class TagsComponent implements OnInit, OnDestroy { tagName = ''; tags: Tag[] = []; - canCreate: boolean = false; - canDelete: boolean = false; + canCreate = false; + canDelete = false; private destroy$ = new Subject(); @ViewChild(ToastComponent) toast: ToastComponent; From ca587abbd5e8e6691840d88f3d4c05e43d267485 Mon Sep 17 00:00:00 2001 From: Max Burri Date: Tue, 2 Jul 2024 17:04:44 +0200 Subject: [PATCH 03/13] fix: toast-component defaults and place it at the bottom --- .../app/shared/elements/toast/toasts-container.component.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/AMW_angular/io/src/app/shared/elements/toast/toasts-container.component.ts b/AMW_angular/io/src/app/shared/elements/toast/toasts-container.component.ts index f03d4104c..4dce5043f 100644 --- a/AMW_angular/io/src/app/shared/elements/toast/toasts-container.component.ts +++ b/AMW_angular/io/src/app/shared/elements/toast/toasts-container.component.ts @@ -11,7 +11,7 @@ import { ToastService } from './toast-service';
@@ -23,7 +23,7 @@ import { ToastService } from './toast-service'; styles: ` :host { position: fixed; - top: 3rem; + bottom: 3rem; right: 0; z-index: 1200; margin: 0.5rem; From 93d68ddd69a0826739f70c62d26a5b694590d620 Mon Sep 17 00:00:00 2001 From: Max Burri Date: Wed, 3 Jul 2024 08:23:58 +0200 Subject: [PATCH 04/13] refactor: cleanup toast service and component --- .../app/shared/elements/toast/toast-service.ts | 6 +++--- .../toast/toasts-container.component.ts | 18 +++++++++--------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/AMW_angular/io/src/app/shared/elements/toast/toast-service.ts b/AMW_angular/io/src/app/shared/elements/toast/toast-service.ts index 81b2716f3..1aa1d8bdd 100644 --- a/AMW_angular/io/src/app/shared/elements/toast/toast-service.ts +++ b/AMW_angular/io/src/app/shared/elements/toast/toast-service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@angular/core'; export interface Toast { - type: 'light' | 'danger'; + type: 'success' | 'error'; body: string; delay?: number; } @@ -11,11 +11,11 @@ export class ToastService { toasts: Toast[] = []; success(message: string) { - this.show({ type: 'light', body: message }); + this.show({ type: 'success', body: message }); } error(message: string) { - this.show({ type: 'danger', body: message, delay: 15000 }); + this.show({ type: 'error', body: message, delay: 15000 }); } show(toast: Toast) { diff --git a/AMW_angular/io/src/app/shared/elements/toast/toasts-container.component.ts b/AMW_angular/io/src/app/shared/elements/toast/toasts-container.component.ts index 4dce5043f..ef5a461ad 100644 --- a/AMW_angular/io/src/app/shared/elements/toast/toasts-container.component.ts +++ b/AMW_angular/io/src/app/shared/elements/toast/toasts-container.component.ts @@ -9,13 +9,13 @@ import { ToastService } from './toast-service'; imports: [NgbToastModule, NgTemplateOutlet], template: `@for (toast of toastService.toasts; track toast) { -
-
+
+
{{ toast.body }}
@@ -33,12 +33,12 @@ import { ToastService } from './toast-service'; margin-bottom: 0.25rem; } - .toast-content { + .content { display: flex; flex-direction: row; } - .toast-image { + .image { background-image: url('toast_alert.png'); background-repeat: no-repeat; height: 50px; @@ -46,18 +46,18 @@ import { ToastService } from './toast-service'; border-radius: var(--bs-border-radius) 0 0 var(--bs-border-radius); } - .light .toast-image { + .success .image { background-color: var(--bs-primary); } - .danger .toast-image { + .error .image { background-color: var(--bs-danger); } - .light .toast-content { + .light .content { color: steelblue; } - .danger .toast-content { + .danger .content { color: darkred; } `, From 3c0aa3b9b9c85a900324918455a60617230a4963 Mon Sep 17 00:00:00 2001 From: Max Burri Date: Wed, 3 Jul 2024 08:51:01 +0200 Subject: [PATCH 05/13] feat: ToastService spec --- .../shared/elements/toast/toast-service.ts | 7 ++- .../elements/toast/toast.service.spec.ts | 43 +++++++++++++++++++ 2 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 AMW_angular/io/src/app/shared/elements/toast/toast.service.spec.ts diff --git a/AMW_angular/io/src/app/shared/elements/toast/toast-service.ts b/AMW_angular/io/src/app/shared/elements/toast/toast-service.ts index 1aa1d8bdd..5431cc364 100644 --- a/AMW_angular/io/src/app/shared/elements/toast/toast-service.ts +++ b/AMW_angular/io/src/app/shared/elements/toast/toast-service.ts @@ -6,16 +6,19 @@ export interface Toast { delay?: number; } +const DEFAULT_SUCCESS_TIMEOUT = 5000; +const DEFAULT_ERROR_TIMEOUT = 15000; + @Injectable({ providedIn: 'root' }) export class ToastService { toasts: Toast[] = []; success(message: string) { - this.show({ type: 'success', body: message }); + this.show({ type: 'success', body: message, delay: DEFAULT_SUCCESS_TIMEOUT }); } error(message: string) { - this.show({ type: 'error', body: message, delay: 15000 }); + this.show({ type: 'error', body: message, delay: DEFAULT_ERROR_TIMEOUT }); } show(toast: Toast) { diff --git a/AMW_angular/io/src/app/shared/elements/toast/toast.service.spec.ts b/AMW_angular/io/src/app/shared/elements/toast/toast.service.spec.ts new file mode 100644 index 000000000..0fb3443b5 --- /dev/null +++ b/AMW_angular/io/src/app/shared/elements/toast/toast.service.spec.ts @@ -0,0 +1,43 @@ +import { ToastService } from './toast-service'; + +describe('ToastService', () => { + let service: ToastService; + + beforeEach(() => { + service = new ToastService(); + }); + + it('#success should add a toast with type success', () => { + service.success('success-message'); + expect(service.toasts.length).toBe(1); + const toast = service.toasts[0]; + expect(toast.type).toBe('success'); + expect(toast.body).toBe('success-message'); + expect(toast.delay).toBe(5000); + }); + + it('#error should add a toast with type error and longer delay', () => { + service.error('error-message'); + const toast = service.toasts[0]; + expect(toast.type).toBe('error'); + expect(toast.body).toBe('error-message'); + expect(toast.delay).toBe(15000); + }); + + it('#show should add a custom toast', () => { + service.show({ body: 'custom-message', type: 'success', delay: 100 }); + + const toast = service.toasts[0]; + expect(toast.type).toBe('success'); + expect(toast.body).toBe('custom-message'); + expect(toast.delay).toBe(100); + }); + + it('#remove should remove a toast', () => { + service.success('success-message'); + service.error('error-message'); + expect(service.toasts.length).toBe(2); + service.remove(service.toasts[0]); + expect(service.toasts.length).toBe(1); + }); +}); From dba2f6710da6b45b2b868f675da8a6f6509fd13a Mon Sep 17 00:00:00 2001 From: Max Burri Date: Wed, 3 Jul 2024 09:08:40 +0200 Subject: [PATCH 06/13] test: ToastContainerComponent - also renamed it --- AMW_angular/io/src/app/app.component.ts | 4 +-- .../toast/toast-container.component.spec.ts | 30 +++++++++++++++++++ ...ponent.ts => toast-container.component.ts} | 2 +- 3 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 AMW_angular/io/src/app/shared/elements/toast/toast-container.component.spec.ts rename AMW_angular/io/src/app/shared/elements/toast/{toasts-container.component.ts => toast-container.component.ts} (97%) diff --git a/AMW_angular/io/src/app/app.component.ts b/AMW_angular/io/src/app/app.component.ts index 1800d3a6a..2a6de6000 100644 --- a/AMW_angular/io/src/app/app.component.ts +++ b/AMW_angular/io/src/app/app.component.ts @@ -5,7 +5,7 @@ import { AppConfiguration } from './setting/app-configuration'; import { AMW_LOGOUT_URL } from './core/amw-constants'; import { AsyncPipe } from '@angular/common'; import { NavigationComponent } from './navigation/navigation.component'; -import { ToastsContainerComponent } from './shared/elements/toast/toasts-container.component'; +import { ToastContainerComponent } from './shared/elements/toast/toast-container.component'; @Component({ selector: 'app', @@ -13,7 +13,7 @@ import { ToastsContainerComponent } from './shared/elements/toast/toasts-contain styleUrls: ['./app.component.scss'], templateUrl: './app.component.html', standalone: true, - imports: [RouterOutlet, AsyncPipe, NavigationComponent, ToastsContainerComponent], + imports: [RouterOutlet, AsyncPipe, NavigationComponent, ToastContainerComponent], }) export class AppComponent implements OnInit { logoutUrl: string; diff --git a/AMW_angular/io/src/app/shared/elements/toast/toast-container.component.spec.ts b/AMW_angular/io/src/app/shared/elements/toast/toast-container.component.spec.ts new file mode 100644 index 000000000..6e0b700aa --- /dev/null +++ b/AMW_angular/io/src/app/shared/elements/toast/toast-container.component.spec.ts @@ -0,0 +1,30 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; +import { ToastContainerComponent } from './toast-container.component'; +import { ToastService } from './toast-service'; + +describe('ToastContainerComponent', () => { + let component: ToastContainerComponent; + let toastService: ToastService; + let fixture: ComponentFixture; + + beforeEach(() => { + TestBed.configureTestingModule({ + providers: [ToastContainerComponent, { provide: ToastService, useClass: ToastService }], + }); + fixture = TestBed.createComponent(ToastContainerComponent); + component = TestBed.inject(ToastContainerComponent); + toastService = TestBed.inject(ToastService); + }); + + it('should create the component', () => { + expect(component).toBeDefined(); + }); + + it('should show the toast', () => { + component.toastService.success('success-message'); + fixture.detectChanges(); + const element = fixture.nativeElement; + const message = element.querySelector('.toast-body .content'); + expect(message.textContent).toBe('success-message'); + }); +}); diff --git a/AMW_angular/io/src/app/shared/elements/toast/toasts-container.component.ts b/AMW_angular/io/src/app/shared/elements/toast/toast-container.component.ts similarity index 97% rename from AMW_angular/io/src/app/shared/elements/toast/toasts-container.component.ts rename to AMW_angular/io/src/app/shared/elements/toast/toast-container.component.ts index ef5a461ad..4226ca399 100644 --- a/AMW_angular/io/src/app/shared/elements/toast/toasts-container.component.ts +++ b/AMW_angular/io/src/app/shared/elements/toast/toast-container.component.ts @@ -62,6 +62,6 @@ import { ToastService } from './toast-service'; } `, }) -export class ToastsContainerComponent { +export class ToastContainerComponent { constructor(public toastService: ToastService) {} } From 482281284b2a7eff1c3e4931023def68db32a0ae Mon Sep 17 00:00:00 2001 From: Max Burri Date: Wed, 3 Jul 2024 09:27:01 +0200 Subject: [PATCH 07/13] refactor: remove old ToastComponent and use the new one everywhere --- .../deployments/deployments.component.html | 1 - .../app/deployments/deployments.component.ts | 50 +++++++------- .../io/src/app/layout/page/page.component.ts | 3 +- .../deployment-parameter.component.html | 47 ++++++------- .../deployment-parameter.component.ts | 27 ++++---- .../settings/releases/releases.component.html | 1 - .../settings/releases/releases.component.ts | 31 ++++----- .../src/app/settings/tags/tags.component.html | 33 ++++----- .../src/app/settings/tags/tags.component.ts | 10 +-- .../toast/toast-container.component.spec.ts | 2 +- .../toast/toast-container.component.ts | 2 +- .../elements/toast/toast.component.scss | 67 ------------------ .../elements/toast/toast.component.spec.ts | 69 ------------------- .../shared/elements/toast/toast.component.ts | 58 ---------------- .../elements/toast/toast.service.spec.ts | 2 +- .../{toast-service.ts => toast.service.ts} | 0 16 files changed, 93 insertions(+), 310 deletions(-) delete mode 100644 AMW_angular/io/src/app/shared/elements/toast/toast.component.scss delete mode 100644 AMW_angular/io/src/app/shared/elements/toast/toast.component.spec.ts delete mode 100644 AMW_angular/io/src/app/shared/elements/toast/toast.component.ts rename AMW_angular/io/src/app/shared/elements/toast/{toast-service.ts => toast.service.ts} (100%) diff --git a/AMW_angular/io/src/app/deployments/deployments.component.html b/AMW_angular/io/src/app/deployments/deployments.component.html index 2b083c9ad..7fd3f8dc5 100644 --- a/AMW_angular/io/src/app/deployments/deployments.component.html +++ b/AMW_angular/io/src/app/deployments/deployments.component.html @@ -8,7 +8,6 @@ } @if (errorMessage) { } -
diff --git a/AMW_angular/io/src/app/deployments/deployments.component.ts b/AMW_angular/io/src/app/deployments/deployments.component.ts index a8f7156f4..4a900e22c 100644 --- a/AMW_angular/io/src/app/deployments/deployments.component.ts +++ b/AMW_angular/io/src/app/deployments/deployments.component.ts @@ -1,7 +1,7 @@ -import { Location, NgIf, NgFor } from '@angular/common'; +import { Location, NgFor, NgIf } from '@angular/common'; import { Component, OnInit, ViewChild } from '@angular/core'; -import { NgModel, FormsModule } from '@angular/forms'; -import { ActivatedRoute } from '@angular/router'; +import { FormsModule, NgModel } from '@angular/forms'; +import { ActivatedRoute, Params } from '@angular/router'; import * as _ from 'lodash'; import * as datefns from 'date-fns'; import { Subscription, timer } from 'rxjs'; @@ -14,27 +14,25 @@ import { DeploymentService } from '../deployment/deployment.service'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { DeploymentsEditModalComponent } from './deployments-edit-modal.component'; import { DateTimeModel } from '../shared/date-time-picker/date-time.model'; -import { ToastComponent } from 'src/app/shared/elements/toast/toast.component'; import { PaginationComponent } from '../shared/pagination/pagination.component'; import { DeploymentsListComponent } from './deployments-list.component'; import { IconComponent } from '../shared/icon/icon.component'; import { DateTimePickerComponent } from '../shared/date-time-picker/date-time-picker.component'; -import { ToastComponent as ToastComponent_1 } from '../shared/elements/toast/toast.component'; import { NotificationComponent } from '../shared/elements/notification/notification.component'; import { LoadingIndicatorComponent } from '../shared/elements/loading-indicator.component'; import { PageComponent } from '../layout/page/page.component'; +import { ToastService } from '../shared/elements/toast/toast.service'; declare let $: any; @Component({ - selector: 'amw-deployments', + selector: 'app-deployments', templateUrl: './deployments.component.html', standalone: true, imports: [ LoadingIndicatorComponent, NgIf, NotificationComponent, - ToastComponent_1, FormsModule, NgFor, DateTimePickerComponent, @@ -45,11 +43,11 @@ declare let $: any; ], }) export class DeploymentsComponent implements OnInit { - defaultComparator: string = 'eq'; + defaultComparator = 'eq'; // initially by queryParam paramFilters: DeploymentFilter[] = []; - autoload: boolean = true; + autoload = true; // enhanced filters for deployment service filtersForBackend: DeploymentFilter[] = []; @@ -60,11 +58,11 @@ export class DeploymentsComponent implements OnInit { filterTypes: DeploymentFilterType[] = []; comparatorOptions: ComparatorFilterOption[] = []; comparatorOptionsMap: { [key: string]: string } = {}; - hasPermissionToRequestDeployments: boolean = false; - csvSeparator: string = ''; + hasPermissionToRequestDeployments = false; + csvSeparator = ''; // available edit actions - hasPermissionShakedownTest: boolean = false; + hasPermissionShakedownTest = false; deploymentDate: number; // for deployment date change // available filterValues (if any) @@ -83,28 +81,27 @@ export class DeploymentsComponent implements OnInit { csvDocument: ArrayBuffer; // sorting with default values - sortCol: string = 'd.deploymentDate'; - sortDirection: string = 'DESC'; + sortCol = 'd.deploymentDate'; + sortDirection = 'DESC'; // pagination with default values - maxResults: number = 10; - offset: number = 0; + maxResults = 10; + offset = 0; allResults: number; currentPage: number; lastPage: number; // auto refresh refreshIntervals: number[] = [0, 5, 10, 30, 60, 120]; - refreshInterval: number = 0; + refreshInterval = 0; timerSubscription: Subscription; - errorMessage: string = ''; - successMessage: string = ''; - isLoading: boolean = true; + errorMessage = ''; + successMessage = ''; + isLoading = true; @ViewChild('selectModel', { static: true }) selectModel: NgModel; - @ViewChild(ToastComponent) toast: ToastComponent; constructor( private activatedRoute: ActivatedRoute, @@ -112,13 +109,14 @@ export class DeploymentsComponent implements OnInit { private deploymentService: DeploymentService, private resourceService: ResourceService, private modalService: NgbModal, + private toastService: ToastService, ) {} ngOnInit() { - this.activatedRoute.queryParams.subscribe((param: any) => { - if (param['filters']) { + this.activatedRoute.queryParams.subscribe((param: Params) => { + if (param.filters) { try { - this.paramFilters = JSON.parse(param['filters']); + this.paramFilters = JSON.parse(param.filters); } catch (e) { this.errorMessage = 'Error parsing filter'; this.autoload = false; @@ -301,9 +299,9 @@ export class DeploymentsComponent implements OnInit { const url: string = decodeURIComponent(window.location.href); try { await navigator.clipboard.writeText(url); - this.toast.display('URL copied to clipboard.'); + this.toastService.success('URL copied to clipboard.'); } catch (err) { - this.toast.display('Failed to copy URL. Please try again.', 'error'); + this.toastService.error('Failed to copy URL. Please try again.'); } } diff --git a/AMW_angular/io/src/app/layout/page/page.component.ts b/AMW_angular/io/src/app/layout/page/page.component.ts index 6505e6dc2..fcdd467a0 100644 --- a/AMW_angular/io/src/app/layout/page/page.component.ts +++ b/AMW_angular/io/src/app/layout/page/page.component.ts @@ -1,13 +1,12 @@ import { Component } from '@angular/core'; import { CommonModule } from '@angular/common'; import { ReactiveFormsModule } from '@angular/forms'; -import { ToastComponent } from '../../shared/elements/toast/toast.component'; import { RouterLink } from '@angular/router'; @Component({ selector: 'app-page', standalone: true, - imports: [CommonModule, ReactiveFormsModule, ToastComponent, RouterLink], + imports: [CommonModule, ReactiveFormsModule, RouterLink], template: `
diff --git a/AMW_angular/io/src/app/settings/deployment-parameter/deployment-parameter.component.html b/AMW_angular/io/src/app/settings/deployment-parameter/deployment-parameter.component.html index 8c2eaf253..346df565a 100644 --- a/AMW_angular/io/src/app/settings/deployment-parameter/deployment-parameter.component.html +++ b/AMW_angular/io/src/app/settings/deployment-parameter/deployment-parameter.component.html @@ -4,13 +4,7 @@

Deployment Parameter Keys

@if (canCreate) { - +
- diff --git a/AMW_angular/io/src/app/settings/deployment-parameter/deployment-parameter.component.ts b/AMW_angular/io/src/app/settings/deployment-parameter/deployment-parameter.component.ts index eaf876689..ceebf324f 100644 --- a/AMW_angular/io/src/app/settings/deployment-parameter/deployment-parameter.component.ts +++ b/AMW_angular/io/src/app/settings/deployment-parameter/deployment-parameter.component.ts @@ -1,34 +1,33 @@ -import { Component, OnInit, ViewChild } from '@angular/core'; +import { Component, OnDestroy, OnInit } from '@angular/core'; import { CommonModule } from '@angular/common'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; -import { ToastComponent } from '../../shared/elements/toast/toast.component'; import { HttpClient } from '@angular/common/http'; import { IconComponent } from '../../shared/icon/icon.component'; import { takeUntil } from 'rxjs/operators'; import { AuthService } from '../../auth/auth.service'; import { Subject } from 'rxjs'; +import { ToastService } from '../../shared/elements/toast/toast.service'; type Key = { id: number; name: string }; @Component({ selector: 'app-deployment-parameter', standalone: true, - imports: [CommonModule, ReactiveFormsModule, ToastComponent, FormsModule, IconComponent], + imports: [CommonModule, ReactiveFormsModule, FormsModule, IconComponent], templateUrl: './deployment-parameter.component.html', styleUrl: './deployment-parameter.component.scss', }) -export class DeploymentParameterComponent implements OnInit { +export class DeploymentParameterComponent implements OnInit, OnDestroy { keyName = ''; paramKeys: Key[] = []; - canCreate: boolean = false; - canDelete: boolean = false; + canCreate = false; + canDelete = false; private destroy$ = new Subject(); - @ViewChild(ToastComponent) toast: ToastComponent; - constructor( private http: HttpClient, private authService: AuthService, + private toastService: ToastService, ) {} ngOnInit(): void { @@ -64,26 +63,26 @@ export class DeploymentParameterComponent implements OnInit { this.http.post('/AMW_rest/resources/deployments/deploymentParameterKeys', this.keyName).subscribe({ next: (newKey) => { this.paramKeys.push(newKey); - this.toast.display('Key added.'); + this.toastService.success('Key added.'); this.keyName = ''; }, error: (error) => { - this.toast.display(error.error.message, 'error', 5000); + this.toastService.error(error.error.message); }, }); } else { - this.toast.display('Key name must not be null or empty', 'error', 5000); + this.toastService.error('Key name must not be null or empty'); } } deleteKey(keyId: number): void { this.http.delete(`/AMW_rest/resources/deployments/deploymentParameterKeys/${keyId}`).subscribe({ - next: (response) => { + next: () => { this.paramKeys = this.paramKeys.filter((key) => key.id !== keyId); - this.toast.display('Key deleted.'); + this.toastService.success('Key deleted.'); }, error: (error) => { - this.toast.display(error.error.message, 'error', 5000); + this.toastService.error(error.error.message); }, }); } diff --git a/AMW_angular/io/src/app/settings/releases/releases.component.html b/AMW_angular/io/src/app/settings/releases/releases.component.html index fbc9e8df8..bef3abdab 100644 --- a/AMW_angular/io/src/app/settings/releases/releases.component.html +++ b/AMW_angular/io/src/app/settings/releases/releases.component.html @@ -1,5 +1,4 @@ -

Releases

diff --git a/AMW_angular/io/src/app/settings/releases/releases.component.ts b/AMW_angular/io/src/app/settings/releases/releases.component.ts index 411fa8959..c789370e9 100644 --- a/AMW_angular/io/src/app/settings/releases/releases.component.ts +++ b/AMW_angular/io/src/app/settings/releases/releases.component.ts @@ -1,23 +1,22 @@ -import { Component, OnInit, ViewChild } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { AsyncPipe, DatePipe, NgFor, NgIf } from '@angular/common'; import { LoadingIndicatorComponent } from '../../shared/elements/loading-indicator.component'; -import { BehaviorSubject, Observable, Subject } from 'rxjs'; +import { BehaviorSubject, combineLatest, Observable, Subject } from 'rxjs'; import { HttpClient } from '@angular/common/http'; import { IconComponent } from '../../shared/icon/icon.component'; import { PaginationComponent } from '../../shared/pagination/pagination.component'; -import { ToastComponent } from 'src/app/shared/elements/toast/toast.component'; import { DATE_FORMAT } from '../../core/amw-constants'; import { ReleaseEditComponent } from './release-edit.component'; import { Release } from './release'; import { ReleasesService } from './releases.service'; import { NgbModal } from '@ng-bootstrap/ng-bootstrap'; import { AuthService } from '../../auth/auth.service'; -import { combineLatest } from 'rxjs'; import { map, takeUntil } from 'rxjs/operators'; import { ReleaseDeleteComponent } from './release-delete.component'; +import { ToastService } from '../../shared/elements/toast/toast.service'; @Component({ - selector: 'amw-releases', + selector: 'app-releases', standalone: true, imports: [ AsyncPipe, @@ -29,7 +28,6 @@ import { ReleaseDeleteComponent } from './release-delete.component'; PaginationComponent, ReleaseEditComponent, ReleaseDeleteComponent, - ToastComponent, ], providers: [AuthService], templateUrl: './releases.component.html', @@ -46,30 +44,29 @@ export class ReleasesComponent implements OnInit { dateFormat = DATE_FORMAT; // pagination with default values - maxResults: number = 10; - offset: number = 0; + maxResults = 10; + offset = 0; allResults: number; currentPage: number; lastPage: number; - isLoading: boolean = true; + isLoading = true; - canCreate: boolean = false; - canEdit: boolean = false; - canDelete: boolean = false; - - @ViewChild(ToastComponent) toast: ToastComponent; + canCreate = false; + canEdit = false; + canDelete = false; constructor( private authService: AuthService, private http: HttpClient, private modalService: NgbModal, private releasesService: ReleasesService, + private toastService: ToastService, ) {} ngOnInit(): void { this.error$.pipe(takeUntil(this.destroy$)).subscribe((msg) => { - msg != '' ? this.toast.display(msg, 'error', 5000) : null; + msg !== '' ? this.toastService.error(msg) : null; }); this.getUserPermissions(); this.count$ = this.releasesService.getCount(); @@ -151,7 +148,7 @@ export class ReleasesComponent implements OnInit { next: (r) => r, error: (e) => this.error$.next(e), complete: () => { - this.toast.display('Release saved successfully.', 'success'); + this.toastService.success('Release saved successfully.'); this.getReleases(); }, }); @@ -181,7 +178,7 @@ export class ReleasesComponent implements OnInit { next: (r) => r, error: (e) => this.error$.next(e), complete: () => { - this.toast.display('Release deleted.', 'success'); + this.toastService.success('Release deleted.'); this.getReleases(); }, }); diff --git a/AMW_angular/io/src/app/settings/tags/tags.component.html b/AMW_angular/io/src/app/settings/tags/tags.component.html index fe7f0860a..ec80c03b1 100644 --- a/AMW_angular/io/src/app/settings/tags/tags.component.html +++ b/AMW_angular/io/src/app/settings/tags/tags.component.html @@ -4,14 +4,10 @@

Tags

@if (canCreate) { - - + + }
@@ -26,18 +22,17 @@

Tags

@for (tag of tags; track tag) { - - {{ tag.name }} - + + {{ tag.name }} + @if (canDelete) { - - } - - - } + + } + + + } -
diff --git a/AMW_angular/io/src/app/settings/tags/tags.component.ts b/AMW_angular/io/src/app/settings/tags/tags.component.ts index 499f82226..ae6ad035c 100644 --- a/AMW_angular/io/src/app/settings/tags/tags.component.ts +++ b/AMW_angular/io/src/app/settings/tags/tags.component.ts @@ -1,13 +1,11 @@ -import { Component, OnDestroy, OnInit, ViewChild } from '@angular/core'; +import { Component, OnDestroy, OnInit } from '@angular/core'; import { HttpClient } from '@angular/common/http'; -import { ToastComponent } from 'src/app/shared/elements/toast/toast.component'; -import { ToastComponent as ToastComponent_1 } from '../../shared/elements/toast/toast.component'; import { FormsModule } from '@angular/forms'; import { IconComponent } from '../../shared/icon/icon.component'; import { Subject } from 'rxjs'; import { AuthService } from '../../auth/auth.service'; import { takeUntil } from 'rxjs/operators'; -import { ToastService } from '../../shared/elements/toast/toast-service'; +import { ToastService } from '../../shared/elements/toast/toast.service'; type Tag = { id: number; name: string }; @@ -16,7 +14,7 @@ type Tag = { id: number; name: string }; templateUrl: './tags.component.html', styleUrl: './tags.component.scss', standalone: true, - imports: [FormsModule, ToastComponent_1, IconComponent], + imports: [FormsModule, IconComponent], }) export class TagsComponent implements OnInit, OnDestroy { tagName = ''; @@ -25,8 +23,6 @@ export class TagsComponent implements OnInit, OnDestroy { canDelete = false; private destroy$ = new Subject(); - @ViewChild(ToastComponent) toast: ToastComponent; - constructor( private http: HttpClient, private authService: AuthService, diff --git a/AMW_angular/io/src/app/shared/elements/toast/toast-container.component.spec.ts b/AMW_angular/io/src/app/shared/elements/toast/toast-container.component.spec.ts index 6e0b700aa..97eafb6c5 100644 --- a/AMW_angular/io/src/app/shared/elements/toast/toast-container.component.spec.ts +++ b/AMW_angular/io/src/app/shared/elements/toast/toast-container.component.spec.ts @@ -1,6 +1,6 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { ToastContainerComponent } from './toast-container.component'; -import { ToastService } from './toast-service'; +import { ToastService } from './toast.service'; describe('ToastContainerComponent', () => { let component: ToastContainerComponent; diff --git a/AMW_angular/io/src/app/shared/elements/toast/toast-container.component.ts b/AMW_angular/io/src/app/shared/elements/toast/toast-container.component.ts index 4226ca399..d239f11c6 100644 --- a/AMW_angular/io/src/app/shared/elements/toast/toast-container.component.ts +++ b/AMW_angular/io/src/app/shared/elements/toast/toast-container.component.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; import { NgbToastModule } from '@ng-bootstrap/ng-bootstrap'; import { NgTemplateOutlet } from '@angular/common'; -import { ToastService } from './toast-service'; +import { ToastService } from './toast.service'; @Component({ selector: 'app-toasts', diff --git a/AMW_angular/io/src/app/shared/elements/toast/toast.component.scss b/AMW_angular/io/src/app/shared/elements/toast/toast.component.scss deleted file mode 100644 index eebf4cebb..000000000 --- a/AMW_angular/io/src/app/shared/elements/toast/toast.component.scss +++ /dev/null @@ -1,67 +0,0 @@ -.toast { - display: flex; - z-index: 1050; - width: auto; - padding: 0; - position: fixed; - right: 2rem; - bottom: 2.5rem; - border-radius: 8px; -} - -.toast-image { - background-image: url('toast_alert.png'); - width: 50px; - border-radius: 8px; - border-top-right-radius: 0; - border-bottom-right-radius: 0; -} - -.image-success { - background-color: midnightblue; -} - -.image-error { - background-color: darkred; -} - -.toast-body { - padding-top: 0; -} - -.body-success { - color: steelblue; -} - -.body-error { - color: darkred; -} - -.toast-list { - list-style-type: disc; - padding-left: 1rem; - margin-bottom: 0; -} - -.toast-header { - justify-content: space-between; - padding-top: 0.5rem; - padding-bottom: 0; - border-bottom: 0; -} - -.header-success { - color: steelblue; -} - -.header-error { - color: darkred; -} - -.close { - padding: 0 10px; -} - -.close:hover { - cursor: pointer; -} diff --git a/AMW_angular/io/src/app/shared/elements/toast/toast.component.spec.ts b/AMW_angular/io/src/app/shared/elements/toast/toast.component.spec.ts deleted file mode 100644 index 5c13592f2..000000000 --- a/AMW_angular/io/src/app/shared/elements/toast/toast.component.spec.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; - -import { ToastComponent } from './toast.component'; - -describe('ToastComponent', () => { - let component: ToastComponent; - let fixture: ComponentFixture; - - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ - imports: [ToastComponent], - }).compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(ToastComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); - - it('should display toast if show is true', () => { - component.show = true; - fixture.detectChanges(); - const toastElement = fixture.nativeElement.querySelector('.toast'); - expect(toastElement).not.toBeNull(); - }); - - it('should not display toast if show is false', () => { - component.show = false; - fixture.detectChanges(); - const toastElement = fixture.nativeElement.querySelector('.toast'); - expect(toastElement).toBeNull(); - }); - - it('should display message', () => { - const testMessage = 'Test message'; - component.display(testMessage); - fixture.detectChanges(); - const messageElement = fixture.nativeElement.querySelector('.toast-body li').textContent; - expect(messageElement).toContain(testMessage); - }); - - it('should hide toast', (done) => { - const testMessage = 'Test message'; - const duration = 1000; - component.display(testMessage, 'success', duration); - fixture.detectChanges(); - setTimeout(() => { - fixture.detectChanges(); - const toastElement = fixture.nativeElement.querySelector('.toast'); - expect(toastElement).toBeNull(); - done(); - }, duration + 100); // adding extra time to ensure toast is gone - }); - - it('should close when close button is clicked', () => { - component.show = true; - fixture.detectChanges(); - const closeButton = fixture.nativeElement.querySelector('.close'); - closeButton.click(); - fixture.detectChanges(); - const toastElement = fixture.nativeElement.querySelector('.toast'); - expect(toastElement).toBeNull(); - }); -}); diff --git a/AMW_angular/io/src/app/shared/elements/toast/toast.component.ts b/AMW_angular/io/src/app/shared/elements/toast/toast.component.ts deleted file mode 100644 index f936377aa..000000000 --- a/AMW_angular/io/src/app/shared/elements/toast/toast.component.ts +++ /dev/null @@ -1,58 +0,0 @@ -import { Component, Input } from '@angular/core'; -import { NgIf, NgClass } from '@angular/common'; - -type SuccessOrError = 'success' | 'error'; -@Component({ - selector: 'app-toast', - template: ` - @if (show) { - - } - `, - styleUrls: ['./toast.component.scss'], - standalone: true, - imports: [NgIf, NgClass], -}) -export class ToastComponent { - @Input() message = ''; - @Input() type: SuccessOrError; - show = false; - timeoutId = undefined; - - public display(message: string, type: SuccessOrError = 'success', duration = 3000) { - this.message = message; - this.type = type; - this.show = true; - - if (this.timeoutId) { - clearTimeout(this.timeoutId); - } - - this.timeoutId = setTimeout(() => { - this.show = false; - }, duration); - } - - close() { - this.show = false; - } -} diff --git a/AMW_angular/io/src/app/shared/elements/toast/toast.service.spec.ts b/AMW_angular/io/src/app/shared/elements/toast/toast.service.spec.ts index 0fb3443b5..bed9925fd 100644 --- a/AMW_angular/io/src/app/shared/elements/toast/toast.service.spec.ts +++ b/AMW_angular/io/src/app/shared/elements/toast/toast.service.spec.ts @@ -1,4 +1,4 @@ -import { ToastService } from './toast-service'; +import { ToastService } from './toast.service'; describe('ToastService', () => { let service: ToastService; diff --git a/AMW_angular/io/src/app/shared/elements/toast/toast-service.ts b/AMW_angular/io/src/app/shared/elements/toast/toast.service.ts similarity index 100% rename from AMW_angular/io/src/app/shared/elements/toast/toast-service.ts rename to AMW_angular/io/src/app/shared/elements/toast/toast.service.ts From 09e74bd28efd35de29f78d8025f8a59ba959d358 Mon Sep 17 00:00:00 2001 From: Max Burri Date: Wed, 3 Jul 2024 10:41:00 +0200 Subject: [PATCH 08/13] feat: add a global error handler --- .../app/shared/service/global-error.handler.ts | 15 +++++++++++++++ AMW_angular/io/src/main.ts | 2 ++ 2 files changed, 17 insertions(+) create mode 100644 AMW_angular/io/src/app/shared/service/global-error.handler.ts diff --git a/AMW_angular/io/src/app/shared/service/global-error.handler.ts b/AMW_angular/io/src/app/shared/service/global-error.handler.ts new file mode 100644 index 000000000..209dbef8f --- /dev/null +++ b/AMW_angular/io/src/app/shared/service/global-error.handler.ts @@ -0,0 +1,15 @@ +import { ErrorHandler, Injectable, inject, Provider } from '@angular/core'; +import { ToastService } from '../elements/toast/toast.service'; + +export function provideGlobalErrorHandler(): Provider[] { + return [{ provide: ErrorHandler, useClass: GlobalErrorHandler }]; +} + +@Injectable({ providedIn: 'root' }) +export class GlobalErrorHandler implements ErrorHandler { + toastService = inject(ToastService); + handleError(error: { message: string }): void { + console.error(error); + this.toastService.error(error.message); + } +} diff --git a/AMW_angular/io/src/main.ts b/AMW_angular/io/src/main.ts index 6f6119a96..b7e67be78 100644 --- a/AMW_angular/io/src/main.ts +++ b/AMW_angular/io/src/main.ts @@ -7,6 +7,7 @@ import { provideAnimations } from '@angular/platform-browser/animations'; import { bootstrapApplication } from '@angular/platform-browser'; import { provideRouter, withHashLocation } from '@angular/router'; import { routes } from './app/app.routes'; +import { provideGlobalErrorHandler } from './app/shared/service/global-error.handler'; if (environment.production) { enableProdMode(); @@ -17,5 +18,6 @@ bootstrapApplication(AppComponent, { provideRouter(routes, withHashLocation()), provideAnimations(), provideHttpClient(withInterceptorsFromDi()), + provideGlobalErrorHandler(), ], }).catch((err) => console.error(err)); From 62c8f88dccb95e22fdc3bfeb2fdfab84a352d76e Mon Sep 17 00:00:00 2001 From: Max Burri Date: Wed, 3 Jul 2024 14:57:43 +0200 Subject: [PATCH 09/13] feat: new http interceptor that shows a toast - no need to handle errors in http subscriptions --- .../app/deployments/deployments.component.ts | 9 +++---- .../deployment-parameter.component.ts | 22 ++++++---------- .../src/app/settings/tags/tags.component.ts | 25 ++++++------------- .../interceptors/http-toast.interceptor.ts | 24 ++++++++++++++++++ AMW_angular/io/src/main.ts | 2 ++ 5 files changed, 43 insertions(+), 39 deletions(-) create mode 100644 AMW_angular/io/src/app/shared/interceptors/http-toast.interceptor.ts diff --git a/AMW_angular/io/src/app/deployments/deployments.component.ts b/AMW_angular/io/src/app/deployments/deployments.component.ts index 4a900e22c..64ed86f75 100644 --- a/AMW_angular/io/src/app/deployments/deployments.component.ts +++ b/AMW_angular/io/src/app/deployments/deployments.component.ts @@ -297,12 +297,9 @@ export class DeploymentsComponent implements OnInit { async copyURL() { const url: string = decodeURIComponent(window.location.href); - try { - await navigator.clipboard.writeText(url); - this.toastService.success('URL copied to clipboard.'); - } catch (err) { - this.toastService.error('Failed to copy URL. Please try again.'); - } + await navigator.clipboard.writeText(url); + this.toastService.success('URL copied to clipboard.'); + throw new Error('Failed to copy'); } sortDeploymentsBy(col: string) { diff --git a/AMW_angular/io/src/app/settings/deployment-parameter/deployment-parameter.component.ts b/AMW_angular/io/src/app/settings/deployment-parameter/deployment-parameter.component.ts index ceebf324f..4566d4e0f 100644 --- a/AMW_angular/io/src/app/settings/deployment-parameter/deployment-parameter.component.ts +++ b/AMW_angular/io/src/app/settings/deployment-parameter/deployment-parameter.component.ts @@ -60,30 +60,22 @@ export class DeploymentParameterComponent implements OnInit, OnDestroy { addKey(): void { const trimmedKeyName = this.keyName.trim(); if (trimmedKeyName.length > 0 && trimmedKeyName.toLowerCase() !== 'null') { - this.http.post('/AMW_rest/resources/deployments/deploymentParameterKeys', this.keyName).subscribe({ - next: (newKey) => { + this.http + .post('/AMW_rest/resources/deployments/deploymentParameterKeys', this.keyName) + .subscribe((newKey) => { this.paramKeys.push(newKey); this.toastService.success('Key added.'); this.keyName = ''; - }, - error: (error) => { - this.toastService.error(error.error.message); - }, - }); + }); } else { this.toastService.error('Key name must not be null or empty'); } } deleteKey(keyId: number): void { - this.http.delete(`/AMW_rest/resources/deployments/deploymentParameterKeys/${keyId}`).subscribe({ - next: () => { - this.paramKeys = this.paramKeys.filter((key) => key.id !== keyId); - this.toastService.success('Key deleted.'); - }, - error: (error) => { - this.toastService.error(error.error.message); - }, + this.http.delete(`/AMW_rest/resources/deployments/deploymentParameterKeys/${keyId}`).subscribe(() => { + this.paramKeys = this.paramKeys.filter((key) => key.id !== keyId); + this.toastService.success('Key deleted.'); }); } } diff --git a/AMW_angular/io/src/app/settings/tags/tags.component.ts b/AMW_angular/io/src/app/settings/tags/tags.component.ts index ae6ad035c..a89cbd332 100644 --- a/AMW_angular/io/src/app/settings/tags/tags.component.ts +++ b/AMW_angular/io/src/app/settings/tags/tags.component.ts @@ -58,29 +58,18 @@ export class TagsComponent implements OnInit, OnDestroy { addTag(): void { if (this.tagName.trim().length > 0) { - this.http.post('/AMW_rest/resources/settings/tags', { name: this.tagName }).subscribe({ - next: (newTag) => { - this.toastService.success('Tag added.'); - this.tags.push(newTag); - this.tagName = ''; - }, - error: (error) => { - this.toastService.error(error.error.message); - }, + this.http.post('/AMW_rest/resources/settings/tags', { name: this.tagName }).subscribe((newTag) => { + this.toastService.success('Tag added.'); + this.tags.push(newTag); + this.tagName = ''; }); } } deleteTag(tagId: number): void { - this.http.delete(`/AMW_rest/resources/settings/tags/${tagId}`).subscribe({ - next: () => { - this.tags = this.tags.filter((tag) => tag.id !== tagId); - this.toastService.success('Tag deleted.'); - }, - - error: (error) => { - this.toastService.error(error.error.message); - }, + this.http.delete(`/AMW_rest/resources/settings/tags/${tagId}`).subscribe(() => { + this.tags = this.tags.filter((tag) => tag.id !== tagId); + this.toastService.success('Tag deleted.'); }); } } diff --git a/AMW_angular/io/src/app/shared/interceptors/http-toast.interceptor.ts b/AMW_angular/io/src/app/shared/interceptors/http-toast.interceptor.ts new file mode 100644 index 000000000..452d63a46 --- /dev/null +++ b/AMW_angular/io/src/app/shared/interceptors/http-toast.interceptor.ts @@ -0,0 +1,24 @@ +import { inject, Injectable, Provider } from '@angular/core'; +import { HTTP_INTERCEPTORS, HttpHandler, HttpInterceptor, HttpRequest } from '@angular/common/http'; +import { catchError, EMPTY } from 'rxjs'; +import { ToastService } from '../elements/toast/toast.service'; + +export function provideHttpToastInterceptor(): Provider[] { + return [{ provide: HTTP_INTERCEPTORS, useClass: HttpToastInterceptor, multi: true }]; +} + +@Injectable({ + providedIn: 'root', +}) +export class HttpToastInterceptor implements HttpInterceptor { + toastService = inject(ToastService); + + intercept(req: HttpRequest, next: HttpHandler) { + return next.handle(req).pipe( + catchError((error) => { + this.toastService.error(error.error.message); + return EMPTY; + }), + ); + } +} diff --git a/AMW_angular/io/src/main.ts b/AMW_angular/io/src/main.ts index b7e67be78..e5f557f89 100644 --- a/AMW_angular/io/src/main.ts +++ b/AMW_angular/io/src/main.ts @@ -8,6 +8,7 @@ import { bootstrapApplication } from '@angular/platform-browser'; import { provideRouter, withHashLocation } from '@angular/router'; import { routes } from './app/app.routes'; import { provideGlobalErrorHandler } from './app/shared/service/global-error.handler'; +import { provideHttpToastInterceptor } from './app/shared/interceptors/http-toast.interceptor'; if (environment.production) { enableProdMode(); @@ -19,5 +20,6 @@ bootstrapApplication(AppComponent, { provideAnimations(), provideHttpClient(withInterceptorsFromDi()), provideGlobalErrorHandler(), + provideHttpToastInterceptor(), ], }).catch((err) => console.error(err)); From 54139063f5dd42a205cfa87ad5dbf9a5b73fdf24 Mon Sep 17 00:00:00 2001 From: Yves Peter Date: Mon, 8 Jul 2024 14:13:53 +0200 Subject: [PATCH 10/13] update angular deployment-logs component for new toast --- .../deployments/logs/deployment-logs.component.html | 1 - .../app/deployments/logs/deployment-logs.component.ts | 11 ++++------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/AMW_angular/io/src/app/deployments/logs/deployment-logs.component.html b/AMW_angular/io/src/app/deployments/logs/deployment-logs.component.html index 3e98e4b1a..0e6ce85ec 100644 --- a/AMW_angular/io/src/app/deployments/logs/deployment-logs.component.html +++ b/AMW_angular/io/src/app/deployments/logs/deployment-logs.component.html @@ -19,4 +19,3 @@

Logs for Deployment {{ deploymentId$ | async }}

} } }
- diff --git a/AMW_angular/io/src/app/deployments/logs/deployment-logs.component.ts b/AMW_angular/io/src/app/deployments/logs/deployment-logs.component.ts index a23f88f58..30c032fdd 100644 --- a/AMW_angular/io/src/app/deployments/logs/deployment-logs.component.ts +++ b/AMW_angular/io/src/app/deployments/logs/deployment-logs.component.ts @@ -17,7 +17,7 @@ import { NgbDropdownItem, } from '@ng-bootstrap/ng-bootstrap'; import { PageComponent } from '../../layout/page/page.component'; -import { ToastComponent } from '../../shared/elements/toast/toast.component'; +import { ToastService } from '../../shared/elements/toast/toast.service'; import { NotificationComponent } from '../../shared/elements/notification/notification.component'; import { Deployment } from '../../deployment/deployment'; import { DeploymentLogContentComponent } from './deployment-log-content.component'; @@ -34,7 +34,7 @@ function failed(): Observable { } @Component({ - selector: 'amw-logs', + selector: 'app-logs', styleUrls: ['./deployment-logs.component.scss'], templateUrl: './deployment-logs.component.html', encapsulation: ViewEncapsulation.None, @@ -52,7 +52,6 @@ function failed(): Observable { LoadingIndicatorComponent, AsyncPipe, PageComponent, - ToastComponent, NotificationComponent, DeploymentLogContentComponent, DeploymentLogFileSelectorComponent, @@ -64,10 +63,9 @@ export class DeploymentLogsComponent implements OnInit, OnDestroy { private deploymentLogsService: DeploymentLogsService, private route: ActivatedRoute, private location: Location, + private toastService: ToastService, ) {} - @ViewChild(ToastComponent) toast: ToastComponent; - /** * the deployment id taken from the route param */ @@ -122,8 +120,7 @@ export class DeploymentLogsComponent implements OnInit, OnDestroy { } this.location.replaceState(`/deployments/${current.id}/logs/${current.filename}`); }); - - this.error$.pipe(takeUntil(this.destroy$)).subscribe((msg) => this.toast.display(msg, 'error', 5000)); + this.error$.pipe(takeUntil(this.destroy$)).subscribe((msg) => this.toastService.error(msg)); CodeMirror.defineSimpleMode('simplemode', { start: [ From f25e27e5916219daa814818d9a442658a55abd3e Mon Sep 17 00:00:00 2001 From: Yves Peter Date: Mon, 8 Jul 2024 14:16:06 +0200 Subject: [PATCH 11/13] update polyfill config for angular 18 --- AMW_angular/io/angular.json | 9 +++-- AMW_angular/io/src/polyfills.ts | 56 ------------------------------- AMW_angular/io/tsconfig.app.json | 2 +- AMW_angular/io/tsconfig.spec.json | 2 +- 4 files changed, 9 insertions(+), 60 deletions(-) delete mode 100644 AMW_angular/io/src/polyfills.ts diff --git a/AMW_angular/io/angular.json b/AMW_angular/io/angular.json index 538ab49c6..f9c59d230 100644 --- a/AMW_angular/io/angular.json +++ b/AMW_angular/io/angular.json @@ -22,7 +22,8 @@ }, "index": "src/index.html", "polyfills": [ - "src/polyfills.ts" + "zone.js", + "@angular/localize/init" ], "tsConfig": "tsconfig.app.json", "assets": [ @@ -98,7 +99,11 @@ "builder": "@angular-devkit/build-angular:karma", "options": { "main": "src/test.ts", - "polyfills": "src/polyfills.ts", + "polyfills": [ + "zone.js", + "zone.js/testing", + "@angular/localize/init" + ], "tsConfig": "tsconfig.spec.json", "karmaConfig": "karma.conf.js", "assets": ["src/favicon.ico", "src/assets"], diff --git a/AMW_angular/io/src/polyfills.ts b/AMW_angular/io/src/polyfills.ts deleted file mode 100644 index 2e2312fff..000000000 --- a/AMW_angular/io/src/polyfills.ts +++ /dev/null @@ -1,56 +0,0 @@ -/*************************************************************************************************** - * Load `$localize` onto the global scope - used if i18n tags appear in Angular templates. - */ -import '@angular/localize/init'; -/** - * This file includes polyfills needed by Angular and is loaded before the app. - * You can add your own extra polyfills to this file. - * - * This file is divided into 2 sections: - * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. - * 2. Application imports. Files imported after ZoneJS that should be loaded before your main - * file. - * - * The current setup is for so-called "evergreen" browsers; the last versions of browsers that - * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), - * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. - * - * Learn more in https://angular.io/guide/browser-support - */ - -/*************************************************************************************************** - * BROWSER POLYFILLS - */ - -/** - * By default, zone.js will patch all possible macroTask and DomEvents - * user can disable parts of macroTask/DomEvents patch by setting following flags - * because those flags need to be set before `zone.js` being loaded, and webpack - * will put import in the top of bundle, so user need to create a separate file - * in this directory (for example: zone-flags.ts), and put the following flags - * into that file, and then add the following code before importing zone.js. - * import './zone-flags.ts'; - * - * The flags allowed in zone-flags.ts are listed here. - * - * The following flags will work for all browsers. - * - * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame - * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick - * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames - * - * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js - * with the following flag, it will bypass `zone.js` patch for IE/Edge - * - * (window as any).__Zone_enable_cross_context_check = true; - * - */ - -/*************************************************************************************************** - * Zone JS is required by default for Angular itself. - */ -import 'zone.js'; // Included with Angular CLI. - -/*************************************************************************************************** - * APPLICATION IMPORTS - */ diff --git a/AMW_angular/io/tsconfig.app.json b/AMW_angular/io/tsconfig.app.json index 303bea373..f74843417 100644 --- a/AMW_angular/io/tsconfig.app.json +++ b/AMW_angular/io/tsconfig.app.json @@ -4,7 +4,7 @@ "outDir": "./out-tsc/app", "types": [] }, - "files": ["src/main.ts", "src/polyfills.ts"], + "files": ["src/main.ts"], "include": ["src/**/*.d.ts"], "exclude": ["src/test.ts", "src/**/*.spec.ts"] } diff --git a/AMW_angular/io/tsconfig.spec.json b/AMW_angular/io/tsconfig.spec.json index 430cf757c..1030a83cf 100644 --- a/AMW_angular/io/tsconfig.spec.json +++ b/AMW_angular/io/tsconfig.spec.json @@ -4,6 +4,6 @@ "outDir": "./out-tsc/spec", "types": ["jasmine", "node"] }, - "files": ["src/test.ts", "src/polyfills.ts"], + "files": ["src/test.ts"], "include": ["src/**/*.spec.ts", "src/**/*.d.ts"] } From de9114183b290242c279fdd64879de52f465ebf6 Mon Sep 17 00:00:00 2001 From: Yves Peter Date: Mon, 8 Jul 2024 14:18:42 +0200 Subject: [PATCH 12/13] remove tslint and codelyzer --- AMW_angular/io/package-lock.json | 417 +++++++++++++++++++------------ AMW_angular/io/package.json | 8 +- AMW_angular/io/tslint.json | 98 -------- 3 files changed, 262 insertions(+), 261 deletions(-) delete mode 100644 AMW_angular/io/tslint.json diff --git a/AMW_angular/io/package-lock.json b/AMW_angular/io/package-lock.json index 973b254be..0afa94137 100644 --- a/AMW_angular/io/package-lock.json +++ b/AMW_angular/io/package-lock.json @@ -42,10 +42,10 @@ "@types/bootstrap": "5.2.8", "@types/jasmine": "^5.1.1", "@types/jasminewd2": "^2.0.12", - "@typescript-eslint/eslint-plugin": "6.13.1", - "@typescript-eslint/parser": "6.13.1", + "@typescript-eslint/eslint-plugin": "7.11.0", + "@typescript-eslint/parser": "7.11.0", "codelyzer": "^6.0.2", - "eslint": "^8.54.0", + "eslint": "8.57.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.0.1", "jasmine-core": "~5.1.1", @@ -58,7 +58,6 @@ "prettier": "3.0.3", "prettier-eslint": "^16.1.2", "ts-node": "~10.9.1", - "tslint": "~6.1.3", "typescript": "~5.4.5" } }, @@ -264,18 +263,6 @@ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true }, - "node_modules/@angular-devkit/build-angular/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@angular-devkit/build-angular/node_modules/tslib": { "version": "2.6.2", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", @@ -434,18 +421,6 @@ "@angular-devkit/schematics": ">= 18.0.0 < 19.0.0" } }, - "node_modules/@angular-eslint/schematics/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@angular-eslint/template-parser": { "version": "18.0.1", "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-18.0.1.tgz", @@ -601,18 +576,6 @@ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true }, - "node_modules/@angular/build/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@angular/cli": { "version": "18.0.6", "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-18.0.6.tgz", @@ -646,18 +609,6 @@ "yarn": ">= 1.13.0" } }, - "node_modules/@angular/cli/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@angular/common": { "version": "18.0.5", "resolved": "https://registry.npmjs.org/@angular/common/-/common-18.0.5.tgz", @@ -4912,12 +4863,6 @@ "integrity": "sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==", "dev": true }, - "node_modules/@types/semver": { - "version": "7.5.8", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", - "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", - "dev": true - }, "node_modules/@types/send": { "version": "0.17.4", "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", @@ -4975,33 +4920,31 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "6.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.13.1.tgz", - "integrity": "sha512-5bQDGkXaxD46bPvQt08BUz9YSaO4S0fB1LB5JHQuXTfkGPI3+UUeS387C/e9jRie5GqT8u5kFTrMvAjtX4O5kA==", + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.11.0.tgz", + "integrity": "sha512-P+qEahbgeHW4JQ/87FuItjBj8O3MYv5gELDzr8QaQ7fsll1gSMTYb6j87MYyxwf3DtD7uGFB9ShwgmCJB5KmaQ==", "dev": true, "dependencies": { - "@eslint-community/regexpp": "^4.5.1", - "@typescript-eslint/scope-manager": "6.13.1", - "@typescript-eslint/type-utils": "6.13.1", - "@typescript-eslint/utils": "6.13.1", - "@typescript-eslint/visitor-keys": "6.13.1", - "debug": "^4.3.4", + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "7.11.0", + "@typescript-eslint/type-utils": "7.11.0", + "@typescript-eslint/utils": "7.11.0", + "@typescript-eslint/visitor-keys": "7.11.0", "graphemer": "^1.4.0", - "ignore": "^5.2.4", + "ignore": "^5.3.1", "natural-compare": "^1.4.0", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", - "eslint": "^7.0.0 || ^8.0.0" + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" }, "peerDependenciesMeta": { "typescript": { @@ -5009,26 +4952,49 @@ } } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/type-utils": { - "version": "6.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.13.1.tgz", - "integrity": "sha512-A2qPlgpxx2v//3meMqQyB1qqTg1h1dJvzca7TugM3Yc2USDY+fsRBiojAEo92HO7f5hW5mjAUF6qobOPzlBCBQ==", + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.11.0.tgz", + "integrity": "sha512-xlAWwPleNRHwF37AhrZurOxA1wyXowW4PqVXZVUNCLjB48CqdPJoJWkrpH2nij9Q3Lb7rtWindtoXwxjxlKKCA==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "6.13.1", - "@typescript-eslint/utils": "6.13.1", - "debug": "^4.3.4", - "ts-api-utils": "^1.0.1" + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.11.0", + "@typescript-eslint/types": "7.11.0", + "@typescript-eslint/typescript-estree": "7.11.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "^8.56.0" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.11.0.tgz", + "integrity": "sha512-yimw99teuaXVWsBcPO1Ais02kwJ1jmNA1KxE7ng0aT7ndr1pT1wqj0OJnsYVGKKlc4QJai86l/025L6z8CljOg==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "7.11.0", + "@typescript-eslint/types": "7.11.0", + "@typescript-eslint/typescript-estree": "7.11.0", + "@typescript-eslint/visitor-keys": "7.11.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" }, "peerDependenciesMeta": { "typescript": { @@ -5036,52 +5002,43 @@ } } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { - "version": "6.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.13.1.tgz", - "integrity": "sha512-ouPn/zVoan92JgAegesTXDB/oUp6BP1v8WpfYcqh649ejNc9Qv+B4FF2Ff626kO1xg0wWwwG48lAJ4JuesgdOw==", + "node_modules/@typescript-eslint/scope-manager": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.11.0.tgz", + "integrity": "sha512-27tGdVEiutD4POirLZX4YzT180vevUURJl4wJGmm6TrQoiYwuxTIY98PBp6L2oN+JQxzE0URvYlzJaBHIekXAw==", "dev": true, "dependencies": { - "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.12", - "@types/semver": "^7.5.0", - "@typescript-eslint/scope-manager": "6.13.1", - "@typescript-eslint/types": "6.13.1", - "@typescript-eslint/typescript-estree": "6.13.1", - "semver": "^7.5.4" + "@typescript-eslint/types": "7.11.0", + "@typescript-eslint/visitor-keys": "7.11.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" } }, - "node_modules/@typescript-eslint/parser": { - "version": "6.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.13.1.tgz", - "integrity": "sha512-fs2XOhWCzRhqMmQf0eicLa/CWSaYss2feXsy7xBD/pLyWke/jCIVc2s1ikEAtSW7ina1HNhv7kONoEfVNEcdDQ==", + "node_modules/@typescript-eslint/type-utils": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.11.0.tgz", + "integrity": "sha512-WmppUEgYy+y1NTseNMJ6mCFxt03/7jTOy08bcg7bxJJdsM4nuhnchyBbE8vryveaJUf62noH7LodPSo5Z0WUCg==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "6.13.1", - "@typescript-eslint/types": "6.13.1", - "@typescript-eslint/typescript-estree": "6.13.1", - "@typescript-eslint/visitor-keys": "6.13.1", - "debug": "^4.3.4" + "@typescript-eslint/typescript-estree": "7.11.0", + "@typescript-eslint/utils": "7.11.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "^8.56.0" }, "peerDependenciesMeta": { "typescript": { @@ -5089,30 +5046,35 @@ } } }, - "node_modules/@typescript-eslint/scope-manager": { - "version": "6.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.13.1.tgz", - "integrity": "sha512-BW0kJ7ceiKi56GbT2KKzZzN+nDxzQK2DS6x0PiSMPjciPgd/JRQGMibyaN2cPt2cAvuoH0oNvn2fwonHI+4QUQ==", + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/utils": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.11.0.tgz", + "integrity": "sha512-xlAWwPleNRHwF37AhrZurOxA1wyXowW4PqVXZVUNCLjB48CqdPJoJWkrpH2nij9Q3Lb7rtWindtoXwxjxlKKCA==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.13.1", - "@typescript-eslint/visitor-keys": "6.13.1" + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.11.0", + "@typescript-eslint/types": "7.11.0", + "@typescript-eslint/typescript-estree": "7.11.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" } }, "node_modules/@typescript-eslint/types": { - "version": "6.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.13.1.tgz", - "integrity": "sha512-gjeEskSmiEKKFIbnhDXUyiqVma1gRCQNbVZ1C8q7Zjcxh3WZMbzWVfGE9rHfWd1msQtPS0BVD9Jz9jded44eKg==", + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.11.0.tgz", + "integrity": "sha512-MPEsDRZTyCiXkD4vd3zywDCifi7tatc4K37KqTprCvaXptP7Xlpdw0NR2hRJTetG5TxbWDB79Ys4kLmHliEo/w==", "dev": true, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -5120,21 +5082,22 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "6.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.13.1.tgz", - "integrity": "sha512-sBLQsvOC0Q7LGcUHO5qpG1HxRgePbT6wwqOiGLpR8uOJvPJbfs0mW3jPA3ujsDvfiVwVlWUDESNXv44KtINkUQ==", + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.11.0.tgz", + "integrity": "sha512-cxkhZ2C/iyi3/6U9EPc5y+a6csqHItndvN/CzbNXTNrsC3/ASoYQZEt9uMaEp+xFNjasqQyszp5TumAVKKvJeQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.13.1", - "@typescript-eslint/visitor-keys": "6.13.1", + "@typescript-eslint/types": "7.11.0", + "@typescript-eslint/visitor-keys": "7.11.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", - "semver": "^7.5.4", - "ts-api-utils": "^1.0.1" + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -5146,6 +5109,30 @@ } } }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/@typescript-eslint/utils": { "version": "7.14.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.14.1.tgz", @@ -5275,16 +5262,16 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "6.13.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.13.1.tgz", - "integrity": "sha512-NDhQUy2tg6XGNBGDRm1XybOHSia8mcXmlbKWoQP+nm1BIIMxa55shyJfZkHpEBN62KNPLrocSM2PdPcaLgDKMQ==", + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.11.0.tgz", + "integrity": "sha512-7syYk4MzjxTEk0g/w3iqtgxnFQspDJfn6QKD36xMuuhTzjcxY7F8EmBLnALjVyaOF1/bVocu3bS/2/F7rXrveQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "6.13.1", - "eslint-visitor-keys": "^3.4.1" + "@typescript-eslint/types": "7.11.0", + "eslint-visitor-keys": "^3.4.3" }, "engines": { - "node": "^16.0.0 || >=18.0.0" + "node": "^18.18.0 || >=20.0.0" }, "funding": { "type": "opencollective", @@ -6184,6 +6171,7 @@ "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", "integrity": "sha512-wxXCdllwGhI2kCC0MnvTGYTMvnVZTvqgypkiTI8Pa5tcz2i6VqsqwYGgqwXji+4RgCzms6EajE4IxiUH6HH8nQ==", "dev": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -12766,6 +12754,133 @@ } } }, + "node_modules/prettier-eslint/node_modules/@typescript-eslint/parser": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", + "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/prettier-eslint/node_modules/@typescript-eslint/scope-manager": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", + "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/prettier-eslint/node_modules/@typescript-eslint/types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", + "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/prettier-eslint/node_modules/@typescript-eslint/typescript-estree": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", + "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/prettier-eslint/node_modules/@typescript-eslint/visitor-keys": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", + "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/prettier-eslint/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/prettier-eslint/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/prettier-linter-helpers": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", @@ -13434,12 +13549,9 @@ } }, "node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", - "dependencies": { - "lru-cache": "^6.0.0" - }, + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "bin": { "semver": "bin/semver.js" }, @@ -13465,22 +13577,6 @@ "semver": "bin/semver" } }, - "node_modules/semver/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, "node_modules/send": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", @@ -14574,6 +14670,7 @@ "integrity": "sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg==", "deprecated": "TSLint has been deprecated in favor of ESLint. Please see https://github.com/palantir/tslint/issues/4534 for more information.", "dev": true, + "peer": true, "dependencies": { "@babel/code-frame": "^7.0.0", "builtin-modules": "^1.1.1", @@ -14604,6 +14701,7 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, + "peer": true, "bin": { "semver": "bin/semver" } @@ -14612,13 +14710,15 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true + "dev": true, + "peer": true }, "node_modules/tsutils": { "version": "2.29.0", "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==", "dev": true, + "peer": true, "dependencies": { "tslib": "^1.8.1" }, @@ -14630,7 +14730,8 @@ "version": "1.14.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true + "dev": true, + "peer": true }, "node_modules/tuf-js": { "version": "2.2.1", diff --git a/AMW_angular/io/package.json b/AMW_angular/io/package.json index c7a55c31f..9fcb379f7 100644 --- a/AMW_angular/io/package.json +++ b/AMW_angular/io/package.json @@ -50,10 +50,9 @@ "@types/bootstrap": "5.2.8", "@types/jasmine": "^5.1.1", "@types/jasminewd2": "^2.0.12", - "@typescript-eslint/eslint-plugin": "6.13.1", - "@typescript-eslint/parser": "6.13.1", - "codelyzer": "^6.0.2", - "eslint": "^8.54.0", + "@typescript-eslint/eslint-plugin": "7.11.0", + "@typescript-eslint/parser": "7.11.0", + "eslint": "8.57.0", "eslint-config-prettier": "^9.1.0", "eslint-plugin-prettier": "^5.0.1", "jasmine-core": "~5.1.1", @@ -66,7 +65,6 @@ "prettier": "3.0.3", "prettier-eslint": "^16.1.2", "ts-node": "~10.9.1", - "tslint": "~6.1.3", "typescript": "~5.4.5" } } diff --git a/AMW_angular/io/tslint.json b/AMW_angular/io/tslint.json deleted file mode 100644 index fc49a35b1..000000000 --- a/AMW_angular/io/tslint.json +++ /dev/null @@ -1,98 +0,0 @@ -{ - "extends": "tslint:recommended", - "rules": { - "align": { - "options": ["parameters", "statements"] - }, - "array-type": false, - "arrow-parens": false, - "arrow-return-shorthand": true, - "curly": true, - "deprecation": { - "severity": "warning" - }, - "component-class-suffix": true, - "contextual-lifecycle": true, - "directive-class-suffix": true, - "directive-selector": [true, "attribute", "app", "camelCase"], - "component-selector": [true, "element", "app", "kebab-case"], - "eofline": true, - "import-blacklist": [true, "rxjs/Rx"], - "import-spacing": true, - "indent": { - "options": ["spaces"] - }, - "interface-name": false, - "max-classes-per-file": false, - "max-line-length": [true, 140], - "member-access": false, - "member-ordering": [ - true, - { - "order": ["static-field", "instance-field", "static-method", "instance-method"] - } - ], - "no-consecutive-blank-lines": false, - "no-console": [true, "debug", "info", "time", "timeEnd", "trace"], - "no-empty": false, - "no-inferrable-types": [true, "ignore-params"], - "no-non-null-assertion": true, - "no-redundant-jsdoc": true, - "no-switch-case-fall-through": true, - "no-var-requires": false, - "object-literal-key-quotes": [true, "as-needed"], - "object-literal-sort-keys": false, - "ordered-imports": false, - "quotemark": [true, "single"], - "semicolon": { - "options": ["always"] - }, - "space-before-function-paren": { - "options": { - "anonymous": "never", - "asyncArrow": "always", - "constructor": "never", - "method": "never", - "named": "never" - } - }, - "trailing-comma": false, - "no-conflicting-lifecycle": true, - "no-host-metadata-property": true, - "no-input-rename": true, - "no-inputs-metadata-property": true, - "no-output-native": true, - "no-output-on-prefix": true, - "no-output-rename": true, - "no-outputs-metadata-property": true, - "template-banana-in-box": true, - "template-no-negated-async": true, - "typedef-whitespace": { - "options": [ - { - "call-signature": "nospace", - "index-signature": "nospace", - "parameter": "nospace", - "property-declaration": "nospace", - "variable-declaration": "nospace" - }, - { - "call-signature": "onespace", - "index-signature": "onespace", - "parameter": "onespace", - "property-declaration": "onespace", - "variable-declaration": "onespace" - } - ] - }, - "use-lifecycle-interface": true, - "use-pipe-transform-interface": true, - "variable-name": { - "options": ["ban-keywords", "check-format", "allow-pascal-case"] - }, - "whitespace": { - "options": ["check-branch", "check-decl", "check-operator", "check-separator", "check-type", "check-typecast"] - } - }, - "rulesDirectory": ["codelyzer"] -} From 7d4c34edb4453927cdc3a4dd16e89d855b57dd10 Mon Sep 17 00:00:00 2001 From: Yves Peter Date: Mon, 8 Jul 2024 14:18:53 +0200 Subject: [PATCH 13/13] update changelog --- release-changelog.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/release-changelog.md b/release-changelog.md index 8bf501fb1..cf326ed9b 100644 --- a/release-changelog.md +++ b/release-changelog.md @@ -4,6 +4,9 @@ * Replace JSF GUI in Settings -> Deployment Parameter page with Angular [#737](https://github.com/liimaorg/liima/issues/737) * Upgrade to Angular 17.1 and switch to new Vite build [#734](https://github.com/liimaorg/liima/issues/734) * Migrate to angular17 control-flow [#727](https://github.com/liimaorg/liima/issues/727) +* Angular 18 Upgrade [#755](https://github.com/liimaorg/liima/issues/755) +* Angular: create ToastContainer Component [#744](https://github.com/liimaorg/liima/issues/744) +* Limit deployment log file size to 10MB [#413](https://github.com/liimaorg/liima/issues/413) * Node and js version update, GH action updates [#741](https://github.com/liimaorg/liima/pull/741) * Update Java Script dependencies