This is an automated email from the ASF dual-hosted git repository.
zrhoffman 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 e20656a8ed [TPv2] Update page titles and url for create() call (#7998)
e20656a8ed is described below
commit e20656a8ed189397252e27dd48e8f0b604b6f18b
Author: Rima Shah <[email protected]>
AuthorDate: Fri Apr 26 15:06:36 2024 -0600
[TPv2] Update page titles and url for create() call (#7998)
* Updated asn and server for title change, updated all detail .ts files to
fix title issue, replaced variable name, header with navSvc, added setTitles(),
removed replaceState and updated route for delete and create functionality,
fixed Unit Tests in origin, users, cache-groups, fixed tests - finally, added
delete dialog to tenant, and fixed title for CDN
* updated changelog
---
CHANGELOG.md | 1 +
.../traffic-portal/src/app/api/origin.service.ts | 8 +--
.../asns/detail/asn-detail.component.html | 8 +--
.../asns/detail/asn-detail.component.spec.ts | 6 +--
.../asns/detail/asn-detail.component.ts | 61 +++++++++++++++-------
.../asns/table/asns-table.component.ts | 4 +-
.../cache-group-details.component.spec.ts | 11 +---
.../cache-group-details.component.ts | 14 ++---
.../detail/coordinate-detail.component.ts | 27 +++++++---
.../divisions/detail/division-detail.component.ts | 28 +++++++---
.../regions/detail/region-detail.component.ts | 30 ++++++++---
.../regions/table/regions-table.component.ts | 8 +--
.../core/cdns/cdn-detail/cdn-detail.component.ts | 9 ++--
.../app/core/cdns/cdn-table/cdn-table.component.ts | 3 ++
.../origins/detail/origin-detail.component.spec.ts | 5 +-
.../core/origins/detail/origin-detail.component.ts | 28 +++++++---
.../core/origins/table/origins-table.component.ts | 2 +-
.../detail/parameter-detail.component.ts | 27 +++++++---
.../profile-detail/profile-detail.component.ts | 14 ++++-
.../servers/capabilities/capabilities.component.ts | 3 +-
.../capability-details.component.ts | 8 +--
.../phys-loc/detail/phys-loc-detail.component.ts | 28 +++++++---
.../server-details/server-details.component.ts | 9 ++--
.../servers-table/servers-table.component.ts | 5 +-
.../status-details/status-details.component.ts | 22 ++++++--
.../topology-details/topology-details.component.ts | 9 ++--
.../app/core/types/detail/type-detail.component.ts | 27 +++++++---
.../users/roles/detail/role-detail.component.ts | 18 +++----
.../users/roles/table/roles-table.component.ts | 4 +-
.../tenant-details.component.spec.ts | 3 +-
.../tenant-details/tenant-details.component.ts | 41 ++++++++++++---
.../user-details/user-details.component.spec.ts | 5 +-
.../users/user-details/user-details.component.ts | 28 ++++++++--
.../navigation/tp-header/tp-header.component.ts | 10 ++--
34 files changed, 353 insertions(+), 161 deletions(-)
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 28140a402c..5ac673fdff 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -20,6 +20,7 @@ The format is based on [Keep a
Changelog](http://keepachangelog.com/en/1.0.0/).
- [#7872](https://github.com/apache/trafficcontrol/issues/7872) *Traffic
Router*: Updated Apache Tomcat from 9.0.43, 9.0.67, 9.0.83, and 9.0.86 to
9.0.87.
### Fixed
+- [#7998](https://github.com/apache/trafficcontrol/pull/7998) *Traffic
Portalv2* Fixed (create and update) page titles across every feature
- [#7984](https://github.com/apache/trafficcontrol/pull/7984) *Traffic Ops*
Fixed TO Client cert authentication with respect to returning response cookie.
- [#7957](https://github.com/apache/trafficcontrol/pull/7957) *Traffic Ops*
Fix the incorrect display of delivery services assigned to ORG servers.
- [#7917](https://github.com/apache/trafficcontrol/pull/7917) *Traffic Ops*
Removed `Alerts` field from struct `ProfileExportResponse`.
diff --git a/experimental/traffic-portal/src/app/api/origin.service.ts
b/experimental/traffic-portal/src/app/api/origin.service.ts
index d38142253f..76816af3d8 100644
--- a/experimental/traffic-portal/src/app/api/origin.service.ts
+++ b/experimental/traffic-portal/src/app/api/origin.service.ts
@@ -79,9 +79,7 @@ export class OriginService extends APIService {
* @param originOrId The ID of the Origin to delete.
* @returns The deleted Origin.
*/
- public async deleteOrigin(
- originOrId: number | RequestOriginResponse
- ): Promise<RequestOriginResponse> {
+ public async deleteOrigin(originOrId: number | RequestOriginResponse):
Promise<RequestOriginResponse> {
const id = typeof originOrId === "number" ? originOrId :
originOrId.id;
return
this.delete<RequestOriginResponse>(`origins?id=${id}`).toPromise();
}
@@ -92,9 +90,7 @@ export class OriginService extends APIService {
* @param origin The Origin to create.
* @returns The created Origin.
*/
- public async createOrigin(
- origin: RequestOrigin
- ): Promise<RequestOriginResponse> {
+ public async createOrigin(origin: RequestOrigin):
Promise<RequestOriginResponse> {
return this.post<RequestOriginResponse>("origins",
origin).toPromise();
}
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 3ee7189db3..7d0f9c00bf 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
@@ -16,7 +16,7 @@ limitations under the License.
<tp-loading *ngIf="!asn"></tp-loading>
<form ngNativeValidate (ngSubmit)="submit($event)" *ngIf="asn">
<mat-card-content class="container">
- <mat-form-field *ngIf="!new">
+ <mat-form-field *ngIf="!isNew">
<mat-label>ID</mat-label>
<input matInput type="text" name="id" disabled
readonly [defaultValue]="asn.id" />
</mat-form-field>
@@ -27,7 +27,7 @@ limitations under the License.
<mat-form-field>
<mat-label>Cache Group</mat-label>
<mat-select name="cachegroup"
[(ngModel)]="asn.cachegroupId" required>
- <mat-option *ngFor="let cachegroup of
cachegroups" [value]="cachegroup.id">{{cachegroup.name}}</mat-option>
+ <mat-option *ngFor="let cachegroup of
cacheGroups" [value]="cachegroup.id">{{cachegroup.name}}</mat-option>
</mat-select>
<mat-hint>
<a mat-icon-button
[disabled]="!asn.cachegroupId" class="small-icon-button" matTooltip="View Cache
Group Details" aria-label="View Cache Group Details" color="primary"
[routerLink]="'/core/cache-groups/' + asn.cachegroupId" target="_blank">
@@ -35,12 +35,12 @@ limitations under the License.
</a>
</mat-hint>
</mat-form-field>
- <mat-form-field *ngIf="!new">
+ <mat-form-field *ngIf="!isNew">
<mat-label>Last Updated</mat-label>
<input matInput type="text" name="lastUpdated"
disabled readonly [defaultValue]="asn.lastUpdated" /> </mat-form-field>
</mat-card-content>
<mat-card-actions align="end">
- <button mat-raised-button type="button" *ngIf="!new"
color="warn" (click)="deleteAsn()">Delete</button>
+ <button mat-raised-button type="button" *ngIf="!isNew"
color="warn" (click)="deleteAsn()">Delete</button>
<button mat-raised-button type="submit"
color="primary">Save</button>
</mat-card-actions>
</form>
diff --git
a/experimental/traffic-portal/src/app/core/cache-groups/asns/detail/asn-detail.component.spec.ts
b/experimental/traffic-portal/src/app/core/cache-groups/asns/detail/asn-detail.component.spec.ts
index 278140921a..0226b6f16a 100644
---
a/experimental/traffic-portal/src/app/core/cache-groups/asns/detail/asn-detail.component.spec.ts
+++
b/experimental/traffic-portal/src/app/core/cache-groups/asns/detail/asn-detail.component.spec.ts
@@ -58,8 +58,8 @@ describe("AsnDetailComponent", () => {
await fixture.whenStable();
expect(paramMap).toHaveBeenCalled();
expect(component.asn).not.toBeNull();
- expect(component.asn.asn).toBe(1);
- expect(component.new).toBeTrue();
+ expect(component.asn.asn).toBe(0);
+ expect(component.isNew).toBeTrue();
});
it("existing asn", async () => {
@@ -72,6 +72,6 @@ describe("AsnDetailComponent", () => {
expect(paramMap).toHaveBeenCalled();
expect(component.asn).not.toBeNull();
expect(component.asn.asn).toBe(0);
- expect(component.new).toBeFalse();
+ expect(component.isNew).toBeFalse();
});
});
diff --git
a/experimental/traffic-portal/src/app/core/cache-groups/asns/detail/asn-detail.component.ts
b/experimental/traffic-portal/src/app/core/cache-groups/asns/detail/asn-detail.component.ts
index cc80a543f7..905ab4f523 100644
---
a/experimental/traffic-portal/src/app/core/cache-groups/asns/detail/asn-detail.component.ts
+++
b/experimental/traffic-portal/src/app/core/cache-groups/asns/detail/asn-detail.component.ts
@@ -11,10 +11,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import { Location } from "@angular/common";
+
import { Component, OnInit } from "@angular/core";
import { MatDialog } from "@angular/material/dialog";
-import { ActivatedRoute } from "@angular/router";
+import { ActivatedRoute, Router } from "@angular/router";
import { ResponseASN, ResponseCacheGroup } from "trafficops-types";
import { CacheGroupService } from "src/app/api";
@@ -31,16 +31,16 @@ import { NavigationService } from
"src/app/shared/navigation/navigation.service"
templateUrl: "./asn-detail.component.html"
})
export class ASNDetailComponent implements OnInit {
- public new = false;
+ public isNew = false;
public asn!: ResponseASN;
- public cachegroups!: Array<ResponseCacheGroup>;
+ public cacheGroups = new Array<ResponseCacheGroup>();
constructor(
private readonly route: ActivatedRoute,
+ private readonly router: Router,
private readonly cacheGroupService: CacheGroupService,
- private readonly location: Location,
private readonly dialog: MatDialog,
- private readonly header: NavigationService,
+ private readonly navSvc: NavigationService,
private readonly log: LoggingService,
) {
}
@@ -49,21 +49,28 @@ export class ASNDetailComponent implements OnInit {
* Angular lifecycle hook where data is initialized.
*/
public async ngOnInit(): Promise<void> {
- this.cachegroups = await
this.cacheGroupService.getCacheGroups();
+ this.cacheGroupService.getCacheGroups().then(
+ cgs => {
+ this.cacheGroups = cgs;
+ }
+ );
+
const ID = this.route.snapshot.paramMap.get("id");
if (ID === null) {
this.log.error("missing required route parameter 'id'");
return;
}
- if (ID === "new") {
- this.header.headerTitle.next("New ASN");
- this.new = true;
+ this.isNew = ID === "new";
+
+ if (this.isNew) {
+ this.setTitle();
+ this.isNew = true;
this.asn = {
- asn: 1,
- cachegroup: "test",
- cachegroupId: 1,
- id: 1,
+ asn: 0,
+ cachegroup: "",
+ cachegroupId: 0,
+ id: 0,
lastUpdated: new Date()
};
return;
@@ -75,17 +82,31 @@ export class ASNDetailComponent implements OnInit {
}
this.asn = await this.cacheGroupService.getASNs(numID);
- this.header.headerTitle.next(`ASN: ${this.asn.asn}`);
+ this.setTitle();
+ }
+
+ /**
+ * Sets the headerTitle based on current ASN state.
+ *
+ * @private
+ */
+ private setTitle(): void {
+ const title = this.isNew ? "New ASN" : `ASN: ${this.asn.asn}`;
+ this.navSvc.headerTitle.next(title);
}
/**
* Deletes the current ASN.
*/
public async deleteAsn(): Promise<void> {
- if (this.new) {
+ if (this.isNew) {
this.log.error("Unable to delete new ASN");
return;
}
+ if(!this.asn.asn) {
+ this.log.error("Missing ASN number");
+ return;
+ }
const ref = this.dialog.open(DecisionDialogComponent, {
data: {message: `Are you sure you want to delete ASN
${this.asn.asn} with id ${this.asn.id}`,
title: "Confirm Delete"}
@@ -93,7 +114,7 @@ export class ASNDetailComponent implements OnInit {
ref.afterClosed().subscribe(result => {
if(result) {
this.cacheGroupService.deleteASN(this.asn.id);
- this.location.back();
+ this.router.navigate(["core/asns"]);
}
});
}
@@ -106,12 +127,14 @@ export class ASNDetailComponent implements OnInit {
public async submit(e: Event): Promise<void> {
e.preventDefault();
e.stopPropagation();
- if(this.new) {
+ if(this.isNew) {
this.asn = await
this.cacheGroupService.createASN(this.asn);
- this.new = false;
+ this.isNew = false;
+ await this.router.navigate(["core/asns", this.asn.id]);
} else {
this.asn = await
this.cacheGroupService.updateASN(this.asn);
}
+ this.setTitle();
}
}
diff --git
a/experimental/traffic-portal/src/app/core/cache-groups/asns/table/asns-table.component.ts
b/experimental/traffic-portal/src/app/core/cache-groups/asns/table/asns-table.component.ts
index 1ab0c37145..a52d290c34 100644
---
a/experimental/traffic-portal/src/app/core/cache-groups/asns/table/asns-table.component.ts
+++
b/experimental/traffic-portal/src/app/core/cache-groups/asns/table/asns-table.component.ts
@@ -44,7 +44,7 @@ export class ASNsTableComponent implements OnInit {
constructor(
private readonly route: ActivatedRoute,
- private readonly headerSvc: NavigationService,
+ private readonly navSvc: NavigationService,
private readonly api: CacheGroupService,
private readonly dialog: MatDialog,
public readonly auth: CurrentUserService,
@@ -52,7 +52,7 @@ export class ASNsTableComponent implements OnInit {
) {
this.fuzzySubject = new BehaviorSubject<string>("");
this.asns = this.api.getASNs();
- this.headerSvc.headerTitle.next("ASNs");
+ this.navSvc.headerTitle.next("ASNs");
}
/** Initializes table data, loading it from Traffic Ops. */
diff --git
a/experimental/traffic-portal/src/app/core/cache-groups/cache-group-details/cache-group-details.component.spec.ts
b/experimental/traffic-portal/src/app/core/cache-groups/cache-group-details/cache-group-details.component.spec.ts
index a8a1d14546..c7f0074512 100644
---
a/experimental/traffic-portal/src/app/core/cache-groups/cache-group-details/cache-group-details.component.spec.ts
+++
b/experimental/traffic-portal/src/app/core/cache-groups/cache-group-details/cache-group-details.component.spec.ts
@@ -44,18 +44,11 @@ describe("CacheGroupDetailsComponent", () => {
imports: [
APITestingModule,
RouterTestingModule.withRoutes([
- {
- component:
CacheGroupDetailsComponent,
- path: ""
- },
- {
- component:
CacheGroupDetailsComponent,
- path: "cache-groups/:id"
- }
+ {component: CacheGroupDetailsComponent,
path: "core/cache-groups/:id"},
+ {component: CacheGroupDetailsComponent,
path: "core/cache-groups"}
]),
MatDialogModule,
NoopAnimationsModule,
-
],
providers: [ { provide: NavigationService, useValue:
navSvc } ]
}).compileComponents();
diff --git
a/experimental/traffic-portal/src/app/core/cache-groups/cache-group-details/cache-group-details.component.ts
b/experimental/traffic-portal/src/app/core/cache-groups/cache-group-details/cache-group-details.component.ts
index 7842b7b810..cf6ff4bb29 100644
---
a/experimental/traffic-portal/src/app/core/cache-groups/cache-group-details/cache-group-details.component.ts
+++
b/experimental/traffic-portal/src/app/core/cache-groups/cache-group-details/cache-group-details.component.ts
@@ -12,15 +12,14 @@
* limitations under the License.
*/
-import { Location } from "@angular/common";
-import { Component, type OnInit } from "@angular/core";
+import { Component, OnInit } from "@angular/core";
import { FormControl } from "@angular/forms";
import { MatDialog } from "@angular/material/dialog";
-import { ActivatedRoute } from "@angular/router";
-import { LocalizationMethod, localizationMethodToString, TypeFromResponse,
type ResponseCacheGroup } from "trafficops-types";
+import { ActivatedRoute, Router } from "@angular/router";
+import { LocalizationMethod, localizationMethodToString, TypeFromResponse,
ResponseCacheGroup } from "trafficops-types";
import { CacheGroupService, TypeService } from "src/app/api";
-import { DecisionDialogComponent, type DecisionDialogData } from
"src/app/shared/dialogs/decision-dialog/decision-dialog.component";
+import { DecisionDialogComponent, DecisionDialogData } from
"src/app/shared/dialogs/decision-dialog/decision-dialog.component";
import { LoggingService } from "src/app/shared/logging.service";
import { NavigationService } from
"src/app/shared/navigation/navigation.service";
@@ -69,9 +68,9 @@ export class CacheGroupDetailsComponent implements OnInit {
constructor(
private readonly route: ActivatedRoute,
+ private readonly router: Router,
private readonly api: CacheGroupService,
private readonly typesAPI: TypeService,
- private readonly location: Location,
private readonly dialog: MatDialog,
private readonly navSvc: NavigationService,
private readonly log: LoggingService,
@@ -182,7 +181,7 @@ export class CacheGroupDetailsComponent implements OnInit {
ref.afterClosed().subscribe(result => {
if (result) {
this.api.deleteCacheGroup(this.cacheGroup);
- this.location.replaceState("core/cache-groups");
+ this.router.navigate(["core/cache-groups"]);
}
});
}
@@ -208,6 +207,7 @@ export class CacheGroupDetailsComponent implements OnInit {
if (this.new) {
this.cacheGroup = await
this.api.createCacheGroup(this.cacheGroup);
this.new = false;
+ await this.router.navigate(["core/cache-groups",
this.cacheGroup.id]);
} else {
this.cacheGroup = await
this.api.updateCacheGroup(this.cacheGroup);
}
diff --git
a/experimental/traffic-portal/src/app/core/cache-groups/coordinates/detail/coordinate-detail.component.ts
b/experimental/traffic-portal/src/app/core/cache-groups/coordinates/detail/coordinate-detail.component.ts
index 91b46961a4..f52e371087 100644
---
a/experimental/traffic-portal/src/app/core/cache-groups/coordinates/detail/coordinate-detail.component.ts
+++
b/experimental/traffic-portal/src/app/core/cache-groups/coordinates/detail/coordinate-detail.component.ts
@@ -12,10 +12,9 @@
* limitations under the License.
*/
-import { Location } from "@angular/common";
import { Component, OnInit } from "@angular/core";
import { MatDialog } from "@angular/material/dialog";
-import { ActivatedRoute } from "@angular/router";
+import { ActivatedRoute, Router } from "@angular/router";
import { ResponseCoordinate } from "trafficops-types";
import { CacheGroupService } from "src/app/api";
@@ -37,8 +36,8 @@ export class CoordinateDetailComponent implements OnInit {
constructor(
private readonly route: ActivatedRoute,
+ private readonly router: Router,
private readonly cacheGroupService: CacheGroupService,
- private readonly location: Location,
private readonly dialog: MatDialog,
private readonly navSvc: NavigationService,
private readonly log: LoggingService,
@@ -54,8 +53,10 @@ export class CoordinateDetailComponent implements OnInit {
return;
}
- if (ID === "new") {
- this.navSvc.headerTitle.next("New Coordinate");
+ this.new = ID === "new";
+
+ if (this.new) {
+ this.setTitle();
this.new = true;
this.coordinate = {
id: -1,
@@ -73,7 +74,17 @@ export class CoordinateDetailComponent implements OnInit {
}
this.coordinate = await
this.cacheGroupService.getCoordinates(numID);
- this.navSvc.headerTitle.next(`Coordinate:
${this.coordinate.name}`);
+ this.setTitle();
+ }
+
+ /**
+ * Sets the headerTitle based on current Coordinate state.
+ *
+ * @private
+ */
+ private setTitle(): void {
+ const title = this.new ? "New Coordinate" : `Coordinate:
${this.coordinate.name}`;
+ this.navSvc.headerTitle.next(title);
}
/**
@@ -91,7 +102,7 @@ export class CoordinateDetailComponent implements OnInit {
ref.afterClosed().subscribe(result => {
if(result) {
this.cacheGroupService.deleteCoordinate(this.coordinate.id);
- this.location.back();
+ this.router.navigate(["core/coordinates"]);
}
});
}
@@ -107,9 +118,11 @@ export class CoordinateDetailComponent implements OnInit {
if(this.new) {
this.coordinate = await
this.cacheGroupService.createCoordinate(this.coordinate);
this.new = false;
+ await this.router.navigate(["core/coordinates",
this.coordinate.id]);
} else {
this.coordinate = await
this.cacheGroupService.updateCoordinate(this.coordinate);
}
+ this.setTitle();
}
}
diff --git
a/experimental/traffic-portal/src/app/core/cache-groups/divisions/detail/division-detail.component.ts
b/experimental/traffic-portal/src/app/core/cache-groups/divisions/detail/division-detail.component.ts
index 4a9081e598..80ce54203e 100644
---
a/experimental/traffic-portal/src/app/core/cache-groups/divisions/detail/division-detail.component.ts
+++
b/experimental/traffic-portal/src/app/core/cache-groups/divisions/detail/division-detail.component.ts
@@ -11,10 +11,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import { Location } from "@angular/common";
+
import { Component, OnInit } from "@angular/core";
import { MatDialog } from "@angular/material/dialog";
-import { ActivatedRoute } from "@angular/router";
+import { ActivatedRoute, Router } from "@angular/router";
import { ResponseDivision } from "trafficops-types";
import { CacheGroupService } from "src/app/api";
@@ -35,8 +35,8 @@ export class DivisionDetailComponent implements OnInit {
constructor(
private readonly route: ActivatedRoute,
+ private readonly router: Router,
private readonly cacheGroupService: CacheGroupService,
- private readonly location: Location,
private readonly dialog: MatDialog,
private readonly navSvc: NavigationService,
private readonly log: LoggingService,
@@ -52,8 +52,10 @@ export class DivisionDetailComponent implements OnInit {
return;
}
- if (ID === "new") {
- this.navSvc.headerTitle.next("New Division");
+ this.new = ID === "new";
+
+ if (this.new) {
+ this.setTitle();
this.new = true;
this.division = {
id: -1,
@@ -69,7 +71,17 @@ export class DivisionDetailComponent implements OnInit {
}
this.division = await
this.cacheGroupService.getDivisions(numID);
- this.navSvc.headerTitle.next(`Division: ${this.division.name}`);
+ this.setTitle();
+ }
+
+ /**
+ * Sets the headerTitle based on current Division state.
+ *
+ * @private
+ */
+ private setTitle(): void {
+ const title = this.new ? "New Division" : `Division:
${this.division.name}`;
+ this.navSvc.headerTitle.next(title);
}
/**
@@ -87,7 +99,7 @@ export class DivisionDetailComponent implements OnInit {
ref.afterClosed().subscribe(result => {
if(result) {
this.cacheGroupService.deleteDivision(this.division.id);
- this.location.back();
+ this.router.navigate(["core/divisions"]);
}
});
}
@@ -103,9 +115,11 @@ export class DivisionDetailComponent implements OnInit {
if(this.new) {
this.division = await
this.cacheGroupService.createDivision(this.division);
this.new = false;
+ await this.router.navigate(["core/divisions",
this.division.id]);
} else {
this.division = await
this.cacheGroupService.updateDivision(this.division);
}
+ this.setTitle();
}
}
diff --git
a/experimental/traffic-portal/src/app/core/cache-groups/regions/detail/region-detail.component.ts
b/experimental/traffic-portal/src/app/core/cache-groups/regions/detail/region-detail.component.ts
index 042f7faddf..4a6323b297 100644
---
a/experimental/traffic-portal/src/app/core/cache-groups/regions/detail/region-detail.component.ts
+++
b/experimental/traffic-portal/src/app/core/cache-groups/regions/detail/region-detail.component.ts
@@ -11,10 +11,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import { Location } from "@angular/common";
+
import { Component, OnInit } from "@angular/core";
import { MatDialog } from "@angular/material/dialog";
-import { ActivatedRoute } from "@angular/router";
+import { ActivatedRoute, Router } from "@angular/router";
import { ResponseDivision, ResponseRegion } from "trafficops-types";
import { CacheGroupService } from "src/app/api";
@@ -37,10 +37,10 @@ export class RegionDetailComponent implements OnInit {
constructor(
private readonly route: ActivatedRoute,
+ private readonly router: Router,
private readonly cacheGroupService: CacheGroupService,
- private readonly location: Location,
private readonly dialog: MatDialog,
- private readonly header: NavigationService,
+ private readonly navSvc: NavigationService,
private readonly log: LoggingService,
) {
}
@@ -56,8 +56,10 @@ export class RegionDetailComponent implements OnInit {
return;
}
- if (ID === "new") {
- this.header.headerTitle.next("New Region");
+ this.new = ID === "new";
+
+ if (this.new) {
+ this.setTitle();
this.new = true;
this.region = {
division: -1,
@@ -75,7 +77,17 @@ export class RegionDetailComponent implements OnInit {
}
this.region = await this.cacheGroupService.getRegions(numID);
- this.header.headerTitle.next(`Region: ${this.region.name}`);
+ this.setTitle();
+ }
+
+ /**
+ * Sets the headerTitle based on current Region state.
+ *
+ * @private
+ */
+ private setTitle(): void {
+ const title = this.new ? "New Region" : `Region:
${this.region.name}`;
+ this.navSvc.headerTitle.next(title);
}
/**
@@ -93,7 +105,7 @@ export class RegionDetailComponent implements OnInit {
ref.afterClosed().subscribe(result => {
if(result) {
this.cacheGroupService.deleteRegion(this.region.id);
- this.location.back();
+ this.router.navigate(["core/regions"]);
}
});
}
@@ -109,9 +121,11 @@ export class RegionDetailComponent implements OnInit {
if(this.new) {
this.region = await
this.cacheGroupService.createRegion(this.region);
this.new = false;
+ await this.router.navigate(["core/regions",
this.region.id]);
} else {
this.region = await
this.cacheGroupService.updateRegion(this.region);
}
+ this.setTitle();
}
}
diff --git
a/experimental/traffic-portal/src/app/core/cache-groups/regions/table/regions-table.component.ts
b/experimental/traffic-portal/src/app/core/cache-groups/regions/table/regions-table.component.ts
index e4e966f89d..005d899f1c 100644
---
a/experimental/traffic-portal/src/app/core/cache-groups/regions/table/regions-table.component.ts
+++
b/experimental/traffic-portal/src/app/core/cache-groups/regions/table/regions-table.component.ts
@@ -12,10 +12,10 @@
* limitations under the License.
*/
-import { Component, type OnInit } from "@angular/core";
+import { Component, OnInit } from "@angular/core";
import { FormControl } from "@angular/forms";
import { MatDialog } from "@angular/material/dialog";
-import { ActivatedRoute, type Params } from "@angular/router";
+import { ActivatedRoute, Params } from "@angular/router";
import { BehaviorSubject } from "rxjs";
import type { Region, ResponseRegion } from "trafficops-types";
@@ -44,7 +44,7 @@ export class RegionsTableComponent implements OnInit {
constructor(
private readonly route: ActivatedRoute,
- private readonly headerSvc: NavigationService,
+ private readonly navSvc: NavigationService,
private readonly api: CacheGroupService,
private readonly dialog: MatDialog,
public readonly auth: CurrentUserService,
@@ -52,7 +52,7 @@ export class RegionsTableComponent implements OnInit {
) {
this.fuzzySubject = new BehaviorSubject<string>("");
this.regions = this.api.getRegions();
- this.headerSvc.headerTitle.next("Regions");
+ this.navSvc.headerTitle.next("Regions");
}
/** Initializes table data, loading it from Traffic Ops. */
diff --git
a/experimental/traffic-portal/src/app/core/cdns/cdn-detail/cdn-detail.component.ts
b/experimental/traffic-portal/src/app/core/cdns/cdn-detail/cdn-detail.component.ts
index 53fe744732..cc09162c98 100644
---
a/experimental/traffic-portal/src/app/core/cdns/cdn-detail/cdn-detail.component.ts
+++
b/experimental/traffic-portal/src/app/core/cdns/cdn-detail/cdn-detail.component.ts
@@ -12,10 +12,9 @@
* limitations under the License.
*/
-import { Location } from "@angular/common";
import { Component, OnInit } from "@angular/core";
import { MatDialog } from "@angular/material/dialog";
-import { ActivatedRoute } from "@angular/router";
+import { ActivatedRoute, Router } from "@angular/router";
import { ResponseCDN } from "trafficops-types";
import { CDNService } from "src/app/api";
@@ -48,8 +47,8 @@ export class CDNDetailComponent implements OnInit {
constructor(
private readonly route: ActivatedRoute,
+ private readonly router: Router,
private readonly api: CDNService,
- private readonly location: Location,
private readonly dialog: MatDialog,
private readonly navSvc: NavigationService,
private readonly log: LoggingService,
@@ -84,6 +83,7 @@ export class CDNDetailComponent implements OnInit {
return;
}
this.cdn = this.cdns.splice(index, 1)[0];
+ this.setTitle();
}
/**
@@ -116,7 +116,7 @@ export class CDNDetailComponent implements OnInit {
ref.afterClosed().subscribe(result => {
if (result) {
this.api.deleteCDN(this.cdn);
- this.location.replaceState("core/cdns");
+ this.router.navigate(["core/cdns"]);
}
});
}
@@ -133,6 +133,7 @@ export class CDNDetailComponent implements OnInit {
if (this.new) {
this.cdn = await this.api.createCDN(this.cdn);
this.new = false;
+ await this.router.navigate(["core/cdns", this.cdn.id]);
} else {
this.cdn = await this.api.updateCDN(this.cdn);
}
diff --git
a/experimental/traffic-portal/src/app/core/cdns/cdn-table/cdn-table.component.ts
b/experimental/traffic-portal/src/app/core/cdns/cdn-table/cdn-table.component.ts
index 8bf05e0199..c64526b317 100644
---
a/experimental/traffic-portal/src/app/core/cdns/cdn-table/cdn-table.component.ts
+++
b/experimental/traffic-portal/src/app/core/cdns/cdn-table/cdn-table.component.ts
@@ -32,6 +32,7 @@ import type {
DoubleClickLink
} from "src/app/shared/generic-table/generic-table.component";
import { LoggingService } from "src/app/shared/logging.service";
+import { NavigationService } from
"src/app/shared/navigation/navigation.service";
/**
* CDNTableComponent is the controller for the "CDNs" table.
@@ -163,12 +164,14 @@ export class CDNTableComponent implements OnInit {
private readonly alerts: AlertService,
private readonly api: CDNService,
public readonly auth: CurrentUserService,
+ private readonly navSvc: NavigationService,
private readonly dialog: MatDialog,
private readonly route: ActivatedRoute,
private readonly log: LoggingService,
) {
this.fuzzySubject = new BehaviorSubject<string>("");
this.cdns = this.api.getCDNs();
+ this.navSvc.headerTitle.next("CDNs");
}
/** Initializes table data, loading it from Traffic Ops. */
diff --git
a/experimental/traffic-portal/src/app/core/origins/detail/origin-detail.component.spec.ts
b/experimental/traffic-portal/src/app/core/origins/detail/origin-detail.component.spec.ts
index 62501ed52b..f1c98e263f 100644
---
a/experimental/traffic-portal/src/app/core/origins/detail/origin-detail.component.spec.ts
+++
b/experimental/traffic-portal/src/app/core/origins/detail/origin-detail.component.spec.ts
@@ -44,7 +44,10 @@ describe("OriginDetailComponent", () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [OriginDetailComponent],
- imports: [APITestingModule, RouterTestingModule,
MatDialogModule, NoopAnimationsModule],
+ imports: [APITestingModule,
RouterTestingModule.withRoutes( [
+ {component: OriginDetailComponent, path:
"core/origins/:id"},
+ {component: OriginDetailComponent, path:
"core/origins"},
+ ]), MatDialogModule, NoopAnimationsModule],
providers: [{provide: NavigationService, useValue:
navSvc}],
}).compileComponents();
diff --git
a/experimental/traffic-portal/src/app/core/origins/detail/origin-detail.component.ts
b/experimental/traffic-portal/src/app/core/origins/detail/origin-detail.component.ts
index 1d9c64046a..c50724475b 100644
---
a/experimental/traffic-portal/src/app/core/origins/detail/origin-detail.component.ts
+++
b/experimental/traffic-portal/src/app/core/origins/detail/origin-detail.component.ts
@@ -12,10 +12,9 @@
* limitations under the License.
*/
-import { Location } from "@angular/common";
import { Component, OnInit } from "@angular/core";
import { MatDialog } from "@angular/material/dialog";
-import { ActivatedRoute } from "@angular/router";
+import { ActivatedRoute, Router } from "@angular/router";
import type {
RequestOrigin,
RequestOriginResponse,
@@ -57,8 +56,8 @@ export class OriginDetailComponent implements OnInit {
constructor(
private readonly route: ActivatedRoute,
+ private readonly router: Router,
private readonly originService: OriginService,
- private readonly location: Location,
private readonly dialog: MatDialog,
private readonly navSvc: NavigationService,
private readonly log: LoggingService,
@@ -84,8 +83,11 @@ export class OriginDetailComponent implements OnInit {
this.log.error("missing required route parameter 'id'");
return;
}
- if (ID === "new") {
- this.navSvc.headerTitle.next("New Origin");
+
+ this.new = ID === "new";
+
+ if (this.new) {
+ this.setTitle();
this.new = true;
this.origin = {
cachegroup: null,
@@ -116,7 +118,17 @@ export class OriginDetailComponent implements OnInit {
return;
}
this.origin = await this.originService.getOrigins(numID);
- this.navSvc.headerTitle.next(`Origin: ${this.origin.name}`);
+ this.setTitle();
+ }
+
+ /**
+ * Sets the headerTitle based on current Origin state.
+ *
+ * @private
+ */
+ private setTitle(): void {
+ const title = this.new ? "New Origin" : `Origin:
${this.origin.name}`;
+ this.navSvc.headerTitle.next(title);
}
/**
@@ -136,7 +148,7 @@ export class OriginDetailComponent implements OnInit {
ref.afterClosed().subscribe((result) => {
if (result) {
this.originService.deleteOrigin(this.origin);
- this.location.back();
+ this.router.navigate(["core/origins"]);
}
});
}
@@ -189,8 +201,10 @@ export class OriginDetailComponent implements OnInit {
this.origin = await
this.originService.createOrigin(requestOrigin);
this.new = false;
+ await this.router.navigate(["core/origins",
this.origin.id]);
} else {
this.origin = await
this.originService.updateOrigin(this.origin);
}
+ this.setTitle();
}
}
diff --git
a/experimental/traffic-portal/src/app/core/origins/table/origins-table.component.ts
b/experimental/traffic-portal/src/app/core/origins/table/origins-table.component.ts
index 984879aa6a..06653b9dce 100644
---
a/experimental/traffic-portal/src/app/core/origins/table/origins-table.component.ts
+++
b/experimental/traffic-portal/src/app/core/origins/table/origins-table.component.ts
@@ -12,7 +12,7 @@
* limitations under the License.
*/
-import { Component, type OnInit } from "@angular/core";
+import { Component, OnInit } from "@angular/core";
import { FormControl } from "@angular/forms";
import { MatDialog } from "@angular/material/dialog";
import { ActivatedRoute } from "@angular/router";
diff --git
a/experimental/traffic-portal/src/app/core/parameters/detail/parameter-detail.component.ts
b/experimental/traffic-portal/src/app/core/parameters/detail/parameter-detail.component.ts
index a78d4e11a8..4c00e04a1f 100644
---
a/experimental/traffic-portal/src/app/core/parameters/detail/parameter-detail.component.ts
+++
b/experimental/traffic-portal/src/app/core/parameters/detail/parameter-detail.component.ts
@@ -12,10 +12,9 @@
* limitations under the License.
*/
-import { Location } from "@angular/common";
import { Component, OnInit } from "@angular/core";
import { MatDialog } from "@angular/material/dialog";
-import { ActivatedRoute } from "@angular/router";
+import { ActivatedRoute, Router } from "@angular/router";
import { ResponseParameter } from "trafficops-types";
import { ProfileService } from "src/app/api";
@@ -41,8 +40,8 @@ export class ParameterDetailComponent implements OnInit {
constructor(
private readonly route: ActivatedRoute,
+ private readonly router: Router,
private readonly profileService: ProfileService,
- private readonly location: Location,
private readonly dialog: MatDialog,
private readonly navSvc: NavigationService,
private readonly log: LoggingService,
@@ -58,8 +57,10 @@ export class ParameterDetailComponent implements OnInit {
return;
}
- if (ID === "new") {
- this.navSvc.headerTitle.next("New Parameter");
+ this.new = ID === "new";
+
+ if (this.new) {
+ this.setTitle();
this.new = true;
this.parameter = {
configFile: "",
@@ -80,7 +81,17 @@ export class ParameterDetailComponent implements OnInit {
}
this.parameter = await this.profileService.getParameters(numID);
- this.navSvc.headerTitle.next(`Parameter: ${this.parameter.name}
(${this.parameter.id})`);
+ this.setTitle();
+ }
+
+ /**
+ * Sets the headerTitle based on current Parameter state.
+ *
+ * @private
+ */
+ private setTitle(): void {
+ const title = this.new ? "New Parameter" : `Parameter:
${this.parameter.name} (${this.parameter.id})`;
+ this.navSvc.headerTitle.next(title);
}
/**
@@ -98,7 +109,7 @@ export class ParameterDetailComponent implements OnInit {
ref.afterClosed().subscribe(result => {
if(result) {
this.profileService.deleteParameter(this.parameter.id);
- this.location.back();
+ this.router.navigate(["core/parameters"]);
}
});
}
@@ -114,8 +125,10 @@ export class ParameterDetailComponent implements OnInit {
if(this.new) {
this.parameter = await
this.profileService.createParameter(this.parameter);
this.new = false;
+ await this.router.navigate(["core/parameters",
this.parameter.id]);
} else {
this.parameter = await
this.profileService.updateParameter(this.parameter);
}
+ this.setTitle();
}
}
diff --git
a/experimental/traffic-portal/src/app/core/profiles/profile-detail/profile-detail.component.ts
b/experimental/traffic-portal/src/app/core/profiles/profile-detail/profile-detail.component.ts
index cfc4381399..413fb08496 100644
---
a/experimental/traffic-portal/src/app/core/profiles/profile-detail/profile-detail.component.ts
+++
b/experimental/traffic-portal/src/app/core/profiles/profile-detail/profile-detail.component.ts
@@ -84,7 +84,7 @@ export class ProfileDetailComponent implements OnInit {
throw new Error(`route parameter 'id' was
non-number: ${{ id }}`);
} else {
this.profile = await
this.api.getProfiles(Number(id));
- this.navSvc.headerTitle.next(`Profile:
${this.profile.name}`);
+ this.setTitle();
}
this.loading = false;
} else {
@@ -104,6 +104,16 @@ export class ProfileDetailComponent implements OnInit {
}
}
+ /**
+ * Sets the headerTitle based on current Profile state.
+ *
+ * @private
+ */
+ private setTitle(): void {
+ const title = this.new ? "New Profile" : `Profile:
${this.profile.name}`;
+ this.navSvc.headerTitle.next(title);
+ }
+
/**
* Submits new/updated profile.
*
@@ -115,9 +125,11 @@ export class ProfileDetailComponent implements OnInit {
if(this.new) {
this.profile = await
this.api.createProfile(this.profile);
this.new = false;
+ await this.router.navigate(["core/profiles",
this.profile.id]);
} else {
this.profile = await
this.api.updateProfile(this.profile);
}
+ this.setTitle();
}
/**
diff --git
a/experimental/traffic-portal/src/app/core/servers/capabilities/capabilities.component.ts
b/experimental/traffic-portal/src/app/core/servers/capabilities/capabilities.component.ts
index 88a0e30aa5..ca724f5f88 100644
---
a/experimental/traffic-portal/src/app/core/servers/capabilities/capabilities.component.ts
+++
b/experimental/traffic-portal/src/app/core/servers/capabilities/capabilities.component.ts
@@ -11,7 +11,8 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import { Component, type OnInit } from "@angular/core";
+
+import { Component, OnInit } from "@angular/core";
import { FormControl } from "@angular/forms";
import { MatDialog } from "@angular/material/dialog";
import { ActivatedRoute } from "@angular/router";
diff --git
a/experimental/traffic-portal/src/app/core/servers/capabilities/capability-details/capability-details.component.ts
b/experimental/traffic-portal/src/app/core/servers/capabilities/capability-details/capability-details.component.ts
index 0d8cd1a912..a57c97067e 100644
---
a/experimental/traffic-portal/src/app/core/servers/capabilities/capability-details/capability-details.component.ts
+++
b/experimental/traffic-portal/src/app/core/servers/capabilities/capability-details/capability-details.component.ts
@@ -11,7 +11,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import { Location } from "@angular/common";
+
import { Component, OnInit } from "@angular/core";
import { MatDialog } from "@angular/material/dialog";
import { ActivatedRoute, Router } from "@angular/router";
@@ -46,7 +46,6 @@ export class CapabilityDetailsComponent implements OnInit {
private readonly dialog: MatDialog,
private readonly navSvc: NavigationService,
private readonly api: ServerService,
- private readonly location: Location
) {}
/**
@@ -93,7 +92,7 @@ export class CapabilityDetailsComponent implements OnInit {
const result = await ref.afterClosed().toPromise();
if(result) {
await this.api.deleteCapability(this.capability);
- this.location.back();
+ await this.router.navigate(["core/capabilities"]);
}
}
@@ -108,10 +107,11 @@ export class CapabilityDetailsComponent implements OnInit
{
if(this.new) {
this.capability = await
this.api.createCapability(this.capability);
this.new = false;
+ this.setHeader("New Capability");
} else {
this.capability = await
this.api.updateCapability(this.name, this.capability);
+ this.navSvc.headerTitle.next(`Capability:
${this.capability.name}`);
}
this.router.navigate([`/core/capabilities/${this.capability.name}`],
{replaceUrl: true});
- this.setHeader(this.name);
}
}
diff --git
a/experimental/traffic-portal/src/app/core/servers/phys-loc/detail/phys-loc-detail.component.ts
b/experimental/traffic-portal/src/app/core/servers/phys-loc/detail/phys-loc-detail.component.ts
index 51b9461615..557e3778c6 100644
---
a/experimental/traffic-portal/src/app/core/servers/phys-loc/detail/phys-loc-detail.component.ts
+++
b/experimental/traffic-portal/src/app/core/servers/phys-loc/detail/phys-loc-detail.component.ts
@@ -11,10 +11,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import { Location } from "@angular/common";
+
import { Component, OnInit } from "@angular/core";
import { MatDialog } from "@angular/material/dialog";
-import { ActivatedRoute } from "@angular/router";
+import { ActivatedRoute, Router } from "@angular/router";
import { ResponsePhysicalLocation, ResponseRegion } from "trafficops-types";
import { CacheGroupService, PhysicalLocationService } from "src/app/api";
@@ -38,8 +38,8 @@ export class PhysLocDetailComponent implements OnInit {
constructor(
private readonly route: ActivatedRoute,
+ private readonly router: Router,
private readonly cacheGroupService: CacheGroupService,
- private readonly location: Location,
private readonly dialog: MatDialog,
private readonly navSvc: NavigationService,
private readonly physLocService: PhysicalLocationService,
@@ -57,8 +57,10 @@ export class PhysLocDetailComponent implements OnInit {
return;
}
- if (ID === "new") {
- this.navSvc.headerTitle.next("New Physical Location");
+ this.new = ID === "new";
+
+ if (this.new) {
+ this.setTitle();
this.new = true;
this.physLocation = {
address: "",
@@ -85,7 +87,17 @@ export class PhysLocDetailComponent implements OnInit {
}
this.physLocation = await
this.physLocService.getPhysicalLocations(numID);
- this.navSvc.headerTitle.next(`Physical Location:
${this.physLocation.name}`);
+ this.setTitle();
+ }
+
+ /**
+ * Sets the headerTitle based on current Physical Location state.
+ *
+ * @private
+ */
+ private setTitle(): void {
+ const title = this.new ? "New Physical Location" : `Physical
Location: ${this.physLocation.name}`;
+ this.navSvc.headerTitle.next(title);
}
/**
@@ -103,7 +115,7 @@ export class PhysLocDetailComponent implements OnInit {
ref.afterClosed().subscribe(result => {
if(result) {
this.physLocService.deletePhysicalLocation(this.physLocation.id);
- this.location.back();
+ this.router.navigate(["core/phys-locs"]);
}
});
}
@@ -119,8 +131,10 @@ export class PhysLocDetailComponent implements OnInit {
if(this.new) {
this.physLocation = await
this.physLocService.createPhysicalLocation(this.physLocation);
this.new = false;
+ await this.router.navigate(["core/phys-locs",
this.physLocation.id]);
} else {
this.physLocation = await
this.physLocService.updatePhysicalLocation(this.physLocation);
}
+ this.setTitle();
}
}
diff --git
a/experimental/traffic-portal/src/app/core/servers/server-details/server-details.component.ts
b/experimental/traffic-portal/src/app/core/servers/server-details/server-details.component.ts
index 9b1f25b139..b58fe73161 100644
---
a/experimental/traffic-portal/src/app/core/servers/server-details/server-details.component.ts
+++
b/experimental/traffic-portal/src/app/core/servers/server-details/server-details.component.ts
@@ -176,7 +176,7 @@ export class ServerDetailsComponent implements OnInit {
this.serverService.getServers(Number(ID)).then(
s => {
this.server = s;
- this.updateTitlebar();
+ this.updateTitleBar();
}
).catch(
e => {
@@ -231,7 +231,7 @@ export class ServerDetailsComponent implements OnInit {
updPending: false,
xmppId: ""
};
- this.updateTitlebar();
+ this.updateTitleBar();
}
}
@@ -240,7 +240,7 @@ export class ServerDetailsComponent implements OnInit {
*
* @private
*/
- private updateTitlebar(): void {
+ private updateTitleBar(): void {
if (this.isNew) {
this.navSvc.headerTitle.next("New Server");
} else {
@@ -265,6 +265,7 @@ export class ServerDetailsComponent implements OnInit {
this.isNew = false;
this.server = s;
this.router.navigate(["server", s.id]);
+ this.updateTitleBar();
},
err => {
this.log.error("failed to create
server:", err);
@@ -274,7 +275,7 @@ export class ServerDetailsComponent implements OnInit {
this.serverService.updateServer(this.server).then(
responseServer => {
this.server = responseServer;
- this.updateTitlebar();
+ this.updateTitleBar();
},
err => {
this.log.error(`failed to update
server: ${err}`);
diff --git
a/experimental/traffic-portal/src/app/core/servers/servers-table/servers-table.component.ts
b/experimental/traffic-portal/src/app/core/servers/servers-table/servers-table.component.ts
index d1bea8b259..2f08850c81 100644
---
a/experimental/traffic-portal/src/app/core/servers/servers-table/servers-table.component.ts
+++
b/experimental/traffic-portal/src/app/core/servers/servers-table/servers-table.component.ts
@@ -12,13 +12,13 @@
* limitations under the License.
*/
-import { Component , type OnInit} from "@angular/core";
+import { Component , OnInit} from "@angular/core";
import { FormControl } from "@angular/forms";
import { MatDialog } from "@angular/material/dialog";
import { ActivatedRoute } from "@angular/router";
import type { ITooltipParams } from "ag-grid-community";
import { BehaviorSubject } from "rxjs";
-import { ResponseCDN, type ResponseServer, serviceAddresses } from
"trafficops-types";
+import { ResponseCDN, ResponseServer, serviceAddresses } from
"trafficops-types";
import { CDNService, ServerService } from "src/app/api";
import { UpdateStatusComponent } from
"src/app/core/servers/update-status/update-status.component";
@@ -397,6 +397,7 @@ export class ServersTableComponent implements OnInit {
switch(action) {
case "dequeue":
data.title = "Clear Server Updates";
+ break;
case "queue":
const ref =
this.dialog.open<CollectionChoiceDialogComponent,
CollectionChoiceDialogData<number>, number | false>(
CollectionChoiceDialogComponent,
diff --git
a/experimental/traffic-portal/src/app/core/statuses/status-details/status-details.component.ts
b/experimental/traffic-portal/src/app/core/statuses/status-details/status-details.component.ts
index d071120d11..7f389111d6 100644
---
a/experimental/traffic-portal/src/app/core/statuses/status-details/status-details.component.ts
+++
b/experimental/traffic-portal/src/app/core/statuses/status-details/status-details.component.ts
@@ -12,11 +12,10 @@
* limitations under the License.
*/
-import { Location } from "@angular/common";
import { Component } from "@angular/core";
import { FormControl, FormGroup } from "@angular/forms";
import { MatDialog } from "@angular/material/dialog";
-import { ActivatedRoute } from "@angular/router";
+import { ActivatedRoute, Router } from "@angular/router";
import { RequestStatus, ResponseStatus } from "trafficops-types";
import { ServerService } from "src/app/api";
@@ -52,9 +51,9 @@ export class StatusDetailsComponent {
constructor(
private readonly api: ServerService,
private readonly route: ActivatedRoute,
+ private readonly router: Router,
private readonly dialog: MatDialog,
private readonly navSvc: NavigationService,
- private readonly location: Location,
) {
// Getting id from the route
const id = this.route.snapshot.paramMap.get("id");
@@ -82,7 +81,7 @@ export class StatusDetailsComponent {
this.statusDetails = await this.api.getStatuses(Number(id));
// Set page title with status Name
- this.navSvc.headerTitle.next(`Status
${this.statusDetails.name}`);
+ this.setTitle();
// Patch the form with existing data we got from service
requested above.
this.statusDetailsForm.setValue({
@@ -93,6 +92,16 @@ export class StatusDetailsComponent {
this.loading = false;
}
+ /**
+ * Sets the headerTitle based on current Status state.
+ *
+ * @private
+ */
+ private setTitle(): void {
+ const title = this.new ? "New Status" : `Status:
${this.statusDetails.name}`;
+ this.navSvc.headerTitle.next(title);
+ }
+
/**
* On submitting the form we check for whether we are performing Create
or Edit
*
@@ -109,6 +118,8 @@ export class StatusDetailsComponent {
name:
this.statusDetailsForm.controls.name.value
};
this.statusDetails = await
this.api.createStatus(newData);
+ this.new = false;
+ await this.router.navigate(["core/statuses",
this.statusDetails.id]);
} else {
const editData: ResponseStatus = {
description:
this.statusDetailsForm.controls.description.value,
@@ -118,6 +129,7 @@ export class StatusDetailsComponent {
};
this.statusDetails = await
this.api.updateStatusDetail(editData);
}
+ this.setTitle();
}
}
@@ -135,7 +147,7 @@ export class StatusDetailsComponent {
ref.afterClosed().subscribe(result => {
if (result) {
this.api.deleteStatus(this.statusDetails.id);
- this.location.back();
+ this.router.navigate(["core/statuses"]);
}
});
}
diff --git
a/experimental/traffic-portal/src/app/core/topologies/topology-details/topology-details.component.ts
b/experimental/traffic-portal/src/app/core/topologies/topology-details/topology-details.component.ts
index de41c41781..8cf4e9a25f 100644
---
a/experimental/traffic-portal/src/app/core/topologies/topology-details/topology-details.component.ts
+++
b/experimental/traffic-portal/src/app/core/topologies/topology-details/topology-details.component.ts
@@ -11,12 +11,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
import { NestedTreeControl } from "@angular/cdk/tree";
-import { Location } from "@angular/common";
import { Component, OnInit } from "@angular/core";
import { MatDialog } from "@angular/material/dialog";
import { MatTreeNestedDataSource } from "@angular/material/tree";
-import { ActivatedRoute } from "@angular/router";
+import { ActivatedRoute, Router } from "@angular/router";
import { ResponseTopology } from "trafficops-types";
import { TopologyService, TopTreeNode } from "src/app/api";
@@ -56,8 +56,8 @@ export class TopologyDetailsComponent implements OnInit {
constructor(
private readonly route: ActivatedRoute,
+ private readonly router: Router,
private readonly api: TopologyService,
- private readonly location: Location,
private readonly dialog: MatDialog,
private readonly navSvc: NavigationService,
private readonly log: LoggingService,
@@ -130,7 +130,7 @@ export class TopologyDetailsComponent implements OnInit {
ref.afterClosed().subscribe(result => {
if (result) {
this.api.deleteTopology(this.topology);
- this.location.replaceState("core/topologies");
+ this.router.navigate(["core/topologies"]);
}
});
}
@@ -149,6 +149,7 @@ export class TopologyDetailsComponent implements OnInit {
if (this.new) {
this.topology = await
this.api.createTopology(this.topology);
this.new = false;
+ await this.router.navigate(["core/topologies",
this.topology.name]);
} else {
this.topology = await
this.api.updateTopology(this.topology, this.oldName);
}
diff --git
a/experimental/traffic-portal/src/app/core/types/detail/type-detail.component.ts
b/experimental/traffic-portal/src/app/core/types/detail/type-detail.component.ts
index ef1ec52507..7c52a8fe92 100644
---
a/experimental/traffic-portal/src/app/core/types/detail/type-detail.component.ts
+++
b/experimental/traffic-portal/src/app/core/types/detail/type-detail.component.ts
@@ -12,10 +12,9 @@
* limitations under the License.
*/
-import { Location } from "@angular/common";
import { Component, OnInit } from "@angular/core";
import { MatDialog } from "@angular/material/dialog";
-import { ActivatedRoute } from "@angular/router";
+import { ActivatedRoute, Router } from "@angular/router";
import { TypeFromResponse } from "trafficops-types";
import { TypeService } from "src/app/api";
@@ -37,8 +36,8 @@ export class TypeDetailComponent implements OnInit {
constructor(
private readonly route: ActivatedRoute,
+ private readonly router: Router,
private readonly typeService: TypeService,
- private readonly location: Location,
private readonly dialog: MatDialog,
private readonly navSvc: NavigationService,
private readonly log: LoggingService,
@@ -54,8 +53,10 @@ export class TypeDetailComponent implements OnInit {
return;
}
- if (ID === "new") {
- this.navSvc.headerTitle.next("New Type");
+ this.new = ID === "new";
+
+ if (this.new) {
+ this.setTitle();
this.new = true;
this.type = {
description: "",
@@ -74,7 +75,17 @@ export class TypeDetailComponent implements OnInit {
}
this.type = await this.typeService.getTypes(numID);
- this.navSvc.headerTitle.next(`Type: ${this.type.name}`);
+ this.setTitle();
+ }
+
+ /**
+ * Sets the headerTitle based on current Type state.
+ *
+ * @private
+ */
+ private setTitle(): void {
+ const title = this.new ? "New Type" : `Type: ${this.type.name}`;
+ this.navSvc.headerTitle.next(title);
}
/**
@@ -92,7 +103,7 @@ export class TypeDetailComponent implements OnInit {
ref.afterClosed().subscribe(result => {
if(result) {
this.typeService.deleteType(this.type.id);
- this.location.back();
+ this.router.navigate(["core/types"]);
}
});
}
@@ -108,9 +119,11 @@ export class TypeDetailComponent implements OnInit {
if(this.new) {
this.type = await
this.typeService.createType(this.type);
this.new = false;
+ await this.router.navigate(["core/types",
this.type.id]);
} else {
this.type = await
this.typeService.updateType(this.type);
}
+ this.setTitle();
}
}
diff --git
a/experimental/traffic-portal/src/app/core/users/roles/detail/role-detail.component.ts
b/experimental/traffic-portal/src/app/core/users/roles/detail/role-detail.component.ts
index c6203eeccf..e5179474d9 100644
---
a/experimental/traffic-portal/src/app/core/users/roles/detail/role-detail.component.ts
+++
b/experimental/traffic-portal/src/app/core/users/roles/detail/role-detail.component.ts
@@ -11,7 +11,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import { Location } from "@angular/common";
+
import { Component, OnInit } from "@angular/core";
import { MatDialog } from "@angular/material/dialog";
import { ActivatedRoute, Router } from "@angular/router";
@@ -44,9 +44,8 @@ export class RoleDetailComponent implements OnInit {
private readonly route: ActivatedRoute,
private readonly router: Router,
private readonly userService: UserService,
- private readonly location: Location,
private readonly dialog: MatDialog,
- private readonly header: NavigationService,
+ private readonly navSvc: NavigationService,
private readonly log: LoggingService,
) { }
@@ -56,7 +55,7 @@ export class RoleDetailComponent implements OnInit {
public async ngOnInit(): Promise<void> {
const role = this.route.snapshot.paramMap.get("name");
if (role === null) {
- this.header.headerTitle.next("New Role");
+ this.setHeader("New Role");
this.new = true;
this.role = {
description: "",
@@ -69,7 +68,7 @@ export class RoleDetailComponent implements OnInit {
this.role = await this.userService.getRoles(role);
this.name = this.role.name;
this.permissions = this.role.permissions?.join("\n")??"";
- this.header.headerTitle.next(`Role: ${this.name}`);
+ this.navSvc.headerTitle.next(`Role: ${this.name}`);
}
/**
@@ -80,7 +79,7 @@ export class RoleDetailComponent implements OnInit {
*/
private setHeader(name: string): void {
this.name = name;
- this.header.headerTitle.next(`Role: ${name}`);
+ this.navSvc.headerTitle.next(`Role: ${name}`);
}
/**
@@ -98,7 +97,7 @@ export class RoleDetailComponent implements OnInit {
const result = await ref.afterClosed().toPromise();
if(result) {
await this.userService.deleteRole(this.role);
- this.location.back();
+ await this.router.navigate(["core/roles"]);
}
}
@@ -123,10 +122,9 @@ export class RoleDetailComponent implements OnInit {
this.new = false;
} else {
this.role = await
this.userService.updateRole(this.name, this.role);
+ this.navSvc.headerTitle.next(`Role: ${this.role.name}`);
}
- this.router.navigate([`/core/roles/${this.role.name}`],
{replaceUrl: true});
- this.setHeader(this.name);
-
+ await this.router.navigate(["core/roles", this.role.name],
{replaceUrl: true});
}
}
diff --git
a/experimental/traffic-portal/src/app/core/users/roles/table/roles-table.component.ts
b/experimental/traffic-portal/src/app/core/users/roles/table/roles-table.component.ts
index dfc9228aa5..faa7d3937c 100644
---
a/experimental/traffic-portal/src/app/core/users/roles/table/roles-table.component.ts
+++
b/experimental/traffic-portal/src/app/core/users/roles/table/roles-table.component.ts
@@ -40,7 +40,7 @@ export class RolesTableComponent implements OnInit {
constructor(
private readonly route: ActivatedRoute,
- private readonly headerSvc: NavigationService,
+ private readonly navSvc: NavigationService,
private readonly api: UserService,
private readonly dialog: MatDialog,
public readonly auth: CurrentUserService,
@@ -48,7 +48,7 @@ export class RolesTableComponent implements OnInit {
) {
this.fuzzySubject = new BehaviorSubject<string>("");
this.roles = this.api.getRoles();
- this.headerSvc.headerTitle.next("Roles");
+ this.navSvc.headerTitle.next("Roles");
}
/** Initializes table data, loading it from Traffic Ops. */
diff --git
a/experimental/traffic-portal/src/app/core/users/tenants/tenant-details/tenant-details.component.spec.ts
b/experimental/traffic-portal/src/app/core/users/tenants/tenant-details/tenant-details.component.spec.ts
index 33c094895b..7396970c5b 100644
---
a/experimental/traffic-portal/src/app/core/users/tenants/tenant-details/tenant-details.component.spec.ts
+++
b/experimental/traffic-portal/src/app/core/users/tenants/tenant-details/tenant-details.component.spec.ts
@@ -12,6 +12,7 @@
* limitations under the License.
*/
import { ComponentFixture, TestBed } from "@angular/core/testing";
+import { MatDialogModule } from "@angular/material/dialog";
import { ActivatedRoute } from "@angular/router";
import { RouterTestingModule } from "@angular/router/testing";
@@ -28,7 +29,7 @@ describe("TenantDetailsComponent", () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ TenantDetailsComponent ],
- imports: [ APITestingModule, RouterTestingModule ],
+ imports: [ APITestingModule, MatDialogModule,
RouterTestingModule ],
})
.compileComponents();
diff --git
a/experimental/traffic-portal/src/app/core/users/tenants/tenant-details/tenant-details.component.ts
b/experimental/traffic-portal/src/app/core/users/tenants/tenant-details/tenant-details.component.ts
index 43d9cb8e0b..763bac912e 100644
---
a/experimental/traffic-portal/src/app/core/users/tenants/tenant-details/tenant-details.component.ts
+++
b/experimental/traffic-portal/src/app/core/users/tenants/tenant-details/tenant-details.component.ts
@@ -11,14 +11,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-import { Location } from "@angular/common";
+
import { Component, OnInit } from "@angular/core";
-import { ActivatedRoute } from "@angular/router";
+import { MatDialog } from "@angular/material/dialog";
+import { ActivatedRoute, Router } from "@angular/router";
import { RequestTenant, ResponseTenant, Tenant } from "trafficops-types";
import { UserService } from "src/app/api";
import { TreeData } from "src/app/models";
+import { DecisionDialogComponent } from
"src/app/shared/dialogs/decision-dialog/decision-dialog.component";
import { LoggingService } from "src/app/shared/logging.service";
+import { NavigationService } from
"src/app/shared/navigation/navigation.service";
/**
* TenantsDetailsComponent is the controller for the tenant add/edit form.
@@ -36,8 +39,10 @@ export class TenantDetailsComponent implements OnInit {
constructor(
private readonly route: ActivatedRoute,
+ private readonly router: Router,
private readonly userService: UserService,
- private readonly location: Location,
+ private readonly dialog: MatDialog,
+ private readonly navSvc: NavigationService,
private readonly log: LoggingService,
) {
this.displayTenant = {
@@ -114,7 +119,10 @@ export class TenantDetailsComponent implements OnInit {
this.tenants = await this.userService.getTenants();
this.constructTreeData();
- if (ID === "new") {
+ this.new = ID === "new";
+
+ if (this.new) {
+ this.setTitle();
this.new = true;
this.tenant = {
active: true,
@@ -134,6 +142,17 @@ export class TenantDetailsComponent implements OnInit {
}
this.tenant = tenant;
this.disabled = this.isRoot();
+ this.setTitle();
+ }
+
+ /**
+ * Sets the headerTitle based on current Tenant state.
+ *
+ * @private
+ */
+ private setTitle(): void {
+ const title = this.new ? "New Tenant" : `Tenant:
${this.tenant.name}`;
+ this.navSvc.headerTitle.next(title);
}
/**
@@ -150,9 +169,11 @@ export class TenantDetailsComponent implements OnInit {
if (this.new) {
this.tenant = await
this.userService.createTenant(this.tenant as RequestTenant);
this.new = false;
+ await this.router.navigate(["core/tenants",
(this.tenant as ResponseTenant).id]);
} else {
this.tenant = await
this.userService.updateTenant(this.tenant as ResponseTenant);
}
+ this.setTitle();
}
/**
@@ -163,8 +184,16 @@ export class TenantDetailsComponent implements OnInit {
this.log.error("Unable to delete new tenant");
return;
}
- await this.userService.deleteTenant((this.tenant as
ResponseTenant).id);
- this.location.back();
+ const ref = this.dialog.open(DecisionDialogComponent, {
+ data: {message: `Are you sure you want to delete
tenantn ${this.tenant.name}`,
+ title: "Confirm Delete"}
+ });
+ ref.afterClosed().subscribe(result => {
+ if (result) {
+ this.userService.deleteTenant((this.tenant as
ResponseTenant).id);
+ this.router.navigate(["core/tenants"]);
+ }
+ });
}
/**
diff --git
a/experimental/traffic-portal/src/app/core/users/user-details/user-details.component.spec.ts
b/experimental/traffic-portal/src/app/core/users/user-details/user-details.component.spec.ts
index 6c57059963..836e956b7c 100644
---
a/experimental/traffic-portal/src/app/core/users/user-details/user-details.component.spec.ts
+++
b/experimental/traffic-portal/src/app/core/users/user-details/user-details.component.spec.ts
@@ -31,7 +31,10 @@ describe("UserDetailsComponent", () => {
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ UserDetailsComponent ],
- imports: [ APITestingModule, RouterTestingModule ],
+ imports: [ APITestingModule,
RouterTestingModule.withRoutes( [
+ {component: UserDetailsComponent, path:
"core/users"},
+ {component: UserDetailsComponent, path:
"core/users/:id"},
+ ])],
providers: [{provide: CurrentUserService, useClass:
CurrentUserTestingService}]
}).compileComponents();
fixture = TestBed.createComponent(UserDetailsComponent);
diff --git
a/experimental/traffic-portal/src/app/core/users/user-details/user-details.component.ts
b/experimental/traffic-portal/src/app/core/users/user-details/user-details.component.ts
index 21b14cff69..08b33bec2b 100644
---
a/experimental/traffic-portal/src/app/core/users/user-details/user-details.component.ts
+++
b/experimental/traffic-portal/src/app/core/users/user-details/user-details.component.ts
@@ -12,14 +12,15 @@
* limitations under the License.
*/
-import { Component, type OnInit } from "@angular/core";
+import { Component, OnInit } from "@angular/core";
import type { MatSelectChange } from "@angular/material/select";
-import { ActivatedRoute } from "@angular/router";
+import { ActivatedRoute, Router } from "@angular/router";
import type { PostRequestUser, ResponseRole, ResponseTenant, ResponseUser,
User } from "trafficops-types";
import { UserService } from "src/app/api";
import { CurrentUserService } from
"src/app/shared/current-user/current-user.service";
import { LoggingService } from "src/app/shared/logging.service";
+import { NavigationService } from
"src/app/shared/navigation/navigation.service";
/**
* UserDetailsComponent is the controller for the page for viewing/editing a
@@ -40,8 +41,10 @@ export class UserDetailsComponent implements OnInit {
constructor(
private readonly userService: UserService,
private readonly route: ActivatedRoute,
+ private readonly router: Router,
private readonly currentUserService: CurrentUserService,
- private readonly log: LoggingService
+ private readonly log: LoggingService,
+ private readonly navSvc: NavigationService,
) { }
/** Angular lifecycle hook */
@@ -56,7 +59,10 @@ export class UserDetailsComponent implements OnInit {
return;
}
await rolesAndTenants;
- if (ID === "new") {
+ this.new = ID === "new";
+
+ if (this.new) {
+ this.setTitle();
this.new = true;
this.user = {
confirmLocalPasswd: "",
@@ -75,6 +81,7 @@ export class UserDetailsComponent implements OnInit {
return;
}
this.user = await this.userService.getUsers(numID);
+ this.setTitle();
}
/**
@@ -90,6 +97,16 @@ export class UserDetailsComponent implements OnInit {
return this.new;
}
+ /**
+ * Sets the headerTitle based on current User state.
+ *
+ * @private
+ */
+ private setTitle(): void {
+ const title = this.new ? "New User" : `User:
${this.user.username}`;
+ this.navSvc.headerTitle.next(title);
+ }
+
/**
* Handler for the user edit form submission.
*
@@ -102,9 +119,10 @@ export class UserDetailsComponent implements OnInit {
if (this.isNew(this.user)) {
this.user = await
this.userService.createUser(this.user);
this.new = false;
- return;
+ await this.router.navigate(["core/users",
this.user.id]);
}
this.user = await this.userService.updateUser(this.user);
+ this.setTitle();
}
/**
diff --git
a/experimental/traffic-portal/src/app/shared/navigation/tp-header/tp-header.component.ts
b/experimental/traffic-portal/src/app/shared/navigation/tp-header/tp-header.component.ts
index b84ef8bf7b..12ae4ef043 100644
---
a/experimental/traffic-portal/src/app/shared/navigation/tp-header/tp-header.component.ts
+++
b/experimental/traffic-portal/src/app/shared/navigation/tp-header/tp-header.component.ts
@@ -45,23 +45,23 @@ export class TpHeaderComponent implements OnInit {
* Angular lifecycle hook
*/
public ngOnInit(): void {
- this.headerSvc.headerTitle.subscribe(title => {
+ this.navSvc.headerTitle.subscribe(title => {
this.title = title;
});
- this.headerSvc.headerHidden.subscribe(hidden => {
+ this.navSvc.headerHidden.subscribe(hidden => {
this.hidden = hidden;
});
- this.headerSvc.horizontalNavsUpdated.subscribe(navs => {
+ this.navSvc.horizontalNavsUpdated.subscribe(navs => {
this.horizNavs = navs;
});
- this.headerSvc.verticalNavsUpdated.subscribe(navs => {
+ this.navSvc.verticalNavsUpdated.subscribe(navs => {
this.vertNavs = navs;
});
}
constructor(
public readonly themeSvc: ThemeManagerService,
- private readonly headerSvc: NavigationService,
+ private readonly navSvc: NavigationService,
private readonly log: LoggingService,
) { }