mirror of
https://github.com/google/nomulus.git
synced 2025-07-23 19:20:44 +02:00
Replace less with scss, add homepage widgets, add registrars selector and registrars page (#2114)
* Replace less compiler with scss * Replace less with scss, add homepage widgets, add registrars selector and registrars page
This commit is contained in:
parent
6b5ec36eed
commit
1929654f8c
62 changed files with 11927 additions and 730 deletions
|
@ -7,7 +7,7 @@
|
|||
"projectType": "application",
|
||||
"schematics": {
|
||||
"@schematics/angular:component": {
|
||||
"style": "less"
|
||||
"style": "scss"
|
||||
}
|
||||
},
|
||||
"root": "",
|
||||
|
@ -22,15 +22,18 @@
|
|||
"main": "src/main.ts",
|
||||
"polyfills": "src/polyfills.ts",
|
||||
"tsConfig": "tsconfig.app.json",
|
||||
"inlineStyleLanguage": "less",
|
||||
"inlineStyleLanguage": "scss",
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/assets"
|
||||
],
|
||||
"styles": [
|
||||
"./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
|
||||
"src/styles.less"
|
||||
"src/theme.scss",
|
||||
"src/styles.scss"
|
||||
],
|
||||
"stylePreprocessorOptions": {
|
||||
"includePaths": ["node_modules/"]
|
||||
},
|
||||
"scripts": []
|
||||
},
|
||||
"configurations": {
|
||||
|
@ -91,15 +94,18 @@
|
|||
"polyfills": "src/polyfills.ts",
|
||||
"tsConfig": "tsconfig.spec.json",
|
||||
"karmaConfig": "karma.conf.js",
|
||||
"inlineStyleLanguage": "less",
|
||||
"inlineStyleLanguage": "scss",
|
||||
"assets": [
|
||||
"src/favicon.ico",
|
||||
"src/assets"
|
||||
],
|
||||
"styles": [
|
||||
"./node_modules/@angular/material/prebuilt-themes/indigo-pink.css",
|
||||
"src/styles.less"
|
||||
"src/theme.scss",
|
||||
"src/styles.scss"
|
||||
],
|
||||
"stylePreprocessorOptions": {
|
||||
"includePaths": ["node_modules/"]
|
||||
},
|
||||
"scripts": []
|
||||
}
|
||||
},
|
||||
|
|
11444
console-webapp/package-lock.json
generated
11444
console-webapp/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -18,51 +18,56 @@ import { TldsComponent } from './tlds/tlds.component';
|
|||
import { HomeComponent } from './home/home.component';
|
||||
import { SettingsComponent } from './settings/settings.component';
|
||||
import SettingsContactComponent from './settings/contact/contact.component';
|
||||
import SettingsRegistrarsComponent from './settings/registrars/registrars.component';
|
||||
import SettingsWhoisComponent from './settings/whois/whois.component';
|
||||
import SettingsUsersComponent from './settings/users/users.component';
|
||||
import SettingsSecurityComponent from './settings/security/security.component';
|
||||
import { RegistrarGuard } from './registrar/registrar.guard';
|
||||
import { RegistrarComponent } from './registrar/registrar.component';
|
||||
import { RegistrarComponent } from './registrar/registrarsTable.component';
|
||||
import { EmptyRegistrar } from './registrar/emptyRegistrar.component';
|
||||
|
||||
const routes: Routes = [
|
||||
{ path: '', redirectTo: '/home', pathMatch: 'full' },
|
||||
{ path: 'registrars', component: RegistrarComponent },
|
||||
{ path: 'empty-registrar', component: EmptyRegistrar },
|
||||
{ path: 'home', component: HomeComponent, canActivate: [RegistrarGuard] },
|
||||
{ path: 'tlds', component: TldsComponent, canActivate: [RegistrarGuard] },
|
||||
{
|
||||
path: 'settings',
|
||||
component: SettingsComponent,
|
||||
canActivate: [RegistrarGuard],
|
||||
children: [
|
||||
{
|
||||
path: '',
|
||||
redirectTo: 'contact',
|
||||
redirectTo: 'registrars',
|
||||
pathMatch: 'full',
|
||||
},
|
||||
{
|
||||
path: 'contact',
|
||||
component: SettingsContactComponent,
|
||||
canActivate: [RegistrarGuard],
|
||||
},
|
||||
{
|
||||
path: 'whois',
|
||||
component: SettingsWhoisComponent,
|
||||
canActivate: [RegistrarGuard],
|
||||
},
|
||||
{
|
||||
path: 'security',
|
||||
component: SettingsSecurityComponent,
|
||||
canActivate: [RegistrarGuard],
|
||||
},
|
||||
{
|
||||
path: 'epp-password',
|
||||
component: SettingsSecurityComponent,
|
||||
canActivate: [RegistrarGuard],
|
||||
},
|
||||
{
|
||||
path: 'users',
|
||||
component: SettingsUsersComponent,
|
||||
canActivate: [RegistrarGuard],
|
||||
},
|
||||
{
|
||||
path: 'registrars',
|
||||
component: SettingsRegistrarsComponent,
|
||||
component: RegistrarComponent,
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
|
@ -12,13 +12,13 @@
|
|||
<a mat-list-item [routerLink]="'/settings'" routerLinkActive="active">
|
||||
Settings
|
||||
</a>
|
||||
<a mat-list-item [routerLink]="'/registrars'" routerLinkActive="active">
|
||||
Select Registrar
|
||||
</a>
|
||||
</mat-nav-list>
|
||||
</mat-sidenav>
|
||||
<mat-sidenav-content class="console-app__content-wrapper">
|
||||
<div class="console-app__content">
|
||||
<div *ngIf="globalLoader.isLoading" class="console-app__global-spinner">
|
||||
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
|
||||
</div>
|
||||
<div class="console-app__content" *ngIf="renderRouter">
|
||||
<router-outlet></router-outlet>
|
||||
</div>
|
||||
</mat-sidenav-content>
|
||||
|
|
|
@ -13,8 +13,8 @@
|
|||
// limitations under the License.
|
||||
|
||||
:host {
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica,
|
||||
Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol";
|
||||
font-family: Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji",
|
||||
"Segoe UI Emoji", "Segoe UI Symbol" !important;
|
||||
font-size: 14px;
|
||||
color: #333;
|
||||
box-sizing: border-box;
|
||||
|
@ -47,4 +47,7 @@
|
|||
max-width: 1340px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
&__global-spinner {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
}
|
|
@ -13,10 +13,25 @@
|
|||
// limitations under the License.
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
import { RegistrarService } from './registrar/registrar.service';
|
||||
import { GlobalLoaderService } from './shared/services/globalLoader.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-root',
|
||||
templateUrl: './app.component.html',
|
||||
styleUrls: ['./app.component.less'],
|
||||
styleUrls: ['./app.component.scss'],
|
||||
})
|
||||
export class AppComponent {}
|
||||
export class AppComponent {
|
||||
renderRouter: boolean = true;
|
||||
constructor(
|
||||
protected registrarService: RegistrarService,
|
||||
protected globalLoader: GlobalLoaderService
|
||||
) {
|
||||
registrarService.activeRegistrarIdChange.subscribe(() => {
|
||||
this.renderRouter = false;
|
||||
setTimeout(() => {
|
||||
this.renderRouter = true;
|
||||
}, 400);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -31,9 +31,20 @@ import SettingsContactComponent, {
|
|||
ContactDetailsDialogComponent,
|
||||
} from './settings/contact/contact.component';
|
||||
import { HttpClientModule } from '@angular/common/http';
|
||||
import { RegistrarComponent } from './registrar/registrar.component';
|
||||
import { RegistrarComponent } from './registrar/registrarsTable.component';
|
||||
import { RegistrarGuard } from './registrar/registrar.guard';
|
||||
import SecurityComponent from './settings/security/security.component';
|
||||
import { MAT_FORM_FIELD_DEFAULT_OPTIONS } from '@angular/material/form-field';
|
||||
import { EmptyRegistrar } from './registrar/emptyRegistrar.component';
|
||||
import { RegistrarSelectorComponent } from './registrar/registrar-selector.component';
|
||||
import { GlobalLoaderService } from './shared/services/globalLoader.service';
|
||||
import { ContactWidgetComponent } from './home/widgets/contact-widget.component';
|
||||
import { PromotionsWidgetComponent } from './home/widgets/promotions-widget.component';
|
||||
import { TldsWidgetComponent } from './home/widgets/tlds-widget.component';
|
||||
import { ResourcesWidgetComponent } from './home/widgets/resources-widget.component';
|
||||
import { EppWidgetComponent } from './home/widgets/epp-widget.component';
|
||||
import { BillingWidgetComponent } from './home/widgets/billing-widget.component';
|
||||
import { DomainsWidgetComponent } from './home/widgets/domains-widget.component';
|
||||
|
||||
@NgModule({
|
||||
declarations: [
|
||||
|
@ -46,6 +57,15 @@ import SecurityComponent from './settings/security/security.component';
|
|||
ContactDetailsDialogComponent,
|
||||
RegistrarComponent,
|
||||
SecurityComponent,
|
||||
EmptyRegistrar,
|
||||
RegistrarSelectorComponent,
|
||||
ContactWidgetComponent,
|
||||
DomainsWidgetComponent,
|
||||
PromotionsWidgetComponent,
|
||||
TldsWidgetComponent,
|
||||
ResourcesWidgetComponent,
|
||||
EppWidgetComponent,
|
||||
BillingWidgetComponent,
|
||||
],
|
||||
imports: [
|
||||
HttpClientModule,
|
||||
|
@ -55,7 +75,17 @@ import SecurityComponent from './settings/security/security.component';
|
|||
AppRoutingModule,
|
||||
BrowserAnimationsModule,
|
||||
],
|
||||
providers: [BackendService, RegistrarGuard],
|
||||
providers: [
|
||||
GlobalLoaderService,
|
||||
BackendService,
|
||||
RegistrarGuard,
|
||||
{
|
||||
provide: MAT_FORM_FIELD_DEFAULT_OPTIONS,
|
||||
useValue: {
|
||||
subscriptSizing: 'dynamic',
|
||||
},
|
||||
},
|
||||
],
|
||||
bootstrap: [AppComponent],
|
||||
})
|
||||
export class AppModule {}
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
</button>
|
||||
<span>Google Registry</span>
|
||||
<span class="spacer"></span>
|
||||
<app-registrar-selector />
|
||||
<button mat-icon-button aria-label="Open FAQ">
|
||||
<mat-icon>question_mark</mat-icon>
|
||||
</button>
|
||||
|
|
|
@ -12,6 +12,9 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
.console-app__header {
|
||||
margin-top: 0;
|
||||
}
|
||||
.spacer {
|
||||
flex: 1;
|
||||
}
|
|
@ -17,7 +17,7 @@ import { Component, EventEmitter, Output } from '@angular/core';
|
|||
@Component({
|
||||
selector: 'app-header',
|
||||
templateUrl: './header.component.html',
|
||||
styleUrls: ['./header.component.less'],
|
||||
styleUrls: ['./header.component.scss'],
|
||||
})
|
||||
export class HeaderComponent {
|
||||
private isNavOpen = false;
|
||||
|
|
|
@ -1,21 +1,13 @@
|
|||
<h3>Recent Activity</h3>
|
||||
<table
|
||||
mat-table
|
||||
[dataSource]="dataSource"
|
||||
class="mat-elevation-z8 console-home__activity"
|
||||
>
|
||||
<ng-container
|
||||
*ngFor="let column of columns"
|
||||
[matColumnDef]="column.columnDef"
|
||||
>
|
||||
<th mat-header-cell *matHeaderCellDef>
|
||||
{{ column.header }}
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let row">
|
||||
{{ column.cell(row) }}
|
||||
</td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
|
||||
</table>
|
||||
<div class="console-app__home">
|
||||
<h1>Welcome to the Google Registry Console</h1>
|
||||
<div class="console-app__home-widgets">
|
||||
<div app-domains-widget class="console-app__widget-wrapper__wide"></div>
|
||||
<div app-contact-widget class="console-app__widget-wrapper__wide"></div>
|
||||
<div app-tlds-widget></div>
|
||||
<div app-promotions-widget class="console-app__widget-wrapper__wide"></div>
|
||||
<div app-promotions-widget class="console-app__widget-wrapper__wide"></div>
|
||||
<div app-resources-widget></div>
|
||||
<div app-billing-widget></div>
|
||||
<div app-epp-widget></div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
// Copyright 2022 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.
|
|
@ -12,11 +12,20 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
html,
|
||||
body {
|
||||
.console-app {
|
||||
&__home {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
&__home-widgets {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fill, minmax(240px, 1fr));
|
||||
grid-gap: 20px;
|
||||
|
||||
mat-card {
|
||||
height: 100%;
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: Roboto, "Helvetica Neue", sans-serif;
|
||||
h1 {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -12,220 +12,12 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
|
||||
export interface ActivityRecord {
|
||||
eventType: string;
|
||||
userName: string;
|
||||
registrarName: string;
|
||||
timestamp: string;
|
||||
details: string;
|
||||
}
|
||||
|
||||
const MOCK_DATA: ActivityRecord[] = [
|
||||
{
|
||||
eventType: 'Export DUMS',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Update Contact',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Delete Domain',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Export DUMS',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Update Contact',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Delete Domain',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Export DUMS',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Update Contact',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Delete Domain',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Export DUMS',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Update Contact',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Delete Domain',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Export DUMS',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Update Contact',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Delete Domain',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Export DUMS',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Update Contact',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Delete Domain',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Export DUMS',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Update Contact',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Delete Domain',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Export DUMS',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Update Contact',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
{
|
||||
eventType: 'Delete Domain',
|
||||
userName: 'user3',
|
||||
registrarName: 'registrar1',
|
||||
timestamp: '2022-03-15T19:46:39.007',
|
||||
details: 'All Domains under management exported as .csv file',
|
||||
},
|
||||
];
|
||||
import { Component, ViewEncapsulation } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-home',
|
||||
templateUrl: './home.component.html',
|
||||
styleUrls: ['./home.component.less'],
|
||||
styleUrls: ['./home.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
})
|
||||
export class HomeComponent {
|
||||
columns = [
|
||||
{
|
||||
columnDef: 'eventType',
|
||||
header: 'Event Type',
|
||||
cell: (record: ActivityRecord) => `${record.eventType}`,
|
||||
},
|
||||
{
|
||||
columnDef: 'userName',
|
||||
header: 'User',
|
||||
cell: (record: ActivityRecord) => `${record.userName}`,
|
||||
},
|
||||
{
|
||||
columnDef: 'registrarName',
|
||||
header: 'Registrar',
|
||||
cell: (record: ActivityRecord) => `${record.registrarName}`,
|
||||
},
|
||||
{
|
||||
columnDef: 'timestamp',
|
||||
header: 'Timestamp',
|
||||
cell: (record: ActivityRecord) => `${record.timestamp}`,
|
||||
},
|
||||
{
|
||||
columnDef: 'details',
|
||||
header: 'Details',
|
||||
cell: (record: ActivityRecord) => `${record.details}`,
|
||||
},
|
||||
];
|
||||
dataSource = MOCK_DATA;
|
||||
displayedColumns = this.columns.map((c) => c.columnDef);
|
||||
}
|
||||
export class HomeComponent {}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
<mat-card>
|
||||
<mat-card-content>
|
||||
<div class="console-app__widget">
|
||||
<div class="console-app__widget_left">
|
||||
<mat-icon class="console-app__widget-icon">account_balance</mat-icon>
|
||||
<h1 class="console-app__widget-title">Billing Info</h1>
|
||||
<h4 class="secondary-text text-center">
|
||||
View important billing and payments information.
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
|
@ -15,8 +15,9 @@
|
|||
import { Component } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'app-registrars',
|
||||
templateUrl: './registrars.component.html',
|
||||
styleUrls: ['./registrars.component.less'],
|
||||
selector: '[app-billing-widget]',
|
||||
templateUrl: './billing-widget.component.html',
|
||||
})
|
||||
export default class RegistrarsComponent {}
|
||||
export class BillingWidgetComponent {
|
||||
constructor() {}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<mat-card>
|
||||
<mat-card-content>
|
||||
<div class="console-app__widget">
|
||||
<div class="console-app__widget_left">
|
||||
<mat-icon class="console-app__widget-icon">call</mat-icon>
|
||||
<h1 class="console-app__widget-title">Contact Support</h1>
|
||||
<h4 class="secondary-text text-center">
|
||||
View Google Registry support email and phone information
|
||||
</h4>
|
||||
</div>
|
||||
<div class="console-app__widget_right">
|
||||
<button mat-button color="primary" class="console-app__widget-link">
|
||||
Give us a Call
|
||||
</button>
|
||||
<p class="secondary-text">
|
||||
Call Google Registry support at +1 (404) 978 8419
|
||||
</p>
|
||||
<button mat-button color="primary" class="console-app__widget-link">
|
||||
Send us an Email
|
||||
</button>
|
||||
<p class="secondary-text">
|
||||
Email Google Registry at support@google.com
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
|
@ -0,0 +1,23 @@
|
|||
// 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 } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: '[app-contact-widget]',
|
||||
templateUrl: './contact-widget.component.html',
|
||||
})
|
||||
export class ContactWidgetComponent {
|
||||
constructor() {}
|
||||
}
|
|
@ -0,0 +1,25 @@
|
|||
<mat-card>
|
||||
<mat-card-content>
|
||||
<div class="console-app__widget">
|
||||
<div class="console-app__widget_left">
|
||||
<mat-icon class="console-app__widget-icon">view_list</mat-icon>
|
||||
<h1 class="console-app__widget-title">Domains</h1>
|
||||
<h4 class="secondary-text text-center">
|
||||
Manage domain names and registry lock settings.
|
||||
</h4>
|
||||
</div>
|
||||
<div class="console-app__widget_right">
|
||||
<button mat-button color="primary" class="console-app__widget-link">
|
||||
Create a Domain
|
||||
</button>
|
||||
<p class="secondary-text">Register a new domain name</p>
|
||||
<button mat-button color="primary" class="console-app__widget-link">
|
||||
View DUMs
|
||||
</button>
|
||||
<p class="secondary-text">
|
||||
Download a csv of all domains under management
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
|
@ -0,0 +1,23 @@
|
|||
// 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 } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: '[app-domains-widget]',
|
||||
templateUrl: './domains-widget.component.html',
|
||||
})
|
||||
export class DomainsWidgetComponent {
|
||||
constructor() {}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
<mat-card>
|
||||
<mat-card-content>
|
||||
<div class="console-app__widget">
|
||||
<div class="console-app__widget_left">
|
||||
<mat-icon class="console-app__widget-icon">computer</mat-icon>
|
||||
<h1 class="console-app__widget-title">EPP Console</h1>
|
||||
<h4 class="secondary-text text-center">
|
||||
Test run and execute EPP commands using XML files.
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
|
@ -11,3 +11,13 @@
|
|||
// 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 } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: '[app-epp-widget]',
|
||||
templateUrl: './epp-widget.component.html',
|
||||
})
|
||||
export class EppWidgetComponent {
|
||||
constructor() {}
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
<mat-card class="console-app__widget-wrapper__wide">
|
||||
<mat-card-content>
|
||||
<div class="console-app__widget">
|
||||
<div class="console-app__widget_left">
|
||||
<mat-icon class="console-app__widget-icon">subject</mat-icon>
|
||||
<h1 class="console-app__widget-title">Promotions</h1>
|
||||
<h4 class="secondary-text text-center">
|
||||
Manage Google Registry promotions and view onboarding process.
|
||||
</h4>
|
||||
</div>
|
||||
<div class="console-app__widget_right">
|
||||
<button mat-button color="primary" class="console-app__widget-link">
|
||||
Manage Preferred Partner Program
|
||||
</button>
|
||||
<p class="secondary-text">
|
||||
Onboard or view current preferred partner status
|
||||
</p>
|
||||
<button mat-button color="primary" class="console-app__widget-link">
|
||||
Manage Registry Lock Program
|
||||
</button>
|
||||
<p class="secondary-text">
|
||||
Onboard or view current registry lock status
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
|
@ -0,0 +1,23 @@
|
|||
// 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 } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: '[app-promotions-widget]',
|
||||
templateUrl: './promotions-widget.component.html',
|
||||
})
|
||||
export class PromotionsWidgetComponent {
|
||||
constructor() {}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
<mat-card>
|
||||
<mat-card-content>
|
||||
<div class="console-app__widget">
|
||||
<div class="console-app__widget_left">
|
||||
<mat-icon class="console-app__widget-icon">menu_book</mat-icon>
|
||||
<h1 class="console-app__widget-title">Resources</h1>
|
||||
<h4 class="secondary-text text-center">
|
||||
Use Google Drive to view onboarding FAQs, and technical documentation.
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
|
@ -0,0 +1,23 @@
|
|||
// 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 } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: '[app-resources-widget]',
|
||||
templateUrl: './resources-widget.component.html',
|
||||
})
|
||||
export class ResourcesWidgetComponent {
|
||||
constructor() {}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
<mat-card>
|
||||
<mat-card-content>
|
||||
<div class="console-app__widget">
|
||||
<div class="console-app__widget_left">
|
||||
<mat-icon class="console-app__widget-icon">list_alt</mat-icon>
|
||||
<h1 class="console-app__widget-title">TLDs</h1>
|
||||
<h4 class="secondary-text text-center">
|
||||
View launch phase information for all onboarded and available TLDs.
|
||||
</h4>
|
||||
</div>
|
||||
</div>
|
||||
</mat-card-content>
|
||||
</mat-card>
|
23
console-webapp/src/app/home/widgets/tlds-widget.component.ts
Normal file
23
console-webapp/src/app/home/widgets/tlds-widget.component.ts
Normal file
|
@ -0,0 +1,23 @@
|
|||
// 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 } from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: '[app-tlds-widget]',
|
||||
templateUrl: './tlds-widget.component.html',
|
||||
})
|
||||
export class TldsWidgetComponent {
|
||||
constructor() {}
|
||||
}
|
|
@ -44,6 +44,7 @@ import { CdkMenuModule } from '@angular/cdk/menu';
|
|||
import { DialogModule } from '@angular/cdk/dialog';
|
||||
import { MatSidenavModule } from '@angular/material/sidenav';
|
||||
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
||||
import { MatPaginatorModule } from '@angular/material/paginator';
|
||||
|
||||
@NgModule({
|
||||
exports: [
|
||||
|
@ -79,6 +80,7 @@ import { MatSnackBarModule } from '@angular/material/snack-bar';
|
|||
OverlayModule,
|
||||
DialogModule,
|
||||
MatSnackBarModule,
|
||||
MatPaginatorModule,
|
||||
],
|
||||
})
|
||||
export class MaterialModule {}
|
||||
|
|
|
@ -0,0 +1,7 @@
|
|||
<div class="console-app__emty-registrar">
|
||||
<h1>
|
||||
<mat-icon class="console-app__emty-registrar-icon">block</mat-icon>
|
||||
</h1>
|
||||
<h1>No registrar selected</h1>
|
||||
<h4 class="mat-body-2">Please select a registrar</h4>
|
||||
</div>
|
|
@ -0,0 +1,17 @@
|
|||
.console-app {
|
||||
&__emty-registrar {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
top: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
|
||||
&-icon {
|
||||
transform: scale(3);
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -13,33 +13,32 @@
|
|||
// limitations under the License.
|
||||
|
||||
import { Component } from '@angular/core';
|
||||
import { RegistrarService } from './registrar.service';
|
||||
import { ActivatedRoute, Router } from '@angular/router';
|
||||
import { RegistrarService } from './registrar.service';
|
||||
import { Subscription } from 'rxjs';
|
||||
|
||||
@Component({
|
||||
selector: 'app-registrar',
|
||||
templateUrl: './registrar.component.html',
|
||||
styleUrls: ['./registrar.component.less'],
|
||||
selector: 'app-empty-registrar',
|
||||
templateUrl: './emptyRegistrar.component.html',
|
||||
styleUrls: ['./emptyRegistrar.component.scss'],
|
||||
})
|
||||
export class RegistrarComponent {
|
||||
private lastActiveRegistrarId: string;
|
||||
export class EmptyRegistrar {
|
||||
private registrarIdChangeSubscription?: Subscription;
|
||||
|
||||
constructor(
|
||||
private route: ActivatedRoute,
|
||||
protected registrarService: RegistrarService,
|
||||
private router: Router
|
||||
) {
|
||||
this.lastActiveRegistrarId = registrarService.activeRegistrarId;
|
||||
}
|
||||
|
||||
ngDoCheck() {
|
||||
if (
|
||||
this.registrarService.activeRegistrarId &&
|
||||
this.registrarService.activeRegistrarId !== this.lastActiveRegistrarId &&
|
||||
this.route.snapshot.paramMap.get('nextUrl')
|
||||
) {
|
||||
this.lastActiveRegistrarId = this.registrarService.activeRegistrarId;
|
||||
this.registrarIdChangeSubscription =
|
||||
registrarService.activeRegistrarIdChange.subscribe((newRegistrarId) => {
|
||||
if (newRegistrarId) {
|
||||
this.router.navigate([this.route.snapshot.paramMap.get('nextUrl')]);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ngOnDestroy() {
|
||||
this.registrarIdChangeSubscription?.unsubscribe();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
<div class="console-app__registrar">
|
||||
<div>
|
||||
<mat-form-field class="mat-form-field-density-5" appearance="fill">
|
||||
<mat-label>Registrar</mat-label>
|
||||
<mat-select
|
||||
[ngModel]="registrarService.activeRegistrarId"
|
||||
(selectionChange)="registrarService.updateRegistrar($event.value)"
|
||||
>
|
||||
<mat-option
|
||||
*ngFor="let registrar of registrarService.registrars"
|
||||
[value]="registrar.registrarName"
|
||||
>
|
||||
{{ registrar.registrarName }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
||||
</div>
|
|
@ -0,0 +1,18 @@
|
|||
.console-app {
|
||||
&__registrar {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: baseline;
|
||||
// Fix for angular v15 label issue
|
||||
// https://github.com/angular/components/issues/26579
|
||||
.mat-mdc-floating-label {
|
||||
display: inline !important;
|
||||
}
|
||||
.mat-mdc-select-arrow-wrapper {
|
||||
transform: translateY(0) !important;
|
||||
}
|
||||
}
|
||||
&__title {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
}
|
|
@ -14,18 +14,18 @@
|
|||
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import RegistrarsComponent from './registrars.component';
|
||||
import { RegistrarSelectorComponent } from './registrar-selector.component';
|
||||
|
||||
describe('RegistrarsComponent', () => {
|
||||
let component: RegistrarsComponent;
|
||||
let fixture: ComponentFixture<RegistrarsComponent>;
|
||||
describe('RegistrarSelectorComponent', () => {
|
||||
let component: RegistrarSelectorComponent;
|
||||
let fixture: ComponentFixture<RegistrarSelectorComponent>;
|
||||
|
||||
beforeEach(async () => {
|
||||
await TestBed.configureTestingModule({
|
||||
declarations: [RegistrarsComponent],
|
||||
declarations: [RegistrarSelectorComponent],
|
||||
}).compileComponents();
|
||||
|
||||
fixture = TestBed.createComponent(RegistrarsComponent);
|
||||
fixture = TestBed.createComponent(RegistrarSelectorComponent);
|
||||
component = fixture.componentInstance;
|
||||
fixture.detectChanges();
|
||||
});
|
|
@ -0,0 +1,25 @@
|
|||
// 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 } from '@angular/core';
|
||||
import { RegistrarService } from './registrar.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-registrar-selector',
|
||||
templateUrl: './registrar-selector.component.html',
|
||||
styleUrls: ['./registrar-selector.component.scss'],
|
||||
})
|
||||
export class RegistrarSelectorComponent {
|
||||
constructor(protected registrarService: RegistrarService) {}
|
||||
}
|
|
@ -1,17 +0,0 @@
|
|||
<div class="console-app__registrar">
|
||||
<h4 class="console-app__title">
|
||||
{{ registrarService.activeRegistrarId === "" ? "Select" : "Switch" }}
|
||||
registrar:
|
||||
</h4>
|
||||
<mat-form-field>
|
||||
<mat-label>Registrar</mat-label>
|
||||
<mat-select [(ngModel)]="registrarService.activeRegistrarId">
|
||||
<mat-option
|
||||
*ngFor="let registrar of registrarService.registrars"
|
||||
[value]="registrar"
|
||||
>
|
||||
{{ registrar }}
|
||||
</mat-option>
|
||||
</mat-select>
|
||||
</mat-form-field>
|
||||
</div>
|
|
@ -1,11 +0,0 @@
|
|||
.console-app {
|
||||
&__registrar {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-top: 1rem;
|
||||
}
|
||||
&__title {
|
||||
margin-right: 1rem;
|
||||
}
|
||||
}
|
|
@ -29,6 +29,6 @@ export class RegistrarGuard {
|
|||
if (this.registrarService.activeRegistrarId) {
|
||||
return true;
|
||||
}
|
||||
return this.router.navigate([`/registrars`, { nextUrl: state.url }]);
|
||||
return this.router.navigate([`/empty-registrar`, { nextUrl: state.url }]);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -14,16 +14,59 @@
|
|||
|
||||
import { Injectable } from '@angular/core';
|
||||
import { BackendService } from '../shared/services/backend.service';
|
||||
import { Subject } from 'rxjs';
|
||||
import {
|
||||
GlobalLoader,
|
||||
GlobalLoaderService,
|
||||
} from '../shared/services/globalLoader.service';
|
||||
|
||||
interface Address {
|
||||
street?: string[];
|
||||
city?: string;
|
||||
countryCode?: string;
|
||||
zip?: string;
|
||||
state?: string;
|
||||
}
|
||||
|
||||
export interface Registrar {
|
||||
allowedTlds?: string[];
|
||||
ipAddressAllowList?: string[];
|
||||
emailAddress?: string;
|
||||
billingAccountMap?: object;
|
||||
driveFolderId?: string;
|
||||
ianaIdentifier?: number;
|
||||
icannReferralEmail?: string;
|
||||
localizedAddress?: Address;
|
||||
registrarId: string;
|
||||
registrarName: string;
|
||||
registryLockAllowed?: boolean;
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class RegistrarService {
|
||||
export class RegistrarService implements GlobalLoader {
|
||||
activeRegistrarId: string = '';
|
||||
registrars: string[] = [];
|
||||
constructor(private backend: BackendService) {
|
||||
registrars: Registrar[] = [];
|
||||
activeRegistrarIdChange: Subject<string> = new Subject<string>();
|
||||
|
||||
constructor(
|
||||
private backend: BackendService,
|
||||
private globalLoader: GlobalLoaderService
|
||||
) {
|
||||
this.backend.getRegistrars().subscribe((r) => {
|
||||
this.globalLoader.stopGlobalLoader(this);
|
||||
this.registrars = r;
|
||||
});
|
||||
this.globalLoader.startGlobalLoader(this);
|
||||
}
|
||||
|
||||
public updateRegistrar(registrarId: string) {
|
||||
this.activeRegistrarId = registrarId;
|
||||
this.activeRegistrarIdChange.next(registrarId);
|
||||
}
|
||||
|
||||
loadingTimeout() {
|
||||
// TODO: Decide what to do when timeout happens
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
<div class="console-app__registrars">
|
||||
<table
|
||||
mat-table
|
||||
[dataSource]="registrarService.registrars"
|
||||
class="mat-elevation-z8"
|
||||
>
|
||||
<ng-container
|
||||
*ngFor="let column of columns"
|
||||
[matColumnDef]="column.columnDef"
|
||||
>
|
||||
<th mat-header-cell *matHeaderCellDef>
|
||||
{{ column.header }}
|
||||
</th>
|
||||
<td mat-cell *matCellDef="let row" [innerHTML]="column.cell(row)"></td>
|
||||
</ng-container>
|
||||
|
||||
<tr mat-header-row *matHeaderRowDef="displayedColumns"></tr>
|
||||
<tr mat-row *matRowDef="let row; columns: displayedColumns"></tr>
|
||||
</table>
|
||||
<mat-paginator
|
||||
class="mat-elevation-z8"
|
||||
[pageSizeOptions]="[5, 10, 20]"
|
||||
showFirstLastButtons
|
||||
></mat-paginator>
|
||||
</div>
|
|
@ -0,0 +1,5 @@
|
|||
.console-app {
|
||||
&__registrars {
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
}
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
import { ComponentFixture, TestBed } from '@angular/core/testing';
|
||||
|
||||
import { RegistrarComponent } from './registrar.component';
|
||||
import { RegistrarComponent } from './registrarsTable.component';
|
||||
import { BackendService } from '../shared/services/backend.service';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
import { HttpClientTestingModule } from '@angular/common/http/testing';
|
|
@ -0,0 +1,75 @@
|
|||
// 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 } from '@angular/core';
|
||||
import { Registrar, RegistrarService } from './registrar.service';
|
||||
|
||||
@Component({
|
||||
selector: 'app-registrar',
|
||||
templateUrl: './registrarsTable.component.html',
|
||||
styleUrls: ['./registrarsTable.component.scss'],
|
||||
})
|
||||
export class RegistrarComponent {
|
||||
columns = [
|
||||
{
|
||||
columnDef: 'registrarId',
|
||||
header: 'Registrar Id',
|
||||
cell: (record: Registrar) => `${record.registrarId || ''}`,
|
||||
},
|
||||
{
|
||||
columnDef: 'registrarName',
|
||||
header: 'Name',
|
||||
cell: (record: Registrar) => `${record.registrarName || ''}`,
|
||||
},
|
||||
{
|
||||
columnDef: 'allowedTlds',
|
||||
header: 'TLDs',
|
||||
cell: (record: Registrar) => `${(record.allowedTlds || []).join(', ')}`,
|
||||
},
|
||||
{
|
||||
columnDef: 'emailAddress',
|
||||
header: 'Username',
|
||||
cell: (record: Registrar) => `${record.emailAddress || ''}`,
|
||||
},
|
||||
{
|
||||
columnDef: 'ianaIdentifier',
|
||||
header: 'IANA ID',
|
||||
cell: (record: Registrar) => `${record.ianaIdentifier || ''}`,
|
||||
},
|
||||
{
|
||||
columnDef: 'billingAccountMap',
|
||||
header: 'Billing Accounts',
|
||||
cell: (record: Registrar) =>
|
||||
// @ts-ignore - completely legit line, but TS keeps complaining
|
||||
`${Object.entries(record.billingAccountMap).reduce(
|
||||
(acc, [key, val]) => {
|
||||
return `${acc}${key}=${val}<br/>`;
|
||||
},
|
||||
''
|
||||
)}`,
|
||||
},
|
||||
{
|
||||
columnDef: 'registryLockAllowed',
|
||||
header: 'Registry Lock',
|
||||
cell: (record: Registrar) => `${record.registryLockAllowed}`,
|
||||
},
|
||||
{
|
||||
columnDef: 'driveId',
|
||||
header: 'Drive ID',
|
||||
cell: (record: Registrar) => `${record.driveFolderId || ''}`,
|
||||
},
|
||||
];
|
||||
displayedColumns = this.columns.map((c) => c.columnDef);
|
||||
constructor(protected registrarService: RegistrarService) {}
|
||||
}
|
|
@ -2,6 +2,15 @@
|
|||
<mat-progress-bar mode="indeterminate"></mat-progress-bar>
|
||||
</div>
|
||||
<div *ngIf="!loading">
|
||||
<div
|
||||
class="contact__empty-contacts"
|
||||
*ngIf="contactService.contacts.length === 0"
|
||||
>
|
||||
<mat-icon class="contact__empty-contacts-icon secondary-text"
|
||||
>apps_outage</mat-icon
|
||||
>
|
||||
<h1>No contacts found</h1>
|
||||
</div>
|
||||
<div *ngFor="let group of groupedData">
|
||||
<div class="contact__cards-wrapper" *ngIf="group.contacts.length">
|
||||
<h3>{{ group.label }}s</h3>
|
||||
|
|
|
@ -37,6 +37,18 @@
|
|||
justify-content: flex-start;
|
||||
margin: 2rem 0;
|
||||
}
|
||||
&__empty-contacts {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-direction: column;
|
||||
}
|
||||
&__empty-contacts-icon {
|
||||
width: 4rem;
|
||||
height: 4rem;
|
||||
font-size: 4rem;
|
||||
margin-top: 1.5rem;
|
||||
}
|
||||
}
|
||||
.contact-details {
|
||||
&__input {
|
|
@ -77,7 +77,7 @@ class ContactDetailsEventsResponder {
|
|||
@Component({
|
||||
selector: 'app-contact-details-dialog',
|
||||
templateUrl: 'contact-details.component.html',
|
||||
styleUrls: ['./contact.component.less'],
|
||||
styleUrls: ['./contact.component.scss'],
|
||||
})
|
||||
export class ContactDetailsDialogComponent {
|
||||
contact: Contact;
|
||||
|
@ -140,7 +140,7 @@ export class ContactDetailsDialogComponent {
|
|||
@Component({
|
||||
selector: 'app-contact',
|
||||
templateUrl: './contact.component.html',
|
||||
styleUrls: ['./contact.component.less'],
|
||||
styleUrls: ['./contact.component.scss'],
|
||||
})
|
||||
export default class ContactComponent {
|
||||
loading: boolean = false;
|
||||
|
@ -158,7 +158,7 @@ export default class ContactComponent {
|
|||
}
|
||||
|
||||
public get groupedData() {
|
||||
return this.contactService.contacts.reduce((acc, contact) => {
|
||||
return this.contactService.contacts?.reduce((acc, contact) => {
|
||||
contact.types.forEach((type) => {
|
||||
acc
|
||||
.find((group: GroupedContacts) => group.value === type)
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
<p>registrars component works!</p>
|
|
@ -20,7 +20,7 @@ import { MatSnackBar } from '@angular/material/snack-bar';
|
|||
@Component({
|
||||
selector: 'app-security',
|
||||
templateUrl: './security.component.html',
|
||||
styleUrls: ['./security.component.less'],
|
||||
styleUrls: ['./security.component.scss'],
|
||||
providers: [SecurityService],
|
||||
})
|
||||
export default class SecurityComponent {
|
||||
|
|
|
@ -17,7 +17,7 @@ import { Component, ViewEncapsulation } from '@angular/core';
|
|||
@Component({
|
||||
selector: 'app-settings',
|
||||
templateUrl: './settings.component.html',
|
||||
styleUrls: ['./settings.component.less'],
|
||||
styleUrls: ['./settings.component.scss'],
|
||||
encapsulation: ViewEncapsulation.None,
|
||||
})
|
||||
export class SettingsComponent {}
|
||||
|
|
|
@ -17,6 +17,6 @@ import { Component } from '@angular/core';
|
|||
@Component({
|
||||
selector: 'app-users',
|
||||
templateUrl: './users.component.html',
|
||||
styleUrls: ['./users.component.less'],
|
||||
styleUrls: ['./users.component.scss'],
|
||||
})
|
||||
export default class UsersComponent {}
|
||||
|
|
|
@ -17,6 +17,6 @@ import { Component } from '@angular/core';
|
|||
@Component({
|
||||
selector: 'app-whois',
|
||||
templateUrl: './whois.component.html',
|
||||
styleUrls: ['./whois.component.less'],
|
||||
styleUrls: ['./whois.component.scss'],
|
||||
})
|
||||
export default class WhoisComponent {}
|
||||
|
|
|
@ -18,6 +18,7 @@ import { catchError, Observable, of } from 'rxjs';
|
|||
import { SecuritySettingsBackendModel } from 'src/app/settings/security/security.service';
|
||||
|
||||
import { Contact } from '../../settings/contact/contact.service';
|
||||
import { Registrar } from '../../registrar/registrar.service';
|
||||
|
||||
@Injectable()
|
||||
export class BackendService {
|
||||
|
@ -60,10 +61,10 @@ export class BackendService {
|
|||
);
|
||||
}
|
||||
|
||||
getRegistrars(): Observable<string[]> {
|
||||
getRegistrars(): Observable<Registrar[]> {
|
||||
return this.http
|
||||
.get<string[]>('/console-api/registrars')
|
||||
.pipe(catchError((err) => this.errorCatcher<string[]>(err)));
|
||||
.get<Registrar[]>('/console-api/registrars')
|
||||
.pipe(catchError((err) => this.errorCatcher<Registrar[]>(err)));
|
||||
}
|
||||
|
||||
getSecuritySettings(
|
||||
|
|
|
@ -0,0 +1,60 @@
|
|||
// 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 { Observable, Subscription, timeout } from 'rxjs';
|
||||
|
||||
export interface GlobalLoader {
|
||||
loadingTimeout: () => void;
|
||||
}
|
||||
|
||||
/**
|
||||
* This class responsible for global application loading indicator
|
||||
*
|
||||
* <p>Only to be used for when the activity should indicate that the entire application is busy
|
||||
* For instance - when initial user information is loading, which is crucial for any subsequent
|
||||
* interaction with the application
|
||||
*/
|
||||
@Injectable({
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class GlobalLoaderService {
|
||||
private static readonly TIMEOUT_MS = 3000;
|
||||
private loaders = new Map<GlobalLoader, Subscription>();
|
||||
public isLoading: boolean = false;
|
||||
|
||||
private syncLoading() {
|
||||
this.isLoading = this.loaders.size > 0;
|
||||
}
|
||||
|
||||
startGlobalLoader(c: GlobalLoader) {
|
||||
const subscription = new Observable(() => {})
|
||||
.pipe(timeout(GlobalLoaderService.TIMEOUT_MS))
|
||||
.subscribe({
|
||||
error: () => {
|
||||
this.loaders.delete(c);
|
||||
c.loadingTimeout();
|
||||
this.syncLoading();
|
||||
},
|
||||
});
|
||||
this.loaders.set(c, subscription);
|
||||
this.syncLoading();
|
||||
}
|
||||
|
||||
stopGlobalLoader(c: GlobalLoader) {
|
||||
this.loaders.get(c)?.unsubscribe();
|
||||
this.loaders.delete(c);
|
||||
this.syncLoading();
|
||||
}
|
||||
}
|
|
@ -17,6 +17,6 @@ import { Component } from '@angular/core';
|
|||
@Component({
|
||||
selector: 'app-tlds',
|
||||
templateUrl: './tlds.component.html',
|
||||
styleUrls: ['./tlds.component.less'],
|
||||
styleUrls: ['./tlds.component.scss'],
|
||||
})
|
||||
export class TldsComponent {}
|
||||
|
|
63
console-webapp/src/styles.scss
Normal file
63
console-webapp/src/styles.scss
Normal file
|
@ -0,0 +1,63 @@
|
|||
// Copyright 2022 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.
|
||||
@use "@angular/material" as mat;
|
||||
@import "app/registrar/registrar-selector.component.scss";
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: Roboto, "Helvetica Neue", sans-serif;
|
||||
}
|
||||
|
||||
.text-center {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.console-app {
|
||||
&__widget {
|
||||
display: flex;
|
||||
gap: 10px;
|
||||
&-wrapper__wide {
|
||||
grid-column: span 2;
|
||||
}
|
||||
&-link {
|
||||
padding: 0 !important;
|
||||
text-align: left;
|
||||
margin-bottom: 0.5rem;
|
||||
}
|
||||
&-title {
|
||||
color: var(--primary) !important;
|
||||
}
|
||||
&-icon {
|
||||
font-size: 4rem;
|
||||
line-height: 4rem;
|
||||
height: 4rem !important;
|
||||
width: 4rem !important;
|
||||
}
|
||||
&_left {
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
}
|
||||
&_right {
|
||||
flex: 1;
|
||||
border-left: 1px solid var(--secondary);
|
||||
padding-left: 20px;
|
||||
}
|
||||
}
|
||||
}
|
69
console-webapp/src/theme.scss
Normal file
69
console-webapp/src/theme.scss
Normal file
|
@ -0,0 +1,69 @@
|
|||
@use "sass:map";
|
||||
@use "@angular/material" as mat;
|
||||
|
||||
/** Copied from docs section **/
|
||||
|
||||
// Include the common styles for Angular Material. We include this here so that you only
|
||||
// have to load a single css file for Angular Material in your app.
|
||||
// Be sure that you only ever include this mixin once!
|
||||
@include mat.core();
|
||||
|
||||
// Define the palettes for your theme using the Material Design palettes available in palette.scss
|
||||
// (imported above). For each palette, you can optionally specify a default, lighter, and darker
|
||||
// hue. Available color palettes: https://material.io/design/color/
|
||||
$theme-primary: mat.define-palette(mat.$indigo-palette);
|
||||
$theme-accent: mat.define-palette(mat.$pink-palette, A200, A100, A400);
|
||||
|
||||
// The warn palette is optional (defaults to red).
|
||||
$theme-warn: mat.define-palette(mat.$red-palette);
|
||||
|
||||
// Create the theme object. A theme consists of configurations for individual
|
||||
// theming systems such as "color" or "typography".
|
||||
$theme: mat.define-light-theme(
|
||||
(
|
||||
color: (
|
||||
primary: $theme-primary,
|
||||
accent: $theme-accent,
|
||||
warn: $theme-warn,
|
||||
),
|
||||
density: 0,
|
||||
)
|
||||
);
|
||||
|
||||
/** Application specific section **/
|
||||
|
||||
@mixin form-field-density($density) {
|
||||
$field-typography: mat.define-typography-config(
|
||||
$body-1: mat.define-typography-level(12px, 24px, 400),
|
||||
);
|
||||
@include mat.typography-level($field-typography, "body-1");
|
||||
@include mat.form-field-density($density);
|
||||
}
|
||||
|
||||
// Define lowest possible density class to be used in application
|
||||
// In the same manner -1...-5 classes can be defined
|
||||
.mat-form-field-density-5 {
|
||||
@include form-field-density(-5);
|
||||
}
|
||||
|
||||
$foreground: map.merge($theme, mat.$light-theme-foreground-palette);
|
||||
|
||||
// Access and define a class with secondary color exposed
|
||||
.secondary-text {
|
||||
color: map.get($foreground, "secondary-text");
|
||||
}
|
||||
|
||||
:root {
|
||||
--primary: #{mat.get-color-from-palette($theme-primary, 500)};
|
||||
--secondary: #{map.get($foreground, "secondary-text")};
|
||||
}
|
||||
|
||||
@include mat.all-component-themes($theme);
|
||||
@import "@angular/material/theming";
|
||||
|
||||
// Define application specific typography settings, font-family, etc
|
||||
$typography-configuration: mat-typography-config(
|
||||
$font-family: 'Roboto, "Helvetica Neue", sans-serif',
|
||||
);
|
||||
|
||||
@include angular-material-typography($typography-configuration);
|
Loading…
Add table
Add a link
Reference in a new issue