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')