You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficcontrol.apache.org by rs...@apache.org on 2023/05/03 16:07:56 UTC
[trafficcontrol] branch master updated: Template linting for TPv2 (#7462)
This is an automated email from the ASF dual-hosted git repository.
rshah pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficcontrol.git
The following commit(s) were added to refs/heads/master by this push:
new b96f7d34e7 Template linting for TPv2 (#7462)
b96f7d34e7 is described below
commit b96f7d34e7b7c5d9c056a6b184a3ae491417a829
Author: ocket8888 <oc...@apache.org>
AuthorDate: Wed May 3 10:07:49 2023 -0600
Template linting for TPv2 (#7462)
* Add template linting rules
* increase allowable complexity, change to warning, eliminate no-call-expression
* fix missing button types
also, some links incorrectly used `button` tags instead of `a` tags;
fixed those too
* Remove duplicate attribute
* fixed unbound labels
* rework complex conditional in template
* Fix login button has incorrect type
* Remove extraneous space
* Fix e2e tests looking for button id that no longer exists
* Fix button title
---
experimental/traffic-portal/.eslintrc.json | 51 +++++++++++++++++++++-
.../tests/deliveryServices/ds.invalidate.spec.ts | 4 +-
.../asns/detail/asn-detail.component.html | 2 +-
.../cache-group-table.component.html | 2 +-
.../core/currentuser/currentuser.component.html | 4 +-
.../core/currentuser/currentuser.component.spec.ts | 44 +++++++++++++++++++
.../app/core/currentuser/currentuser.component.ts | 15 +++++++
.../update-password-dialog.component.html | 2 +-
.../deliveryservice/deliveryservice.component.html | 2 +-
.../new-invalidation-job-dialog.component.html | 2 +-
.../new-delivery-service.component.html | 24 +++++-----
.../phys-loc/table/phys-loc-table.component.html | 2 +-
.../server-details/server-details.component.html | 2 +-
.../users/user-details/user-details.component.html | 2 +-
.../user-registration-dialog.component.html | 2 +-
.../src/app/core/users/users.component.html | 2 +-
.../src/app/login/login.component.html | 2 +-
.../reset-password-dialog.component.html | 2 +-
.../collection-choice-dialog.component.html | 6 +--
.../decision-dialog/decision-dialog.component.html | 4 +-
.../dialogs/text-dialog/text-dialog.component.html | 2 +-
.../generic-table/generic-table.component.html | 4 +-
.../navigation/tp-header/tp-header.component.html | 18 ++++----
23 files changed, 154 insertions(+), 46 deletions(-)
diff --git a/experimental/traffic-portal/.eslintrc.json b/experimental/traffic-portal/.eslintrc.json
index 4311f5802f..aec9f06b96 100644
--- a/experimental/traffic-portal/.eslintrc.json
+++ b/experimental/traffic-portal/.eslintrc.json
@@ -372,7 +372,56 @@
"extends": [
"plugin:@angular-eslint/template/recommended"
],
- "rules": {}
+ // Rules that are commented out in this block are not available
+ // until Angular 15, and should be un-commented once that upgrade is
+ // done.
+ "rules": {
+ "@angular-eslint/template/accessibility-alt-text": "error",
+ "@angular-eslint/template/accessibility-elements-content": "error",
+ // "@angular-eslint/template/accessibility-interactive-supports-focus": "error",
+ "@angular-eslint/template/accessibility-label-has-associated-control": "error",
+ // "@angular-eslint/template/accessibility-role-has-required-aria": "error",
+ "@angular-eslint/template/accessibility-table-scope": "error",
+ "@angular-eslint/template/accessibility-valid-aria": "error",
+ // I want to see the results of this before committing to it,
+ // which is difficult to do until I can actually use it.
+ // "@angular-eslint/template/attributes-order": "warn",
+ "@angular-eslint/template/banana-in-box": "error",
+ "@angular-eslint/template/button-has-type": "error",
+ // Currently a warning because of suspected false positives.
+ "@angular-eslint/template/click-events-have-key-events": "warn",
+ "@angular-eslint/template/conditional-complexity": [
+ "error",
+ {
+ "maxComplexity": 2
+ }
+ ],
+ // Warning because it's difficult to know exactly when a
+ // refactor is strictly necessary and also because fixing this
+ // would be a huge changeset.
+ "@angular-eslint/template/cyclomatic-complexity": [
+ "warn",
+ {
+ "maxComplexity": 8
+ }
+ ],
+ "@angular-eslint/template/eqeqeq": "error",
+ "@angular-eslint/template/mouse-events-have-key-events": "error",
+ "@angular-eslint/template/no-any": "error",
+ // Currently a warning because of rampant use, and fixing such
+ // usages would be out-of-scope for the PR adding this linting,
+ // IMO.
+ "@angular-eslint/template/no-autofocus": "warn",
+ "@angular-eslint/template/no-distracting-elements": "error",
+ "@angular-eslint/template/no-duplicate-attributes": "error",
+ // "@angular-eslint/template/no-inline-styles": "warn",
+ // "@angular-eslint/template/no-interpolation-in-attributes": "error",
+ "@angular-eslint/template/no-negated-async": "error",
+ "@angular-eslint/template/no-positive-tabindex": "error",
+ // Warning because not always necessary, and appears to have no
+ // options to control when it is required.
+ "@angular-eslint/template/use-track-by-function": "warn"
+ }
}
]
}
diff --git a/experimental/traffic-portal/nightwatch/tests/deliveryServices/ds.invalidate.spec.ts b/experimental/traffic-portal/nightwatch/tests/deliveryServices/ds.invalidate.spec.ts
index c7d8ff52e9..3a755dedc4 100644
--- a/experimental/traffic-portal/nightwatch/tests/deliveryServices/ds.invalidate.spec.ts
+++ b/experimental/traffic-portal/nightwatch/tests/deliveryServices/ds.invalidate.spec.ts
@@ -38,7 +38,7 @@ describe("DS Invalidation Jobs Spec", () => {
await browser.waitForElementVisible("tp-new-invalidation-job-dialog")
.assert.valueEquals("input[name='startDate']", startDate.toLocaleDateString())
.setValue("input[name='regexp']", "/invalidateMe")
- .click("button#submit");
+ .click("button[type=submit]");
await common
.assert.textContains("@snackbarEle", "created")
.click("simple-snack-bar button");
@@ -51,7 +51,7 @@ describe("DS Invalidation Jobs Spec", () => {
.assert.valueEquals("input[name='startDate']", startDate.toLocaleDateString())
.assert.valueEquals("input[name='regexp']", "invalidateMe")
.setValue("input[name='regexp']", "/invalidateMe2")
- .click("button#submit");
+ .click("button[type=submit]");
await common
.assert.textContains("@snackbarEle", "created")
.click("simple-snack-bar button");
diff --git a/experimental/traffic-portal/src/app/core/cache-groups/asns/detail/asn-detail.component.html b/experimental/traffic-portal/src/app/core/cache-groups/asns/detail/asn-detail.component.html
index 64565c879b..e575bff0a4 100644
--- a/experimental/traffic-portal/src/app/core/cache-groups/asns/detail/asn-detail.component.html
+++ b/experimental/traffic-portal/src/app/core/cache-groups/asns/detail/asn-detail.component.html
@@ -26,7 +26,7 @@ limitations under the License.
</mat-form-field>
<mat-form-field>
<mat-label>Cache Group</mat-label>
- <mat-select name="cachegroup"[(ngModel)]="asn.cachegroupId" required>
+ <mat-select name="cachegroup" [(ngModel)]="asn.cachegroupId" required>
<mat-option *ngFor="let cachegroup of cachegroups" [value]="cachegroup.id">{{cachegroup.name}}</mat-option>
</mat-select>
</mat-form-field>
diff --git a/experimental/traffic-portal/src/app/core/cache-groups/cache-group-table/cache-group-table.component.html b/experimental/traffic-portal/src/app/core/cache-groups/cache-group-table/cache-group-table.component.html
index eff44869e3..1444862745 100644
--- a/experimental/traffic-portal/src/app/core/cache-groups/cache-group-table/cache-group-table.component.html
+++ b/experimental/traffic-portal/src/app/core/cache-groups/cache-group-table/cache-group-table.component.html
@@ -25,4 +25,4 @@ limitations under the License.
</tp-generic-table>
</mat-card>
-<button class="page-fab" mat-fab title="Create a new Cache Group" *ngIf="auth.hasPermission('CACHE-GROUP:CREATE')" routerLink="new"><mat-icon>add</mat-icon></button>
+<a class="page-fab" mat-fab title="Create a new Cache Group" *ngIf="auth.hasPermission('CACHE-GROUP:CREATE')" routerLink="new"><mat-icon>add</mat-icon></a>
diff --git a/experimental/traffic-portal/src/app/core/currentuser/currentuser.component.html b/experimental/traffic-portal/src/app/core/currentuser/currentuser.component.html
index 3b6157e820..a10e4f98f4 100644
--- a/experimental/traffic-portal/src/app/core/currentuser/currentuser.component.html
+++ b/experimental/traffic-portal/src/app/core/currentuser/currentuser.component.html
@@ -19,7 +19,7 @@ limitations under the License.
<p *ngIf=currentUser.addressLine1>{{currentUser.addressLine1}}</p>
<p *ngIf=currentUser.addressLine2>{{currentUser.addressLine2}}</p>
<p *ngIf=currentUser.company>{{currentUser.company}}</p>
- <p *ngIf="currentUser.city || currentUser.country || currentUser.stateOrProvince || currentUser.postalCode"><span *ngIf="currentUser.city">{{currentUser.city}}<span *ngIf="currentUser.country || currentUser.stateOrProvince || currentUser.postalCode"> </span></span><span *ngIf="currentUser.stateOrProvince">{{currentUser.stateOrProvince}}<span *ngIf="currentUser.country || currentUser.postalCode">, </span></span><span *ngIf="currentUser.country">{{currentUser.country}}<span *ngIf=" [...]
+ <p *ngIf="hasBottomAddress()"><span *ngIf="currentUser.city">{{currentUser.city}}<span *ngIf="currentUser.country || currentUser.stateOrProvince || currentUser.postalCode"> </span></span><span *ngIf="currentUser.stateOrProvince">{{currentUser.stateOrProvince}}<span *ngIf="currentUser.country || currentUser.postalCode">, </span></span><span *ngIf="currentUser.country">{{currentUser.country}}<span *ngIf="currentUser.postalCode">, </span></span><span *ngIf=currentUser.postalCode>{{c [...]
</address>
<div>
<h2>User Theme</h2>
@@ -75,7 +75,7 @@ limitations under the License.
</mat-form-field>
</mat-card-content>
<mat-card-actions>
- <button mat-raised-button style="grid-area: k;">Submit</button>
+ <button mat-raised-button style="grid-area: k;" type="submit">Submit</button>
<button mat-raised-button color="accent" style="grid-area: l;" type="button" (click)="updatePassword()">Update Password</button>
<button type="button" mat-raised-button color="warn" (click)="cancelEdit()" style="grid-area: m;">Cancel</button>
</mat-card-actions>
diff --git a/experimental/traffic-portal/src/app/core/currentuser/currentuser.component.spec.ts b/experimental/traffic-portal/src/app/core/currentuser/currentuser.component.spec.ts
index 851d6d3476..c29f9056b0 100644
--- a/experimental/traffic-portal/src/app/core/currentuser/currentuser.component.spec.ts
+++ b/experimental/traffic-portal/src/app/core/currentuser/currentuser.component.spec.ts
@@ -167,4 +167,48 @@ describe("CurrentuserComponent", () => {
expect(updateSpy).toHaveBeenCalledTimes(2);
}));
+
+ it("determines whether a user has a 'bottom-level' address", () => {
+ component.currentUser = null;
+ expect(component.hasBottomAddress()).toBeFalse();
+ component.currentUser = {
+ addressLine1: null,
+ addressLine2: null,
+ changeLogCount: 0,
+ city: null,
+ company: null,
+ country: null,
+ email: "em@i.l",
+ fullName: "",
+ gid: null,
+ id: 1,
+ lastAuthenticated: null,
+ lastUpdated: new Date(),
+ localUser: false,
+ newUser: false,
+ phoneNumber: null,
+ postalCode: null,
+ publicSshKey: null,
+ registrationSent: null,
+ role: "",
+ stateOrProvince: null,
+ tenant: "",
+ tenantId: 1,
+ ucdn: "",
+ uid: null,
+ username: "",
+ };
+ expect(component.hasBottomAddress()).toBeFalse();
+ component.currentUser.city = "Townsville";
+ expect(component.hasBottomAddress()).toBeTrue();
+ component.currentUser.city = null;
+ component.currentUser.country = "Nationstan";
+ expect(component.hasBottomAddress()).toBeTrue();
+ component.currentUser.country = null;
+ component.currentUser.stateOrProvince = "Provincia";
+ expect(component.hasBottomAddress()).toBeTrue();
+ component.currentUser.stateOrProvince = null;
+ component.currentUser.postalCode = "00000";
+ expect(component.hasBottomAddress()).toBeTrue();
+ });
});
diff --git a/experimental/traffic-portal/src/app/core/currentuser/currentuser.component.ts b/experimental/traffic-portal/src/app/core/currentuser/currentuser.component.ts
index 1e69ddfc9c..8362d33044 100644
--- a/experimental/traffic-portal/src/app/core/currentuser/currentuser.component.ts
+++ b/experimental/traffic-portal/src/app/core/currentuser/currentuser.component.ts
@@ -153,4 +153,19 @@ export class CurrentuserComponent implements OnInit {
this.cancelEdit();
}
}
+
+ /**
+ * Checks if the form's user has a "bottom-level" address, meaning any
+ * combination of state/province, postal code, city, and/or country.
+ *
+ * @returns `true` if the user has a "bottom-level" address, `false`
+ * otherwise.
+ */
+ public hasBottomAddress(): boolean {
+ if (!this.currentUser) {
+ return false;
+ }
+ const {city, country, stateOrProvince, postalCode} = this.currentUser;
+ return !!(city || country || stateOrProvince || postalCode);
+ }
}
diff --git a/experimental/traffic-portal/src/app/core/currentuser/update-password-dialog/update-password-dialog.component.html b/experimental/traffic-portal/src/app/core/currentuser/update-password-dialog/update-password-dialog.component.html
index 9636f702b1..cc1ea16d22 100644
--- a/experimental/traffic-portal/src/app/core/currentuser/update-password-dialog/update-password-dialog.component.html
+++ b/experimental/traffic-portal/src/app/core/currentuser/update-password-dialog/update-password-dialog.component.html
@@ -24,7 +24,7 @@ limitations under the License.
</mat-form-field>
</div>
<div mat-dialog-actions>
- <button mat-stroked-button>Submit</button>
+ <button type="submit" mat-stroked-button>Submit</button>
<button type="button" mat-stroked-button color="warn" (click)="cancel()">Cancel</button>
</div>
</form>
diff --git a/experimental/traffic-portal/src/app/core/deliveryservice/deliveryservice.component.html b/experimental/traffic-portal/src/app/core/deliveryservice/deliveryservice.component.html
index 8570f35aca..832cc5522a 100644
--- a/experimental/traffic-portal/src/app/core/deliveryservice/deliveryservice.component.html
+++ b/experimental/traffic-portal/src/app/core/deliveryservice/deliveryservice.component.html
@@ -35,7 +35,7 @@ limitations under the License.
</mat-form-field>
</div>
<div class="actions">
- <button name="timespanRefresh" mat-raised-button>Refresh</button>
+ <button type="submit" name="timespanRefresh" mat-raised-button>Refresh</button>
<mat-icon *ngIf="steeringTargetsFor.size > 0" [matTooltip]="steeringTargetDisplay()" >assistant_direction</mat-icon>
</div>
</form>
diff --git a/experimental/traffic-portal/src/app/core/deliveryservice/invalidation-jobs/new-invalidation-job-dialog/new-invalidation-job-dialog.component.html b/experimental/traffic-portal/src/app/core/deliveryservice/invalidation-jobs/new-invalidation-job-dialog/new-invalidation-job-dialog.component.html
index 09e38bc85f..98b8895aed 100644
--- a/experimental/traffic-portal/src/app/core/deliveryservice/invalidation-jobs/new-invalidation-job-dialog/new-invalidation-job-dialog.component.html
+++ b/experimental/traffic-portal/src/app/core/deliveryservice/invalidation-jobs/new-invalidation-job-dialog/new-invalidation-job-dialog.component.html
@@ -36,7 +36,7 @@ limitations under the License.
</mat-form-field>
</div>
<footer mat-dialog-actions>
- <button mat-raised-button id="submit">Submit</button>
+ <button mat-raised-button type="submit">Submit</button>
<button mat-raised-button color="warn" type="button" (click)="cancel()">Cancel</button>
</footer>
</form>
diff --git a/experimental/traffic-portal/src/app/core/deliveryservice/new-delivery-service/new-delivery-service.component.html b/experimental/traffic-portal/src/app/core/deliveryservice/new-delivery-service/new-delivery-service.component.html
index 697b1a6d84..0bf814f6bf 100644
--- a/experimental/traffic-portal/src/app/core/deliveryservice/new-delivery-service/new-delivery-service.component.html
+++ b/experimental/traffic-portal/src/app/core/deliveryservice/new-delivery-service/new-delivery-service.component.html
@@ -16,14 +16,14 @@ limitations under the License.
<form #form1="ngForm" ngNativeValidate ngDefaultControl (ngSubmit)="setOriginURL()">
<h2>Step 1 - Origin Server</h2>
<div class="form-content">
- <label for="origin">I want to create a Delivery Service for:</label>
+ <label for="origin">I want to create a Delivery Service for</label>
<input [formControl]="originURL" type="url" id="origin" name="origin" placeholder="this URL" autofocus title="Must be a URL (should start with `http://` or `https://`)" pattern="(https?|HTTPS?)://[a-zA-Z][a-zA-z0-9\-]*(\.[a-zA-Z][a-zA-z0-9\-]*)*(/[\w\.]+)*/?" required/>
<label for="active-immediately">This Delivery Service should become active immediately</label>
<input [formControl]="activeImmediately" id="active-immediately" type="checkbox" name="active-immediately" title="This Delivery Service should become active immediately"/>
</div>
<div class="buttons-holder">
<button mat-raised-button color="warn" type="reset">Clear</button>
- <button mat-raised-button>Next</button>
+ <button type="submit" mat-raised-button>Next</button>
</div>
</form>
</mat-step>
@@ -31,22 +31,22 @@ limitations under the License.
<form #form2="ngForm" ngNativeValidate ngDefaultControl (ngSubmit)="setMetaInformation()">
<h2>Step 2 - Meta Information</h2>
<div class="form-content">
- <label for="displayName">This Delivery Service's name will be:</label>
+ <label for="displayName">This Delivery Service's name will be</label>
<input type="text" autofocus title="This will be the name of the Delivery Service as it appears on the 'Home' screen" name="displayName" id="displayName" (change)="updateDisplayName()" [formControl]="displayName" placeholder="{{deliveryService.displayName}}" required>
- <label for="longDesc">Please briefly describe this Delivery Service's purpose and function here:</label>
+ <label for="longDesc">Please briefly describe this Delivery Service's purpose and function</label>
<textarea id="longDesc" name="longDesc" title="No character limit - be as verbose as you like." required placeholder="e.g. This Delivery Service is for my website's image assets." [formControl]="description" rows="3"></textarea>
</div>
<div>
<input type="checkbox" class="sub-form" id="info-URL-sub-form" hidden/>
<label for="info-URL-sub-form" class="sub-form">Add Informational URL</label>
<div class="form-content">
- <label for="infoURL" id="info-URL-label">For more information, people can look at this URL:</label>
+ <label for="infoURL" id="info-URL-label">For more information, people can look at this URL</label>
<input [formControl]="infoURL" type="url" name="infoURL" id="infoURL" placeholder="e.g. https://company.jira.com/ticket/9001"/>
</div>
</div>
<div class="buttons-holder">
<button mat-raised-button type="reset" matStepperPrevious>Previous</button>
- <button mat-raised-button>Next</button>
+ <button mat-raised-button type="submit">Next</button>
</div>
</form>
</mat-step>
@@ -54,7 +54,7 @@ limitations under the License.
<form ngNativeValidate ngDefaultControl (ngSubmit)="setInfrastructureInformation()">
<h2>Step 3 - Infrastructure</h2>
<div class="form-content">
- <label for="cdnObject">This Delivery Service will be a part of this CDN:</label>
+ <label for="cdnObject">This Delivery Service will be a part of this CDN</label>
<select [formControl]="cdnObject" name="cdnObject" id="cdnObject" required>
<option *ngFor="let cdn of cdns" [selected]="cdn.id === deliveryService.cdnId" [ngValue]="cdn">{{cdn.name}}</option>
</select>
@@ -67,22 +67,22 @@ limitations under the License.
<select [formControl]="dsType" name="routingType" id="routingType">
<option *ngFor="let t of dsTypes" [selected]="t.id === deliveryService.typeId" [ngValue]="t">{{t.description}}</option>
</select>
- <label id="protocol">How to handle request protocols</label>
- <mat-radio-group aria-labelledby="protocol" [formControl]="protocol" name="protocol">
- <mat-radio-button *ngFor="let p of protocols" [value]="p" name="protocol">{{protocolToString(p)}}</mat-radio-button>
+ <label for="protocol">How to handle request protocols</label>
+ <mat-radio-group aria-labelledby="protocol" [formControl]="protocol" id="protocol" name="protocol">
+ <mat-radio-button *ngFor="let p of protocols" [value]="p">{{protocolToString(p)}}</mat-radio-button>
</mat-radio-group>
<label for="disableIPv6">Disable IPv6 Routing</label>
<input type="checkbox" id="disableIPv6" name="disableIPv6" [formControl]="disableIPv6"/>
<fieldset name="bypass" id="bypass" *ngIf="bypassable(deliveryService)">
<legend>Bypass Options</legend>
- <label>When the Delivery Service traffic becomes too heavy, clients can be redirected here:</label>
+ <label for="bypass-loc">When the Delivery Service traffic becomes too heavy, clients can be redirected here</label>
<input type="text" name="bypass-loc" id="bypass-loc" [formControl]="bypassLoc" title="can be either an IP (v4 or v6) address or a Fully Qualified Domain Name" pattern="(^[A-z]([A-z\d\-]*[A-z\d])?(\.[A-z]([A-z\d\-]*[A-z\d])?)*$)|(^(1\d\d|2[0-4]\d|25[0-5]|\d\d?)(\.(1\d\d|2[0-4]\d|25[0-5]|\d\d?)){3}$)|(^[a-fA-F\d]{1,4}(::?([a-fA-F\d]){1,4})*$)" /><!-- Yeah, I know that's pretty gnarly, and it doesn't exactly validate IPv6 addresses but it's a good litmus test -->
</fieldset>
</div>
</div>
<div class="buttons-holder">
<button mat-raised-button type="reset" matStepperPrevious>Previous</button>
- <button mat-raised-button>Submit</button>
+ <button mat-raised-button type="submit">Submit</button>
</div>
</form>
</mat-step>
diff --git a/experimental/traffic-portal/src/app/core/servers/phys-loc/table/phys-loc-table.component.html b/experimental/traffic-portal/src/app/core/servers/phys-loc/table/phys-loc-table.component.html
index 82fb885cae..c2600b0bee 100644
--- a/experimental/traffic-portal/src/app/core/servers/phys-loc/table/phys-loc-table.component.html
+++ b/experimental/traffic-portal/src/app/core/servers/phys-loc/table/phys-loc-table.component.html
@@ -26,4 +26,4 @@ limitations under the License.
</tp-generic-table>
</mat-card>
-<button class="page-fab" mat-fab title="Create a new Division" *ngIf="auth.hasPermission('PHYSICAL-LOCATION:CREATE')" routerLink="new"><mat-icon>add</mat-icon></button>
+<a class="page-fab" mat-fab title="Create a new Physical Location" *ngIf="auth.hasPermission('PHYSICAL-LOCATION:CREATE')" routerLink="new"><mat-icon>add</mat-icon></a>
diff --git a/experimental/traffic-portal/src/app/core/servers/server-details/server-details.component.html b/experimental/traffic-portal/src/app/core/servers/server-details/server-details.component.html
index 6528a7f7de..db0d273db2 100644
--- a/experimental/traffic-portal/src/app/core/servers/server-details/server-details.component.html
+++ b/experimental/traffic-portal/src/app/core/servers/server-details/server-details.component.html
@@ -189,7 +189,7 @@ limitations under the License.
</div>
</fieldset>
<div class="buttons">
- <button mat-raised-button>Submit</button>
+ <button mat-raised-button type="submit">Submit</button>
</div>
</form>
</mat-card-content>
diff --git a/experimental/traffic-portal/src/app/core/users/user-details/user-details.component.html b/experimental/traffic-portal/src/app/core/users/user-details/user-details.component.html
index a0eb58ca7f..a20e3b44a5 100644
--- a/experimental/traffic-portal/src/app/core/users/user-details/user-details.component.html
+++ b/experimental/traffic-portal/src/app/core/users/user-details/user-details.component.html
@@ -106,7 +106,7 @@ limitations under the License.
</mat-form-field>
</mat-card-content>
<mat-card-actions align="end">
- <button mat-raised-button color="primary">Save</button>
+ <button mat-raised-button color="primary" type="submit">Save</button>
</mat-card-actions>
</form>
</mat-card>
diff --git a/experimental/traffic-portal/src/app/core/users/user-registration-dialog/user-registration-dialog.component.html b/experimental/traffic-portal/src/app/core/users/user-registration-dialog/user-registration-dialog.component.html
index 5c41700a50..819c7a9325 100644
--- a/experimental/traffic-portal/src/app/core/users/user-registration-dialog/user-registration-dialog.component.html
+++ b/experimental/traffic-portal/src/app/core/users/user-registration-dialog/user-registration-dialog.component.html
@@ -32,7 +32,7 @@ limitations under the License.
</mat-form-field>
</mat-dialog-content>
<mat-dialog-actions>
- <button mat-stroked-button>Submit</button>
+ <button type="submit" mat-stroked-button>Submit</button>
<button mat-stroked-button color="warn" type="button" mat-dialog-close>Cancel</button>
</mat-dialog-actions>
</form>
diff --git a/experimental/traffic-portal/src/app/core/users/users.component.html b/experimental/traffic-portal/src/app/core/users/users.component.html
index 5f5eb8e93f..d04532049e 100644
--- a/experimental/traffic-portal/src/app/core/users/users.component.html
+++ b/experimental/traffic-portal/src/app/core/users/users.component.html
@@ -34,7 +34,7 @@ limitations under the License.
<a cdkMenuItem routerLink="new" color="accent" mat-mini-fab aria-label="Create user from scratch" title="Create user from scratch">
<mat-icon>person_add</mat-icon>
</a>
- <button cdkMenuItem color="accent" mat-mini-fab color="accent" aria-label="Register a new user by email" title="Register a new user by email" (click)="register()">
+ <button type="button" cdkMenuItem color="accent" mat-mini-fab aria-label="Register a new user by email" title="Register a new user by email" (click)="register()">
<mat-icon>contact_mail</mat-icon>
</button>
</menu>
diff --git a/experimental/traffic-portal/src/app/login/login.component.html b/experimental/traffic-portal/src/app/login/login.component.html
index 3ade57fa60..20af5767be 100644
--- a/experimental/traffic-portal/src/app/login/login.component.html
+++ b/experimental/traffic-portal/src/app/login/login.component.html
@@ -27,7 +27,7 @@ limitations under the License.
<tp-obscured-text-input [autocomplete]="passwordAutocomplete" required="true" [(value)]="p" name="p"></tp-obscured-text-input>
</mat-form-field>
<div>
- <button name="login" mat-raised-button color="primary">Login</button>
+ <button name="login" mat-raised-button color="primary" type="submit">Login</button>
<button name="clear" mat-raised-button color="warn" type="reset">Clear</button>
<button name="reset" mat-button color="accent" type="button" (click)="resetPassword()">Forgot Password</button>
</div>
diff --git a/experimental/traffic-portal/src/app/login/reset-password-dialog/reset-password-dialog.component.html b/experimental/traffic-portal/src/app/login/reset-password-dialog/reset-password-dialog.component.html
index f89270fea5..052e4c994c 100644
--- a/experimental/traffic-portal/src/app/login/reset-password-dialog/reset-password-dialog.component.html
+++ b/experimental/traffic-portal/src/app/login/reset-password-dialog/reset-password-dialog.component.html
@@ -21,6 +21,6 @@ limitations under the License.
</mat-dialog-content>
<mat-dialog-actions>
<button mat-raised-button color="warn" type="button" mat-dialog-close>Cancel</button>
- <button mat-raised-button color="primary">Submit</button>
+ <button mat-raised-button color="primary" type="submit">Submit</button>
</mat-dialog-actions>
</form>
diff --git a/experimental/traffic-portal/src/app/shared/dialogs/collection-choice-dialog/collection-choice-dialog.component.html b/experimental/traffic-portal/src/app/shared/dialogs/collection-choice-dialog/collection-choice-dialog.component.html
index b60e1656f9..a790af2464 100644
--- a/experimental/traffic-portal/src/app/shared/dialogs/collection-choice-dialog/collection-choice-dialog.component.html
+++ b/experimental/traffic-portal/src/app/shared/dialogs/collection-choice-dialog/collection-choice-dialog.component.html
@@ -16,7 +16,7 @@ limitations under the License.
<mat-dialog-content>
<p>{{dialogData.message}}</p>
<mat-form-field>
- <label>{{dialogData.label}}</label>
+ <mat-label>{{dialogData.label}}</mat-label>
<mat-select name="{{dialogData.label}}" [(ngModel)]="selected" required>
<mat-option *ngFor="let item of dialogData.collection" [value]="item.value">{{item.label}}</mat-option>
</mat-select>
@@ -26,6 +26,6 @@ limitations under the License.
</mat-form-field>
</mat-dialog-content>
<mat-dialog-actions>
- <button mat-button [disabled]="!selected" [mat-dialog-close]="selected">Confirm</button>
- <button mat-button [mat-dialog-close]="false">Cancel</button>
+ <button type="submit" mat-button [disabled]="!selected" [mat-dialog-close]="selected">Confirm</button>
+ <button type="button" mat-button [mat-dialog-close]="false">Cancel</button>
</mat-dialog-actions>
diff --git a/experimental/traffic-portal/src/app/shared/dialogs/decision-dialog/decision-dialog.component.html b/experimental/traffic-portal/src/app/shared/dialogs/decision-dialog/decision-dialog.component.html
index 8b55e5e1e8..284a62fead 100644
--- a/experimental/traffic-portal/src/app/shared/dialogs/decision-dialog/decision-dialog.component.html
+++ b/experimental/traffic-portal/src/app/shared/dialogs/decision-dialog/decision-dialog.component.html
@@ -15,6 +15,6 @@ limitations under the License.
<h2 mat-dialog-title>{{dialogData.title}}</h2>
<mat-dialog-content>{{dialogData.message}}</mat-dialog-content>
<mat-dialog-actions>
- <button mat-button [mat-dialog-close]="true">Confirm</button>
- <button mat-button [mat-dialog-close]="false">Cancel</button>
+ <button type="submit" mat-button [mat-dialog-close]="true">Confirm</button>
+ <button type="button" mat-button [mat-dialog-close]="false">Cancel</button>
</mat-dialog-actions>
diff --git a/experimental/traffic-portal/src/app/shared/dialogs/text-dialog/text-dialog.component.html b/experimental/traffic-portal/src/app/shared/dialogs/text-dialog/text-dialog.component.html
index 3cbb124de0..1a5fab1947 100644
--- a/experimental/traffic-portal/src/app/shared/dialogs/text-dialog/text-dialog.component.html
+++ b/experimental/traffic-portal/src/app/shared/dialogs/text-dialog/text-dialog.component.html
@@ -15,5 +15,5 @@ limitations under the License.
<h2 mat-dialog-title>{{dialogData.title}}</h2>
<mat-dialog-content>{{dialogData.message}}</mat-dialog-content>
<mat-dialog-actions>
- <button mat-button mat-dialog-close>Ok</button>
+ <button type="submit" mat-button mat-dialog-close>Ok</button>
</mat-dialog-actions>
diff --git a/experimental/traffic-portal/src/app/shared/generic-table/generic-table.component.html b/experimental/traffic-portal/src/app/shared/generic-table/generic-table.component.html
index 5a21c5396e..20dbf15054 100644
--- a/experimental/traffic-portal/src/app/shared/generic-table/generic-table.component.html
+++ b/experimental/traffic-portal/src/app/shared/generic-table/generic-table.component.html
@@ -19,12 +19,12 @@ limitations under the License.
<button mat-flat-button type="button" (click)="download()" title="save as CSV"><fa-icon [icon]="downloadIcon"></fa-icon></button>
<button mat-flat-button type="button" (click)="gridAPI.sizeColumnsToFit()">Resize</button>
<div class="toggle-columns" role="group" title="Select Table Columns">
- <button mat-flat-button [matMenuTriggerFor]="menu">
+ <button type="button" mat-flat-button [matMenuTriggerFor]="menu">
<fa-icon [icon]="columnsIcon"></fa-icon>
<fa-icon [icon]="caretIcon" class="caret" [ngClass]="{'rotate': showMenu}"></fa-icon>
</button>
<mat-menu #menu="matMenu">
- <button mat-menu-item *ngFor="let c of columns" (click)="toggleVisibility($event, c.getColId())">
+ <button type="button" mat-menu-item *ngFor="let c of columns" (click)="toggleVisibility($event, c.getColId())">
<mat-checkbox [checked]="c.isVisible()" (click)="$event.preventDefault()" [name]="c.getColDef().headerName">
{{c.getColDef().headerName}}
</mat-checkbox>
diff --git a/experimental/traffic-portal/src/app/shared/navigation/tp-header/tp-header.component.html b/experimental/traffic-portal/src/app/shared/navigation/tp-header/tp-header.component.html
index 87d79132cd..87f28829bc 100644
--- a/experimental/traffic-portal/src/app/shared/navigation/tp-header/tp-header.component.html
+++ b/experimental/traffic-portal/src/app/shared/navigation/tp-header/tp-header.component.html
@@ -21,37 +21,37 @@ limitations under the License.
<ul>
<li *ngFor="let nav of horizNavs">
<a *ngIf="navShown(nav, 'anchor')" mat-button [routerLink]="navRouterLink(nav)">{{nav.text}}</a>
- <button *ngIf="navShown(nav, 'button')" mat-button (click)="navClick(nav)">{{nav.text}}</button>
+ <button type="button" *ngIf="navShown(nav, 'button')" mat-button (click)="navClick(nav)">{{nav.text}}</button>
</li>
<li>
- <button mat-icon-button [matMenuTriggerFor]="expandedMenu">
+ <button type="button" mat-icon-button [matMenuTriggerFor]="expandedMenu">
<mat-icon>manage_accounts</mat-icon>
</button>
<mat-menu #expandedMenu="matMenu">
- <button mat-menu-item [matMenuTriggerFor]="themeMenu">Theme</button>
+ <button type="button" mat-menu-item [matMenuTriggerFor]="themeMenu">Theme</button>
<div *ngFor="let nav of vertNavs">
<a *ngIf="navShown(nav, 'anchor')" mat-menu-item [routerLink]="navRouterLink(nav)">{{nav.text}}</a>
- <button *ngIf="navShown(nav, 'button')" mat-menu-item (click)="navClick(nav)">{{nav.text}}</button>
+ <button type="button" *ngIf="navShown(nav, 'button')" mat-menu-item (click)="navClick(nav)">{{nav.text}}</button>
</div>
</mat-menu>
</li>
</ul>
</nav>
<nav id="collapsed">
- <button mat-icon-button [matMenuTriggerFor]="collapsedMenu"><mat-icon>menu</mat-icon></button>
+ <button type="button" mat-icon-button [matMenuTriggerFor]="collapsedMenu"><mat-icon>menu</mat-icon></button>
<mat-menu #collapsedMenu="matMenu">
<li *ngFor="let nav of horizNavs">
<a *ngIf="navShown(nav, 'anchor')" mat-menu-item [routerLink]="navRouterLink(nav)">{{nav.text}}</a>
- <button *ngIf="navShown(nav, 'button')" mat-menu-item (click)="navClick(nav)">{{nav.text}}</button>
+ <button type="button" *ngIf="navShown(nav, 'button')" mat-menu-item (click)="navClick(nav)">{{nav.text}}</button>
</li>
- <button mat-menu-item [matMenuTriggerFor]="themeMenu">Theme</button>
+ <button type="button" mat-menu-item [matMenuTriggerFor]="themeMenu">Theme</button>
<li *ngFor="let nav of vertNavs">
<a *ngIf="navShown(nav, 'anchor')" mat-menu-item [routerLink]="navRouterLink(nav)">{{nav.text}}</a>
- <button *ngIf="navShown(nav, 'button')" mat-menu-item (click)="navClick(nav)">{{nav.text}}</button>
+ <button type="button" *ngIf="navShown(nav, 'button')" mat-menu-item (click)="navClick(nav)">{{nav.text}}</button>
</li>
</mat-menu>
</nav>
<mat-menu #themeMenu="matMenu">
- <button mat-menu-item *ngFor="let theme of themeSvc.themes" (click)="themeSvc.loadTheme(theme)">{{theme.name}}</button>
+ <button type="button" mat-menu-item *ngFor="let theme of themeSvc.themes" (click)="themeSvc.loadTheme(theme)">{{theme.name}}</button>
</mat-menu>
</mat-toolbar>