Commit ef9e0a8a authored by Chris Hines's avatar Chris Hines
Browse files

fix up the account info which wasn't refreshing properly

parent a7280607
Pipeline #7817 passed with stages
in 5 minutes and 29 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>
<div fxLayout=column fxLayoutAlign="space-between" style="width: 100%; height: 100%">
<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>
<div *ngIf="identity$.value !== null && identity$.value !== undefined">
<!--<div *ngIf="identity$.value.systemalerts.value !== null">-->
<mat-list>
<div *ngFor="let h of (identity$.value.systemalerts | async)">
<mat-list-item>
<div *ngIf="h.stat == 'error'">
<div class='health-warn'>
{{ h.msg }}
</div>
</div>
</mat-list-item>
</div>
</mat-list>
<!--</div>-->
<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 *ngIf="((identity$ | async).accountalerts | async) ; else loadingaa">
<mat-list>
<div *ngFor="let h of identity$.value.accountalerts.value">
<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>
</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>
<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>
<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>
</mat-list>
</div>
</ng-template>
<ng-template #loadingaa>
<h2> Loading account info...</h2>
</ng-template>
</div>
</div>
......@@ -2,6 +2,10 @@ import { Component, OnInit, Input } from '@angular/core';
import { Identity } from '../identity';
import { Router, ActivatedRoute, ParamMap } from '@angular/router';
import { TesService } from '../tes.service';
import { BehaviorSubject, Subscription } from 'rxjs';
import { filter } from 'rxjs/operators';
import {Strudelapp} from '../strudelapp';
import {Health} from '../computesite';
@Component({
selector: 'app-accountinfo',
......@@ -9,14 +13,43 @@ import { TesService } from '../tes.service';
styleUrls: ['./accountinfo.component.css']
})
export class AccountinfoComponent implements OnInit {
@Input() identity: Identity;
@Input() identity$: BehaviorSubject<Identity>;
private subscriptions: Subscription[];
private aa: Health[];
private sa: Health[];
@Input() app$: BehaviorSubject<Strudelapp>;
constructor(
private router: Router,
public tesService: TesService,
) { }
) {
this.subscriptions = [];
this.aa = [];
this.sa = [];
}
ngOnInit() {
console.log('account info initialised');
console.log(this.identity$.value);
this.identity$.subscribe((i) => this.updateSubs(i));
}
updateSubs(i: Identity) {
console.log('identity changed, updating subscriptions');
var s: Subscription;
for (s of this.subscriptions) {
console.log('calling unsub');
s.unsubscribe();
}
if (i === null) {
console.log('id is actually null nothing to subscribe');
return
}
console.log(i.accountalerts);
console.log(i.systemalerts);
this.subscriptions.push(i.accountalerts.subscribe((v) => {this.aa = v ; console.log('updated aa'); console.log(i.displayName()); console.log(v);}));
this.subscriptions.push(i.systemalerts.subscribe((v) => {this.sa = v ; console.log('updated sa'); console.log(i.displayName()); console.log(v)}));
}
calculateCols(data) {
......@@ -57,13 +90,4 @@ export class AccountinfoComponent implements OnInit {
}
}
getHealth(o) {
if (o == null) {
return
}
for (let id of o) {
this.tesService.getHealthAlerts(id);
}
}
}
......@@ -10,7 +10,6 @@
<mat-sidenav-container style="height: 100vh; width: 100%">
<!--<mat-sidenav-container>-->
<mat-sidenav closed>
1st sidenav
</mat-sidenav>
<mat-sidenav-content>
<div fxLayout="column" fxLayoutAlign="space-between stretch" style="height: 100%; width: 100%">
......
......@@ -137,16 +137,16 @@ export class ComputesitesService {
return this.computesites.value;
}
private siteMatch(cert: any, cs: Computesite): string {
private siteMatch(cert: any, cs: Computesite): string[] {
var fp: string = (<Computesite>cs).cafingerprint;
if ('Signing CA' in cert) {
for (let ca of cert['Signing CA']) {
if (ca == fp) {
return cert['Principals'][0]
return cert['Principals']
}
}
}
return null;
return [];
}
private updateIdentities(resp) {
......@@ -156,29 +156,31 @@ export class ComputesitesService {
var appidentities: Identity[] = [];
var ftidentities: Identity[] = [];
// If the agent contents is set to null we are probably still updating it
console.log('updateIdentities ... check your subscriptions');
if (resp == null) {
return
}
for (cs of this.computesites.value) {
for (let i in certs) {
let principal = this.siteMatch(certs[i],cs);
if (principal != null) {
let id = new Identity(principal,cs);
identities.push(id);
if (cs.appCatalogUri != null) {
appidentities.push(id);
}
if (cs.dtn != null ) {
ftidentities.push(id);
let principals = this.siteMatch(certs[i],cs);
for (let principal of principals) {
if (principal != null) {
let id = new Identity(principal,cs);
identities.push(id);
if (cs.appCatalogUri != null) {
appidentities.push(id);
}
if (cs.dtn != null ) {
ftidentities.push(id);
}
}
}
}
}
}
this.identities.next(identities);
this.ftidentities.next(ftidentities);
this.appidentities.next(appidentities);
}
}
......@@ -40,7 +40,7 @@
</cdk-virtual-scroll-viewport> -->
<table mat-table [dataSource]="fileElements" style="width: 100%">
<table mat-table [dataSource]="fileElements" style="width: 100%; height: 100%; overflow-y: scroll">
<ng-container matColumnDef="icon">
<th mat-header-cell *matHeaderCellDef></th>
<td mat-cell *matCellDef="let element" (contextmenu)="onContextMenu($event, element)">
......
......@@ -16,8 +16,8 @@ export class Identity {
this.username = username;
this.site = site;
this.keyCerts = [];
this.systemalerts = new BehaviorSubject<Health[]>(null);
this.accountalerts = new BehaviorSubject<Health[]>(null);
this.systemalerts = new BehaviorSubject<Health[]>([]);
this.accountalerts = new BehaviorSubject<Health[]>([]);
this.joblist = new BehaviorSubject<Job[]>([]);
this.quotas = [];
}
......
......@@ -56,17 +56,17 @@
</span>
</a>
</nav>
<div *ngIf="(identitySubject | async) !== null" style="width: 100%" class=darker-theme>
<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',identitySubject.value.site.name,'accountinfo']"
[routerLink]="['/launch',identity$.value.site.name,'accountinfo']"
routerLinkActive #rla="routerLinkActive"
[active]="rla.isActive">
Account Info
</a>
<a mat-tab-link
*ngFor="let app of (identitySubject.value.site.appCatalog | async)"
[routerLink]="['/launch',identitySubject.value.site.name,app.name]"
*ngFor="let app of (identity$.value.site.appCatalog | async)"
[routerLink]="['/launch',identity$.value.site.name,app.name]"
routerLinkActive #rla="routerLinkActive"
[active]="rla.isActive">
{{ app.name }}
......@@ -76,15 +76,15 @@
</div>
<div fxLayout="column" fxLayoutAlign="space-between stretch" style="width: 100%; height: 100%" >
<div *ngIf="identitySubject | async as identity">
<div *ngIf="identity !== undefined && identity !== null && (appSubject | async) === null" style="padding-left: 5%; padding-right: 5%; padding-top: 5%;">
<app-accountinfo [identity]="identity"></app-accountinfo>
<!--<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%;">
<app-accountinfo [identity$]="identity$" [app$]="app$"></app-accountinfo>
</div>
<div *ngIf="identity !== undefined && identity !== null && (appSubject | async) !== undefined && (appSubject | async) !== null" style="padding-left: 5%; padding-right: 5%; padding-top: 5%;">
<app-launch-dialog [identity]="identitySubject | async" [appSubject]="appSubject"></app-launch-dialog>
<app-joblist [identitySubject]="identitySubject" [appSubject]="appSubject"></app-joblist>
<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-joblist [identitySubject]="identity$" [appSubject]="app$"></app-joblist>
</div>
</div>
</div>
</mat-sidenav-content>
......
......@@ -44,10 +44,10 @@ export interface Quota {
export class LauncherComponent implements OnInit {
public strudelapps: Strudelapp[];
public appSubject: BehaviorSubject<Strudelapp>;
public app$: BehaviorSubject<Strudelapp>;
public authorised: boolean;
public identity: Identity;
public identitySubject: BehaviorSubject<Identity>;
public identity$: BehaviorSubject<Identity>;
public identities: Identity[];
public sshauthzservers: SshAuthzServer[];
......@@ -56,8 +56,6 @@ export class LauncherComponent implements OnInit {
private subscriptions: Subscription[];
//public quotas: BehaviorSubject<any[]>;
displayedColumns: string[] = [];
private identity$: Observable<Identity>;
private app$: Observable<Strudelapp>;
private app: Strudelapp;
......@@ -75,8 +73,8 @@ export class LauncherComponent implements OnInit {
this.subscriptions.push(this.authService.sshAuthzServers.subscribe(o => {this.updateSshAuthZServers(o)}));
this.subscriptions.push(this.authService.loggedInAuthZ.subscribe(o => this.navLogin(o)));
this.subscriptions.push(this.computeSitesService.appidentities.subscribe(o => this.getHealth(o)));
this.appSubject = new BehaviorSubject<Strudelapp>(null);
this.identitySubject = new BehaviorSubject<Identity>(null);
this.app$ = new BehaviorSubject<Strudelapp>(null);
this.identity$ = new BehaviorSubject<Identity>(null);
this.identity = null;
//this.quotas = new BehaviorSubject<any[]>([]);
}
......@@ -149,6 +147,7 @@ export class LauncherComponent implements OnInit {
if (o == null) {
return
}
this.tesService.cancelHealthRequests();
for (let id of o) {
this.tesService.getHealthAlerts(id);
}
......@@ -160,25 +159,29 @@ export class LauncherComponent implements OnInit {
ngOnInit() {
this.strudelapps = [];
/*this.identity$ = this.route.paramMap.pipe(
switchMap((params: ParamMap) => this.getId(params.get('site')))
);*/
this.route.paramMap.subscribe((params: ParamMap) => this.updateIdApp(params));
/*this.app$ = this.route.paramMap.pipe(
switchMap((params: ParamMap) => this.getApp(params.get('app')))
);
this.identity$.subscribe((v) => {console.log('id changed'); console.log(v)});
this.identity$.subscribe((v) => this.identity = v);
this.app$.subscribe((v) => { console.log('app changed'); console.log(v)});*/
//this.site$.subscribe ( (v) => { this.getId(v) });
//this.app$.subscribe( (v) => { this.getApp(v) });
// if the conents of the ssh agent changes we will get a whole new set of identity objects. In that case we must update out id subject
this.computeSitesService.appidentities.pipe(filter((v) => v !== null)).subscribe( () => this.refreshId());
}
refreshId() {
var ids: string;
var id: Identity;
if (this.identity$ !== null) {
ids = this.identity$.value.site.name;
} else {
return
}
id = this.getId(ids);
this.identity$.next(id);
}
updateIdApp(params: ParamMap) {
var ids: string = params.get('site');
var apps: string = params.get('app');
if (ids === null) {
this.identitySubject.next(null);
this.identity$.next(null);
return;
}
var id: Identity = this.getId(ids);
......@@ -187,22 +190,20 @@ export class LauncherComponent implements OnInit {
this.computeSitesService.appidentities.pipe(skip(1),filter((v) => v !== null && v.length > 0),take(1)).subscribe(() => this.updateIdApp(params));
return
}
if (id !== this.identitySubject.value) {
this.identitySubject.next(id);
if (id !== this.identity$.value) {
this.identity$.next(id);
}
if (apps === null) {
apps = 'acocuntinfo';
//this.appSubject.next(null);
//return;
}
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));
return
}
var app: Strudelapp = this.getApp(id,apps);
if (app !== this.appSubject.value) {
this.appSubject.next(app);
if (app !== this.app$.value) {
this.app$.next(app);
}}
getApp(id,v: any): Strudelapp {
......@@ -242,21 +243,13 @@ export class LauncherComponent implements OnInit {
}
selectId(id: Identity) {
this.identitySubject.next(id);
this.identity$.next(id);
this.identity = id;
this.appSubject.next(null);
//if (id != null) {
// We will subscribe to account alerts until the id changes (in which case we will subscribe to account alerts
// on the next id
// BUT
// since identitySubject is a behaviorsubject and already has a value, we must skip(1)
// id.accountalerts.pipe(takeUntil(this.identitySubject.pipe(skip(1)))).subscribe((msgs) => { this.quotas.next(msgs.filter(q => q.type =='quota')) });
//}
this.app$.next(null);
}
selectApp(app: Strudelapp) {
this.appSubject.next(app);
this.app$.next(app);
}
......
import { Injectable } from '@angular/core';
import { Injectable, EventEmitter } from '@angular/core';
import { HttpClientModule, HttpClient, HttpHeaders, HttpErrorResponse } from '@angular/common/http';
import { Observable, Subject, BehaviorSubject, of, from } from 'rxjs';
import { fromEvent, throwError, Subscription } from 'rxjs';
import { catchError, map, tap } from 'rxjs/operators';
import { fromEvent, throwError, Subscription, merge } from 'rxjs';
import { catchError, map, tap, filter } from 'rxjs/operators';
import { Job } from './job';
import { AppAction, Strudelapp, StrudelappInstance } from './strudelapp';
import { Computesite, Health } from './computesite';
......@@ -49,7 +49,7 @@ private updateJobSub: Subscription;
private updateUserHealthSub: Subscription;
private cachetincidents: BehaviorSubject<Health[]>;
private nextUpdate: Subscription;
private cancelRequests: Subject<string>;
private cancelRequests$: Subject<boolean>;
public identitySubject: BehaviorSubject<Identity>;
public appSubject: BehaviorSubject<Strudelapp>;
private openapps: any[];
......@@ -70,7 +70,7 @@ private openapps: any[];
//this.userhealth = new BehaviorSubject<Health[]>([{'stat':'ok','msg':''}])
this.apiserver = new BehaviorSubject<APIServer>(null);
this.apiservers = new BehaviorSubject<APIServer[]>([]);
this.cancelRequests = new Subject<string>();
this.cancelRequests$ = new Subject<boolean>();
this.openapps = [];
//this.identitySubject = new BehaviorSubject<Identity>(null);
//this.appSubject = new BehaviorSubject<Strudelapp>(null);
......@@ -185,7 +185,7 @@ public setStatusMsg(statusMsg: BehaviorSubject<any>) {
public cancelHealthRequests() {
this.cancelRequests.next('cancel');
this.cancelRequests$.next(true);
}
private getUserHealthError(error: any, identity: Identity) {
......@@ -249,14 +249,13 @@ getUserHealth(identity: Identity) {
params.set('username',JSON.stringify(identity.username));
this.updateUserHealthSub = this.http.get<Health[]>(this.Base+'/stat'+'?'+params.toString(),options)
.pipe(takeUntil(this.cancelRequests))
.pipe(takeUntil(this.cancelRequests$))
.subscribe(resp => this.addUserHealth(identity,resp), error => this.getUserHealthError(error,identity));
}
getHealthAlerts(identity: Identity) {
console.log('execute getHealthAlerts');
identity.accountalerts.next(null);
identity.systemalerts.next(null);
//identity.accountalerts.next(null);
//identity.systemalerts.next([]);
this.getCachetIncidents(identity);
this.getUserHealth(identity);
}
......@@ -273,16 +272,18 @@ getCachetIncidents(identity: Identity) {
}
for (let uri of identity.site.cacheturis) {
this.http.get(uri,options)
.pipe(takeUntil(this.cancelRequests))
.pipe(takeUntil(this.cancelRequests$))
.subscribe(resp => this.addCachetIncidents(identity,resp), error => this.getCachetIncidentsError(error,identity));
}
}
addCachetIncidents(identity,resp) {
let ci = identity.systemalerts.value;
console.log('got an sa response');
/*let ci = identity.systemalerts.value;
if (ci == null) {
ci = []
}
}*/
let ci = [];
for (let i of resp.data) {
if (i.status == 3 || i.status == 4) {
continue;
......@@ -293,13 +294,17 @@ addCachetIncidents(identity,resp) {
ci.push(h);
}
identity.systemalerts.next(ci);
console.log('update system alerts for ',identity.displayName());
console.log(identity.systemalerts.value);
console.log(identity.systemalerts);
}
addUserHealth(identity,resp) {
let ci = identity.accountalerts.value;
/*let ci = identity.accountalerts.value;
if (ci == null) {
ci = []
}
}*/
let ci = []
for (let i of resp) {
let h = new Health();
h.stat = i.stat;
......@@ -313,7 +318,10 @@ addUserHealth(identity,resp) {
}
ci.push(h);
}
console.log('update account alerts for ',identity.displayName());
identity.accountalerts.next(ci);
console.log(identity.accountalerts.value);
console.log(identity.accountalerts);
}
......
<!-- <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="column" fxLayoutAlign="space-around stretch" style="height: 100%; width: 100%" >
<div fxLayout="column" fxLayoutAlign="flex-start stretch" style="height: 100%; width: 100%" >
<div fxLayout="row" fxLayout="space-between stretch" fxLayoutGap="1%" style="height: 90%">
<!-- <div fxFlex *ngFor="let idx of [0,1]" style="height: 100%; overflow-y: auto"> -->
<div fxFlex *ngFor="let idx of [0,1]" style="height: 100%">
<!-- <div style="height: 800px; background-color: #00ffff; overflow-y: scroll"></div> -->
<div fxLayout="column" fxLayoutAlign="space-around stretch" style="width: 100%" >
<mat-form-field>
<mat-select (selectionChange)="setId(idx,$event)" placeholder="Choose a server">
<mat-option *ngFor="let s of computesitesService.ftidentities | async" [value]="s">
{{ s.username }}@{{s.site.name }}
</mat-option>
</mat-select>
</mat-form-field>
<span class="mat-body"> {{ path[idx] }}</span>
<div *ngIf="working[idx] | async">
<mat-spinner></mat-spinner>
</div>
<!--<div *ngIf="!(working[idx] | async)" style="height: 100%; overflow-y: auto">-->
<div *ngIf="!(working[idx] | async)" style="table-layout: fixed; overflow-y: auto; display: table">
<div fxFlex style="overflow: auto">
<file-explorer [fileElements]="fileElements[idx] | async"
[path]="pathSubject[idx] | async"
(navigatedDown)="navigateToFolder(idx,$event)"
(navigatedUp)="navigateUp(idx,$event)"
[canNavigateUp]="canNavigateUp[idx] | async"
(sendFile)="queueFile(idx,$event)"
(folderAdded)="newDirectory(idx,$event)">
</file-explorer>
</div>
</div>
</div>
</div>
<!--<div fxLayout="row" fxLayout="space-around stretch" fxLayoutGap="1%" style="height: 90%">-->
<!--<div fxLayout="row" fxLayout="space-around stretch" fxLayoutGap="1%" style="height: 90%">-->
<div fxLayout="row" fxLayout="space-around stretch" fxLayoutGap="1%" style="height: 75%">
- <div fxFlex *ngFor="let idx of [0,1]" style="height: 100%;">
<!-- <div *ngFor="let idx of [0,1]" style="height: 100% " fxFlex>-->
<!--<div fxLayout="column" fxLayoutAlign="none stretch" style="width: 100%; height: 100%" >-->
<!--<div style="width: 100%; height: 100%" >-->
<mat-form-field style="width:100%">
<mat-select (selectionChange)="setId(idx,$event)" placeholder="Choose a server">
<mat-option *ngFor="let s of computesitesService.ftidentities | async" [value]="s">
{{ s.username }}@{{s.site.name }}
</mat-option>
</mat-select>
</mat-form-field>
<span class="mat-body"> {{ path[idx] }}</span>
<div *ngIf="working[idx] | async">
<mat-spinner></mat-spinner>
<