From ec5f3255bab7583e7dccd1afaef380d91102f050 Mon Sep 17 00:00:00 2001
From: Chris Hines <chris.hines@monash.edu>
Date: Fri, 28 Jun 2019 17:37:04 +0800
Subject: [PATCH] Strudel2 now has a Light theme and a Dark Theme

---
 angular.json                             |  3 +-
 src/app/app-routing.module.ts            | 11 ++--
 src/app/app.component.html               |  8 +++
 src/app/app.component.ts                 |  8 ++-
 src/app/app.module.ts                    |  5 +-
 src/app/joblist/joblist.component.html   | 26 ++++----
 src/app/joblist/joblist.component.ts     |  2 +-
 src/app/keygen/keygen.component.html     | 14 +----
 src/app/launcher/launcher.component.html | 13 +++-
 src/app/launcher/launcher.component.ts   | 79 ++++++++++++++++++------
 src/app/tes.service.ts                   |  9 +++
 src/health-warn.scss                     | 10 +++
 src/styles.css                           |  3 -
 src/styles.scss                          | 39 ++++++++++++
 14 files changed, 173 insertions(+), 57 deletions(-)
 create mode 100644 src/health-warn.scss
 delete mode 100644 src/styles.css
 create mode 100644 src/styles.scss

diff --git a/angular.json b/angular.json
index fdd4dcf..236fe57 100644
--- a/angular.json
+++ b/angular.json
@@ -21,7 +21,8 @@
               "src/favicon.ico"
             ],
             "styles": [
-              "src/styles.css"
+              "src/styles.scss",
+              "src/health-warn.scss"
             ],
             "scripts": []
           },
diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts
index d6b0cd5..eddb7fb 100644
--- a/src/app/app-routing.module.ts
+++ b/src/app/app-routing.module.ts
@@ -4,6 +4,7 @@ import { LauncherComponent } from './launcher/launcher.component';
 import { KeygenComponent } from './keygen/keygen.component';
 import { TransferComponent } from './transfer/transfer.component';
 import { ShareconnectComponent } from './shareconnect/shareconnect.component';
+import { JoblistComponent } from './joblist/joblist.component';
 
 
 // import { TokenextractorComponent } from './tokenextractor/tokenextractor.component';
@@ -11,12 +12,12 @@ import { ShareconnectComponent } from './shareconnect/shareconnect.component';
 
 const routes: Routes = [
   { path: '', redirectTo: 'launch', pathMatch: 'full'},
-  { path: 'launch', component: LauncherComponent},
-  { path: 'finishlaunch', component: LauncherComponent},
-  { path: 'cancellaunch', component: LauncherComponent},
+  { path: 'launch', component: JoblistComponent},
+  //  { path: 'finishlaunch', component: LauncherComponent},
+  //{ path: 'cancellaunch', component: LauncherComponent},
   { path: 'sshauthz_callback', component: KeygenComponent},
-  { path: 'transfer', component: TransferComponent },
-  { path: 'shareconnect', component: ShareconnectComponent }
+  // { path: 'transfer', component: TransferComponent },
+  //{ path: 'shareconnect', component: ShareconnectComponent }
 
 
   // { path: 'sshauthz_callback', component: LauncherComponent}
diff --git a/src/app/app.component.html b/src/app/app.component.html
index a54e574..8a5de05 100644
--- a/src/app/app.component.html
+++ b/src/app/app.component.html
@@ -1,2 +1,10 @@
 <!-- <router-outlet class="fill-remaining-space"></router-outlet> -->
+<!--<div *ngIf="(tesService.theme | async) == 'strudel-dark-theme'" class="strudel-dark-theme" style="width: 100vw; height: 100vh">
 <router-outlet></router-outlet>
+</div>
+<div *ngIf="(tesService.theme | async) == 'strudel-light-theme'" class="strudel-light-theme" style="width: 100vw; height: 100vh">
+<router-outlet></router-outlet>
+</div> -->
+
+<app-launcher></app-launcher>
+<!--<router-outlet></router-outlet>-->
diff --git a/src/app/app.component.ts b/src/app/app.component.ts
index e08e960..f938199 100644
--- a/src/app/app.component.ts
+++ b/src/app/app.component.ts
@@ -4,6 +4,8 @@ import { AuthorisationService} from './authorisation.service';
 import { ComputesitesService} from './computesites.service';
 import {BehaviorSubject} from 'rxjs/BehaviorSubject';
 import { MatSnackBar } from '@angular/material';
+import {OverlayContainer} from '@angular/cdk/overlay';
+
 
 
 @Component({
@@ -24,7 +26,7 @@ export class AppComponent {
   constructor(private tesService: TesService,
               private authService: AuthorisationService,
               private computesitesService: ComputesitesService,
-              public snackBar: MatSnackBar,) {
+              public snackBar: MatSnackBar) {
 
    };
 
@@ -36,6 +38,7 @@ export class AppComponent {
     this.computesitesService.setStatusMsg(this.statusMsg);
     this.authService.setStatusMsg(this.statusMsg);
     this.statusMsg.subscribe(msg => this.displayMessage(msg));
+
   }
 
 
@@ -48,6 +51,9 @@ export class AppComponent {
      this.snackBarRef = this.snackBar.open(msg,'Dismiss');
    }
  }
+
+
+
   // login() {
   //   console.log("login");
   //   this.authService.login()
diff --git a/src/app/app.module.ts b/src/app/app.module.ts
index 66fc38e..2db06c7 100644
--- a/src/app/app.module.ts
+++ b/src/app/app.module.ts
@@ -47,6 +47,8 @@ import { Sv2SideNavComponent } from './sv2-side-nav/sv2-side-nav.component';
 import { ShareconnectComponent } from './shareconnect/shareconnect.component';
 import { LaunchDialogComponent } from './launch-dialog/launch-dialog.component';
 import { ModaldialogComponent } from './modaldialog/modaldialog.component'
+import {OverlayModule} from '@angular/cdk/overlay';
+
 // import { FileExplorerModule } from './file-explorer/file-explorer.module';
 
 
@@ -68,7 +70,7 @@ import { ModaldialogComponent } from './modaldialog/modaldialog.component'
     Sv2SideNavComponent,
     ShareconnectComponent,
     LaunchDialogComponent,
-    ModaldialogComponent
+    ModaldialogComponent,
   ],
   imports: [
   BrowserModule,
@@ -94,6 +96,7 @@ import { ModaldialogComponent } from './modaldialog/modaldialog.component'
   FileExplorerModule,
   FlexLayoutModule,
   MatProgressBarModule,
+  OverlayModule,
 
 
   ],
diff --git a/src/app/joblist/joblist.component.html b/src/app/joblist/joblist.component.html
index 4b6183b..1229da1 100644
--- a/src/app/joblist/joblist.component.html
+++ b/src/app/joblist/joblist.component.html
@@ -1,35 +1,33 @@
-<!-- <div *ngIf="identities.length == 0">
-  <mat-card>
-    Click identity and login to a service to start an application.
-  </mat-card>
-</div>
-<div *ngFor="let id of identities"> -->
 <mat-card style="width: 100%" style="box-sizing: border-box;">
-    <div *ngIf="identity === undefined || identity == null" >
+   <div *ngIf="(tesService.identitySubject | async) === null" >
       Click login and select a provider or select one you've already logged in to.
     </div>
-    <div *ngIf="(identity !== undefined) && (identity !== null)">
+   <div *ngIf="(tesService.identitySubject | async) !== null" >
         <div *ngFor="let h of tesService.cachetincidents | async">
-            <div *ngIf="h.stat == 'error'" style="color: warn">
-                <mat-card color='warn' style='width: 100%'>
+            <div *ngIf="h.stat == 'error'">
+                <mat-card style='width: 100%'>
+                    <div class='health-warn'>
                   {{ h.msg }}
+                    </div>
                 </mat-card>
             </div>
         </div>
         <div *ngFor="let h of tesService.userhealth | async">
-            <div *ngIf="h.stat == 'error'" style="color: warn">
-                <mat-card color='warn' style='width: 100%'>
+            <div *ngIf="h.stat == 'error'">
+                <mat-card style='width: 100%'>
+                    <div class='health-warn'>
                   {{ h.msg }}
+                    </div>
                 </mat-card>
             </div>
         </div>
-        Jobs running as {{ identity.displayName() }}      
+        Jobs running as {{ (tesService.identitySubject | async).displayName() }}      
       <div *ngFor="let job of tesService.joblist | async">
         <app-job [jobdata]=job></app-job>
       </div>
       <button mat-button (click)="refreshJobs()" style="width: 100%; text-align: right">Refresh Job list</button>
 
-    </div>
+   </div>
 </mat-card>
 
 <!-- <iframe src="http://localhost:5200" frameborder="0" style="width: 100%"></iframe> -->
diff --git a/src/app/joblist/joblist.component.ts b/src/app/joblist/joblist.component.ts
index 70e696a..d77c229 100644
--- a/src/app/joblist/joblist.component.ts
+++ b/src/app/joblist/joblist.component.ts
@@ -31,7 +31,7 @@ export class JoblistComponent implements OnInit {
   }
 
   public refreshJobs(): void {
-    this.tesService.getJobs(this.identity);
+    this.tesService.getJobs(this.tesService.identitySubject.value);
   }
 
 }
diff --git a/src/app/keygen/keygen.component.html b/src/app/keygen/keygen.component.html
index c5a8e0b..872fc63 100644
--- a/src/app/keygen/keygen.component.html
+++ b/src/app/keygen/keygen.component.html
@@ -1,11 +1,3 @@
-<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
-  </mat-card>
+<mat-card>
+Generating cryptographic tokens ... this should only take a few seconds
+</mat-card>
diff --git a/src/app/launcher/launcher.component.html b/src/app/launcher/launcher.component.html
index 12f607f..a7400ba 100644
--- a/src/app/launcher/launcher.component.html
+++ b/src/app/launcher/launcher.component.html
@@ -61,11 +61,22 @@
         <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>
     </mat-expansion-panel>
 	</mat-accordion>
 </mat-sidenav>
 
-  <app-joblist [identity]="(identitySubject | async)"></app-joblist>
+<!--<app-joblist [identity]="(identitySubject | async)"></app-joblist>-->
+  <router-outlet></router-outlet>
   <div fxFlex></div>
 
 </mat-sidenav-container>
diff --git a/src/app/launcher/launcher.component.ts b/src/app/launcher/launcher.component.ts
index 3875a4f..cd36080 100644
--- a/src/app/launcher/launcher.component.ts
+++ b/src/app/launcher/launcher.component.ts
@@ -21,6 +21,10 @@ import { ComputesitesService } from '../computesites.service';
 import { BehaviorSubject } from 'rxjs/BehaviorSubject';
 
 
+import {OverlayContainer} from '@angular/cdk/overlay';
+
+
+
 
 
 
@@ -32,11 +36,12 @@ import { BehaviorSubject } from 'rxjs/BehaviorSubject';
 export class LauncherComponent implements OnInit {
   public strudelapps: Strudelapp[];
   @Input() menuopen: boolean;
+  public themeSubject: BehaviorSubject<string>;
 
   public app: Strudelapp;
   public authorised: boolean;
   public identity: Identity;
-  public identitySubject: BehaviorSubject<Identity>;
+  //  public identitySubject: BehaviorSubject<Identity>;
 
   public identities: Identity[];
   public sshauthzservers: SshAuthzServer[];
@@ -45,21 +50,26 @@ export class LauncherComponent implements OnInit {
   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,
                 public backendSelectionService: BackendSelectionService,
                 public authService: AuthorisationService,
                 public computeSitesService: ComputesitesService,
+                public overlayContainer: OverlayContainer,
                 ) {
       this.authService.sshAuthzServers.subscribe(o => {this.updateSshAuthZServers(o)});
-      this.identitySubject = new BehaviorSubject(undefined);
       this.computeSitesService.appidentities.subscribe(o => this.verifyIdValid(o));
-    this.backendSelectionService.apiserver.subscribe((s) => this.selectedApiServer = s);
+      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) {
-      let currentId = this.identitySubject.value
+      let currentId = this.tesService.identitySubject.value
       if (currentId === undefined || currentId == null) {
           return;
       }
@@ -68,7 +78,7 @@ export class LauncherComponent implements OnInit {
               return;
           }
       }
-      this.identitySubject.next(null);
+      this.tesService.identitySubject.next(null);
       //if (!(this.identitySubject.value in this.computeSitesService.appidentities.value)) {
       //    this.identitySubject.next(null);
       //}
@@ -80,20 +90,28 @@ export class LauncherComponent implements OnInit {
 
   ngOnInit() {
     this.strudelapps = [];
-      //    setTimeout( () => this.authService.updateAgentContents() )
-  }
-
-
-  //updateIdentities(identities) {
-  //  this.identities = identities;
-  //  console.log(this.identities);
-  //  if (this.identities.length > 0) {
-  //    this.identity = this.identities[0];
+    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);
 
-  //  } else {
-  //    this.strudelapps = [];
-  //  }
-  //}
+  }
 
 
   logout() {
@@ -114,7 +132,7 @@ export class LauncherComponent implements OnInit {
 
   selectId(id: Identity) {
     this.identity=id;
-    this.identitySubject.next(id);
+    this.tesService.identitySubject.next(id);
     this.tesService.clearJobs();
     this.tesService.getJobs(id);
     this.tesService.cancelHealthRequests();
@@ -152,4 +170,27 @@ export class LauncherComponent implements OnInit {
       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);
+  }
 }
diff --git a/src/app/tes.service.ts b/src/app/tes.service.ts
index 6f0c937..cde58cb 100644
--- a/src/app/tes.service.ts
+++ b/src/app/tes.service.ts
@@ -52,6 +52,9 @@ private updateUserHealthSub: Subscription;
 private cachetincidents: BehaviorSubject<Health[]>;
 private nextUpdate: Subscription;
 private cancelRequests: Subject<string>;
+public theme: BehaviorSubject<string>;
+public identitySubject: BehaviorSubject<Identity>;
+
 // public batchinterface: {[id: string] : BatchInterface};
 
   constructor(private http: HttpClient,
@@ -70,10 +73,12 @@ private cancelRequests: Subject<string>;
     this.apiserver = new BehaviorSubject<APIServer>(null);
     this.apiservers = new BehaviorSubject<APIServer[]>([]);
     this.cancelRequests = new Subject<string>();
+    this.identitySubject = new BehaviorSubject<Identity>(null);
 
     this.timerSubscription = null;
     this.appwindowWatcher = null;
       this.backendSelectionService.apiserver.subscribe( (value) => { if (value != null) {this.twsproxy = value.tws ; this.Base = value.tes }});
+    this.theme = new BehaviorSubject('strudel-light-theme');
     // this.batchinterface = {};
     // this.computesitesService.identities.subscribe(identities => this.startPolling(identities));
  }
@@ -82,6 +87,9 @@ public setStatusMsg(statusMsg: BehaviorSubject<any>) {
   this.statusMsg = statusMsg;
 }
 
+ public setTheme(theme: string) {
+   this.theme.next(theme);
+ }
 
  private buildParams(app: Strudelapp, identity: Identity, batchinterface: BatchInterface, appinst?: any): string {
    let params = new URLSearchParams();
@@ -167,6 +175,7 @@ public setStatusMsg(statusMsg: BehaviorSubject<any>) {
  private getCachetIncidentsError(error: any) {
    return this.getJobsError(error)
  }
+
  
  public cancelHealthRequests() {
     this.cancelRequests.next('cancel')
diff --git a/src/health-warn.scss b/src/health-warn.scss
new file mode 100644
index 0000000..170b6ca
--- /dev/null
+++ b/src/health-warn.scss
@@ -0,0 +1,10 @@
+@mixin health-warning-theme($theme) {
+  $primary: map-get($theme, primary);
+  $warn: map-get($theme, warn);
+  $background: map-get($theme, background);
+  $foreground: map-get($theme, foreground);
+  
+  .health-warn {
+    color: mat-color($warn);
+  }
+}
diff --git a/src/styles.css b/src/styles.css
deleted file mode 100644
index f81c956..0000000
--- a/src/styles.css
+++ /dev/null
@@ -1,3 +0,0 @@
-/* You can add global styles to this file, and also import other style files */
-@import url( 'https://fonts.googleapis.com/css?family=Roboto:400,700|Material+Icons');
-@import "~@angular/material/prebuilt-themes/indigo-pink.css";
diff --git a/src/styles.scss b/src/styles.scss
new file mode 100644
index 0000000..bd99ec6
--- /dev/null
+++ b/src/styles.scss
@@ -0,0 +1,39 @@
+@import "~@angular/material/theming";
+@import "~@angular/material/prebuilt-themes/deeppurple-amber.css";
+@import 'health-warn.scss';
+@import url('https://fonts.googleapis.com/css?family=Roboto:400,700|Material+Icons');
+// Plus imports for other components in your app.
+
+// Include the common styles for Angular Material. We include this here so that you only
+// have to load a single css file for Angular Material in your app.
+// **Be sure that you only ever include this mixin once!**
+@include mat-core();
+
+// Define the default theme (same as the example above).
+$strudel-app-primary: mat-palette($mat-indigo);
+$strudel-app-accent:  mat-palette($mat-pink, A200, A100, A400);
+$strudel-app-theme:   mat-light-theme($strudel-app-primary, $strudel-app-accent);
+$health-warn: $mat-pink;
+
+// Include the default theme styles.
+@include angular-material-theme($strudel-app-theme);
+@include health-warning-theme($strudel-app-theme);
+
+
+// Define an alternate dark theme.
+$dark-primary: mat-palette($mat-blue-grey);
+$dark-accent:  mat-palette($mat-amber, A200, A100, A400);
+$dark-warn:    mat-palette($mat-deep-orange);
+$dark-theme:   mat-dark-theme($dark-primary, $dark-accent, $dark-warn);
+
+// Include the alternative theme styles inside of a block with a CSS class. You can make this
+// CSS class whatever you want. In this example, any component inside of an element with
+// `.strudel-dark-theme` will be affected by this alternate dark theme instead of the default theme.
+.strudel-light-theme {
+  @include angular-material-theme($strudel-app-theme);
+  @include health-warning-theme($strudel-app-theme);
+}
+.strudel-dark-theme {
+  @include angular-material-theme($dark-theme);
+  @include health-warning-theme($dark-theme);
+}
-- 
GitLab