Commit 02910f23 authored by Chris Hines's avatar Chris Hines
Browse files

moving to new UI, separate login and settings screens

parent 0f177293
Pipeline #7395 passed with stages
in 3 minutes and 19 seconds
......@@ -7,6 +7,7 @@ import { ShareconnectComponent } from './shareconnect/shareconnect.component';
import { JoblistComponent } from './joblist/joblist.component';
import {LoginComponent} from './login/login.component';
import {SettingsComponent} from './settings/settings.component';
// import { TokenextractorComponent } from './tokenextractor/tokenextractor.component';
......@@ -17,6 +18,7 @@ const routes: Routes = [
//{ path: 'launch', component: JoblistComponent},
{ path: 'launch', component: LauncherComponent},
{ path: 'login', component: LoginComponent},
{ path: 'settings', component: SettingsComponent },
// { path: 'finishlaunch', component: LauncherComponent},
//{ path: 'cancellaunch', component: LauncherComponent},
{ path: 'sshauthz_callback', component: KeygenComponent},
......
......@@ -7,4 +7,9 @@
</div> -->
<!--<app-launcher></app-launcher>-->
<mat-sidenav-container style="height: 100%; width: 100%">
<mat-sidenav></mat-sidenav>
<mat-sidenav-content>
<router-outlet></router-outlet>
</mat-sidenav-content>
</mat-sidenav-container>
......@@ -38,6 +38,7 @@ export class AppComponent {
this.computesitesService.setStatusMsg(this.statusMsg);
this.authService.setStatusMsg(this.statusMsg);
this.statusMsg.subscribe(msg => this.displayMessage(msg));
this.setTheme()
}
......@@ -51,6 +52,22 @@ export class AppComponent {
this.snackBarRef = this.snackBar.open(msg,'Dismiss');
}
}
setTheme() {
var theme;
theme=localStorage.getItem('strudel-theme');
if (theme == null) {
theme = 'strudel-theme-light';
}
let classList = document.querySelector('app-root').classList
var c;
for (c of classList.value.split(' ')) {
if (c.indexOf('strudel-') == 0) {
console.log('remove class'+c);
classList.remove(c);
}
}
classList.add(theme);
}
......
......@@ -24,6 +24,7 @@ import { StrudelappsService } from './strudelapps.service';
import { AuthorisationService } from './authorisation.service';
import { FlexLayoutModule } from '@angular/flex-layout';
import { FileExplorerModule } from './file-explorer/file-explorer.module';
import { MatMenuModule } from '@angular/material';
import { TesService} from './tes.service';
......@@ -49,6 +50,7 @@ import { LaunchDialogComponent } from './launch-dialog/launch-dialog.component';
import { ModaldialogComponent } from './modaldialog/modaldialog.component'
import {OverlayModule} from '@angular/cdk/overlay';
import { LoginComponent } from './login/login.component';
import { SettingsComponent } from './settings/settings.component';
// import { FileExplorerModule } from './file-explorer/file-explorer.module';
......@@ -73,6 +75,7 @@ import { LoginComponent } from './login/login.component';
LaunchDialogComponent,
ModaldialogComponent,
LoginComponent,
SettingsComponent,
],
imports: [
BrowserModule,
......@@ -99,6 +102,7 @@ import { LoginComponent } from './login/login.component';
FlexLayoutModule,
MatProgressBarModule,
OverlayModule,
MatMenuModule,
],
......
......@@ -60,4 +60,5 @@ export class SshAuthzServer {
userdefined: boolean;
cafp: string;
signup: string;
desc: string;
}
......@@ -12,30 +12,9 @@
</mat-toolbar>
<mat-sidenav-container style="height: 100%; width: 100%">
<mat-sidenav #idSideNav mode="side" opened>
<div fxLayout="column" style="height: 100%">
<div>
<mat-accordion>
<!-- <mat-accordion> -->
<div *ngIf="(computeSitesService.appidentities | async).length == 0">
<mat-expansion-panel>
<mat-expansion-panel-header>
<mat-panel-title>
Login
</mat-panel-title>
</mat-expansion-panel-header>
<div *ngFor="let sshauthzserver of (authService.loggedOutAuthZ | async)">
<button mat-button (click)=login(sshauthzserver) fxFlex style="text-align: left"> Login to {{ sshauthzserver.name }}</button>
<button mat-icon-button *ngIf="sshauthzserver.userdefined === true"><mat-icon>remove</mat-icon></button>
</div>
<div *ngFor="let sshauthzserver of (authService.loggedOutAuthZ | async)">
<button mat-button (click)=signup(sshauthzserver) style="text-align: left"> Signup for {{ sshauthzserver.name }}</button>
</div>
<!--<button mat-button (click) =logout() style="text-align: left">Logout</button>-->
<button mat-button (click) ="authService.updateAgentContents()" style="text-align: left">Refresh</button>
</mat-expansion-panel>
</div>
<div *ngIf="(computeSitesService.appidentities | async).length > 0">
<button mat-button (click) =logout() style="text-align: left; width: 100%">Logout</button>
</div>
<div *ngFor="let id of computeSitesService.appidentities | async">
<mat-expansion-panel (click)=selectId(id)>
<mat-expansion-panel-header>
......@@ -44,36 +23,22 @@
<app-strudelapplist [applist]=id.site.appCatalog [identity]="id"></app-strudelapplist>
</mat-expansion-panel>
</div>
<mat-expansion-panel>
<mat-expansion-panel-header>
Advanced
</mat-expansion-panel-header>
Select an API server
<div style="width: 100%">
<mat-form-field>
<mat-select [ngModel]="selectedApiServer" (selectionChange)="backendSelectionService.setApiServer($event.value)">
<mat-option *ngFor="let apis of backendSelectionService.apiservers|async" [value]="apis">
{{ apis.name }}
</mat-option>
</mat-select>
</mat-form-field>
</mat-accordion>
</div>
<button type="button" mat-button (click)="fileInput.click()">Load Config</button>
<input hidden (change)="loadConfig($event)" accept=".json" #fileInput type="file" id="file">
<button mat-button (click)=resetConfig()>Reset Config</button>
<div style="width: 100%">
Select a theme
<mat-form-field >
<mat-select [(value)] ="theme" (selectionChange)="selectTheme($event.value)">
<mat-option *ngFor="let opttheme of themes" [value]="opttheme">
{{ opttheme.name }}
</mat-option>
</mat-select>
</mat-form-field>
<div fxFlex></div>
<mat-menu #actionmenu="matMenu">
<div *ngIf="(computeSitesService.appidentities | async).length > 0">
<button mat-menu-item (click)="logout()"><mat-icon>logout</mat-icon>Logout</button>
</div>
</mat-expansion-panel>
</mat-accordion>
</mat-sidenav>
<button mat-menu-item routerLink="/settings"><mat-icon>settings</mat-icon>Settings</button>
<button mat-menu-item routerLink="/login">Login</button>
</mat-menu>
<button mat-icon-button [matMenuTriggerFor]="actionmenu">
<mat-icon>more_vert</mat-icon>
</button>
</div>
</mat-sidenav>
<app-joblist [identity]="(identitySubject | async)"></app-joblist>
<!--<router-outlet></router-outlet>-->
......
......@@ -36,7 +36,6 @@ import {OverlayContainer} from '@angular/cdk/overlay';
export class LauncherComponent implements OnInit {
public strudelapps: Strudelapp[];
@Input() menuopen: boolean;
public themeSubject: BehaviorSubject<string>;
public app: Strudelapp;
public authorised: boolean;
......@@ -47,12 +46,6 @@ export class LauncherComponent implements OnInit {
public sshauthzservers: SshAuthzServer[];
private launchwindow: any;
private launchwindowWatcher: any;
public selectedApiServer: any;
private file: any;
private config: any;
public theme: any;
public themes: any[] = [ {'name':'Light','value':'strudel-light-theme'},
{'name': 'Dark','value':'strudel-dark-theme'}]
constructor( public dialog: MatDialog,
public tesService: TesService,
......@@ -63,9 +56,6 @@ export class LauncherComponent implements OnInit {
) {
this.authService.sshAuthzServers.subscribe(o => {this.updateSshAuthZServers(o)});
this.computeSitesService.appidentities.subscribe(o => this.verifyIdValid(o));
this.backendSelectionService.apiserver.subscribe((s) => this.selectedApiServer = s);
this.themeSubject = new BehaviorSubject<string>('strudel-dark-theme');
this.themeSubject.subscribe(v => this.setTheme(v));
}
verifyIdValid(o) {
......@@ -90,26 +80,6 @@ export class LauncherComponent implements OnInit {
ngOnInit() {
this.strudelapps = [];
var lstheme: string;
try {
console.log('retrieve theme from localStorage');
lstheme=localStorage.getItem('strudel-theme');
console.log(lstheme)
} catch {
}
if (lstheme == null) {
console.log('no theme set, using light');
lstheme = 'strudel-light-theme';
}
//Set the value of this.theme so that the selection shows a value rather than a blank
console.log('trying to find the initial value for theme');
for (let t of this.themes) {
if (t.value == lstheme) {
console.log('found the initial value',t);
this.theme = t;
}
}
this.setTheme(lstheme);
}
......@@ -140,57 +110,4 @@ export class LauncherComponent implements OnInit {
this.tesService.getCachetIncidents(id);
}
loadConfig(event) {
const reader = new FileReader();
reader.onload = (e: any) => {
try {
this.config = JSON.parse(e.target.result);
if ('computesites' in this.config) {
this.computeSitesService.storeLocalComputeSites(this.config['computesites'])
}
if ('apps' in this.config) {
this.computeSitesService.storeLocalStrudelApps(this.config['sitename'],this.config['apps']);
}
if ('authz' in this.config) {
this.authService.storeLocalAuthZ(this.config['authz'])
}
} catch {
console.log('local config file is invalid')
}
};
reader.readAsText(event.target.files[0]);
}
resetConfig() {
this.computeSitesService.removeLocalStrudelApps();
this.computeSitesService.removeLocalComputeSites();
this.authService.removeLocalAuthZ()
}
setTheme(v) {
console.log('Theme selected');
console.log(v);
let theme = v;
console.log(this.overlayContainer.getContainerElement().classList);
let classList = document.querySelector('app-root').classList
console.log('this theme');
console.log(this.theme);
if (theme == 'strudel-light-theme') {
classList.remove('strudel-dark-theme');
classList.add('strudel-light-theme');
}
if (theme == 'strudel-dark-theme') {
classList.remove('strudel-light-theme');
classList.add('strudel-dark-theme');
}
console.log('setting localStorage theme',v);
}
selectTheme(event) {
this.themeSubject.next(event.value);
localStorage.setItem('strudel-theme',event.value);
}
}
<mat-sidenav-container style="height: 100%; width: 100%">
<mat-sidenav>
</mat-sidenav>
<mat-sidenav-content>
<div fxFlex style="flex: 1 1 0%; box-sizing: border-box">
<div fxLayout="column" fxLayoutAlign="space-around stretch" style="height: 100%; width: 100%" >
<div fxLayout="row">
<div fxFlex></div>
<div fxFlex fxLayout="column">
<div style="width: 100%">
<mat-form-field fxFlex>
<mat-label>Choose a server</mat-label>
<mat-select [(value)]="selected" (selectionChange)="selectSite($event.value)">
<mat-option *ngFor="let sshauthzserver of (authService.loggedOutAuthZ | async)" [value]="sshauthzserver">
{{ sshauthzserver.name }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<div style="width: 100%">
<button fxFlex mat-button (click)="login()">Login</button>
<button fxFlex mat-button routerLink="/launch">Cancel</button>
</div>
<div *ngIf="selected !== undefined">
{{ selected.desc }}
</div>
</div>
<div fxFlex></div>
</div>
<div fxFlex></div>
<button mat-icon-button routerLink="/settings"><mat-icon>settings</mat-icon></button>
</div>
</div>
</mat-sidenav-content>
</mat-sidenav-container>
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { LoginComponent } from './login.component';
describe('LoginComponent', () => {
let component: LoginComponent;
let fixture: ComponentFixture<LoginComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ LoginComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(LoginComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, OnInit } from '@angular/core';
import { MatDialog, MatDialogRef, MAT_DIALOG_DATA, MatDialogModule, MatDialogConfig } from '@angular/material';
import {OverlayContainer} from '@angular/cdk/overlay';
import { BehaviorSubject } from 'rxjs/BehaviorSubject';
import {Strudelapp} from '../strudelapp';
import { StrudelappsService } from '../strudelapps.service';
import { TesService } from '../tes.service';
import {BackendSelectionService } from '../backend-selection.service';
import { AuthorisationService } from '../authorisation.service';
import { Identity } from '../identity';
import { Computesite } from '../computesite';
import { LogoutdialogComponent } from '../logoutdialog/logoutdialog.component';
import { SshAuthzServer } from '../identity';
import { ComputesitesService } from '../computesites.service';
@Component({
selector: 'app-login',
templateUrl: './login.component.html',
styleUrls: ['./login.component.css']
})
export class LoginComponent implements OnInit {
public strudelapps: Strudelapp[];
public themeSubject: BehaviorSubject<string>;
public app: Strudelapp;
public authorised: boolean;
public identity: Identity;
// public identitySubject: BehaviorSubject<Identity>;
public identities: Identity[];
public sshauthzservers: SshAuthzServer[];
private launchwindow: any;
private launchwindowWatcher: any;
public selectedApiServer: any;
private file: any;
private config: any;
public theme: any;
public themes: any[] = [ {'name':'Light','value':'strudel-light-theme'},
{'name': 'Dark','value':'strudel-dark-theme'}]
public selected: any;
constructor( public dialog: MatDialog,
public tesService: TesService,
public backendSelectionService: BackendSelectionService,
public authService: AuthorisationService,
public computeSitesService: ComputesitesService,
public overlayContainer: OverlayContainer,
) {
this.authService.sshAuthzServers.subscribe(o => {this.updateSshAuthZServers(o)});
this.computeSitesService.appidentities.subscribe(o => this.verifyIdValid(o));
this.backendSelectionService.apiserver.subscribe((s) => this.selectedApiServer = s);
this.themeSubject = new BehaviorSubject<string>('strudel-dark-theme');
this.themeSubject.subscribe(v => this.setTheme(v));
}
updateSshAuthZServers(o) {
this.sshauthzservers = o;
}
ngOnInit() {
this.strudelapps = [];
var lstheme: string;
try {
console.log('retrieve theme from localStorage');
lstheme=localStorage.getItem('strudel-theme');
console.log(lstheme)
} catch {
}
if (lstheme == null) {
console.log('no theme set, using light');
lstheme = 'strudel-light-theme';
}
//Set the value of this.theme so that the selection shows a value rather than a blank
console.log('trying to find the initial value for theme');
for (let t of this.themes) {
if (t.value == lstheme) {
console.log('found the initial value',t);
this.theme = t;
}
}
this.setTheme(lstheme);
}
verifyIdValid(o) {
let currentId = this.tesService.identitySubject.value
if (currentId === undefined || currentId == null) {
return;
}
for (let id of this.computeSitesService.appidentities.value) {
if (currentId == id) {
return;
}
}
this.tesService.identitySubject.next(null);
//if (!(this.identitySubject.value in this.computeSitesService.appidentities.value)) {
// this.identitySubject.next(null);
//}
}
logout() {
let dialogRef = this.dialog.open(LogoutdialogComponent, {
width: '250px',
height: '400px',
});
}
login () {
this.authService.login(this.selected);
}
signup(sshauthzserver) {
window.open(sshauthzserver.signup);
}
selectSite(event: any) {
console.log('selecteSite');
console.log(event);
console.log(this.selected);
}
selectId(id: Identity) {
this.identity=id;
this.tesService.identitySubject.next(id);
this.tesService.clearJobs();
this.tesService.getJobs(id);
this.tesService.cancelHealthRequests();
this.tesService.getUserHealth(id);
this.tesService.getCachetIncidents(id);
}
loadConfig(event) {
const reader = new FileReader();
reader.onload = (e: any) => {
try {
this.config = JSON.parse(e.target.result);
if ('computesites' in this.config) {
this.computeSitesService.storeLocalComputeSites(this.config['computesites'])
}
if ('apps' in this.config) {
this.computeSitesService.storeLocalStrudelApps(this.config['sitename'],this.config['apps']);
}
if ('authz' in this.config) {
this.authService.storeLocalAuthZ(this.config['authz'])
}
} catch {
console.log('local config file is invalid')
}
};
reader.readAsText(event.target.files[0]);
}
resetConfig() {
this.computeSitesService.removeLocalStrudelApps();
this.computeSitesService.removeLocalComputeSites();
this.authService.removeLocalAuthZ()
}
setTheme(v) {
console.log('Theme selected');
console.log(v);
let theme = v;
console.log(this.overlayContainer.getContainerElement().classList);
let classList = document.querySelector('app-root').classList
console.log('this theme');
console.log(this.theme);
if (theme == 'strudel-light-theme') {
classList.remove('strudel-dark-theme');
classList.add('strudel-light-theme');
}
if (theme == 'strudel-dark-theme') {
classList.remove('strudel-light-theme');
classList.add('strudel-dark-theme');
}
console.log('setting localStorage theme',v);
}
selectTheme(event) {
this.themeSubject.next(event.value);
localStorage.setItem('strudel-theme',event.value);
}
}
Select an API server
<div style="width: 100%">
<mat-form-field>
<mat-select [ngModel]="selectedApiServer" (selectionChange)="backendSelectionService.setApiServer($event.value)">
<mat-option *ngFor="let apis of backendSelectionService.apiservers|async" [value]="apis">
{{ apis.name }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<button type="button" mat-button (click)="fileInput.click()">Load Config</button>
<input hidden (change)="loadConfig($event)" accept=".json" #fileInput type="file" id="file">
<button mat-button (click)=resetConfig()>Reset Config</button>
<div style="width: 100%">
Select a theme
<mat-form-field >
<mat-select [(value)] ="theme" (selectionChange)="selectTheme($event.value)">
<mat-option *ngFor="let opttheme of themes" [value]="opttheme">
{{ opttheme.name }}
</mat-option>
</mat-select>
</mat-form-field>
</div>
<button mat-button routerLink="/launch">Cancel</button>
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { SettingsComponent } from './settings.component';
describe('SettingsComponent', () => {
let component: SettingsComponent;
let fixture: ComponentFixture<SettingsComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ SettingsComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(SettingsComponent);
component = fixture.componentInstance;