Commit 5edb03d0 authored by Chris Hines's avatar Chris Hines
Browse files

ui overhaul

parent 49ed5c68
Pipeline #7795 passed with stages
in 4 minutes and 59 seconds
<div fxLayout=column fxLayoutAlign="space-between" style="width: 100%; height: 100%">
<div *ngIf="(identity.systemalerts | async) == null || (identity.accountalerts | async) == null; then loading else displayAlerts"></div>
<ng-template #loading><h2> Loading ...</h2></ng-template>
<ng-template #displayAlerts>
<!-- This is all the system level alerts-->
<!--<div style="padding-left: 5%; padding-right: 5%; padding-top: 5%">-->
<div >
<mat-list>
<div *ngFor="let h of (identity.systemalerts | async)">
<mat-list-item>
<div *ngIf="h.stat == 'error'">
<div class='health-warn'>
{{ h.msg }}
</div>
</div>
</mat-list-item>
</div>
</mat-list>
<mat-list>
<div *ngFor="let h of (identity.accountalerts | async)">
<div *ngIf="h.type === undefined || h.type != 'quota'">
<mat-list-item>
<div [ngClass]="h.stat == 'error' || h.stat == 'warn' ? 'health-warn': 'health-ok'">
{{ h.msg }}
</div>
</mat-list-item>
</div>
<div *ngIf="h.type == 'table'">
<h3>{{ h.title }}</h3>
<table mat-table [dataSource]="h.data.rows" style="width: 100%">
<ng-container *ngFor="let c of h.data.cols" matColumnDef="{{c.key}}">
<th mat-header-cell *matHeaderCellDef style="text-align: right">{{ c.header }} </th>
<td mat-cell *matCellDef="let row;" style="text-align: right"> {{row[c.key]}}</td>
</ng-container>
<tr mat-header-row *matHeaderRowDef="calculateCols(h.data.cols); sticky: true" ></tr>
<tr mat-row *matRowDef="let row; columns: calculateCols(h.data.cols)" [ngClass]="rowClass(row)" ></tr>
</table>
</div>
</div>
</mat-list>
</div>
</ng-template>
</div>
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { AccountinfoComponent } from './accountinfo.component';
describe('AccountinfoComponent', () => {
let component: AccountinfoComponent;
let fixture: ComponentFixture<AccountinfoComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ AccountinfoComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(AccountinfoComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, OnInit, Input } from '@angular/core';
import { Identity } from '../identity';
import { Router, ActivatedRoute, ParamMap } from '@angular/router';
import { TesService } from '../tes.service';
@Component({
selector: 'app-accountinfo',
templateUrl: './accountinfo.component.html',
styleUrls: ['./accountinfo.component.css']
})
export class AccountinfoComponent implements OnInit {
@Input() identity: Identity;
constructor(
private router: Router,
public tesService: TesService,
) { }
ngOnInit() {
}
calculateCols(data) {
return data.map(function(r) { return r.key });
}
humanKBytes(n: number) {
if (n > 1024*1024*1024) {
let v = n/1024/1024/1024;
return v.toFixed(0)+'TB';
}
if (n > 1024*1024) {
let v = n/1024/1024;
return v.toFixed(0)+'GB';
}
if (n > 1024) {
let v = n/1024;
return v.toFixed(0)+'MB';
}
return '0 MB';
}
rowClass(row) {
if (row.stat == 'error' || row.stat == 'warn') {
return 'health-warn';
} else {
return 'health-ok';
}
}
navLogin(o) {
if (o == null) {
return
}
if (o.length == 0) {
this.router.navigate(['/login']);
} else {
}
}
getHealth(o) {
if (o == null) {
return
}
for (let id of o) {
this.tesService.getHealthAlerts(id);
}
}
}
...@@ -18,13 +18,15 @@ const routes: Routes = [ ...@@ -18,13 +18,15 @@ const routes: Routes = [
{ path: '', redirectTo: 'launch', pathMatch: 'full'}, { path: '', redirectTo: 'launch', pathMatch: 'full'},
//{ path: 'launch', component: JoblistComponent}, //{ path: 'launch', component: JoblistComponent},
{ path: 'launch', component: LauncherComponent}, { path: 'launch', component: LauncherComponent},
{ path: 'launch/:site', component: LauncherComponent},
{ path: 'launch/:site/:app', component: LauncherComponent},
{ path: 'login', component: LoginComponent}, { path: 'login', component: LoginComponent},
{ path: 'logout', component: LogoutComponent}, { path: 'logout', component: LogoutComponent},
{ path: 'settings', component: SettingsComponent }, { path: 'settings', component: SettingsComponent },
// { path: 'finishlaunch', component: LauncherComponent}, // { path: 'finishlaunch', component: LauncherComponent},
//{ path: 'cancellaunch', component: LauncherComponent}, //{ path: 'cancellaunch', component: LauncherComponent},
{ path: 'sshauthz_callback', component: KeygenComponent}, { path: 'sshauthz_callback', component: KeygenComponent},
// { path: 'transfer', component: TransferComponent }, { path: 'transfer', component: TransferComponent },
//{ path: 'shareconnect', component: ShareconnectComponent } //{ path: 'shareconnect', component: ShareconnectComponent }
......
...@@ -7,9 +7,37 @@ ...@@ -7,9 +7,37 @@
</div> --> </div> -->
<!--<app-launcher></app-launcher>--> <!--<app-launcher></app-launcher>-->
<mat-sidenav-container style="height: 100%; width: 100%"> <mat-sidenav-container style="height: 100vh; width: 100%">
<mat-sidenav></mat-sidenav> <!--<mat-sidenav-container>-->
<mat-sidenav closed>
1st sidenav
</mat-sidenav>
<mat-sidenav-content> <mat-sidenav-content>
<router-outlet></router-outlet> <div fxLayout="column" fxLayoutAlign="space-between stretch" style="height: 100%; width: 100%">
<mat-toolbar color="primary">
<div fxLayout="row" style="width: 100%">
<mat-toolbar-row style="width: 100%">
<img src="assets/MASSIVElogoTransparent128x128.png" style="width: auto; height: 90%">
<span>Strudel2</span>
<span fxFlex></span>
<span class="fill-horizontal-space"></span>
<button mat-icon-button [matMenuTriggerFor]="actionmenu">
<mat-icon>person</mat-icon>
</button>
<mat-menu #actionmenu="matMenu">
<div *ngFor="let az of (authService.loggedInAuthZ | async)">
<button mat-menu-item routerLink="/logout"><mat-icon>logout</mat-icon>Log out of {{ az.name }}</button>
</div>
<button mat-menu-item routerLink="/settings"><mat-icon>settings</mat-icon>Settings</button>
<button *ngIf="(authService.loggedOutAuthZ | async).length > 0" mat-menu-item routerLink="/login"><mat-icon>exit_to_app</mat-icon>More services</button>
</mat-menu>
</mat-toolbar-row>
</div>
</mat-toolbar>
<div style="height: 100%">
<router-outlet></router-outlet>
</div>
</div>
</mat-sidenav-content> </mat-sidenav-content>
</mat-sidenav-container> </mat-sidenav-container>
...@@ -5,6 +5,7 @@ import { ComputesitesService} from './computesites.service'; ...@@ -5,6 +5,7 @@ import { ComputesitesService} from './computesites.service';
import {BehaviorSubject} from 'rxjs/BehaviorSubject'; import {BehaviorSubject} from 'rxjs/BehaviorSubject';
import { MatSnackBar } from '@angular/material'; import { MatSnackBar } from '@angular/material';
import {OverlayContainer} from '@angular/cdk/overlay'; import {OverlayContainer} from '@angular/cdk/overlay';
import { Computesite, Health } from './computesite';
...@@ -69,6 +70,31 @@ export class AppComponent { ...@@ -69,6 +70,31 @@ export class AppComponent {
classList.add(theme); classList.add(theme);
} }
countErrors(a: Health[], b: Health[]) {
var count: number = 0
var h: Health;
if (a != null) {
for (h of a) {
if (h.stat == 'error' || h.stat == 'warn') {
count++;
}
if(!isNaN(parseInt(h.stat))) {
count = count + parseInt(h.stat);
}
}
}
if (b != null) {
for (h of b) {
if (h.stat == 'error' || h.stat == 'warn') {
count++;
}
if(!isNaN(parseInt(h.stat))) {
count = count + parseInt(h.stat);
}
}
}
return count;
}
// login() { // login() {
......
...@@ -6,13 +6,14 @@ import { AppComponent } from './app.component'; ...@@ -6,13 +6,14 @@ import { AppComponent } from './app.component';
import { LauncherComponent } from './launcher/launcher.component'; import { LauncherComponent } from './launcher/launcher.component';
import { JoblistComponent } from './joblist/joblist.component'; import { JoblistComponent } from './joblist/joblist.component';
import { MatButtonModule } from '@angular/material'; import { MatButtonModule } from '@angular/material';
import { MatButtonToggleModule} from '@angular/material';
import { MatFormFieldModule } from '@angular/material'; import { MatFormFieldModule } from '@angular/material';
import { MatOptionModule } from '@angular/material'; import { MatOptionModule } from '@angular/material';
import { MatInputModule } from '@angular/material'; import { MatInputModule } from '@angular/material';
import { MatSelectModule } from '@angular/material'; import { MatSelectModule } from '@angular/material';
import { MatListModule} from '@angular/material'; import { MatListModule} from '@angular/material';
import { MatTableModule } from '@angular/material/table'; import { MatTableModule } from '@angular/material/table';
import { MatCardModule } from '@angular/material'; import { MatCardModule, MatTabsModule } from '@angular/material';
import { MatToolbarModule } from '@angular/material'; import { MatToolbarModule } from '@angular/material';
import { MatDialogModule, MatDialog } from '@angular/material'; import { MatDialogModule, MatDialog } from '@angular/material';
import { MatSnackBarModule } from "@angular/material"; import { MatSnackBarModule } from "@angular/material";
...@@ -53,6 +54,7 @@ import {OverlayModule} from '@angular/cdk/overlay'; ...@@ -53,6 +54,7 @@ import {OverlayModule} from '@angular/cdk/overlay';
import { LoginComponent } from './login/login.component'; import { LoginComponent } from './login/login.component';
import { SettingsComponent } from './settings/settings.component'; import { SettingsComponent } from './settings/settings.component';
import { LogoutComponent } from './logout/logout.component'; import { LogoutComponent } from './logout/logout.component';
import { AccountinfoComponent } from './accountinfo/accountinfo.component';
// import { FileExplorerModule } from './file-explorer/file-explorer.module'; // import { FileExplorerModule } from './file-explorer/file-explorer.module';
...@@ -79,10 +81,12 @@ import { LogoutComponent } from './logout/logout.component'; ...@@ -79,10 +81,12 @@ import { LogoutComponent } from './logout/logout.component';
LoginComponent, LoginComponent,
SettingsComponent, SettingsComponent,
LogoutComponent, LogoutComponent,
AccountinfoComponent,
], ],
imports: [ imports: [
BrowserModule, BrowserModule,
MatButtonModule, MatButtonModule,
MatButtonToggleModule,
MatFormFieldModule, MatFormFieldModule,
MatOptionModule, MatOptionModule,
MatInputModule, MatInputModule,
...@@ -90,6 +94,7 @@ import { LogoutComponent } from './logout/logout.component'; ...@@ -90,6 +94,7 @@ import { LogoutComponent } from './logout/logout.component';
MatListModule, MatListModule,
MatTableModule, MatTableModule,
MatCardModule, MatCardModule,
MatTabsModule,
MatToolbarModule, MatToolbarModule,
MatDialogModule, MatDialogModule,
MatProgressSpinnerModule, MatProgressSpinnerModule,
......
...@@ -226,15 +226,12 @@ public getKeys(id?: Identity) { ...@@ -226,15 +226,12 @@ public getKeys(id?: Identity) {
let path=sessionStorage.getItem('path'); let path=sessionStorage.getItem('path');
//skip1 because loggedInAuthZ is a behaviour subject and we don't want the current value but the value //skip1 because loggedInAuthZ is a behaviour subject and we don't want the current value but the value
this.loggedInAuthZ.pipe(skip(1),take(1)).subscribe( () => {this.readyToNavigate.next([true,path])}); this.loggedInAuthZ.pipe(skip(1),take(1)).subscribe( () => {this.readyToNavigate.next([true,path])});
console.log('cert generated, adding keycert to agent');
this.sshAdd(keyCert); this.sshAdd(keyCert);
// only navigate once the agent contents has been refreshed // only navigate once the agent contents has been refreshed
} }
public querySshAgentError(error: any) { public querySshAgentError(error: any) {
this.agentContents.next([]); this.agentContents.next([]);
console.log('querySshAgentError');
console.log(error);
if (error.status == 0) { if (error.status == 0) {
this.statusMsg.next("A network error occured. Are you connected to the internet?") this.statusMsg.next("A network error occured. Are you connected to the internet?")
} }
...@@ -253,7 +250,7 @@ public getKeys(id?: Identity) { ...@@ -253,7 +250,7 @@ public getKeys(id?: Identity) {
var anyvar: any; var anyvar: any;
this.http.get<any>(this.backendURI+'/sshagent',options) this.http.get<any>(this.backendURI+'/sshagent',options)
.pipe(catchError(this.handleError(anyvar))) .pipe(catchError(this.handleError(anyvar)))
.subscribe(resp => { this.agentContents.next(resp); console.log('agent response'); console.log(resp); this.statusMsg.next("") }, .subscribe(resp => { this.agentContents.next(resp); this.statusMsg.next("") },
error => this.querySshAgentError(error)); error => this.querySshAgentError(error));
// .subscribe(resp => this.computeSitesService.updateIdentities(resp), // .subscribe(resp => this.computeSitesService.updateIdentities(resp),
// error => this.httperror(error)) // error => this.httperror(error))
......
...@@ -156,9 +156,6 @@ export class ComputesitesService { ...@@ -156,9 +156,6 @@ export class ComputesitesService {
var appidentities: Identity[] = []; var appidentities: Identity[] = [];
var ftidentities: Identity[] = []; var ftidentities: Identity[] = [];
// If the agent contents is set to null we are probably still updating it // If the agent contents is set to null we are probably still updating it
console.log('updating app identities');
console.log(resp);
console.log(this.authorisationService.agentContents.value)
if (resp == null) { if (resp == null) {
return return
......
:host { /*:host {
height: 100%; height: 100%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
...@@ -8,9 +8,9 @@ ...@@ -8,9 +8,9 @@
-moz-user-select: none; -moz-user-select: none;
-ms-user-select: none; -ms-user-select: none;
user-select: none; user-select: none;
} }*/
.file-or-folder { /*.file-or-folder {
padding: 8px; padding: 8px;
overflow: hidden; overflow: hidden;
} }
...@@ -29,11 +29,9 @@ ...@@ -29,11 +29,9 @@
flex: 1 1 auto; flex: 1 1 auto;
} }
.file-table { .file-table {
/* flex: 1 1 auto; */
height: 400px; height: 400px;
/* width: 100%; */
} }
.basic-container { .basic-container {
height: 400px; height: 400px;
} }*/
...@@ -95,6 +95,22 @@ ...@@ -95,6 +95,22 @@
</ng-container> </ng-container>
<tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr> <tr mat-header-row *matHeaderRowDef="displayedColumns; sticky: true"></tr>
<tr mat-row *matRowDef="let row; columns: displayedColumns;" (click)="navigate(row)"></tr> <tr mat-row *matRowDef="let row; columns: displayedColumns;" (click)="navigate(row)"></tr>
<mat-menu #contextMenu="matMenu" [overlapTrigger]="false">
<ng-template matMenuContent let-element="element">
<!-- <button mat-menu-item [matMenuTriggerFor]="moveToMenu" [matMenuTriggerData]="{self: element}">
<mat-icon>open_with</mat-icon>
<span>Move To</span>
</button> -->
<button mat-menu-item (click)="emitSendFile(element)">
<mat-icon>send</mat-icon>
<span>Send file</span>
</button>
<button mat-menu-item (click)="openNewFolderDialog()">
<mat-icon>send</mat-icon>
<span>New directory</span>
</button>
</ng-template>
</mat-menu>
</table> </table>
...@@ -121,19 +137,3 @@ ...@@ -121,19 +137,3 @@
<!-- </div> --> <!-- </div> -->
<!-- </div> --> <!-- </div> -->
<mat-menu #contextMenu="matMenu" [overlapTrigger]="false">
<ng-template matMenuContent let-element="element">
<!-- <button mat-menu-item [matMenuTriggerFor]="moveToMenu" [matMenuTriggerData]="{self: element}">
<mat-icon>open_with</mat-icon>
<span>Move To</span>
</button> -->
<button mat-menu-item (click)="emitSendFile(element)">
<mat-icon>send</mat-icon>
<span>Send file</span>
</button>
<button mat-menu-item (click)="openNewFolderDialog()">
<mat-icon>send</mat-icon>
<span>New directory</span>
</button>
</ng-template>
</mat-menu>
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
<div> {{ timeremaining }} </div> <div> {{ timeremaining }} </div>
</div> </div>
<div fxFlex></div> <div fxFlex></div>
<div fxFlex="15%" fxLayout="row"> <div fxFlex fxLayout="row">
<div fxFlex *ngIf="!nocancel"> <button mat-button (click)="onCancel()" > Cancel </button> </div> <div fxFlex *ngIf="!nocancel"> <button mat-button (click)="onCancel()" > Cancel </button> </div>
<div *ngFor="let action of jobdata.app.actions"> <div *ngFor="let action of jobdata.app.actions">
<div fxFlex *ngIf="action.states === undefined || action.states === null || action.states.indexOf(jobdata.state) != -1"> <div fxFlex *ngIf="action.states === undefined || action.states === null || action.states.indexOf(jobdata.state) != -1">
......
...@@ -71,9 +71,7 @@ export class JobComponent implements OnInit, OnDestroy { ...@@ -71,9 +71,7 @@ export class JobComponent implements OnInit, OnDestroy {
let end = this.parseDate(this.jobdata.endtime); let end = this.parseDate(this.jobdata.endtime);
let remaining = end.valueOf() - Date.now().valueOf(); let remaining = end.valueOf() - Date.now().valueOf();
this.timeremaining = "Time remaining: "+this.secondsToHms(remaining/1000); this.timeremaining = "Time remaining: "+this.secondsToHms(remaining/1000);
} else { }
console.log('jobdata endtime is undefined');
}
} }
secondsToHms(d: number) { secondsToHms(d: number) {
......
<mat-toolbar color="primary">
<mat-toolbar-row>
<button mat-icon-button ><mat-icon>menu</mat-icon></button>
<span>Strudel v2.0</span>
<span class="fill-horizontal-space"></span>
</mat-toolbar-row>
</mat-toolbar>
<mat-card>
Generating cryptographic tokens ... this should only take a few seconds Generating cryptographic tokens ... this should only take a few seconds
</mat-card>
...@@ -5,10 +5,14 @@ ...@@ -5,10 +5,14 @@
<iframe *ngIf="appconfigurl != null" [src]="batchcmdsafeurl" style="height: 1px; min-height: 0px; border: none" #batchbuilderiframe></iframe>--> <iframe *ngIf="appconfigurl != null" [src]="batchcmdsafeurl" style="height: 1px; min-height: 0px; border: none" #batchbuilderiframe></iframe>-->
<div *ngIf="(appSubject | async ) !== null" style="width: 100%"> <div *ngIf="(appSubject | async ) !== null" style="width: 100%">
<iframe [src]="batchcmdsafeurl" style="border: none; border-style: none; border-width: 0px; width: 100%" [style.height]="height+'px'" #batchbuilderiframe></iframe> <iframe [src]="batchcmdsafeurl" style="border: none; border-style: none; border-width: 0px; width: 100%; overflow: auto" [style.height]="height+'px'" #batchbuilderiframe></iframe>
<!--<div *ngIf="appconfigsafeurl !== null && configtoggle">
<iframe [src]="appconfigsafeurl" style="border: none; border-style: none; border-width: 0px; width: 100%" [style.height]="appconfigheight+'px'" #batchbuilderiframe></iframe>
</div>-->
<div fxLayout="row" fxLayoutAlign="space-around"> <div fxLayout="row" fxLayoutAlign="space-around">
<button mat-flat-button (click)="launch()" color="primary" #launchbtn>Launch</button> <button *ngIf="appconfigsafeurl !== null" mat-flat-button (click)="configdialog()" color="primary">Configure</button>
<button mat-flat-button (click)="launch()" color="primary" #launchbtn [disabled]="!readyToLaunch">Launch</button>
</div> </div>
</div> </div>
</div> </div>
...@@ -3,11 +3,13 @@ import { DomSanitizer} from '@angular/platform-browser'; ...@@ -3,11 +3,13 @@ import { DomSanitizer} from '@angular/platform-browser';
import { Renderer2 } from '@angular/core'; import { Renderer2 } from '@angular/core';
//import { MatDialogRef,MAT_DIALOG_DATA } from '@angular/material'; //import { MatDialogRef,MAT_DIALOG_DATA } from '@angular/material';
import { TesService } from '../tes.service'; import { TesService } from '../tes.service';
import { timer, Subscription} from 'rxjs'; import { Observable, merge, pipe, timer, Subscription} from 'rxjs';
import { BehaviorSubject } from 'rxjs'; import { BehaviorSubject } from 'rxjs';
import { take } from 'rxjs/operators';
import { Identity } from '../identity'; import { Identity } from '../identity';
import { Strudelapp } from '../strudelapp'; import { Strudelapp } from '../strudelapp';
import { BatchInterface} from '../batchinterface'; import { BatchInterface} from '../batchinterface';
import { fromEvent } from 'rxjs';
@Component({ @Component({
...@@ -18,6 +20,7 @@ import { BatchInterface} from '../batchinterface'; ...@@ -18,6 +20,7 @@ import { BatchInterface} from '../batchinterface';
export class LaunchDialogComponent implements OnInit { export class LaunchDialogComponent implements OnInit {
@Input() identity: Identity; @Input() identity: Identity;
@Input() appSubject: BehaviorSubject<Strudelapp>; @Input() appSubject: BehaviorSubject<Strudelapp>;
//@Input() app: Strudelapp;
app: Strudelapp; app: Strudelapp;
batchcmdurl: string; batchcmdurl: string;
appconfigurl: string; appconfigurl: string;
...@@ -30,9 +33,13 @@ export class LaunchDialogComponent implements OnInit { ...@@ -30,9 +33,13 @@ export class LaunchDialogComponent implements OnInit {
subscriptions: Subscription[]; subscriptions: