Restyle registrar console based on the new design proposal (#2336)

This commit is contained in:
Pavlo Tkach
2024-03-21 22:05:09 +00:00
committed by GitHub
parent de3af34b66
commit 59f4129ee0
119 changed files with 3468 additions and 2846 deletions
@@ -1,69 +0,0 @@
// 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 { BreakpointObserver } from '@angular/cdk/layout';
import { ComponentType } from '@angular/cdk/portal';
import { Component } from '@angular/core';
import {
MatBottomSheet,
MatBottomSheetRef,
} from '@angular/material/bottom-sheet';
import { MatDialog, MatDialogRef } from '@angular/material/dialog';
const MOBILE_LAYOUT_BREAKPOINT = '(max-width: 599px)';
export interface DialogBottomSheetContent {
init(data: Object): void;
}
/**
* Wraps up a child component in an Angular Material Dalog for desktop or a Bottom Sheet
* component for mobile depending on a screen resolution, with Breaking Point being 599px.
* Child component is required to implement @see DialogBottomSheetContent interface
*/
@Component({
selector: 'app-dialog-bottom-sheet-wrapper',
template: '',
})
export class DialogBottomSheetWrapper {
private elementRef?: MatBottomSheetRef | MatDialogRef<any>;
constructor(
private dialog: MatDialog,
private bottomSheet: MatBottomSheet,
protected breakpointObserver: BreakpointObserver
) {}
open<T extends DialogBottomSheetContent>(
component: ComponentType<T>,
data: any
) {
const config = { data, close: () => this.close() };
if (this.breakpointObserver.isMatched(MOBILE_LAYOUT_BREAKPOINT)) {
this.elementRef = this.bottomSheet.open(component);
this.elementRef.instance.init(config);
} else {
this.elementRef = this.dialog.open(component);
this.elementRef.componentInstance.init(config);
}
}
close() {
if (this.elementRef instanceof MatBottomSheetRef) {
this.elementRef.dismiss();
} else if (this.elementRef instanceof MatDialogRef) {
this.elementRef.close();
}
}
}
@@ -0,0 +1,16 @@
<div class="console-app__notifications">
@for (notification of mockNotifications; track notification.id) {
<div class="console-app__notification">
<div class="console-app__notification-content">
<button mat-mini-fab color="primary" disabled>
<mat-icon mat-mini-fab color="primary"> calendar_month </mat-icon>
</button>
<h4>{{ notification.text }}</h4>
</div>
<button mat-icon-button>
<mat-icon>close</mat-icon>
</button>
</div>
}
</div>
@@ -0,0 +1,23 @@
.console-app {
&__notifications {
margin-bottom: 40px;
}
&__notification {
padding: 20px;
background-color: var(--lightest);
border-radius: 10px;
margin-bottom: 10px;
display: flex;
justify-content: space-between;
align-items: center;
&-content {
display: flex;
align-items: center;
gap: 10px;
}
h4 {
margin: 0;
padding: 0;
}
}
}
@@ -0,0 +1,37 @@
// Copyright 2024 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';
interface Notification {
id: string;
date: Date;
text: string;
}
@Component({
selector: 'app-notifications',
templateUrl: './notifications.component.html',
styleUrls: ['./notifications.component.scss'],
})
export class NotificationsComponent {
protected mockNotifications: Notification[] = [
{
id: '0',
date: new Date(),
text: 'Registry Downtime Planned on June 9, 2024 due to maintenance.',
},
];
constructor() {}
}
@@ -0,0 +1,18 @@
.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%);
white-space: nowrap;
&-icon {
transform: scale(3);
margin-bottom: 0.5rem;
}
}
}
@@ -0,0 +1,37 @@
// Copyright 2024 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 'src/app/registrar/registrar.service';
@Component({
selector: 'app-selected-registrar-wrapper',
styleUrls: ['./selectedRegistrarWrapper.component.scss'],
template: `
@if(registrarService.registrarId()){
<ng-content></ng-content>
} @else {
<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>
}
`,
})
export class SelectedRegistrarWrapper {
constructor(protected registrarService: RegistrarService) {}
}
@@ -0,0 +1,28 @@
// Copyright 2024 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 { Location } from '@angular/common';
import { Directive, HostListener } from '@angular/core';
@Directive({
selector: '[backButton]',
})
export class LocationBackDirective {
constructor(private location: Location) {}
@HostListener('click')
onClick() {
this.location.back();
}
}
@@ -1,4 +1,4 @@
// Copyright 2023 The Nomulus Authors. All Rights Reserved.
// Copyright 2024 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.
@@ -14,14 +14,16 @@
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Injectable } from '@angular/core';
import { catchError, Observable, of } from 'rxjs';
import { Observable, catchError, of, throwError } from 'rxjs';
import { SecuritySettingsBackendModel } from 'src/app/settings/security/security.service';
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';
import {
Registrar,
WhoisRegistrarFields,
} from '../../registrar/registrar.service';
import { Contact } from '../../settings/contact/contact.service';
import { UserData } from './userData.service';
@Injectable()
export class BackendService {
@@ -42,8 +44,11 @@ export class BackendService {
);
}
// return throwError(() => {throw "Failed"});
return of(<Type>mockData);
if (mockData) {
return of(<Type>mockData);
} else {
return throwError(() => error);
}
}
getContacts(registrarId: string): Observable<Contact[]> {
@@ -99,6 +104,12 @@ export class BackendService {
.pipe(catchError((err) => this.errorCatcher<Registrar[]>(err)));
}
postRegistrar(registrar: Registrar): Observable<Registrar> {
return this.http
.post<Registrar>('/console-api/registrar', registrar)
.pipe(catchError((err) => this.errorCatcher<Registrar>(err)));
}
getSecuritySettings(
registrarId: string
): Observable<SecuritySettingsBackendModel> {
@@ -0,0 +1,45 @@
// Copyright 2024 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 { BreakpointObserver } from '@angular/cdk/layout';
import { Injectable, signal } from '@angular/core';
import { distinctUntilChanged } from 'rxjs';
const MOBILE_LAYOUT_BREAKPOINT = '(max-width: 560px)';
const TABLET_LAYOUT_BREAKPOINT = '(max-width: 768px)';
@Injectable({
providedIn: 'root',
})
export class BreakPointObserverService {
isMobileView = signal<boolean>(false);
isTabletView = signal<boolean>(false);
readonly breakpoint$ = this.breakpointObserver
.observe([MOBILE_LAYOUT_BREAKPOINT, TABLET_LAYOUT_BREAKPOINT])
.pipe(distinctUntilChanged());
constructor(protected breakpointObserver: BreakpointObserver) {
this.breakpoint$.subscribe(() => this.breakpointChanged());
}
private breakpointChanged() {
this.isMobileView.set(
this.breakpointObserver.isMatched(MOBILE_LAYOUT_BREAKPOINT)
);
this.isTabletView.set(
this.breakpointObserver.isMatched(TABLET_LAYOUT_BREAKPOINT)
);
}
}
@@ -1,4 +1,4 @@
// Copyright 2023 The Nomulus Authors. All Rights Reserved.
// Copyright 2024 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.
@@ -1,4 +1,4 @@
// Copyright 2023 The Nomulus Authors. All Rights Reserved.
// Copyright 2024 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.
@@ -13,14 +13,16 @@
// limitations under the License.
import { Injectable } from '@angular/core';
import { MatSnackBar } from '@angular/material/snack-bar';
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 {
globalRole: string;
isAdmin: boolean;
// TODO: provide passcode from back-end
passcode?: string;
productName: string;
supportEmail: string;
supportPhoneNumber: string;
@@ -31,7 +33,7 @@ export interface UserData {
providedIn: 'root',
})
export class UserDataService implements GlobalLoader {
public userData?: UserData;
public userData!: UserData;
constructor(
private backend: BackendService,
protected globalLoader: GlobalLoaderService,