From cf4e5552d5d7b2f2a1e671390563e19a96394b43 Mon Sep 17 00:00:00 2001
From: Chris Hines <chris.hines@monash.edu>
Date: Thu, 21 Jan 2021 16:43:33 +1100
Subject: [PATCH] if stat fails, display the error instead of immediately
 refreshing
 https://gitlab.erc.monash.edu.au/hpc-team/strudelv2_spa/-/issues/156

---
 .vscode/launch.json                      | 15 +++++++++++++++
 src/app/computesite.ts                   | 14 +-------------
 src/app/computesites.service.ts          | 20 +++++++++++---------
 src/app/identity.ts                      |  4 ++++
 src/app/joblist/joblist.component.ts     |  2 +-
 src/app/jobs.service.ts                  |  8 +++++---
 src/app/launcher/launcher.component.html |  2 +-
 src/app/launcher/launcher.component.ts   |  6 +++---
 src/app/tes.service.ts                   |  1 -
 src/assets/config/m3apps.test.json       |  2 +-
 10 files changed, 42 insertions(+), 32 deletions(-)
 create mode 100644 .vscode/launch.json

diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..7a9dfa0
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,15 @@
+{
+    // Use IntelliSense to learn about possible attributes.
+    // Hover to view descriptions of existing attributes.
+    // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
+    "version": "0.2.0",
+    "configurations": [
+        {
+            "type": "pwa-chrome",
+            "request": "launch",
+            "name": "Launch Chrome against localhost",
+            "url": "http://localhost:8080",
+            "webRoot": "${workspaceFolder}"
+        }
+    ]
+}
\ No newline at end of file
diff --git a/src/app/computesite.ts b/src/app/computesite.ts
index aa2715f..1ad0c3d 100644
--- a/src/app/computesite.ts
+++ b/src/app/computesite.ts
@@ -12,7 +12,7 @@ export class Computesite {
   cafingerprint: string;  // Certificates contain a CA fingerprint. We use this
                           // to figure out which compute site a certificate is valid
                           // for
-  appCatalog: BehaviorSubject<Strudelapp[]>;
+  
   appCatalogUri: string;
   appCatalogCmd: string;
   internalfirewall: boolean; // Does a firewall exist within the site necessitating an extra level of ssh tunnel
@@ -23,18 +23,6 @@ export class Computesite {
   contact: string;
 }
 
-export class Strudelapp {
-  url: string; // A url used to retrieve extra config options. May be null
-  name: string; // Human readable name
-  startscript: string; // batch script ... should NOT include resource directives
-                       // resource directives like #SBATCH belong in the batchinterface
-  paramscmd: string;  // command to return extra data such as passwords and tokens
-                      // values returned here can be used in the client strings
-  client: {cmd: string[], redir: string};
-  localbind: boolean; // does the application bind to a port on the localhost
-                      // interface or on all interfaces. This behaviour determins
-                      /// how we create tunnels
-}
 
 export class Health {
   stat: string;
diff --git a/src/app/computesites.service.ts b/src/app/computesites.service.ts
index 42b0499..8ef1ab9 100644
--- a/src/app/computesites.service.ts
+++ b/src/app/computesites.service.ts
@@ -1,5 +1,6 @@
 import { Injectable } from '@angular/core';
-import { Computesite, Strudelapp } from './computesite';
+import { Computesite } from './computesite';
+import { Strudelapp } from './strudelapp';
 import {BehaviorSubject, of, combineLatest} from 'rxjs';
 import { HttpClientModule, HttpClient, HttpHeaders, HttpErrorResponse } from '@angular/common/http';
 import { Observable } from 'rxjs';
@@ -46,7 +47,7 @@ export class ComputesitesService {
       let options = { headers: headers, withCredentials: false};
       if (s.appCatalogUri !== null) {
         this.http.get<Strudelapp[]>(s.appCatalogUri,options)
-                         .pipe(catchError(this.handleError('getStrudelApps')))
+                         .pipe(catchError(this.handleError('  s')))
                          .subscribe(resp => this.updateStrudelApps(s,resp));
       }
     }
@@ -64,7 +65,7 @@ export class ComputesitesService {
     if (ids != undefined && ids != null) {
       for (let id of ids) {
         this.getStrudelAppsIdentity(id)
-                           .subscribe(resp => this.updateStrudelApps(id.site,resp));
+                           .subscribe(resp => this.updateStrudelApps(id,resp));
       }
     }
   }
@@ -81,9 +82,12 @@ export class ComputesitesService {
   }
 
   private getStrudelAppsCmd(identity: Identity): Observable<Strudelapp[]> {
+    console.log('running getStrudleAppsCmd',identity)
     if (identity.site.appCatalogCmd != null) {
       return (this.tesService.runCommand(identity,identity.site.appCatalogCmd) as Observable<Strudelapp[]>)
-                    .pipe(catchError(this.handleError('getStrudelApps', <Strudelapp[]>[])))
+                    .pipe(
+                      tap((v) => console.log('getapps',identity,' returned',v)),
+                      catchError(this.handleError('getStrudelApps', <Strudelapp[]>[])))
     }
     return of([] as Strudelapp[])
   }
@@ -107,18 +111,18 @@ export class ComputesitesService {
   }
 
 
-  updateStrudelApps(site: Computesite, apps) {
+  updateStrudelApps(id: Identity, apps) {
     var sapps: Strudelapp[];
     var localapps: Strudelapp[];
     sapps = <Strudelapp[]>apps;
 
-    localapps = JSON.parse(localStorage.getItem(site.name+'-apps'))
+    localapps = JSON.parse(localStorage.getItem(id.site.name+'-apps'))
     if (localapps !== null)  {
       for (let a of localapps) {
         sapps.push(a);
       }
     }
-    site.appCatalog.next(sapps);
+    id.appCatalog.next(sapps);
   }
 
   private handleError<T> (operation = 'operation', result?: T) {
@@ -160,13 +164,11 @@ export class ComputesitesService {
     }
     if (localcomputesites !== null ) {
       for (let cs of localcomputesites) {
-        cs.appCatalog  = new BehaviorSubject<Strudelapp[]>([]);
         computesites.push(cs);
       }
     }
     for (let cs of resp) {
       let computesite = <Computesite>cs;
-      computesite.appCatalog = new BehaviorSubject<Strudelapp[]>([])
       computesites.push(computesite);
     }
     this.computesites.next(computesites);
diff --git a/src/app/identity.ts b/src/app/identity.ts
index ac86100..a332f82 100644
--- a/src/app/identity.ts
+++ b/src/app/identity.ts
@@ -1,6 +1,7 @@
 import {Computesite, Health} from './computesite';
 import {Job} from './job';
 import {BehaviorSubject} from 'rxjs';
+import {Strudelapp} from './strudelapp';
 // Identities are defined by a username on a computer, but rather than just
 // DNS entry, there is extra info in the Computesite
 export class Identity {
@@ -13,6 +14,7 @@ export class Identity {
   joblist: BehaviorSubject<Job[]>;
   quotas: any[];
   expiry: number;
+  appCatalog: BehaviorSubject<Strudelapp[]>;
   constructor( username: string, site: Computesite, expiry: number) {
     this.username = username;
     this.site = site;
@@ -20,8 +22,10 @@ export class Identity {
     this.systemalerts = new BehaviorSubject<Health[]>(null);
     this.accountalerts = new BehaviorSubject<Health[]>(null);
     this.joblist = new BehaviorSubject<Job[]>([]);
+    this.appCatalog = new BehaviorSubject<Strudelapp[]>([]);
     this.quotas = [];
     this.expiry = expiry;
+    
   }
 
   copy_skip_catalog(): Identity {
diff --git a/src/app/joblist/joblist.component.ts b/src/app/joblist/joblist.component.ts
index e336904..7aa175c 100644
--- a/src/app/joblist/joblist.component.ts
+++ b/src/app/joblist/joblist.component.ts
@@ -92,7 +92,7 @@ export class JoblistComponent implements OnInit {
    // any jobs in the joblist that we don't know which application they arem try to figure it out
    for (j of joblist) {
      if (j.app === undefined || j.app == null) {
-       j.app = Strudelapp.getApp(j.appname,identity.site.appCatalog.value);
+       j.app = Strudelapp.getApp(j.appname,identity.appCatalog.value);
      }
      if (j.identity == undefined) {
         j.identity = identity;
diff --git a/src/app/jobs.service.ts b/src/app/jobs.service.ts
index b244cac..a20b802 100644
--- a/src/app/jobs.service.ts
+++ b/src/app/jobs.service.ts
@@ -45,13 +45,15 @@ export class JobsService {
     if (error.hasOwnProperty("error") && error.error.hasOwnProperty("message")) {
       if (error.error.message.indexOf("Permission denied") != -1) {
         this.notifications.notify("Your login appears to have expired. Please log in again");
-        this.authService.updateAgentContents().subscribe((_) => {return});
+        //this.authService.updateAgentContents().subscribe((_) => {return});
         return;
       } 
+      this.notifications.notify("Unable to retrieve a list of running jobs.\nDid your session expire?\nThe error messge was " + error.error.message);
+      return;
     }
-    this.notifications.notify("Unable to retrieve a list of running jobs.\nDid your session expire?")
     console.error(error);
-    this.authService.updateAgentContents().subscribe((_) => {return});
+    this.notifications.notify("Unable to retrieve a list of running jobs.\nDid your session expire?");
+    //this.authService.updateAgentContents().subscribe((_) => {return});
   }
 
 }
diff --git a/src/app/launcher/launcher.component.html b/src/app/launcher/launcher.component.html
index d71b9a8..1211c94 100644
--- a/src/app/launcher/launcher.component.html
+++ b/src/app/launcher/launcher.component.html
@@ -37,7 +37,7 @@
                                 </button>
                         </mat-list-item>
                         
-                        <app-strudelapplist [applist]=id.site.appCatalog [identity]="id" (appChange)="selectApp($event)" style="width: 100%"></app-strudelapplist>
+                        <app-strudelapplist [applist]=id.appCatalog [identity]="id" (appChange)="selectApp($event)" style="width: 100%"></app-strudelapplist>
                         </mat-list>
                     </mat-expansion-panel>
                     <!--<div style="width: 100%; border-bottom: 1px solid var(--panel-border-color);"></div>-->
diff --git a/src/app/launcher/launcher.component.ts b/src/app/launcher/launcher.component.ts
index f9770a8..f5d037f 100644
--- a/src/app/launcher/launcher.component.ts
+++ b/src/app/launcher/launcher.component.ts
@@ -233,8 +233,8 @@ export class LauncherComponent implements OnInit {
     if (apps === null) {
       apps = 'accountinfo';
     }
-    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),take(1)).subscribe(() => this.updateIdApp(params,appidentities));
+    if (id.appCatalog.value === undefined || id.appCatalog.value === null || (id.appCatalog.value).length == 0) {
+      id.appCatalog.pipe(filter((v) => v !== null && v.length > 0),take(1)).subscribe(() => this.updateIdApp(params,appidentities));
       return
     }
     var app: Strudelapp = this.getApp(id,apps);
@@ -247,7 +247,7 @@ export class LauncherComponent implements OnInit {
     if (id == 'accountinfo') {
       return null;
     }
-    return Strudelapp.getApp(v,id.site.appCatalog.value);
+    return Strudelapp.getApp(v,id.appCatalog.value);
   }
 
   getId(v: any, appidentities: Identity[]) {
diff --git a/src/app/tes.service.ts b/src/app/tes.service.ts
index 9d5857b..4aaaef5 100644
--- a/src/app/tes.service.ts
+++ b/src/app/tes.service.ts
@@ -54,7 +54,6 @@ public openWindow$: Subject<any>;
  private buildParams(app: Strudelapp, identity: Identity, batchinterface: BatchInterface, appinst?: any): string {
    let params = new URLSearchParams();
    let id = identity.copy_skip_catalog();
-   id.site.appCatalog = null;
    if (appinst!== null)  {
      params.set('appinstance',JSON.stringify(appinst));
    }
diff --git a/src/assets/config/m3apps.test.json b/src/assets/config/m3apps.test.json
index b12b6fa..bcac520 100644
--- a/src/assets/config/m3apps.test.json
+++ b/src/assets/config/m3apps.test.json
@@ -43,7 +43,7 @@
    "instactions": [ 
        {
            "name": "Connect",
-           "paramscmd": "/usr/local/sv2/jupyter/jupyter_params.sh {jobid}",
+           "paramscmd": "/usr/local/sv2/jupyter/jupyter_params.py {jobid}",
            "client": {"cmd": null, "redir": "?token={token}"},
            "states": ["RUNNING"]
        },
-- 
GitLab