From 36a8908712a5085b3585a335f84be79852b2391f Mon Sep 17 00:00:00 2001 From: gbrodman Date: Mon, 27 Nov 2023 14:58:48 -0500 Subject: [PATCH] Add a basic domain-list page to the new console (#2219) This does not include any styling for now, just wanted to make sure we're all good with regards to the basic approach. I'm open to suggestion on which columns to include. Note: filter searching is not implemented yet because the backend does not allow for it (yet) --- console-webapp/src/app/app-routing.module.ts | 6 ++ console-webapp/src/app/app.module.ts | 2 + .../src/app/domains/domainList.component.html | 54 +++++++++++++ .../src/app/domains/domainList.component.scss | 0 .../app/domains/domainList.component.spec.ts | 36 +++++++++ .../src/app/domains/domainList.component.ts | 80 +++++++++++++++++++ .../src/app/domains/domainList.service.ts | 66 +++++++++++++++ .../widgets/domains-widget.component.html | 7 +- .../home/widgets/domains-widget.component.ts | 8 +- .../app/shared/services/backend.service.ts | 26 ++++++ 10 files changed, 283 insertions(+), 2 deletions(-) create mode 100644 console-webapp/src/app/domains/domainList.component.html create mode 100644 console-webapp/src/app/domains/domainList.component.scss create mode 100644 console-webapp/src/app/domains/domainList.component.spec.ts create mode 100644 console-webapp/src/app/domains/domainList.component.ts create mode 100644 console-webapp/src/app/domains/domainList.service.ts diff --git a/console-webapp/src/app/app-routing.module.ts b/console-webapp/src/app/app-routing.module.ts index e06425e91..62eca80f8 100644 --- a/console-webapp/src/app/app-routing.module.ts +++ b/console-webapp/src/app/app-routing.module.ts @@ -28,6 +28,7 @@ import ContactComponent from './settings/contact/contact.component'; import WhoisComponent from './settings/whois/whois.component'; import SecurityComponent from './settings/security/security.component'; import UsersComponent from './settings/users/users.component'; +import { DomainListComponent } from './domains/domainList.component'; const routes: Routes = [ { path: '', redirectTo: '/home', pathMatch: 'full' }, @@ -35,6 +36,11 @@ const routes: Routes = [ { path: 'empty-registrar', component: EmptyRegistrar }, { path: 'home', component: HomeComponent, canActivate: [RegistrarGuard] }, { path: 'tlds', component: TldsComponent, canActivate: [RegistrarGuard] }, + { + path: DomainListComponent.PATH, + component: DomainListComponent, + canActivate: [RegistrarGuard], + }, { path: SettingsComponent.PATH, component: SettingsComponent, diff --git a/console-webapp/src/app/app.module.ts b/console-webapp/src/app/app.module.ts index 854d00e8d..8b98d343a 100644 --- a/console-webapp/src/app/app.module.ts +++ b/console-webapp/src/app/app.module.ts @@ -53,6 +53,7 @@ import { RegistrarDetailsComponent, RegistrarDetailsWrapperComponent, } from './registrar/registrarDetails.component'; +import { DomainListComponent } from './domains/domainList.component'; @NgModule({ declarations: [ @@ -60,6 +61,7 @@ import { BillingWidgetComponent, ContactDetailsDialogComponent, ContactWidgetComponent, + DomainListComponent, DomainsWidgetComponent, EmptyRegistrar, EppWidgetComponent, diff --git a/console-webapp/src/app/domains/domainList.component.html b/console-webapp/src/app/domains/domainList.component.html new file mode 100644 index 000000000..4cc98f625 --- /dev/null +++ b/console-webapp/src/app/domains/domainList.component.html @@ -0,0 +1,54 @@ +
+ + Filter + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Domain Name{{ element.domainName }}Creation Time + {{ element.creationTime.creationTime }} + Expiration Time + {{ element.registrationExpirationTime }} + Statuses{{ element.statuses }}
No domains found
+ +
+
diff --git a/console-webapp/src/app/domains/domainList.component.scss b/console-webapp/src/app/domains/domainList.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/console-webapp/src/app/domains/domainList.component.spec.ts b/console-webapp/src/app/domains/domainList.component.spec.ts new file mode 100644 index 000000000..e2a526c8a --- /dev/null +++ b/console-webapp/src/app/domains/domainList.component.spec.ts @@ -0,0 +1,36 @@ +// Copyright 2023 The Nomulus Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { DomainListComponent } from './domainList.component'; + +describe('DomainListComponent', () => { + let component: DomainListComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [DomainListComponent], + }).compileComponents(); + + fixture = TestBed.createComponent(DomainListComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/console-webapp/src/app/domains/domainList.component.ts b/console-webapp/src/app/domains/domainList.component.ts new file mode 100644 index 000000000..6c5c754b3 --- /dev/null +++ b/console-webapp/src/app/domains/domainList.component.ts @@ -0,0 +1,80 @@ +// Copyright 2023 The Nomulus Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Component, ViewChild } from '@angular/core'; +import { MatTableDataSource } from '@angular/material/table'; +import { BackendService } from '../shared/services/backend.service'; +import { MatPaginator, PageEvent } from '@angular/material/paginator'; +import { RegistrarService } from '../registrar/registrar.service'; +import { Domain, DomainListService } from './domainList.service'; + +@Component({ + selector: 'app-domain-list', + templateUrl: './domainList.component.html', + styleUrls: ['./domainList.component.scss'], + providers: [DomainListService], +}) +export class DomainListComponent { + public static PATH = 'domain-list'; + + displayedColumns: string[] = [ + 'domainName', + 'creationTime', + 'registrationExpirationTime', + 'statuses', + ]; + + dataSource: MatTableDataSource = new MatTableDataSource(); + isLoading = true; + + pageNumber?: number; + resultsPerPage = 50; + totalResults?: number; + + @ViewChild(MatPaginator, { static: true }) paginator!: MatPaginator; + + constructor( + private backendService: BackendService, + private domainListService: DomainListService, + private registrarService: RegistrarService + ) {} + + ngOnInit() { + this.dataSource.paginator = this.paginator; + this.reloadData(); + } + + reloadData() { + this.isLoading = true; + this.domainListService + .retrieveDomains(this.pageNumber, this.resultsPerPage, this.totalResults) + .subscribe((domainListResult) => { + this.dataSource.data = domainListResult.domains; + this.totalResults = domainListResult.totalResults; + this.isLoading = false; + }); + } + + /** TODO: the backend will need to accept a filter string. */ + applyFilter(event: KeyboardEvent) { + // const filterValue = (event.target as HTMLInputElement).value; + this.reloadData(); + } + + onPageChange(event: PageEvent) { + this.pageNumber = event.pageIndex; + this.resultsPerPage = event.pageSize; + this.reloadData(); + } +} diff --git a/console-webapp/src/app/domains/domainList.service.ts b/console-webapp/src/app/domains/domainList.service.ts new file mode 100644 index 000000000..b2a4a6a4f --- /dev/null +++ b/console-webapp/src/app/domains/domainList.service.ts @@ -0,0 +1,66 @@ +// Copyright 2023 The Nomulus Authors. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +import { Injectable } from '@angular/core'; +import { BackendService } from '../shared/services/backend.service'; +import { RegistrarService } from '../registrar/registrar.service'; +import { tap } from 'rxjs'; + +export interface CreateAutoTimestamp { + creationTime: string; +} + +export interface Domain { + creationTime: CreateAutoTimestamp; + currentSponsorRegistrarId: string; + domainName: string; + registrationExpirationTime: string; + statuses: string[]; +} + +export interface DomainListResult { + checkpointTime: string; + domains: Domain[]; + totalResults: number; +} + +@Injectable() +export class DomainListService { + checkpointTime?: string; + + constructor( + private backendService: BackendService, + private registrarService: RegistrarService + ) {} + + retrieveDomains( + pageNumber?: number, + resultsPerPage?: number, + totalResults?: number + ) { + return this.backendService + .getDomains( + this.registrarService.activeRegistrarId, + this.checkpointTime, + pageNumber, + resultsPerPage, + totalResults + ) + .pipe( + tap((domainListResult: DomainListResult) => { + this.checkpointTime = domainListResult.checkpointTime; + }) + ); + } +} diff --git a/console-webapp/src/app/home/widgets/domains-widget.component.html b/console-webapp/src/app/home/widgets/domains-widget.component.html index 7df3b1621..f30dcdf9b 100644 --- a/console-webapp/src/app/home/widgets/domains-widget.component.html +++ b/console-webapp/src/app/home/widgets/domains-widget.component.html @@ -13,7 +13,12 @@ Create a Domain

Register a new domain name

-

diff --git a/console-webapp/src/app/home/widgets/domains-widget.component.ts b/console-webapp/src/app/home/widgets/domains-widget.component.ts index 6995ce3c1..e17725e28 100644 --- a/console-webapp/src/app/home/widgets/domains-widget.component.ts +++ b/console-webapp/src/app/home/widgets/domains-widget.component.ts @@ -13,11 +13,17 @@ // limitations under the License. import { Component } from '@angular/core'; +import { Router } from '@angular/router'; +import { DomainListComponent } from 'src/app/domains/domainList.component'; @Component({ selector: '[app-domains-widget]', templateUrl: './domains-widget.component.html', }) export class DomainsWidgetComponent { - constructor() {} + constructor(private router: Router) {} + + openDomainsPage() { + this.router.navigate([DomainListComponent.PATH]); + } } diff --git a/console-webapp/src/app/shared/services/backend.service.ts b/console-webapp/src/app/shared/services/backend.service.ts index 09af8da2c..b5d98a3e5 100644 --- a/console-webapp/src/app/shared/services/backend.service.ts +++ b/console-webapp/src/app/shared/services/backend.service.ts @@ -21,6 +21,7 @@ import { Contact } from '../../settings/contact/contact.service'; import { Registrar } from '../../registrar/registrar.service'; import { UserData } from './userData.service'; import { WhoisRegistrarFields } from 'src/app/settings/whois/whois.service'; +import { DomainListResult } from 'src/app/domains/domainList.service'; @Injectable() export class BackendService { @@ -63,6 +64,31 @@ export class BackendService { ); } + getDomains( + registrarId: string, + checkpointTime?: string, + pageNumber?: number, + resultsPerPage?: number, + totalResults?: number + ): Observable { + var url = `/console-api/domain-list?registrarId=${registrarId}`; + if (checkpointTime) { + url += `&checkpointTime=${checkpointTime}`; + } + if (pageNumber) { + url += `&pageNumber=${pageNumber}`; + } + if (resultsPerPage) { + url += `&resultsPerPage=${resultsPerPage}`; + } + if (totalResults) { + url += `&totalResults=${totalResults}`; + } + return this.http + .get(url) + .pipe(catchError((err) => this.errorCatcher(err))); + } + getRegistrars(): Observable { return this.http .get('/console-api/registrars')