From 2d257ed99f5f5b95ab53ee1adb158e7f37eb211d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20Berthaud-M=C3=BCller?= Date: Mon, 18 Dec 2023 18:54:07 +0100 Subject: [PATCH 01/35] Avoid bundling the mock interceptor in prod env --- src/app/app.module.ts | 15 +++------------ src/app/interceptors/request.interceptor.ts | 14 -------------- src/environments/environment.prod.ts | 3 ++- src/environments/environment.tests.ts | 9 +++++++++ src/environments/environment.ts | 11 ++++++++++- 5 files changed, 24 insertions(+), 28 deletions(-) delete mode 100644 src/app/interceptors/request.interceptor.ts diff --git a/src/app/app.module.ts b/src/app/app.module.ts index 4bb390d0..df1b7e96 100644 --- a/src/app/app.module.ts +++ b/src/app/app.module.ts @@ -1,7 +1,7 @@ import { NgModule, APP_INITIALIZER } from '@angular/core'; import { BrowserModule } from '@angular/platform-browser'; import { RouterModule, Routes } from '@angular/router'; -import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; +import { HttpClientModule } from '@angular/common/http'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { FormsModule, ReactiveFormsModule } from '@angular/forms'; import { environment } from '../environments/environment'; @@ -29,11 +29,6 @@ import { AlertService } from './services/alert.service'; import { NavigationService } from './services/navigation.service'; import { HeaderComponent } from './components/header/header.component'; -import { HttpRequestInterceptor } from './interceptors/request.interceptor'; -import { HttpMockRequestInterceptor } from './interceptors/mock.interceptor'; - -export const isMock = environment.mock; - const appRoutes: Routes = [ { path: 'run-test/:domain', component: DomainComponent }, { path: 'run-test', component: DomainComponent }, @@ -82,11 +77,6 @@ const appRoutes: Routes = [ DnsCheckService, AlertService, NavigationService, - { - provide: HTTP_INTERCEPTORS, - useClass: isMock ? HttpMockRequestInterceptor : HttpRequestInterceptor, - multi: true - }, { provide: APP_INITIALIZER, useFactory: (appService: AppService) => { @@ -94,7 +84,8 @@ const appRoutes: Routes = [ }, multi: true, deps: [AppService] - } + }, + ...environment.extraProvider, ], bootstrap: [AppComponent] }) diff --git a/src/app/interceptors/request.interceptor.ts b/src/app/interceptors/request.interceptor.ts deleted file mode 100644 index b602dd8d..00000000 --- a/src/app/interceptors/request.interceptor.ts +++ /dev/null @@ -1,14 +0,0 @@ - -import { Injectable, Injector } from '@angular/core'; -import { HttpEvent, HttpHandler, HttpInterceptor, HttpRequest, HttpResponse } from '@angular/common/http'; -import { Observable, of } from 'rxjs'; - - -@Injectable() -export class HttpRequestInterceptor implements HttpInterceptor { - constructor(private injector: Injector) {} - - intercept(request: HttpRequest, next: HttpHandler): Observable> { - return next.handle(request); - } -} diff --git a/src/environments/environment.prod.ts b/src/environments/environment.prod.ts index 0efb85c2..b77cf492 100644 --- a/src/environments/environment.prod.ts +++ b/src/environments/environment.prod.ts @@ -4,5 +4,6 @@ export const environment = { ...common, production: true, apiEndpoint: '/api', - mock: false + mock: false, + extraProvider: [], }; diff --git a/src/environments/environment.tests.ts b/src/environments/environment.tests.ts index 43e958ad..cfd8cc98 100644 --- a/src/environments/environment.tests.ts +++ b/src/environments/environment.tests.ts @@ -1,4 +1,6 @@ import { common } from "./common"; +import { HTTP_INTERCEPTORS } from "@angular/common/http"; +import { HttpMockRequestInterceptor } from "../app/interceptors/mock.interceptor"; export const environment = { ...common, @@ -8,4 +10,11 @@ export const environment = { // Use a non existent file to always load the config from the environment file configUrl: 'assets/app.config.non-existent.json', pollingInterval: 0.1 * 1000, + extraProvider: [ + { + provide: HTTP_INTERCEPTORS, + useClass: HttpMockRequestInterceptor, + multi: true + } + ] }; diff --git a/src/environments/environment.ts b/src/environments/environment.ts index 919eb5eb..3354051a 100644 --- a/src/environments/environment.ts +++ b/src/environments/environment.ts @@ -3,10 +3,19 @@ // `ng build --env=prod` then `environment.prod.ts` will be used instead. // The list of which env maps to which file can be found in `.angular-cli.json`. import { common } from "./common"; +import { HttpMockRequestInterceptor } from "../app/interceptors/mock.interceptor"; +import { HTTP_INTERCEPTORS } from "@angular/common/http"; export const environment = { ...common, production: false, apiEndpoint: '/api', - mock: true + mock: true, + extraProvider: [ + { + provide: HTTP_INTERCEPTORS, + useClass: HttpMockRequestInterceptor, + multi: true + } + ] }; From 8f73a73078500b976b27c5dd6e47ecd8158a9157 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20Berthaud-M=C3=BCller?= Date: Thu, 22 Feb 2024 15:36:27 +0100 Subject: [PATCH 02/35] refocus domain input on domain input reset --- src/app/components/form/form.component.css | 13 ++++++++++--- src/app/components/form/form.component.html | 4 ++-- src/app/components/form/form.component.ts | 6 +++++- 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/src/app/components/form/form.component.css b/src/app/components/form/form.component.css index 257171b4..601698b0 100644 --- a/src/app/components/form/form.component.css +++ b/src/app/components/form/form.component.css @@ -229,14 +229,21 @@ hr { } .domain .reset-form button { - border: none; color: inherit; padding: 0; + border-radius: 1em; + line-height: 1; + height: 2em; + width: 2em; + border: .2em solid white; + background-color: #939393; } .domain .reset-form button i { - opacity: .5; - transition: opacity 0.1s; + color: white; + width: 1em; + height: 1em; + font-size: 1.3em; } .domain .progress-value { diff --git a/src/app/components/form/form.component.html b/src/app/components/form/form.component.html index 5a4a06c8..699f9678 100644 --- a/src/app/components/form/form.component.html +++ b/src/app/components/form/form.component.html @@ -2,7 +2,7 @@
- - +
diff --git a/src/app/components/form/form.component.ts b/src/app/components/form/form.component.ts index 430187c3..ca0fb652 100644 --- a/src/app/components/form/form.component.ts +++ b/src/app/components/form/form.component.ts @@ -1,4 +1,4 @@ -import {Component, EventEmitter, OnInit, Input, Output, SimpleChanges, OnChanges, SimpleChange, OnDestroy} from '@angular/core'; +import {Component, EventEmitter, OnInit, Input, Output, OnChanges, SimpleChange, OnDestroy, ViewChild, ElementRef} from '@angular/core'; import {ViewEncapsulation} from '@angular/core'; import { FormGroup, @@ -20,6 +20,8 @@ import { AlertService } from '../../services/alert.service'; encapsulation: ViewEncapsulation.None }) export class FormComponent implements OnInit, OnChanges, OnDestroy { + @ViewChild('domainInput') domainInput!: ElementRef; + @Input() isAdvancedOptionEnabled = false; @Input() formProgression; @Input() toggleFinished; @@ -215,6 +217,8 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy { public resetForm() { this.form.controls.domain.reset(''); + this.domainInput.nativeElement.focus(); + } public resetFullForm() { From c57bb57ce52692a6932ba9f934b528fcef0dfa25 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20Berthaud-M=C3=BCller?= Date: Thu, 22 Feb 2024 17:50:31 +0100 Subject: [PATCH 03/35] improve focus handling for nameserver and ds forms --- package-lock.json | 4 +- src/app/components/form/form.component.css | 34 +++++---- src/app/components/form/form.component.html | 32 ++++---- src/app/components/form/form.component.ts | 75 +++++++++++++------ .../components/result/result.component.html | 2 +- .../run-test/run-test.component.html | 4 +- .../components/run-test/run-test.component.ts | 6 -- src/styles.scss | 16 ++-- 8 files changed, 97 insertions(+), 76 deletions(-) diff --git a/package-lock.json b/package-lock.json index b6a2c1ed..35674240 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "zonemaster-gui", - "version": "4.1.0", + "version": "4.1.1", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "zonemaster-gui", - "version": "4.1.0", + "version": "4.1.1", "license": "BSD-2-Clause", "dependencies": { "@angular/animations": "^13.3.11", diff --git a/src/app/components/form/form.component.css b/src/app/components/form/form.component.css index 601698b0..0f09f36e 100644 --- a/src/app/components/form/form.component.css +++ b/src/app/components/form/form.component.css @@ -181,22 +181,25 @@ hr { margin: 0; } -.domain button#advanced-toggle { - background: none; - border: none; - padding: 0; +.domain summary#advanced-toggle { font-weight: bold; + list-style-type: none; } -.domain button#advanced-toggle i { - width: 1em; - margin-right: .25em; - transform: rotate(0); - transition: 0.1s transform; +.domain summary#advanced-toggle i { + margin-right: .5em; +} + +.domain details#advanced-options summary#advanced-toggle .opened-label { + display: none; +} + +.domain details#advanced-options[open] summary#advanced-toggle .opened-label { + display: initial; } -.domain button#advanced-toggle[aria-expanded="true"] i { - transform: rotate(90deg); +.domain details#advanced-options[open] summary#advanced-toggle .closed-label { + display: none; } /* Domain input */ @@ -224,10 +227,6 @@ hr { right: 0.5rem; } -.domain .reset-form button:not(:disabled):hover i { - opacity: 1; -} - .domain .reset-form button { color: inherit; padding: 0; @@ -239,6 +238,11 @@ hr { background-color: #939393; } +.domain .reset-form button:not(:disabled):hover, +.domain .reset-form button:not(:disabled):focus { + background-color: black; +} + .domain .reset-form button i { color: white; width: 1em; diff --git a/src/app/components/form/form.component.html b/src/app/components/form/form.component.html index 699f9678..1d5d4e03 100644 --- a/src/app/components/form/form.component.html +++ b/src/app/components/form/form.component.html @@ -44,21 +44,15 @@
-
-
+
+ + + Show options + Hide options + + -
+
Nameservers
-
+
Nameserver #{{ i + 1}}
@@ -118,6 +112,7 @@
-
+
diff --git a/src/app/components/form/form.component.ts b/src/app/components/form/form.component.ts index ca0fb652..33d35861 100644 --- a/src/app/components/form/form.component.ts +++ b/src/app/components/form/form.component.ts @@ -1,4 +1,4 @@ -import {Component, EventEmitter, OnInit, Input, Output, OnChanges, SimpleChange, OnDestroy, ViewChild, ElementRef} from '@angular/core'; +import {Component, EventEmitter, OnInit, Input, Output, OnChanges, SimpleChange, OnDestroy, ViewChild, ElementRef } from '@angular/core'; import {ViewEncapsulation} from '@angular/core'; import { FormGroup, @@ -20,16 +20,18 @@ import { AlertService } from '../../services/alert.service'; encapsulation: ViewEncapsulation.None }) export class FormComponent implements OnInit, OnChanges, OnDestroy { - @ViewChild('domainInput') domainInput!: ElementRef; + @ViewChild('domainInput') domainInputView!: ElementRef; + @ViewChild('nameserversForm') nameserversFormView!: ElementRef; + @ViewChild('dsInfoForm') dsInfoFormView!: ElementRef; - @Input() isAdvancedOptionEnabled = false; @Input() formProgression; @Input() toggleFinished; @Input() profiles; @Output() onRunTest = new EventEmitter(); @Output() onFetchDataFromParent = new EventEmitter<[string, string]>(); - @Output() onOpenOptions = new EventEmitter(); + + private groupWithSubscription = new WeakSet(); private formConfig = { 'nameservers': { @@ -65,7 +67,8 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy { constructor(private activatedRoute: ActivatedRoute, private formBuilder: FormBuilder, private titleService: Title, - private alertService: AlertService) {} + private alertService: AlertService) { + } ngOnInit() { this.titleService.setTitle('Zonemaster'); @@ -90,6 +93,14 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy { this.routeParamsSubscription.unsubscribe(); } + get nameserversArray() { + return this.form.get('nameservers') as FormArray; + } + + get dsInfoArray() { + return this.form.get('ds_info') as FormArray; + } + private static atLeastOneProtocolValidator(control: AbstractControl) { const ipv4_disabled = control.get('disable_ipv4'); const ipv6_disabled = control.get('disable_ipv6'); @@ -217,8 +228,7 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy { public resetForm() { this.form.controls.domain.reset(''); - this.domainInput.nativeElement.focus(); - + this.domainInputView.nativeElement.focus(); } public resetFullForm() { @@ -235,12 +245,7 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy { const group = this.formBuilder.group(value, this.formOpts[formName]); if (!isPrefilled) { - const valueChangesSubscription = group.valueChanges.subscribe((e) => { - if (group.pristine === false) { - this.addNewRow(formName); - valueChangesSubscription.unsubscribe(); - } - }); + this.addRowIfFormChange(group, formName); } else { group.markAsDirty(); } @@ -255,18 +260,46 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy { control.removeAt(i); } } else { - if (index < control.length) { + const formElement = formName === 'nameservers' ? + this.nameserversFormView.nativeElement : + this.dsInfoFormView.nativeElement; + + if (control.length === 1 || (index === control.length - 1 && !control.at(index - 1).pristine)) { + control.at(index).reset(); + } else { control.removeAt(index); - } - if (control.length === 0) { - this.addNewRow(formName); + const buttons = formElement.querySelectorAll('button.delete'); + + if (index < buttons.length - 1) { + buttons[index + 1].focus(); + } else { + buttons[index - 1].focus(); + } } + + this.addRowIfFormChange(control.at(control.length - 1), formName); } + return false; } - private fetchDataFromParent(type) { + private addRowIfFormChange(group, formName) { + if (group.pristine && !this.groupWithSubscription.has(group)) { + const valueChangesSubscription = group.valueChanges.subscribe((e) => { + if (group.pristine === false) { + this.addNewRow(formName); + valueChangesSubscription.unsubscribe(); + this.groupWithSubscription.delete(group); + } + }); + + // Avoid subscribing the event multiple times + this.groupWithSubscription.add(group); + } + } + + public fetchDataFromParent(type) { this.domain.markAsTouched(); if (this.domain.invalid) { return false; @@ -332,11 +365,7 @@ export class FormComponent implements OnInit, OnChanges, OnDestroy { } public submitForm() { + console.log('submited') this.submitRunTest(); } - - public toggleOptions() { - this.isAdvancedOptionEnabled = !this.isAdvancedOptionEnabled - this.onOpenOptions.emit(this.isAdvancedOptionEnabled); - } } diff --git a/src/app/components/result/result.component.html b/src/app/components/result/result.component.html index 14b5bb09..3404b35c 100644 --- a/src/app/components/result/result.component.html +++ b/src/app/components/result/result.component.html @@ -111,7 +111,7 @@

Test result for  -
+
diff --git a/src/app/components/run-test/run-test.component.html b/src/app/components/run-test/run-test.component.html index 077ccea3..be80045e 100644 --- a/src/app/components/run-test/run-test.component.html +++ b/src/app/components/run-test/run-test.component.html @@ -1,6 +1,6 @@
-
diff --git a/src/app/components/run-test/run-test.component.ts b/src/app/components/run-test/run-test.component.ts index c7dfd179..7bc96a4a 100644 --- a/src/app/components/run-test/run-test.component.ts +++ b/src/app/components/run-test/run-test.component.ts @@ -15,7 +15,6 @@ import { FormComponent } from '../form/form.component'; }) export class RunTestComponent implements OnInit { private intervalTime: number; - public isAdvancedOptionEnabled = false; public runTestProgression = 0; public showResult = false; public showProgressBar = false; @@ -58,10 +57,6 @@ export class RunTestComponent implements OnInit { }); } - public openOptions(value) { - this.isAdvancedOptionEnabled = value; - } - public runTest(data: object) { let testId: string; @@ -82,7 +77,6 @@ export class RunTestComponent implements OnInit { clearInterval(handle); this.alertService.success($localize `Test completed!`, true); self.testId = testId; - self.isAdvancedOptionEnabled = false; self.showResult = true; self.showProgressBar = false; self.runTestProgression = 5; diff --git a/src/styles.scss b/src/styles.scss index ef1e6af7..ca664181 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -99,12 +99,12 @@ footer .tooltip { .faq-question, -details { +details.details-info { margin-bottom: 0.5rem; } .faq-question header, -details summary { +details.details-info summary { transition: .3s background; list-style: none; margin: 0; @@ -117,7 +117,7 @@ details summary { } .faq-question header *, -details summary * { +details.details-info summary * { margin: 0; } @@ -128,9 +128,9 @@ details summary * { .faq-question.open header, .faq-question header:hover, .faq-question header:focus-within, -details[open] summary, -details summary:hover, -details summary:focus { +details.details-info[open] summary, +details.details-info summary:hover, +details.details-info summary:focus { color: var(--primary-color-dark); background-color: var(--primary-color-lighter-hover); } @@ -143,14 +143,14 @@ details summary .control { } .faq-question.open header, -details[open] summary { +details.details-info[open] summary { border-bottom-left-radius: 0; border-bottom-right-radius: 0; } .faq-question.open header ~ *, -details[open] summary ~ * { +details.details-info[open] summary ~ * { padding: .5em .75em; background-color: var(--primary-color-lighter); border: 1px solid var(--primary-color-light); From d55c7f7409535ac7f4c381a291d4062322c7c405 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20Berthaud-M=C3=BCller?= Date: Mon, 26 Feb 2024 13:57:12 +0100 Subject: [PATCH 04/35] fix e2e tests --- e2e/FR10.e2e-spec.ts | 2 +- e2e/utils/app.utils.ts | 3 +- package-lock.json | 66 +++++++++++++++++++++++++++++------------- package.json | 2 +- 4 files changed, 50 insertions(+), 23 deletions(-) diff --git a/e2e/FR10.e2e-spec.ts b/e2e/FR10.e2e-spec.ts index ac04f379..efb4c989 100644 --- a/e2e/FR10.e2e-spec.ts +++ b/e2e/FR10.e2e-spec.ts @@ -15,7 +15,7 @@ test.describe('Zonemaster test FR10 - [On launching the URL opens with a default test('should have [Options] label visible and NOT selected', async ({ page }) => { await expect(page.locator('#advanced-toggle', { hasText: 'Show options' })).toBeVisible(); - await expect(page.locator('#advanced-toggle')).toHaveAttribute('aria-expanded', 'false'); + await expect(page.locator('#advanced-options')).not.toHaveAttribute('open'); }); diff --git a/e2e/utils/app.utils.ts b/e2e/utils/app.utils.ts index 4d08ce40..fd08d20f 100644 --- a/e2e/utils/app.utils.ts +++ b/e2e/utils/app.utils.ts @@ -11,7 +11,8 @@ export function setLang(page, lang) { export async function showOptions(page) { const showOptionSwitch = page.locator('#advanced-toggle'); - if ((await showOptionSwitch.getAttribute('aria-expanded')) === 'false' ) { + const advancedOption = page.locator('#advanced-options'); + if ((await advancedOption.getAttribute('open')) === null ) { return showOptionSwitch.click(); } } diff --git a/package-lock.json b/package-lock.json index 35674240..a90246e3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -32,7 +32,7 @@ "@angular/cli": "^13.3.9", "@angular/compiler-cli": "^13.3.11", "@angular/language-service": "^13.3.11", - "@playwright/test": "^1.28.0", + "@playwright/test": "^1.41.2", "@types/file-saver": "^2.0.1", "@types/node": "^13.11.0", "archiver": "^3.1.1", @@ -3038,19 +3038,18 @@ } }, "node_modules/@playwright/test": { - "version": "1.28.0", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.28.0.tgz", - "integrity": "sha512-vrHs5DFTPwYox5SGKq/7TDn/S4q6RA1zArd7uhO6EyP9hj3XgZBBM12ktMbnDQNxh/fL1IUKsTNLxihmsU38lQ==", + "version": "1.41.2", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.41.2.tgz", + "integrity": "sha512-qQB9h7KbibJzrDpkXkYvsmiDJK14FULCCZgEcoe2AvFAS64oCirWTwzTlAYEbKaRxWs5TFesE1Na6izMv3HfGg==", "dev": true, "dependencies": { - "@types/node": "*", - "playwright-core": "1.28.0" + "playwright": "1.41.2" }, "bin": { "playwright": "cli.js" }, "engines": { - "node": ">=14" + "node": ">=16" } }, "node_modules/@popperjs/core": { @@ -9356,16 +9355,34 @@ "node": ">=8" } }, - "node_modules/playwright-core": { - "version": "1.28.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.28.0.tgz", - "integrity": "sha512-nJLknd28kPBiCNTbqpu6Wmkrh63OEqJSFw9xOfL9qxfNwody7h6/L3O2dZoWQ6Oxcm0VOHjWmGiCUGkc0X3VZA==", + "node_modules/playwright": { + "version": "1.41.2", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.41.2.tgz", + "integrity": "sha512-v0bOa6H2GJChDL8pAeLa/LZC4feoAMbSQm1/jF/ySsWWoaNItvrMP7GEkvEEFyCTUYKMxjQKaTSg5up7nR6/8A==", "dev": true, + "dependencies": { + "playwright-core": "1.41.2" + }, "bin": { "playwright": "cli.js" }, "engines": { - "node": ">=14" + "node": ">=16" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.41.2", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.41.2.tgz", + "integrity": "sha512-VaTvwCA4Y8kxEe+kfm2+uUUw5Lubf38RxF7FpBxLPmGe5sdNkSg5e3ChEigaGrX7qdqT3pt2m/98LiyvU2x6CA==", + "dev": true, + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=16" } }, "node_modules/portfinder": { @@ -14326,13 +14343,12 @@ } }, "@playwright/test": { - "version": "1.28.0", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.28.0.tgz", - "integrity": "sha512-vrHs5DFTPwYox5SGKq/7TDn/S4q6RA1zArd7uhO6EyP9hj3XgZBBM12ktMbnDQNxh/fL1IUKsTNLxihmsU38lQ==", + "version": "1.41.2", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.41.2.tgz", + "integrity": "sha512-qQB9h7KbibJzrDpkXkYvsmiDJK14FULCCZgEcoe2AvFAS64oCirWTwzTlAYEbKaRxWs5TFesE1Na6izMv3HfGg==", "dev": true, "requires": { - "@types/node": "*", - "playwright-core": "1.28.0" + "playwright": "1.41.2" } }, "@popperjs/core": { @@ -19075,10 +19091,20 @@ } } }, + "playwright": { + "version": "1.41.2", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.41.2.tgz", + "integrity": "sha512-v0bOa6H2GJChDL8pAeLa/LZC4feoAMbSQm1/jF/ySsWWoaNItvrMP7GEkvEEFyCTUYKMxjQKaTSg5up7nR6/8A==", + "dev": true, + "requires": { + "fsevents": "2.3.2", + "playwright-core": "1.41.2" + } + }, "playwright-core": { - "version": "1.28.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.28.0.tgz", - "integrity": "sha512-nJLknd28kPBiCNTbqpu6Wmkrh63OEqJSFw9xOfL9qxfNwody7h6/L3O2dZoWQ6Oxcm0VOHjWmGiCUGkc0X3VZA==", + "version": "1.41.2", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.41.2.tgz", + "integrity": "sha512-VaTvwCA4Y8kxEe+kfm2+uUUw5Lubf38RxF7FpBxLPmGe5sdNkSg5e3ChEigaGrX7qdqT3pt2m/98LiyvU2x6CA==", "dev": true }, "portfinder": { diff --git a/package.json b/package.json index 4e0fcfce..a2d6e8bd 100644 --- a/package.json +++ b/package.json @@ -40,7 +40,7 @@ "@angular/cli": "^13.3.9", "@angular/compiler-cli": "^13.3.11", "@angular/language-service": "^13.3.11", - "@playwright/test": "^1.28.0", + "@playwright/test": "^1.41.2", "@types/file-saver": "^2.0.1", "@types/node": "^13.11.0", "archiver": "^3.1.1", From b9769ec0e8ad1413989f89f0ff4b82dce6c31a06 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ga=C3=ABl=20Berthaud-M=C3=BCller?= Date: Mon, 26 Feb 2024 15:25:04 +0100 Subject: [PATCH 05/35] make ids reflect form controls names --- src/app/components/form/form.component.html | 81 ++++++++++----------- 1 file changed, 38 insertions(+), 43 deletions(-) diff --git a/src/app/components/form/form.component.html b/src/app/components/form/form.component.html index 1d5d4e03..9df26290 100644 --- a/src/app/components/form/form.component.html +++ b/src/app/components/form/form.component.html @@ -1,13 +1,12 @@
- +
-
-
-
@@ -67,45 +63,45 @@ Nameservers
-
+
Nameserver #{{ i + 1}}
- +
-
- {{ ns.controls.ns.errors.serverError }} +
+ {{ nameserver.controls.ns.errors.serverError }}
-
+
The name of nameserver is required
-