Add registrar details view (#2186)

This commit is contained in:
Pavlo Tkach 2023-10-26 09:14:09 -04:00 committed by GitHub
parent 23a2861b37
commit 26bae65e1e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 219 additions and 4 deletions

View file

@ -49,6 +49,10 @@ import { SettingsWidgetComponent } from './home/widgets/settings-widget.componen
import { UserDataService } from './shared/services/userData.service'; import { UserDataService } from './shared/services/userData.service';
import WhoisComponent from './settings/whois/whois.component'; import WhoisComponent from './settings/whois/whois.component';
import { SnackBarModule } from './snackbar.module'; import { SnackBarModule } from './snackbar.module';
import {
RegistrarDetailsComponent,
RegistrarDetailsWrapperComponent,
} from './registrar/registrarDetails.component';
@NgModule({ @NgModule({
declarations: [ declarations: [
@ -63,6 +67,8 @@ import { SnackBarModule } from './snackbar.module';
HomeComponent, HomeComponent,
PromotionsWidgetComponent, PromotionsWidgetComponent,
RegistrarComponent, RegistrarComponent,
RegistrarDetailsComponent,
RegistrarDetailsWrapperComponent,
RegistrarSelectorComponent, RegistrarSelectorComponent,
ResourcesWidgetComponent, ResourcesWidgetComponent,
SecurityComponent, SecurityComponent,

View file

@ -45,6 +45,7 @@ import { DialogModule } from '@angular/cdk/dialog';
import { MatSidenavModule } from '@angular/material/sidenav'; import { MatSidenavModule } from '@angular/material/sidenav';
import { MatSnackBarModule } from '@angular/material/snack-bar'; import { MatSnackBarModule } from '@angular/material/snack-bar';
import { MatPaginatorModule } from '@angular/material/paginator'; import { MatPaginatorModule } from '@angular/material/paginator';
import { MatChipsModule } from '@angular/material/chips';
@NgModule({ @NgModule({
exports: [ exports: [
@ -81,6 +82,7 @@ import { MatPaginatorModule } from '@angular/material/paginator';
DialogModule, DialogModule,
MatSnackBarModule, MatSnackBarModule,
MatPaginatorModule, MatPaginatorModule,
MatChipsModule,
], ],
}) })
export class MaterialModule {} export class MaterialModule {}

View file

@ -13,7 +13,9 @@
<mat-label>Registrar</mat-label> <mat-label>Registrar</mat-label>
<mat-select <mat-select
[ngModel]="registrarService.activeRegistrarId" [ngModel]="registrarService.activeRegistrarId"
(selectionChange)="registrarService.updateRegistrar($event.value)" (selectionChange)="
registrarService.updateSelectedRegistrar($event.value)
"
> >
<mat-option <mat-option
*ngFor="let registrar of registrarService.registrars" *ngFor="let registrar of registrarService.registrars"

View file

@ -73,7 +73,7 @@ export class RegistrarService implements GlobalLoader {
)[0]; )[0];
} }
public updateRegistrar(registrarId: string) { public updateSelectedRegistrar(registrarId: string) {
this.activeRegistrarId = registrarId; this.activeRegistrarId = registrarId;
this.activeRegistrarIdChange.next(registrarId); this.activeRegistrarIdChange.next(registrarId);
} }

View file

@ -0,0 +1,40 @@
<div class="registrarDetails">
<h3 mat-dialog-title>Edit Registrar: {{ registrarInEdit.registrarId }}</h3>
<div mat-dialog-content>
<form (ngSubmit)="saveAndClose($event)">
<mat-form-field class="registrarDetails__input">
<mat-label>Registry Lock:</mat-label>
<mat-select
[(ngModel)]="registrarInEdit.registryLockAllowed"
name="registryLockAllowed"
>
<mat-option [value]="true">True</mat-option>
<mat-option [value]="false">False</mat-option>
</mat-select>
</mat-form-field>
<mat-form-field class="registrarDetails__input">
<mat-label>Onboarded TLDs: </mat-label>
<mat-chip-grid #chipGrid aria-label="Enter TLD">
<mat-chip-row
*ngFor="let tld of registrarInEdit.allowedTlds"
(removed)="removeTLD(tld)"
>
{{ tld }}
<button matChipRemove aria-label="'remove ' + tld">
<mat-icon>cancel</mat-icon>
</button>
</mat-chip-row>
</mat-chip-grid>
<input
placeholder="New tld..."
[matChipInputFor]="chipGrid"
(matChipInputTokenEnd)="addTLD($event)"
/>
</mat-form-field>
<mat-dialog-actions>
<button mat-button (click)="onCancel($event)">Cancel</button>
<button type="submit" mat-button color="primary">Save</button>
</mat-dialog-actions>
</form>
</div>
</div>

View file

@ -0,0 +1,8 @@
.registrarDetails {
min-width: 30vw;
&__input {
display: block;
margin-top: 0.5rem;
}
}

View file

@ -0,0 +1,105 @@
// 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, Injector } from '@angular/core';
import { Registrar, RegistrarService } from './registrar.service';
import { BreakpointObserver } from '@angular/cdk/layout';
import {
MAT_BOTTOM_SHEET_DATA,
MatBottomSheet,
MatBottomSheetRef,
} from '@angular/material/bottom-sheet';
import {
MAT_DIALOG_DATA,
MatDialog,
MatDialogRef,
} from '@angular/material/dialog';
import { MatChipInputEvent } from '@angular/material/chips';
const MOBILE_LAYOUT_BREAKPOINT = '(max-width: 599px)';
@Component({
selector: 'app-registrar-details',
templateUrl: './registrarDetails.component.html',
styleUrls: ['./registrarDetails.component.scss'],
})
export class RegistrarDetailsComponent {
registrarInEdit!: Registrar;
private elementRef:
| MatBottomSheetRef<RegistrarDetailsComponent>
| MatDialogRef<RegistrarDetailsComponent>;
constructor(
protected registrarService: RegistrarService,
private injector: Injector
) {
// We only inject one, either Dialog or Bottom Sheet data
// so one of the injectors is expected to fail
try {
var params = this.injector.get(MAT_DIALOG_DATA);
this.elementRef = this.injector.get(MatDialogRef);
} catch (e) {
var params = this.injector.get(MAT_BOTTOM_SHEET_DATA);
this.elementRef = this.injector.get(MatBottomSheetRef);
}
this.registrarInEdit = JSON.parse(JSON.stringify(params.registrar));
}
onCancel(e: MouseEvent) {
if (this.elementRef instanceof MatBottomSheetRef) {
this.elementRef.dismiss();
} else if (this.elementRef instanceof MatDialogRef) {
this.elementRef.close();
}
}
saveAndClose(e: MouseEvent) {
// TODO: Implement save call to API
this.onCancel(e);
}
addTLD(e: MatChipInputEvent) {
this.removeTLD(e.value); // Prevent dups
this.registrarInEdit.allowedTlds = this.registrarInEdit.allowedTlds?.concat(
[e.value.toLowerCase()]
);
}
removeTLD(tld: string) {
this.registrarInEdit.allowedTlds = this.registrarInEdit.allowedTlds?.filter(
(v) => v != tld
);
}
}
@Component({
selector: 'app-registrar-details-wrapper',
template: '',
})
export class RegistrarDetailsWrapperComponent {
constructor(
private dialog: MatDialog,
private bottomSheet: MatBottomSheet,
protected breakpointObserver: BreakpointObserver
) {}
open(registrar: Registrar) {
const config = { data: { registrar } };
if (this.breakpointObserver.isMatched(MOBILE_LAYOUT_BREAKPOINT)) {
this.bottomSheet.open(RegistrarDetailsComponent, config);
} else {
this.dialog.open(RegistrarDetailsComponent, config);
}
}
}

View file

@ -1,10 +1,34 @@
<div class="console-app__registrars"> <div class="console-app__registrars">
<mat-form-field class="console-app__registrars-filter">
<mat-label>Search</mat-label>
<input
matInput
(keyup)="applyFilter($event)"
placeholder="..."
type="search"
/>
<mat-icon matPrefix>search</mat-icon>
</mat-form-field>
<mat-table <mat-table
[dataSource]="dataSource" [dataSource]="dataSource"
class="mat-elevation-z8" class="mat-elevation-z8"
class="console-app__registrars-table" class="console-app__registrars-table"
matSort matSort
> >
<ng-container matColumnDef="edit">
<mat-header-cell *matHeaderCellDef></mat-header-cell>
<mat-cell *matCellDef="let row">
<button
mat-icon-button
color="primary"
aria-label="Edit registrar"
(click)="openDetails($event, row)"
>
<mat-icon>edit</mat-icon>
</button>
</mat-cell>
</ng-container>
<ng-container <ng-container
*ngFor="let column of columns" *ngFor="let column of columns"
[matColumnDef]="column.columnDef" [matColumnDef]="column.columnDef"
@ -13,7 +37,10 @@
<mat-cell *matCellDef="let row" [innerHTML]="column.cell(row)"></mat-cell> <mat-cell *matCellDef="let row" [innerHTML]="column.cell(row)"></mat-cell>
</ng-container> </ng-container>
<mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row> <mat-header-row *matHeaderRowDef="displayedColumns"></mat-header-row>
<mat-row *matRowDef="let row; columns: displayedColumns"></mat-row> <mat-row
*matRowDef="let row; columns: displayedColumns"
(click)="registrarService.updateSelectedRegistrar(row.registrarId)"
></mat-row>
</mat-table> </mat-table>
<mat-paginator <mat-paginator
@ -21,4 +48,7 @@
[pageSizeOptions]="[5, 10, 20]" [pageSizeOptions]="[5, 10, 20]"
showFirstLastButtons showFirstLastButtons
></mat-paginator> ></mat-paginator>
<app-registrar-details-wrapper
#registrarDetailsView
></app-registrar-details-wrapper>
</div> </div>

View file

@ -7,6 +7,11 @@
overflow: auto; overflow: auto;
} }
&__registrars-filter {
min-width: $min-width !important;
width: 100%;
}
&__registrars-table { &__registrars-table {
min-width: $min-width !important; min-width: $min-width !important;
} }
@ -16,6 +21,10 @@
} }
.mat-column { .mat-column {
&-edit {
max-width: 55px;
padding-left: 5px;
}
&-driveId { &-driveId {
min-width: 200px; min-width: 200px;
word-break: break-all; word-break: break-all;

View file

@ -17,6 +17,7 @@ import { Registrar, RegistrarService } from './registrar.service';
import { MatPaginator } from '@angular/material/paginator'; import { MatPaginator } from '@angular/material/paginator';
import { MatSort } from '@angular/material/sort'; import { MatSort } from '@angular/material/sort';
import { MatTableDataSource } from '@angular/material/table'; import { MatTableDataSource } from '@angular/material/table';
import { RegistrarDetailsWrapperComponent } from './registrarDetails.component';
@Component({ @Component({
selector: 'app-registrar', selector: 'app-registrar',
@ -76,10 +77,12 @@ export class RegistrarComponent {
cell: (record: Registrar) => `${record.driveFolderId || ''}`, cell: (record: Registrar) => `${record.driveFolderId || ''}`,
}, },
]; ];
displayedColumns = this.columns.map((c) => c.columnDef); displayedColumns = ['edit'].concat(this.columns.map((c) => c.columnDef));
@ViewChild(MatPaginator) paginator!: MatPaginator; @ViewChild(MatPaginator) paginator!: MatPaginator;
@ViewChild(MatSort) sort!: MatSort; @ViewChild(MatSort) sort!: MatSort;
@ViewChild('registrarDetailsView')
detailsComponentWrapper!: RegistrarDetailsWrapperComponent;
constructor(protected registrarService: RegistrarService) { constructor(protected registrarService: RegistrarService) {
this.dataSource = new MatTableDataSource<Registrar>( this.dataSource = new MatTableDataSource<Registrar>(
@ -91,4 +94,14 @@ export class RegistrarComponent {
this.dataSource.paginator = this.paginator; this.dataSource.paginator = this.paginator;
this.dataSource.sort = this.sort; this.dataSource.sort = this.sort;
} }
openDetails(event: MouseEvent, registrar: Registrar) {
event.stopPropagation();
this.detailsComponentWrapper.open(registrar);
}
applyFilter(event: Event) {
const filterValue = (event.target as HTMLInputElement).value;
this.dataSource.filter = filterValue.trim().toLowerCase();
}
} }