Add resources widget front-end (#2151)

This commit is contained in:
Pavlo Tkach 2023-09-21 13:59:40 -04:00 committed by GitHub
parent 759143535f
commit dded258864
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 151 additions and 29 deletions

View file

@ -24,6 +24,10 @@ import SettingsSecurityComponent from './settings/security/security.component';
import { RegistrarGuard } from './registrar/registrar.guard'; import { RegistrarGuard } from './registrar/registrar.guard';
import { RegistrarComponent } from './registrar/registrarsTable.component'; import { RegistrarComponent } from './registrar/registrarsTable.component';
import { EmptyRegistrar } from './registrar/emptyRegistrar.component'; import { EmptyRegistrar } from './registrar/emptyRegistrar.component';
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';
const routes: Routes = [ const routes: Routes = [
{ path: '', redirectTo: '/home', pathMatch: 'full' }, { path: '', redirectTo: '/home', pathMatch: 'full' },
@ -32,7 +36,7 @@ const routes: Routes = [
{ path: 'home', component: HomeComponent, canActivate: [RegistrarGuard] }, { path: 'home', component: HomeComponent, canActivate: [RegistrarGuard] },
{ path: 'tlds', component: TldsComponent, canActivate: [RegistrarGuard] }, { path: 'tlds', component: TldsComponent, canActivate: [RegistrarGuard] },
{ {
path: 'settings', path: SettingsComponent.PATH,
component: SettingsComponent, component: SettingsComponent,
children: [ children: [
{ {
@ -41,32 +45,27 @@ const routes: Routes = [
pathMatch: 'full', pathMatch: 'full',
}, },
{ {
path: 'contact', path: ContactComponent.PATH,
component: SettingsContactComponent, component: SettingsContactComponent,
canActivate: [RegistrarGuard], canActivate: [RegistrarGuard],
}, },
{ {
path: 'whois', path: WhoisComponent.PATH,
component: SettingsWhoisComponent, component: SettingsWhoisComponent,
canActivate: [RegistrarGuard], canActivate: [RegistrarGuard],
}, },
{ {
path: 'security', path: SecurityComponent.PATH,
component: SettingsSecurityComponent, component: SettingsSecurityComponent,
canActivate: [RegistrarGuard], canActivate: [RegistrarGuard],
}, },
{ {
path: 'epp-password', path: UsersComponent.PATH,
component: SettingsSecurityComponent,
canActivate: [RegistrarGuard],
},
{
path: 'users',
component: SettingsUsersComponent, component: SettingsUsersComponent,
canActivate: [RegistrarGuard], canActivate: [RegistrarGuard],
}, },
{ {
path: 'registrars', path: RegistrarComponent.PATH,
component: RegistrarComponent, component: RegistrarComponent,
}, },
], ],

View file

@ -14,6 +14,7 @@
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { RegistrarService } from './registrar/registrar.service'; import { RegistrarService } from './registrar/registrar.service';
import { UserDataService } from './shared/services/userData.service';
import { GlobalLoaderService } from './shared/services/globalLoader.service'; import { GlobalLoaderService } from './shared/services/globalLoader.service';
@Component({ @Component({
@ -25,6 +26,7 @@ export class AppComponent {
renderRouter: boolean = true; renderRouter: boolean = true;
constructor( constructor(
protected registrarService: RegistrarService, protected registrarService: RegistrarService,
protected userDataService: UserDataService,
protected globalLoader: GlobalLoaderService protected globalLoader: GlobalLoaderService
) { ) {
registrarService.activeRegistrarIdChange.subscribe(() => { registrarService.activeRegistrarIdChange.subscribe(() => {

View file

@ -46,6 +46,7 @@ import { EppWidgetComponent } from './home/widgets/epp-widget.component';
import { BillingWidgetComponent } from './home/widgets/billing-widget.component'; import { BillingWidgetComponent } from './home/widgets/billing-widget.component';
import { DomainsWidgetComponent } from './home/widgets/domains-widget.component'; import { DomainsWidgetComponent } from './home/widgets/domains-widget.component';
import { SettingsWidgetComponent } from './home/widgets/settings-widget.component'; import { SettingsWidgetComponent } from './home/widgets/settings-widget.component';
import { UserDataService } from './shared/services/userData.service';
@NgModule({ @NgModule({
declarations: [ declarations: [
@ -81,6 +82,7 @@ import { SettingsWidgetComponent } from './home/widgets/settings-widget.componen
BackendService, BackendService,
GlobalLoaderService, GlobalLoaderService,
RegistrarGuard, RegistrarGuard,
UserDataService,
{ {
provide: MAT_FORM_FIELD_DEFAULT_OPTIONS, provide: MAT_FORM_FIELD_DEFAULT_OPTIONS,
useValue: { useValue: {

View file

@ -13,13 +13,13 @@
Give us a Call Give us a Call
</button> </button>
<p class="secondary-text"> <p class="secondary-text">
Call Google Registry support at +1 (404) 978 8419 Call Google Registry support at <b>+1 (404) 978 8419</b>
</p> </p>
<button mat-button color="primary" class="console-app__widget-link"> <button mat-button color="primary" class="console-app__widget-link">
Send us an Email Send us an Email
</button> </button>
<p class="secondary-text"> <p class="secondary-text">
Email Google Registry at support@google.com Email Google Registry at <b>support@google.com</b>
</p> </p>
</div> </div>
</div> </div>

View file

@ -1,13 +1,16 @@
<mat-card> <mat-card>
<mat-card-content> <mat-card-content>
<div class="console-app__widget"> <div class="console-app__widget">
<div class="console-app__widget_left"> <a
class="console-app__widget_left"
href="{{ userDataService.userData?.technicalDocsUrl }}"
>
<mat-icon class="console-app__widget-icon">menu_book</mat-icon> <mat-icon class="console-app__widget-icon">menu_book</mat-icon>
<h1 class="console-app__widget-title">Resources</h1> <h1 class="console-app__widget-title">Resources</h1>
<h4 class="secondary-text text-center"> <h4 class="secondary-text text-center">
Use Google Drive to view onboarding FAQs, and technical documentation. Use Google Drive to view onboarding FAQs, and technical documentation.
</h4> </h4>
</div> </a>
</div> </div>
</mat-card-content> </mat-card-content>
</mat-card> </mat-card>

View file

@ -13,11 +13,12 @@
// limitations under the License. // limitations under the License.
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { UserDataService } from 'src/app/shared/services/userData.service';
@Component({ @Component({
selector: '[app-resources-widget]', selector: '[app-resources-widget]',
templateUrl: './resources-widget.component.html', templateUrl: './resources-widget.component.html',
}) })
export class ResourcesWidgetComponent { export class ResourcesWidgetComponent {
constructor() {} constructor(public userDataService: UserDataService) {}
} }

View file

@ -10,11 +10,21 @@
</h4> </h4>
</div> </div>
<div class="console-app__widget_right"> <div class="console-app__widget_right">
<button mat-button color="primary" class="console-app__widget-link"> <button
mat-button
color="primary"
class="console-app__widget-link"
(click)="openContactsPage()"
>
Contact Information Contact Information
</button> </button>
<p class="secondary-text">Manage Primary, Technical, etc contacts.</p> <p class="secondary-text">Manage Primary, Technical, etc contacts.</p>
<button mat-button color="primary" class="console-app__widget-link"> <button
mat-button
color="primary"
class="console-app__widget-link"
(click)="openSecurityPage()"
>
Security Security
</button> </button>
<p class="secondary-text"> <p class="secondary-text">
@ -28,7 +38,12 @@
User Management User Management
</button> </button>
<p class="secondary-text">Create and manage console user accounts</p> <p class="secondary-text">Create and manage console user accounts</p>
<button mat-button color="primary" class="console-app__widget-link"> <button
mat-button
color="primary"
class="console-app__widget-link"
(click)="openRegistrarsPage()"
>
Registrar Management Registrar Management
</button> </button>
<p class="secondary-text">Create and manage registrar accounts</p> <p class="secondary-text">Create and manage registrar accounts</p>

View file

@ -13,11 +13,32 @@
// limitations under the License. // limitations under the License.
import { Component } from '@angular/core'; import { Component } from '@angular/core';
import { Router } from '@angular/router';
import { RegistrarComponent } from 'src/app/registrar/registrarsTable.component';
import ContactComponent from 'src/app/settings/contact/contact.component';
import SecurityComponent from 'src/app/settings/security/security.component';
import { SettingsComponent } from 'src/app/settings/settings.component';
@Component({ @Component({
selector: '[app-settings-widget]', selector: '[app-settings-widget]',
templateUrl: './settings-widget.component.html', templateUrl: './settings-widget.component.html',
}) })
export class SettingsWidgetComponent { export class SettingsWidgetComponent {
constructor() {} constructor(private router: Router) {}
openRegistrarsPage() {
this.navigate(RegistrarComponent.PATH);
}
openSecurityPage() {
this.navigate(SecurityComponent.PATH);
}
openContactsPage() {
this.navigate(ContactComponent.PATH);
}
private navigate(route: string) {
this.router.navigate([SettingsComponent.PATH, route]);
}
} }

View file

@ -19,6 +19,7 @@ import {
GlobalLoader, GlobalLoader,
GlobalLoaderService, GlobalLoaderService,
} from '../shared/services/globalLoader.service'; } from '../shared/services/globalLoader.service';
import { MatSnackBar } from '@angular/material/snack-bar';
interface Address { interface Address {
street?: string[]; street?: string[];
@ -52,7 +53,8 @@ export class RegistrarService implements GlobalLoader {
constructor( constructor(
private backend: BackendService, private backend: BackendService,
private globalLoader: GlobalLoaderService private globalLoader: GlobalLoaderService,
private _snackBar: MatSnackBar
) { ) {
this.loadRegistrars().subscribe((r) => { this.loadRegistrars().subscribe((r) => {
this.globalLoader.stopGlobalLoader(this); this.globalLoader.stopGlobalLoader(this);
@ -82,6 +84,8 @@ export class RegistrarService implements GlobalLoader {
} }
loadingTimeout() { loadingTimeout() {
// TODO: Decide what to do when timeout happens this._snackBar.open('Timeout loading registrars', undefined, {
duration: 1500,
});
} }
} }

View file

@ -21,6 +21,7 @@ import { Registrar, RegistrarService } from './registrar.service';
styleUrls: ['./registrarsTable.component.scss'], styleUrls: ['./registrarsTable.component.scss'],
}) })
export class RegistrarComponent { export class RegistrarComponent {
public static PATH = 'registrars';
columns = [ columns = [
{ {
columnDef: 'registrarId', columnDef: 'registrarId',

View file

@ -143,6 +143,8 @@ export class ContactDetailsDialogComponent {
styleUrls: ['./contact.component.scss'], styleUrls: ['./contact.component.scss'],
}) })
export default class ContactComponent { export default class ContactComponent {
public static PATH = 'contact';
loading: boolean = false; loading: boolean = false;
constructor( constructor(
private dialog: MatDialog, private dialog: MatDialog,

View file

@ -29,6 +29,8 @@ import { RegistrarService } from 'src/app/registrar/registrar.service';
providers: [SecurityService], providers: [SecurityService],
}) })
export default class SecurityComponent { export default class SecurityComponent {
public static PATH = 'security';
loading: boolean = false; loading: boolean = false;
inEdit: boolean = false; inEdit: boolean = false;
dataSource: SecuritySettings = {}; dataSource: SecuritySettings = {};

View file

@ -20,4 +20,6 @@ import { Component, ViewEncapsulation } from '@angular/core';
styleUrls: ['./settings.component.scss'], styleUrls: ['./settings.component.scss'],
encapsulation: ViewEncapsulation.None, encapsulation: ViewEncapsulation.None,
}) })
export class SettingsComponent {} export class SettingsComponent {
public static PATH = 'settings';
}

View file

@ -19,4 +19,6 @@ import { Component } from '@angular/core';
templateUrl: './users.component.html', templateUrl: './users.component.html',
styleUrls: ['./users.component.scss'], styleUrls: ['./users.component.scss'],
}) })
export default class UsersComponent {} export default class UsersComponent {
public static PATH = 'users';
}

View file

@ -19,4 +19,6 @@ import { Component } from '@angular/core';
templateUrl: './whois.component.html', templateUrl: './whois.component.html',
styleUrls: ['./whois.component.scss'], styleUrls: ['./whois.component.scss'],
}) })
export default class WhoisComponent {} export default class WhoisComponent {
public static PATH = 'whois';
}

View file

@ -19,6 +19,7 @@ import { SecuritySettingsBackendModel } from 'src/app/settings/security/security
import { Contact } from '../../settings/contact/contact.service'; import { Contact } from '../../settings/contact/contact.service';
import { Registrar } from '../../registrar/registrar.service'; import { Registrar } from '../../registrar/registrar.service';
import { UserData } from './userData.service';
@Injectable() @Injectable()
export class BackendService { export class BackendService {
@ -90,4 +91,10 @@ export class BackendService {
securitySettings securitySettings
); );
} }
getUserData(): Observable<UserData> {
return this.http
.get<UserData>(`/console-api/userdata`)
.pipe(catchError((err) => this.errorCatcher<UserData>(err)));
}
} }

View file

@ -0,0 +1,56 @@
// 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, tap } from 'rxjs';
import { BackendService } from './backend.service';
import { MatSnackBar } from '@angular/material/snack-bar';
import { GlobalLoader, GlobalLoaderService } from './globalLoader.service';
export interface UserData {
isAdmin: boolean;
globalRole: string;
technicalDocsUrl: string;
}
@Injectable({
providedIn: 'root',
})
export class UserDataService implements GlobalLoader {
public userData?: UserData;
constructor(
private backend: BackendService,
protected globalLoader: GlobalLoaderService,
private _snackBar: MatSnackBar
) {
this.getUserData().subscribe(() => {
this.globalLoader.stopGlobalLoader(this);
});
this.globalLoader.startGlobalLoader(this);
}
getUserData(): Observable<UserData> {
return this.backend.getUserData().pipe(
tap((userData: UserData) => {
this.userData = userData;
})
);
}
loadingTimeout() {
this._snackBar.open('Timeout loading user data', undefined, {
duration: 1500,
});
}
}

View file

@ -45,15 +45,16 @@ body {
padding: 0 !important; padding: 0 !important;
text-align: left; text-align: left;
height: 20px !important; height: 20px !important;
min-width: auto !important;
} }
&-title { &-title {
color: var(--primary) !important; color: var(--primary) !important;
} }
&-icon { &-icon {
font-size: 4rem; font-size: 5rem;
line-height: 4rem; line-height: 5rem;
height: 4rem !important; height: 5rem !important;
width: 4rem !important; width: 5rem !important;
} }
&_left { &_left {
flex: 1; flex: 1;