Skip to content
Snippets Groups Projects
Commit 14144ba2 authored by kbeyro's avatar kbeyro
Browse files

Add left menu and toast

parent 389db0ef
Branches
No related tags found
3 merge requests!152Release/1.9.0,!66Draft: Add left menu and toast,!51Draft: Resolve "New portal layout"
Showing
with 370 additions and 10 deletions
......@@ -8,8 +8,40 @@ body{
flex-direction: column;
}
.flex-container-row {
min-height:100vh;
display: flex;
flex-direction: row;
}
.flex-spacer {
flex: 1 0 auto;
width: 100%;
height: 100%;
/* width: 100%;
height: 100%; */
}
.logged-out-layout {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.logged-in-layout {
display: flex;
flex-direction: row;
min-height: 100vh;
}
.content-area {
flex: 1;
padding: 1rem;
}
.side-menu {
width: var(--left-panel-width);
background-color: #333;
color: white;
height: 100vh ;
position: fixed;
top: 0;
left: 0;
padding: 1rem;
}
\ No newline at end of file
<div class="flex-container">
<app-navbar></app-navbar>
<div *ngIf="!isLoggedIn" class="flex-container"> <!--- -->
<app-navbar ></app-navbar>
<router-outlet></router-outlet>
<div class="flex-spacer"></div>
<nmaas-footer></nmaas-footer>
<!-- <div class="flex-spacer"></div>
<nmaas-footer></nmaas-footer> -->
</div>
<div *ngIf="isLoggedIn" class="flex-container-row">
<div class="side-menu">
<app-left-menu></app-left-menu>
</div>
<div class="flex-spacer">
</div>
<div class="content-area" [style]="{'margin-left': 'var(--left-panel-width)'}">
<router-outlet></router-outlet>
</div>
<!-- <div class="flex-spacer"></div>
<nmaas-footer></nmaas-footer> -->
</div>
<app-toast-container aria-live="polite" aria-atomic="true"></app-toast-container>
\ No newline at end of file
......@@ -16,6 +16,7 @@ export class AppComponent {
config: any;
private timer: IdleTimer;
public isLoggedIn = false;
constructor(private appConfigService: AppConfigService, private configService: ConfigurationService,
private authService: AuthService, private translate: TranslateService,
......@@ -23,6 +24,7 @@ export class AppComponent {
}
async ngOnInit() {
this.isLoggedIn = this.authService.isLogged() ;
if (this.serviceHealth.isServiceAvailable === false) {
this.router.navigate(['/service-unavailable']);
}
......@@ -31,7 +33,9 @@ export class AppComponent {
console.debug('Configuration: ' + JSON.stringify(this.config));
await this.delay(2000);
console.warn("User logged ? -", this.authService.isLogged())
this.updateLogin();
if (this.authService.isLogged()) {
this.isLoggedIn = true;
this.timer = new IdleTimer({
timeout: 900, // 15 min
onTimeout: () => {
......@@ -42,6 +46,13 @@ export class AppComponent {
}
}
private updateLogin() {
this.authService.isLoggedIn$.subscribe(isLogged => {
console.log("User state update", isLogged);
this.isLoggedIn = isLogged;
});
}
public handleDefaultLanguage(): void {
if (this.authService.getSelectedLanguage() != null) {
this.setLanguage(this.authService.getSelectedLanguage());
......
......@@ -26,6 +26,10 @@ import {ServiceUnavailableService} from './service-unavailable/service-unavailab
import {NgTerminalModule} from 'ng-terminal';
import { provideZxvbnServiceForPSM } from 'angular-password-strength-meter/zxcvbn';
import { FormioModule } from '@formio/angular';
import { LeftMenuComponent } from './shared/left-menu/left-menu.component';
import { ToastContainerComponent, ToastMode } from './shared/toast-container/toast-container.component';
import { MessageService } from 'primeng/api';
import { ToastModule } from 'primeng/toast';
export function appConfigFactory(config: AppConfigService) {
return function create() {
......@@ -52,6 +56,8 @@ export const jwtOptionsFactory = (appConfig: AppConfigService) => ({
@NgModule({
declarations: [
AppComponent,
LeftMenuComponent,
ToastContainerComponent
],
imports: [
BrowserModule,
......@@ -78,7 +84,8 @@ export const jwtOptionsFactory = (appConfig: AppConfigService) => ({
}
}),
NgTerminalModule,
FormioModule
FormioModule,
ToastModule,
],
providers: [
AuthGuard,
......@@ -98,7 +105,8 @@ export const jwtOptionsFactory = (appConfig: AppConfigService) => ({
useFactory: serviceAvailableFactory,
deps: [AppConfigService, HttpClient, ServiceUnavailableService],
multi: true,
}
},
MessageService
],
exports: [
TranslateModule
......
......@@ -279,6 +279,7 @@ export class AuthService {
}
get isLoggedIn$(): Observable<boolean> {
this.isLoggedInSubject.next(this.isLogged());
return this.isLoggedInSubject.pipe(
debounceTime(100), // use debounceTime to aggregate multiple emissions https://rxjs.dev/api/operators/debounceTime
);
......
......@@ -18,7 +18,7 @@
<a (click)="useLanguage(lang)">
<img alt="lang flag" class="lang-circle-icon"
src="assets/images/country/{{lang}}_circle.png"/>
<span>{{lang.toUpperCase()}}</span>
<span>{{lang.toUpperCase()}}</span>,
</a>
</li>
</ul>
......
.side-menu {
background-color: #333;
color: white;
height: calc(100vh - 2rem);
position: static;
top: 0;
left: 0;
display: flex;
flex-direction: column;
padding: 1rem;
border: 2px solid red;
}
.side-menu ul {
list-style: none;
padding: 0;
}
.side-menu li {
margin: 0.5rem 0;
}
.side-menu a {
color: white;
text-decoration: none;
}
.side-menu a:hover {
text-decoration: underline;
}
<div class="flex flex-row ">
<div class="side-menu flex">
<ul>
<li><a (click)="showToastTest()">Menu Item 1</a></li>
<li><a href="#">Menu Item 2</a></li>
<li><a href="#">Menu Item 3</a></li>
</ul>
</div>
<div class="flex">
</div>
</div>
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { LeftMenuComponent } from './left-menu.component';
describe('LeftMenuComponent', () => {
let component: LeftMenuComponent;
let fixture: ComponentFixture<LeftMenuComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [LeftMenuComponent]
})
.compileComponents();
fixture = TestBed.createComponent(LeftMenuComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, OnInit } from '@angular/core';
import { ToastContainerComponent, ToastMode } from '../toast-container/toast-container.component';
@Component({
selector: 'app-left-menu',
templateUrl: './left-menu.component.html',
styleUrl: './left-menu.component.css'
})
export class LeftMenuComponent implements OnInit{
constructor(private toast: ToastContainerComponent) {
}
public ngOnInit(): void {
console.log("test left menu ")
}
public showToastTest() {
this.toast.show("Test test", ToastMode.DANGER, "HEADER")
}
}
......@@ -60,6 +60,7 @@ import {SortableHeaderDirective} from '../service/sort-domain.directive';
import {InputTextModule} from 'primeng/inputtext';
import { DomainNamespaceAnnotationsComponent } from './domain-namespace-annotations/domain-namespace-annotations.component';
import { provideZxvbnServiceForPSM } from 'angular-password-strength-meter/zxcvbn';
import { LeftMenuComponent } from './left-menu/left-menu.component';
@NgModule({
......@@ -123,7 +124,7 @@ import { provideZxvbnServiceForPSM } from 'angular-password-strength-meter/zxcv
ContactComponent,
PreferencesComponent,
SortableHeaderDirective,
DomainNamespaceAnnotationsComponent
DomainNamespaceAnnotationsComponent,
],
providers: [
PasswordValidator,
......
<p-toast position="bottom-right" key="success" [baseZIndex]="5000" preventOpenDuplicates="true" >
<ng-template let-message pTemplate="message" >
<div class="flex flex-row" *ngIf="message.severity === 'success'">
<div class="flex flex-shrink-1 mt-2 mr-4 ml-2 mb-2">
<!-- <img src="../../../assets/icons/toast/toast-success.svg" class="" [alt]="'ALT.TOAST_SUCCESS' | translate"> -->
</div>
<div class="flex" style="flex: 1">
<div class="flex flex-column flex-grow-1 justify-content-center align-content-center ">
<div class="flex">
<h3 class="p-toast-message-success text-left mb-1 mt-1"> {{message.summary | translate}}</h3>
</div>
<div class="flex mb-3">
<small class="p-toast-message-success"> {{message.detail | translate}}</small>
</div>
</div>
</div>
</div>
</ng-template>
</p-toast>
<p-toast position="bottom-right" key="info" [baseZIndex]="5000" preventOpenDuplicates="true">
<ng-template let-message pTemplate="message" >
<div class="flex flex-row" *ngIf="message.severity === 'info'">
<div class="flex flex-shrink-1 mt-2 mr-4 ml-2 mb-2">
<!-- <img src="assets/icons/toast/toast-info.svg" class="" [alt]="'ALT.TOAST_INFORMATION'| translate"> -->
</div>
<div class="flex" style="flex: 1">
<div class="flex flex-column flex-grow-1 justify-content-center align-content-center ">
<div class="flex">
<h3 class="p-toast-message-info text-left mb-1 mt-1"> {{message.summary | translate}}</h3>
</div>
<div class="flex mb-1">
<small class="p-toast-message-info"> {{message.detail | translate}}</small>
</div>
</div>
</div>
</div>
</ng-template>
</p-toast>
<p-toast position="bottom-right" key="warn" [baseZIndex]="5000" preventOpenDuplicates="true">
<ng-template let-message pTemplate="message">
<div class="flex flex-row" *ngIf="message.severity === 'warn'">
<div class="flex flex-shrink-1 mt-2 mr-4 ml-2 mb-2">
<!-- <img src="assets/icons/toast/toast-warning.svg" class="" [alt]="'ALT.TOAST_WARNING' | translate"> -->
</div>
<div class="flex" style="flex: 1">
<div class="flex flex-column flex-grow-1 justify-content-center align-content-center ">
<div class="flex">
<h3 class="p-toast-message-warn text-left mb-1 mt-1"> {{message.summary | translate}}</h3>
</div>
<div class="flex mb-1">
<small class="p-toast-message-warn"> {{message.detail | translate}}</small>
</div>
</div>
</div>
</div>
</ng-template>
</p-toast>
<p-toast position="bottom-right" key="error" [baseZIndex]="5000" preventOpenDuplicates="true" >
<ng-template let-message pTemplate="message">
<div class="flex flex-row" *ngIf="message.severity === 'error'">
<div class="flex flex-shrink-1 mt-2 mr-4 ml-2 mb-2">
<!-- <img src="assets/icons/toast/toast-error.svg" class="" [alt]="'ALT.ERROR' | translate"> -->
</div>
<div class="flex" style="flex: 1">
<div class="flex flex-column flex-grow-1 justify-content-center align-content-center ">
<div class="flex">
<h3 class="p-toast-message-error text-left mb-1 mt-1"> {{message.summary | translate}}</h3>
</div>
<div class="flex mb-1">
<small class="p-toast-message-error"> {{message.detail | translate}}</small>
</div>
</div>
</div>
</div>
</ng-template>
</p-toast>
:host ::ng-deep .p-toast {
margin-bottom: 40px;
margin-right: 10px;
z-index: 999;
width: 20vw !important;
}
:host ::ng-deep .p-toast .p-toast-message {
//margin-top: 0;
//padding-top: 0;
//position: absolute;
//bottom: 60px;
right: 10px;
width: 20vw;
border-radius: 12px;
}
:host ::ng-deep .p-toast .p-toast-message .p-toast-message-content .p-toast-message-text {
margin: 0;
}
:host ::ng-deep .p-toast .p-toast-message .p-toast-message-content {
padding: 0;
border-width: 0;
text-align: left;
}
:host ::ng-deep .p-toast .p-toast-message .p-toast-icon-close {
width: 2rem;
height: 2rem;
border-radius: 50%;
background: transparent;
position: absolute;
right: 3px;
transition: background-color 0.2s, color 0.2s, box-shadow 0.2s;
}
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ToastContainerComponent } from './toast-container.component';
import {TranslateFakeLoader, TranslateLoader, TranslateModule} from '@ngx-translate/core';
import {MessageService} from "primeng/api";
describe('ToastContainerComponent', () => {
let component: ToastContainerComponent;
let fixture: ComponentFixture<ToastContainerComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ ToastContainerComponent ],
imports: [
TranslateModule.forRoot({
loader: {
provide: TranslateLoader,
useClass: TranslateFakeLoader,
}
})
],
providers: [
MessageService
]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(ToastContainerComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import {Component, Injectable} from '@angular/core';
import {MessageService} from "primeng/api";
export enum ToastMode {
SUCCESS = 'success',
DANGER = 'error',
NORMAL = 'info',
WARN = 'warn'
}
export interface Toast {
text?: string;
header?: string;
delay?: number;
mode?: ToastMode;
}
@Component({
selector: 'app-toast-container',
templateUrl: './toast-container.component.html',
styleUrls: ['./toast-container.component.scss'],
})
@Injectable( {providedIn: 'root'})
export class ToastContainerComponent{
public ToastMode = ToastMode;
public readonly defaultDelay = 3000;
constructor(private readonly messageService: MessageService){
}
show(text: string, mode: ToastMode = ToastMode.NORMAL, header?: string, delay?: number): void {
console.log("Toast shown.")
this.messageService.add({severity: mode, summary: header, detail: text, life: delay, key: mode})
}
push(toast: Toast): void {
this.messageService.add({severity: toast.mode, summary: toast.header, detail: toast.text, life: toast.delay, key: toast.mode})
}
remove(): void {
this.messageService.clear();
}
}
......@@ -7,6 +7,10 @@
/* These classes are copy pasted from bootstrap 4 to work with formio panel display */
/* remove when applying actual bootstrap 4 */
:root {
--left-panel-width: 300px;
}
.card {
position: relative;
display: -webkit-box;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment