Commit 1dbee646 authored by Chris Hines's avatar Chris Hines
Browse files

new layout plus working on cloudcmd as an app

parent b5d82c9b
Pipeline #7902 passed with stages
in 4 minutes and 37 seconds
...@@ -12,11 +12,11 @@ ...@@ -12,11 +12,11 @@
<mat-sidenav closed> <mat-sidenav closed>
</mat-sidenav> </mat-sidenav>
<mat-sidenav-content> <mat-sidenav-content>
<div fxLayout="column" fxLayoutAlign="space-between stretch" style="height: 100%; width: 100%"> <div fxLayout="column" fxLayoutAlign="none" style="height: 100%; width: 100%">
<mat-toolbar color="primary"> <mat-toolbar color="primary">
<div fxLayout="row" style="width: 100%"> <div fxLayout="row" style="width: 100%">
<mat-toolbar-row style="width: 100%"> <mat-toolbar-row style="width: 100%">
<button mat-icon-button aria-label="toggle menu" (click)=toggleMenu()><mat-icon>menu</mat-icon></button> <button mat-icon-button *ngIf="settingsService.useMenu$ | async" aria-label="toggle menu" (click)=toggleMenu()><mat-icon>menu</mat-icon></button>
<img src="assets/MASSIVElogoTransparent128x128.png" style="width: auto; height: 90%"> <img src="assets/MASSIVElogoTransparent128x128.png" style="width: auto; height: 90%">
<span>Strudel2</span> <span>Strudel2</span>
<span fxFlex></span> <span fxFlex></span>
...@@ -31,11 +31,35 @@ ...@@ -31,11 +31,35 @@
</div> </div>
<button mat-menu-item routerLink="/settings"><mat-icon>settings</mat-icon>Settings</button> <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> <button *ngIf="(authService.loggedOutAuthZ | async).length > 0" mat-menu-item routerLink="/login"><mat-icon>exit_to_app</mat-icon>More services</button>
<div *ngFor="let id of (computeSitesService.appidentities | async)">
<button mat-button fxFlex
[routerLink]="['/launch',id.displayName()]"
routerLinkActive #rla="routerLinkActive"
[disabled]="rla.isActive"
[routerLinkActiveOptions]="{'exact': false}"
style="text-align: left"
>
<mat-icon></mat-icon>
<span
matBadge="{{ countErrors((id.systemalerts | async), (id.accountalerts | async)) }}"
[matBadgeHidden]= "countErrors((id.systemalerts | async), (id.accountalerts | async)) == 0"
matBadgePosition="above before"
matBadgeColor="warn"
matBadgeOverlap="false" matBadgeSize="small"
style="text-align: left; margin-left: 15px; margin-top: 10px">
<!--<span>-->
{{ id.displayName() }}
</span>
</button>
</div>
</mat-menu> </mat-menu>
</mat-toolbar-row> </mat-toolbar-row>
</div> </div>
</mat-toolbar> </mat-toolbar>
<div style="height: 100%"> <div>
<router-outlet></router-outlet> <router-outlet></router-outlet>
</div> </div>
</div> </div>
......
...@@ -27,7 +27,7 @@ export class AppComponent { ...@@ -27,7 +27,7 @@ export class AppComponent {
constructor(private tesService: TesService, constructor(private tesService: TesService,
private authService: AuthorisationService, private authService: AuthorisationService,
private computesitesService: ComputesitesService, private computeSitesService: ComputesitesService,
private settingsService: SettingsService, private settingsService: SettingsService,
public snackBar: MatSnackBar) { public snackBar: MatSnackBar) {
...@@ -38,7 +38,7 @@ export class AppComponent { ...@@ -38,7 +38,7 @@ export class AppComponent {
// this.testingAuth = false; // this.testingAuth = false;
this.statusMsg = new BehaviorSubject<any>(''); this.statusMsg = new BehaviorSubject<any>('');
this.tesService.setStatusMsg(this.statusMsg); this.tesService.setStatusMsg(this.statusMsg);
this.computesitesService.setStatusMsg(this.statusMsg); this.computeSitesService.setStatusMsg(this.statusMsg);
this.authService.setStatusMsg(this.statusMsg); this.authService.setStatusMsg(this.statusMsg);
this.statusMsg.subscribe(msg => this.displayMessage(msg)); this.statusMsg.subscribe(msg => this.displayMessage(msg));
this.settingsService.theme$.subscribe((v) => this.setTheme(v)) this.settingsService.theme$.subscribe((v) => this.setTheme(v))
......
...@@ -14,6 +14,6 @@ export class Job { ...@@ -14,6 +14,6 @@ export class Job {
public batch_host: string; public batch_host: string;
public identity: Identity; public identity: Identity;
public app: Strudelapp; public app: Strudelapp;
public appinst: string; public appinst: any;
public connectionState: number; public connectionState: number;
} }
<!--<div fxFlex style="flex: 1 1 0%; box-sizing: border-box">--> <!--<div fxFlex style="flex: 1 1 0%; box-sizing: border-box">-->
<mat-sidenav-container style="height: 100%" autosize> <div fxLayout="column" fxLayoutAlign="none" style="height: 100%">
<mat-sidenav #idSideNav mode="side" [opened]="(settingsService.menuToggle$ | async) && (settingsService.useMenu$ | async)"> <div *ngIf="!(settingsService.useMenu$ | async)">
<div fxLayout="column" fxLayout="stretch" style="height: 100%"> <mat-divider></mat-divider>
<nav> <div *ngIf="(identity$ | async) !== null" style="width: 100%">
<mat-accordion style="width: 100%" [displayMode]="flat"> <nav mat-tab-nav-bar color=accent backgroundColor=primary>
<div *ngFor="let id of (computeSitesService.appidentities | async)"> <a mat-tab-link
<!--<mat-expansion-panel (afterExpand)="selectId(id)" (closed)="selectId(id)" style="width: 100%">--> [routerLink]="['/launch',identity$.value.displayName(),'accountinfo']"
<mat-expansion-panel style="width: 100%" [expanded]="(identity$ | async) === id"> routerLinkActive #rla="routerLinkActive"
<mat-expansion-panel-header> [active]="rla.isActive">
<mat-panel-title> Account Info
<span fxFlex matBadge="{{ countErrors((id.systemalerts | async), (id.accountalerts | async)) }}" </a>
[matBadgeHidden]= "countErrors((id.systemalerts | async), (id.accountalerts | async)) == 0" <a mat-tab-link
matBadgePosition="above before" *ngFor="let app of (identity$.value.site.appCatalog | async)"
matBadgeColor="warn" [routerLink]="['/launch',identity$.value.displayName(),app.name]"
matBadgeOverlap="false" matBadgeSize="small" routerLinkActive #rla="routerLinkActive"
style="text-align: left; margin-left: 20px; margin-top: 10px" > [active]="rla.isActive">
{{ id.displayName() }} {{ app.name }}
</span> </a>
</mat-panel-title> </nav>
</mat-expansion-panel-header> </div>
<mat-list style="width: 100%">
<mat-list-item>
<button mat-button style="width: 100%; text-align: left"
[routerLink]="['/launch',id.displayName(),'accountinfo']"
routerLinkActive #rla="routerLinkActive">
Account Info
</button>
</mat-list-item>
<app-strudelapplist [applist]=id.site.appCatalog [identity]="id" (appChange)="selectApp($event)" style="width: 100%"></app-strudelapplist>
</mat-list>
</mat-expansion-panel>
</div>
</mat-accordion>
</nav>
</div> </div>
<div fxFlex></div>
</mat-sidenav>
<mat-sidenav-content style="height: 100%">
<div *ngIf="!(settingsService.useMenu$ | async)" class=darker-theme>
<nav mat-tab-nav-bar color="accent" backgroundColor="primary">
<a mat-tab-link
*ngFor="let id of (computeSitesService.appidentities | async)"
[routerLink]="['/launch',id.displayName()]"
routerLinkActive #rla="routerLinkActive"
[routerLinkActiveOptions]="{'exact': false}"
[active]="rla.isActive">
<span fxFlex matBadge="{{ countErrors((id.systemalerts | async), (id.accountalerts | async)) }}"
[matBadgeHidden]= "countErrors((id.systemalerts | async), (id.accountalerts | async)) == 0"
matBadgePosition="above before"
matBadgeColor="warn"
matBadgeOverlap="false" matBadgeSize="small"
style="text-align: left; margin-left: 20px; margin-top: 10px" >
{{ id.displayName() }}
</span>
</a>
</nav>
<div *ngIf="(identity$ | async) !== null" style="width: 100%" class=darker-theme>
<nav mat-tab-nav-bar color=accent backgroundColor=primary>
<a mat-tab-link
[routerLink]="['/launch',identity$.value.displayName(),'accountinfo']"
routerLinkActive #rla="routerLinkActive"
[active]="rla.isActive">
Account Info
</a>
<a mat-tab-link
*ngFor="let app of (identity$.value.site.appCatalog | async)"
[routerLink]="['/launch',identity$.value.displayName(),app.name]"
routerLinkActive #rla="routerLinkActive"
[active]="rla.isActive">
{{ app.name }}
</a>
</nav>
</div>
</div>
<div fxLayout="column" fxLayoutAlign="space-between stretch" style="width: 100%; height: 100%" >
<!--<div *ngIf="identitySubject.value !== undefined && identitySubject.value !== null && appSubject.value === null" style="padding-left: 5%; padding-right: 5%; padding-top: 5%;">--> <!--<div *ngIf="identitySubject.value !== undefined && identitySubject.value !== null && appSubject.value === null" style="padding-left: 5%; padding-right: 5%; padding-top: 5%;">-->
<div *ngIf="(app$ | async) == null" style="padding-left: 5%; padding-right: 5%; padding-top: 5%;"> <div *ngIf="(app$ | async) == null" style="padding-left: 5%; padding-right: 5%; padding-top: 5%; overflow-y: scroll">
<app-accountinfo [identity$]="identity$" [app$]="app$"></app-accountinfo> <app-accountinfo [identity$]="identity$" [app$]="app$"></app-accountinfo>
</div> </div>
<div *ngIf="identity$.value !== undefined && identity$.value !== null && app$.value !== undefined && app$.value !== null" style="padding-left: 5%; padding-right: 5%; padding-top: 5%;"> <div *ngIf="identity$.value !== undefined && identity$.value !== null && app$.value !== undefined && app$.value !== null" style="padding-left: 5%; padding-right: 5%; padding-top: 5%;">
<app-launch-dialog [identity]="identity$ | async" [appSubject]="app$"></app-launch-dialog> <app-launch-dialog [identity]="identity$ | async" [appSubject]="app$"></app-launch-dialog>
<app-joblist [identitySubject]="identity$" [appSubject]="app$"></app-joblist> <div style="height: 5%"></div>
<mat-divider ></mat-divider>
<div style="overflow-y: scroll">
<app-joblist [identitySubject]="identity$" [appSubject]="app$"></app-joblist>
</div>
</div> </div>
</div> </div>
</mat-sidenav-content>
</mat-sidenav-container>
...@@ -168,7 +168,7 @@ export class LauncherComponent implements OnInit { ...@@ -168,7 +168,7 @@ export class LauncherComponent implements OnInit {
refreshId() { refreshId() {
var ids: string; var ids: string;
var id: Identity; var id: Identity;
if (this.identity$ !== null) { if (this.identity$.value !== null) {
ids = this.identity$.value.site.name; ids = this.identity$.value.site.name;
} else { } else {
return return
...@@ -195,7 +195,7 @@ export class LauncherComponent implements OnInit { ...@@ -195,7 +195,7 @@ export class LauncherComponent implements OnInit {
} }
if (apps === null) { if (apps === null) {
apps = 'acocuntinfo'; apps = 'accountinfo';
} }
if (id.site.appCatalog.value === undefined || id.site.appCatalog.value === null || (id.site.appCatalog.value).length == 0) { if (id.site.appCatalog.value === undefined || id.site.appCatalog.value === null || (id.site.appCatalog.value).length == 0) {
id.site.appCatalog.pipe(filter((v) => v !== null && v.length > 0)).subscribe(() => this.updateIdApp(params)); id.site.appCatalog.pipe(filter((v) => v !== null && v.length > 0)).subscribe(() => this.updateIdApp(params));
...@@ -220,13 +220,23 @@ export class LauncherComponent implements OnInit { ...@@ -220,13 +220,23 @@ export class LauncherComponent implements OnInit {
} }
if (this.computeSitesService.appidentities.value === null || this.computeSitesService.appidentities.value == []) { if (this.computeSitesService.appidentities.value === null || this.computeSitesService.appidentities.value == []) {
console.error('no appidentities yet? call back latter'); console.error('no appidentities yet? call back latter');
this.computeSitesService.appidentities.pipe(filter((v) => v !== null)).subscribe(() => this.getId(v)); //this.computeSitesService.appidentities.pipe(filter((v) => v !== null)).subscribe(() => this.getId(v));
return null return null
} }
for ( let id of this.computeSitesService.appidentities.value) { for ( let id of this.computeSitesService.appidentities.value) {
if (v == id.displayName()) { if (v == id.displayName()) {
return id return id
} else {
console.log(v,'is not the same as ',id.displayName());
}
}
for ( let id of this.computeSitesService.appidentities.value) {
if (v == id.site.name) {
return id
} else {
console.log(v,'is not the same as ',id.displayName());
} }
} }
...@@ -242,6 +252,8 @@ export class LauncherComponent implements OnInit { ...@@ -242,6 +252,8 @@ export class LauncherComponent implements OnInit {
for ( let id of this.computeSitesService.appidentities.value) { for ( let id of this.computeSitesService.appidentities.value) {
if (sitename == id.site.name) { if (sitename == id.site.name) {
return id return id
} else {
console.log('sitename',sitename,'is not the same as ',id.site.name);
} }
} }
......
...@@ -12,7 +12,7 @@ export class SettingsService { ...@@ -12,7 +12,7 @@ export class SettingsService {
constructor() { constructor() {
this.menuToggle$ = new BehaviorSubject<boolean>(true); this.menuToggle$ = new BehaviorSubject<boolean>(true);
this.theme$ = new BehaviorSubject<string>('strudel-theme-light'); this.theme$ = new BehaviorSubject<string>('strudel-theme-light');
this.useMenu$ = new BehaviorSubject<boolean>(true); this.useMenu$ = new BehaviorSubject<boolean>(false);
this.getTheme(); this.getTheme();
} }
......
export class AppAction { export class AppAction {
name: string; name: string;
paramscmd: string; paramscmd: string;
client: {cmd: string[], redir: string}; client: {cmd: string[], redir: string, usebasicauth: boolean};
states: string[]; // list of stats such as 'RUNNING' in which the action is valid. null||undefined if its always valid states: string[]; // list of stats such as 'RUNNING' in which the action is valid. null||undefined if its always valid
} }
export class Strudelapp { export class Strudelapp {
......
...@@ -440,7 +440,7 @@ addUserHealth(identity,resp) { ...@@ -440,7 +440,7 @@ addUserHealth(identity,resp) {
//params.set('cmd',JSON.stringify(action.paramscmd)); //params.set('cmd',JSON.stringify(action.paramscmd));
let paramstr = params.toString(); let paramstr = params.toString();
this.http.post<string>(this.Base+'/createtunnel/'+username+'/'+loginhost+'/'+batchhost+'?'+paramstr, job.appinst, options) this.http.post<string>(this.Base+'/createtunnel/'+username+'/'+loginhost+'/'+batchhost+'?'+paramstr, job.appinst, options)
.subscribe(() => { this.getAppUrl(job, action) } ) .subscribe(() => { this.getAppUrl(job, action) }, error => {this.handleTunnelError(job,error)} )
} }
public getAppUrl(job: Job, action: AppAction) { public getAppUrl(job: Job, action: AppAction) {
...@@ -454,7 +454,7 @@ addUserHealth(identity,resp) { ...@@ -454,7 +454,7 @@ addUserHealth(identity,resp) {
job.connectionState = 3; job.connectionState = 3;
this.http.get<string>(this.Base+'/appurl?'+paramstr,options) this.http.get<string>(this.Base+'/appurl?'+paramstr,options)
.pipe(catchError(this.handleError)) .pipe(catchError(this.handleError))
.subscribe(resp => { job.connectionState = 0; this.openAppWindow(resp,job)}); .subscribe(resp => { job.connectionState = 0; this.openAppWindow(resp,job,action)});
} }
...@@ -463,10 +463,23 @@ addUserHealth(identity,resp) { ...@@ -463,10 +463,23 @@ addUserHealth(identity,resp) {
this.getAppInstance(job, action); this.getAppInstance(job, action);
} }
public openAppWindow(url: any, job: Job) { public openAppWindow(url: any, job: Job, action: AppAction) {
var re = /^https:\/\/([a-z0-9\.-]+)\/?/; var re = /^https:\/\/([a-z0-9\.-]+)\/?/;
let twshost = this.twsproxy.replace(re,"$1"); let twshost = this.twsproxy.replace(re,"$1");
console.log('in openappwindow url is ',url);
let windowloc = url.replace(/\{twsproxy\}/g,this.twsproxy).replace(/twshost/g,twshost); let windowloc = url.replace(/\{twsproxy\}/g,this.twsproxy).replace(/twshost/g,twshost);
console.log('window loc is',windowloc);
let user='chines';
let pass='pass';
var authwindow = null;
if (action.client.usebasicauth) {
let authwindowloc = windowloc.replace(/^https:\/\//,'https://'+job.appinst.username+':'+job.appinst.password+'@');
console.log('authwindowloc is',authwindowloc);
console.log(job.appinst);
authwindow = window.open(authwindowloc);
//windowloc = authwindowloc;
}
let appwindow = window.open(windowloc); let appwindow = window.open(windowloc);
if (appwindow == null) { if (appwindow == null) {
...@@ -477,6 +490,9 @@ addUserHealth(identity,resp) { ...@@ -477,6 +490,9 @@ addUserHealth(identity,resp) {
return return
} }
this.openapps.push({'window':appwindow,'job':job}) this.openapps.push({'window':appwindow,'job':job})
if (authwindow !== null) {
authwindow.close();
}
} }
...@@ -549,6 +565,16 @@ private httperror(errorstr: string) { ...@@ -549,6 +565,16 @@ private httperror(errorstr: string) {
// } // }
private handleTunnelError(job: Job, error: any) {
job.connectionState=0;
if (error.stats == 500) {
this.statusMsg.next(error.error.message);
return;
}
this.statusMsg.next('Failed to create a tunnel. Please try again');
return;
}
private handleAppInstanceError(job: Job, error: any) { private handleAppInstanceError(job: Job, error: any) {
console.log(error); console.log(error);
job.connectionState=0; job.connectionState=0;
......
...@@ -147,5 +147,37 @@ ...@@ -147,5 +147,37 @@
"client": {"cmd": null, "redir": null }, "client": {"cmd": null, "redir": null },
"localbind": true, "localbind": true,
"applist": null "applist": null
},
{ "url": null,
"name": "File Explorer",
"startscript": "#!/bin/bash\n/usr/local/sv2/cloudcmd/start.sh\n ",
"actions": [
{
"name": "Connect",
"paramscmd": "/usr/local/sv2/dev/cloudcmd/params.py {jobid}",
"client": {"cmd": null, "redir": "", "usebasicauth": true },
"states": ["RUNNING"]
},
{
"name": "View log",
"paramscmd": "/usr/local/sv2/dev/desktop/logparams.py {jobid}",
"client": {"cmd": null, "redir": "index.html?token={token}" },
"states": ["RUNNING","Finished"]
},
{
"name": "View Usage",
"paramscmd": "/usr/local/sv2/dev/desktop/usageparams.py {jobid}",
"client": {"cmd": null, "redir": "index.html?token={token}" },
"states": ["Finished"]
},
{
"name": "Remove log",
"paramscmd": "/usr/local/sv2/dev/rmlog.py {jobid}",
"client": null,
"states": ["Finished"]
}
],
"localbind": true,
"applist": null
} }
] ]
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment