From b41fa49a0816ac00a0de64ff1cfc081ff1f1a24f Mon Sep 17 00:00:00 2001
From: Brandon Clayton <bclayton@usgs.gov>
Date: Tue, 18 Mar 2025 13:32:18 -0600
Subject: [PATCH 1/6] Use nav service

---
 projects/nshmp-apps/src/app/app.component.ts  |  6 +-
 .../src/app/dashboard/app.component.html      |  8 +-
 .../src/app/dashboard/app.component.ts        | 91 ++++++++++++-------
 .../designmaps/dashboard/app.component.html   |  6 +-
 .../app/designmaps/dashboard/app.component.ts | 14 ++-
 .../app/designmaps/rtgm/app.component.html    |  5 +-
 .../src/app/designmaps/rtgm/app.component.ts  |  9 +-
 .../src/app/dev/dashboard/app.component.html  |  2 +-
 .../src/app/dev/dashboard/app.component.ts    | 15 +--
 .../app/dev/gmm/dashboard/app.component.html  |  2 +-
 .../app/dev/gmm/dashboard/app.component.ts    | 14 ++-
 .../hanging-wall-effects/app.component.html   |  5 +-
 .../gmm/hanging-wall-effects/app.component.ts |  9 +-
 .../dev/hazard/dashboard/app.component.html   |  2 +-
 .../app/dev/hazard/dashboard/app.component.ts | 14 ++-
 .../hazard/dynamic-compare/app.component.html |  5 +-
 .../hazard/dynamic-compare/app.component.ts   |  9 +-
 .../app/dev/math/dashboard/app.component.html |  2 +-
 .../app/dev/math/dashboard/app.component.ts   | 14 ++-
 .../exceedance-explorer/app.component.html    |  5 +-
 .../math/exceedance-explorer/app.component.ts |  6 +-
 .../app/error-pages/404/404.component.html    |  2 +-
 .../src/app/error-pages/404/404.component.ts  |  6 +-
 .../app/error-pages/410/410.component.html    |  2 +-
 .../src/app/error-pages/410/410.component.ts  |  6 +-
 .../app/error-pages/500/500.component.html    |  2 +-
 .../src/app/error-pages/500/500.component.ts  |  6 +-
 .../src/app/gmm/dashboard/app.component.html  |  2 +-
 .../src/app/gmm/dashboard/app.component.ts    | 14 ++-
 .../src/app/gmm/distance/app.component.html   |  5 +-
 .../src/app/gmm/distance/app.component.ts     |  9 +-
 .../src/app/gmm/magnitude/app.component.html  |  5 +-
 .../src/app/gmm/magnitude/app.component.ts    |  9 +-
 .../src/app/gmm/spectra/app.component.html    |  5 +-
 .../src/app/gmm/spectra/app.component.ts      |  9 +-
 .../app/hazard/dashboard/app.component.html   |  2 +-
 .../src/app/hazard/dashboard/app.component.ts | 14 ++-
 .../src/app/hazard/disagg/app.component.html  |  5 +-
 .../src/app/hazard/disagg/app.component.ts    |  9 +-
 .../src/app/hazard/dynamic/app.component.html |  5 +-
 .../src/app/hazard/dynamic/app.component.ts   |  9 +-
 .../src/app/hazard/static/app.component.html  |  5 +-
 .../src/app/hazard/static/app.component.ts    |  9 +-
 .../aws/check-haz-jobs/app.component.html     |  5 +-
 .../aws/check-haz-jobs/app.component.ts       |  9 +-
 .../internal/aws/dashboard/app.component.html |  6 +-
 .../internal/aws/dashboard/app.component.ts   | 14 ++-
 .../aws/haz-job-history/app.component.html    |  5 +-
 .../aws/haz-job-history/app.component.ts      |  9 +-
 .../aws/submit-haz-jobs/app.component.html    |  5 +-
 .../aws/submit-haz-jobs/app.component.ts      |  9 +-
 .../aws/terminate-haz-jobs/app.component.html |  5 +-
 .../aws/terminate-haz-jobs/app.component.ts   |  9 +-
 .../app/internal/dashboard/app.component.html |  2 +-
 .../app/internal/dashboard/app.component.ts   | 19 ++--
 .../src/app/internal/internal.routes.ts       |  2 +-
 .../src/app/ncm/dashboard/app.component.html  |  2 +-
 .../src/app/ncm/dashboard/app.component.ts    | 14 ++-
 .../geophysical-profiles/app.component.html   |  5 +-
 .../ncm/geophysical-profiles/app.component.ts | 10 +-
 .../app/source/dashboard/app.component.html   |  2 +-
 .../src/app/source/dashboard/app.component.ts | 14 ++-
 .../src/app/source/mfd/app.component.html     |  5 +-
 .../src/app/source/mfd/app.component.ts       |  5 +-
 .../app/source/model-maps/app.component.html  |  5 +-
 .../app/source/model-maps/app.component.ts    |  8 +-
 .../source/model-maps/services/app.service.ts |  4 +-
 .../src/app/source/rates/app.component.html   |  5 +-
 .../src/app/source/rates/app.component.ts     |  9 +-
 .../components/content/content.component.ts   | 10 +-
 70 files changed, 322 insertions(+), 258 deletions(-)

diff --git a/projects/nshmp-apps/src/app/app.component.ts b/projects/nshmp-apps/src/app/app.component.ts
index 3e40ce7f3..73e575ac4 100644
--- a/projects/nshmp-apps/src/app/app.component.ts
+++ b/projects/nshmp-apps/src/app/app.component.ts
@@ -5,8 +5,8 @@ import {NshmpService} from '@ghsc/nshmp-lib-ng/nshmp';
 import {VersionInfo} from '@ghsc/nshmp-utils-ts/libs/nshmp-ws-utils';
 import {Subscription} from 'rxjs';
 
+import {NavigationService} from '../shared/services/navigation.service';
 import {TOOLBOX_NAME} from '../shared/utils/applications.utils';
-import {navigation} from '../shared/utils/navigation.utils';
 
 /**
  * USGS Earthquake Hazard Toolbox application router outlet for all applications.
@@ -20,12 +20,10 @@ import {navigation} from '../shared/utils/navigation.utils';
   templateUrl: './app.component.html',
 })
 export class AppComponent implements OnInit, OnDestroy {
-  /** Navigation list for menu */
-  navigationList = navigation();
-
   versionSubscription: Subscription;
 
   constructor(
+    public navService: NavigationService,
     private nshmpService: NshmpService,
     private http: HttpClient,
   ) {}
diff --git a/projects/nshmp-apps/src/app/dashboard/app.component.html b/projects/nshmp-apps/src/app/dashboard/app.component.html
index 359771f0c..dfb27e7f7 100644
--- a/projects/nshmp-apps/src/app/dashboard/app.component.html
+++ b/projects/nshmp-apps/src/app/dashboard/app.component.html
@@ -1,6 +1,10 @@
-<nshmp-lib-ng-template #template [navigationList]="navigationList" [title]="">
+<nshmp-lib-ng-template
+  #template
+  [navigationList]="navService.navigationList()"
+  [title]=""
+>
   <!-- Dashboard -->
-  <nshmp-lib-ng-dashboard [sections]="sections">
+  <nshmp-lib-ng-dashboard [sections]="sections()">
     <nshmp-lib-ng-dashboard-title />
     <nshmp-lib-ng-dashboard-description />
   </nshmp-lib-ng-dashboard>
diff --git a/projects/nshmp-apps/src/app/dashboard/app.component.ts b/projects/nshmp-apps/src/app/dashboard/app.component.ts
index f8bbacf95..cb537fc31 100644
--- a/projects/nshmp-apps/src/app/dashboard/app.component.ts
+++ b/projects/nshmp-apps/src/app/dashboard/app.component.ts
@@ -1,4 +1,4 @@
-import {Component} from '@angular/core';
+import {Component, OnDestroy, OnInit, signal} from '@angular/core';
 import {NshmpLibNgAboutPageComponent} from '@ghsc/nshmp-lib-ng/about';
 import {
   ApplicationSections,
@@ -7,17 +7,11 @@ import {
   NshmpLibNgDashboardTitleComponent,
   NshmpLibNgTemplateComponent,
 } from '@ghsc/nshmp-lib-ng/nshmp';
+import {Subscription} from 'rxjs';
 
-import {apps} from '../../shared/utils/applications.utils';
-import {
-  designMapApps,
-  gmmApps,
-  hazardApps,
-  navigation,
-  ncmApps,
-  serviceApps,
-  sourceModelApps,
-} from '../../shared/utils/navigation.utils';
+import {AuthService} from '../../shared/services/auth.service';
+import {NavigationService} from '../../shared/services/navigation.service';
+import {apps, internalApps} from '../../shared/utils/applications.utils';
 import {AboutComponent} from './components/about/about.component';
 
 /**
@@ -38,33 +32,25 @@ import {AboutComponent} from './components/about/about.component';
   styleUrl: './app.component.scss',
   templateUrl: './app.component.html',
 })
-export class AppComponent {
-  /** Navigation list for menu */
-  navigationList = navigation();
+export class AppComponent implements OnInit, OnDestroy {
+  sections = signal<ApplicationSections[]>([]);
 
-  /** Design map apps  */
-  private designMapApps = designMapApps();
-  /** The GMM applications */
-  private gmmApps = gmmApps();
-  /** Hazard applications */
-  private hazardApps = hazardApps();
-  /** NCM apps  */
-  private ncmApps = ncmApps();
-  /** Source model applications */
-  private sourceModelApps = sourceModelApps();
-  /** Service applications */
-  private serviceApps = serviceApps();
+  private subscription = new Subscription();
 
-  sections: ApplicationSections[] = [
+  private applicationSections: ApplicationSections[] = [
     {
       sections: [
         {
-          applications: this.hazardApps.map(navigation => ({navigation})),
+          applications: this.navService
+            .hazardApps()
+            .map(navigation => ({navigation})),
           routerLink: apps().hazard.dashboard.routerLink,
           title: 'Hazard',
         },
         {
-          applications: this.serviceApps.map(navigation => ({navigation})),
+          applications: this.navService
+            .serviceApps()
+            .map(navigation => ({navigation})),
           title: 'Services',
         },
       ],
@@ -72,22 +58,30 @@ export class AppComponent {
     {
       sections: [
         {
-          applications: this.sourceModelApps.map(navigation => ({navigation})),
+          applications: this.navService
+            .sourceModelApps()
+            .map(navigation => ({navigation})),
           routerLink: apps().source.dashboard.routerLink,
           title: 'Source Model',
         },
         {
-          applications: this.gmmApps.map(navigation => ({navigation})),
+          applications: this.navService
+            .gmmApps()
+            .map(navigation => ({navigation})),
           routerLink: apps().gmm.dashboard.routerLink,
           title: 'Ground Motion Models',
         },
         {
-          applications: this.designMapApps.map(navigation => ({navigation})),
+          applications: this.navService
+            .designMapApps()
+            .map(navigation => ({navigation})),
           routerLink: apps().designMaps.dashboard.routerLink,
           title: 'Design Maps',
         },
         {
-          applications: this.ncmApps.map(navigation => ({navigation})),
+          applications: this.navService
+            .ncmApps()
+            .map(navigation => ({navigation})),
           routerLink: apps().ncm.dashboard.routerLink,
           title: 'National Crustal Model',
         },
@@ -95,5 +89,34 @@ export class AppComponent {
     },
   ];
 
-  constructor() {}
+  constructor(
+    public navService: NavigationService,
+    private authService: AuthService,
+  ) {}
+
+  ngOnDestroy(): void {
+    this.subscription.unsubscribe();
+  }
+
+  ngOnInit(): void {
+    this.sections.set(this.applicationSections);
+    this.checkInternal();
+  }
+
+  private checkInternal(): void {
+    this.subscription = this.authService
+      .isAuthorized(false)
+      .subscribe(isInternal => {
+        if (isInternal) {
+          const sections = this.sections();
+          sections[0]?.sections.push({
+            applications: this.navService
+              .internalMainApps()
+              .map(navigation => ({navigation})),
+            routerLink: internalApps().dashboard.routerLink,
+            title: 'Internal',
+          });
+        }
+      });
+  }
 }
diff --git a/projects/nshmp-apps/src/app/designmaps/dashboard/app.component.html b/projects/nshmp-apps/src/app/designmaps/dashboard/app.component.html
index 1a7c48e65..b83e79210 100644
--- a/projects/nshmp-apps/src/app/designmaps/dashboard/app.component.html
+++ b/projects/nshmp-apps/src/app/designmaps/dashboard/app.component.html
@@ -1,4 +1,8 @@
-<nshmp-lib-ng-template #template [navigationList]="navigationList" [title]="">
+<nshmp-lib-ng-template
+  #template
+  [navigationList]="navService.navigationList()"
+  [title]=""
+>
   <!-- Dashboard -->
   <nshmp-lib-ng-dashboard [sections]="sections">
     <nshmp-lib-ng-dashboard-title>
diff --git a/projects/nshmp-apps/src/app/designmaps/dashboard/app.component.ts b/projects/nshmp-apps/src/app/designmaps/dashboard/app.component.ts
index 0097d4005..378c2654c 100644
--- a/projects/nshmp-apps/src/app/designmaps/dashboard/app.component.ts
+++ b/projects/nshmp-apps/src/app/designmaps/dashboard/app.component.ts
@@ -10,10 +10,7 @@ import {
   NshmpLibNgDashboardTitleComponent,
   NshmpLibNgTemplateComponent,
 } from '@ghsc/nshmp-lib-ng/nshmp';
-import {
-  designMapApps,
-  navigation,
-} from 'projects/nshmp-apps/src/shared/utils/navigation.utils';
+import {NavigationService} from 'projects/nshmp-apps/src/shared/services/navigation.service';
 
 @Component({
   imports: [
@@ -29,18 +26,19 @@ import {
   templateUrl: './app.component.html',
 })
 export class AppComponent {
-  /** Navigation list for menu */
-  navigationList = navigation();
-
   sections: ApplicationSections[] = [
     {
       gridClass: 'grid-col-10',
       sections: [
         {
-          applications: designMapApps().map(navigation => ({navigation})),
+          applications: this.navService
+            .designMapApps()
+            .map(navigation => ({navigation})),
           gridClass: 'grid-col-12 tablet-lg:grid-col-8 grid-offset-1',
         },
       ],
     },
   ];
+
+  constructor(public navService: NavigationService) {}
 }
diff --git a/projects/nshmp-apps/src/app/designmaps/rtgm/app.component.html b/projects/nshmp-apps/src/app/designmaps/rtgm/app.component.html
index 464fe56b0..792c00dff 100644
--- a/projects/nshmp-apps/src/app/designmaps/rtgm/app.component.html
+++ b/projects/nshmp-apps/src/app/designmaps/rtgm/app.component.html
@@ -1,4 +1,7 @@
-<nshmp-lib-ng-template [navigationList]="navigationList" [title]="title">
+<nshmp-lib-ng-template
+  [navigationList]="navService.navigationList()"
+  [title]="title"
+>
   <nshmp-template-content-container>
     <nshmp-template-control-panel>
       <app-control-panel />
diff --git a/projects/nshmp-apps/src/app/designmaps/rtgm/app.component.ts b/projects/nshmp-apps/src/app/designmaps/rtgm/app.component.ts
index b306d8a4a..111023c50 100644
--- a/projects/nshmp-apps/src/app/designmaps/rtgm/app.component.ts
+++ b/projects/nshmp-apps/src/app/designmaps/rtgm/app.component.ts
@@ -7,8 +7,8 @@ import {
   NshmpTemplateMainContentComponent,
   NshmpTemplateSettingsComponent,
 } from '@ghsc/nshmp-template';
+import {NavigationService} from 'projects/nshmp-apps/src/shared/services/navigation.service';
 import {apps} from 'projects/nshmp-apps/src/shared/utils/applications.utils';
-import {navigation} from 'projects/nshmp-apps/src/shared/utils/navigation.utils';
 
 import {AboutComponent} from './components/about/about.component';
 import {ContentComponent} from './components/content/content.component';
@@ -34,12 +34,13 @@ import {AppService} from './services/app.service';
   templateUrl: './app.component.html',
 })
 export class AppComponent implements OnInit {
-  /** Navigation list for menu */
-  navigationList = navigation();
   /** Application title */
   title = apps().designMaps.rtgm.display;
 
-  constructor(private service: AppService) {}
+  constructor(
+    public navService: NavigationService,
+    private service: AppService,
+  ) {}
 
   ngOnInit(): void {
     this.service.init();
diff --git a/projects/nshmp-apps/src/app/dev/dashboard/app.component.html b/projects/nshmp-apps/src/app/dev/dashboard/app.component.html
index 8c2c6ecff..a333b4c60 100644
--- a/projects/nshmp-apps/src/app/dev/dashboard/app.component.html
+++ b/projects/nshmp-apps/src/app/dev/dashboard/app.component.html
@@ -1,6 +1,6 @@
 <nshmp-lib-ng-template
   #template
-  [navigationList]="navigationList"
+  [navigationList]="navService.devNavigation()"
   [title]="title"
 >
   <!-- Dashboard -->
diff --git a/projects/nshmp-apps/src/app/dev/dashboard/app.component.ts b/projects/nshmp-apps/src/app/dev/dashboard/app.component.ts
index 0af03eed3..e2125fc66 100644
--- a/projects/nshmp-apps/src/app/dev/dashboard/app.component.ts
+++ b/projects/nshmp-apps/src/app/dev/dashboard/app.component.ts
@@ -10,8 +10,7 @@ import {
   NshmpLibNgDashboardTitleComponent,
   NshmpLibNgTemplateComponent,
 } from '@ghsc/nshmp-lib-ng/nshmp';
-
-import * as nav from '../../../shared/utils/navigation.utils';
+import {NavigationService} from 'projects/nshmp-apps/src/shared/services/navigation.service';
 
 /**
  * Development dashboard showing links to development applications.
@@ -30,25 +29,21 @@ import * as nav from '../../../shared/utils/navigation.utils';
   templateUrl: './app.component.html',
 })
 export class AppComponent {
-  /** Navigation list for menu */
-  navigationList = nav.devNavigation();
-
   title = 'Development Applications';
 
-  /** Main development applications */
-  private mainApps = nav.devMainApps();
-
   sections: ApplicationSections[] = [
     {
       gridClass: 'grid-col-10',
       sections: [
         {
-          applications: this.mainApps.map(navigation => ({navigation})),
+          applications: this.navService
+            .devMainApps()
+            .map(navigation => ({navigation})),
           gridClass: 'grid-col-12 tablet-lg:grid-col-8 grid-offset-1',
         },
       ],
     },
   ];
 
-  constructor() {}
+  constructor(public navService: NavigationService) {}
 }
diff --git a/projects/nshmp-apps/src/app/dev/gmm/dashboard/app.component.html b/projects/nshmp-apps/src/app/dev/gmm/dashboard/app.component.html
index b1cc26d58..4197a32ce 100644
--- a/projects/nshmp-apps/src/app/dev/gmm/dashboard/app.component.html
+++ b/projects/nshmp-apps/src/app/dev/gmm/dashboard/app.component.html
@@ -1,6 +1,6 @@
 <nshmp-lib-ng-template
   #template
-  [navigationList]="navigationList"
+  [navigationList]="navService.devNavigation()"
   [title]="title"
 >
   <!-- Dashboard -->
diff --git a/projects/nshmp-apps/src/app/dev/gmm/dashboard/app.component.ts b/projects/nshmp-apps/src/app/dev/gmm/dashboard/app.component.ts
index 70992f37e..f7b51d9d0 100644
--- a/projects/nshmp-apps/src/app/dev/gmm/dashboard/app.component.ts
+++ b/projects/nshmp-apps/src/app/dev/gmm/dashboard/app.component.ts
@@ -10,10 +10,7 @@ import {
   NshmpLibNgDashboardTitleComponent,
   NshmpLibNgTemplateComponent,
 } from '@ghsc/nshmp-lib-ng/nshmp';
-import {
-  devGmmApps,
-  devNavigation,
-} from 'projects/nshmp-apps/src/shared/utils/navigation.utils';
+import {NavigationService} from 'projects/nshmp-apps/src/shared/services/navigation.service';
 
 @Component({
   imports: [
@@ -29,9 +26,6 @@ import {
   templateUrl: './app.component.html',
 })
 export class AppComponent {
-  /** Navigation list for menu */
-  navigationList = devNavigation();
-
   title = 'GMM Applications';
 
   sections: ApplicationSections[] = [
@@ -39,10 +33,14 @@ export class AppComponent {
       gridClass: 'grid-col-10',
       sections: [
         {
-          applications: devGmmApps().map(navigation => ({navigation})),
+          applications: this.navService
+            .devGmmApps()
+            .map(navigation => ({navigation})),
           gridClass: 'grid-col-12 tablet-lg:grid-col-8 grid-offset-1',
         },
       ],
     },
   ];
+
+  constructor(public navService: NavigationService) {}
 }
diff --git a/projects/nshmp-apps/src/app/dev/gmm/hanging-wall-effects/app.component.html b/projects/nshmp-apps/src/app/dev/gmm/hanging-wall-effects/app.component.html
index 996e7c48b..43040ceae 100644
--- a/projects/nshmp-apps/src/app/dev/gmm/hanging-wall-effects/app.component.html
+++ b/projects/nshmp-apps/src/app/dev/gmm/hanging-wall-effects/app.component.html
@@ -1,4 +1,7 @@
-<nshmp-lib-ng-template [navigationList]="navigationList" [title]="title">
+<nshmp-lib-ng-template
+  [navigationList]="navService.devNavigation()"
+  [title]="title"
+>
   <nshmp-template-content-container>
     <!-- Control panel -->
     <nshmp-template-control-panel>
diff --git a/projects/nshmp-apps/src/app/dev/gmm/hanging-wall-effects/app.component.ts b/projects/nshmp-apps/src/app/dev/gmm/hanging-wall-effects/app.component.ts
index 199bd29b0..989c42aa8 100644
--- a/projects/nshmp-apps/src/app/dev/gmm/hanging-wall-effects/app.component.ts
+++ b/projects/nshmp-apps/src/app/dev/gmm/hanging-wall-effects/app.component.ts
@@ -7,8 +7,8 @@ import {
   NshmpTemplateMainContentComponent,
   NshmpTemplateSettingsComponent,
 } from '@ghsc/nshmp-template';
+import {NavigationService} from 'projects/nshmp-apps/src/shared/services/navigation.service';
 import {devApps} from 'projects/nshmp-apps/src/shared/utils/applications.utils';
-import {devNavigation} from 'projects/nshmp-apps/src/shared/utils/navigation.utils';
 
 import {AboutComponent} from './components/about/about.component';
 import {ContentComponent} from './components/content/content.component';
@@ -34,12 +34,13 @@ import {AppService} from './services/app.service';
   templateUrl: './app.component.html',
 })
 export class AppComponent implements OnInit {
-  /** Navigation list for menu */
-  navigationList = devNavigation();
   /** Application title */
   title = devApps().gmm.hangingWallEffects.display;
 
-  constructor(private service: AppService) {}
+  constructor(
+    public navService: NavigationService,
+    private service: AppService,
+  ) {}
 
   ngOnInit(): void {
     this.service.init();
diff --git a/projects/nshmp-apps/src/app/dev/hazard/dashboard/app.component.html b/projects/nshmp-apps/src/app/dev/hazard/dashboard/app.component.html
index cd1fb0e48..d607c5379 100644
--- a/projects/nshmp-apps/src/app/dev/hazard/dashboard/app.component.html
+++ b/projects/nshmp-apps/src/app/dev/hazard/dashboard/app.component.html
@@ -1,6 +1,6 @@
 <nshmp-lib-ng-template
   #template
-  [navigationList]="navigationList"
+  [navigationList]="navService.devNavigation()"
   [title]="title"
 >
   <!-- Dashboard -->
diff --git a/projects/nshmp-apps/src/app/dev/hazard/dashboard/app.component.ts b/projects/nshmp-apps/src/app/dev/hazard/dashboard/app.component.ts
index 97870d90b..7933ca369 100644
--- a/projects/nshmp-apps/src/app/dev/hazard/dashboard/app.component.ts
+++ b/projects/nshmp-apps/src/app/dev/hazard/dashboard/app.component.ts
@@ -10,10 +10,7 @@ import {
   NshmpLibNgDashboardTitleComponent,
   NshmpLibNgTemplateComponent,
 } from '@ghsc/nshmp-lib-ng/nshmp';
-import {
-  devHazardApps,
-  devNavigation,
-} from 'projects/nshmp-apps/src/shared/utils/navigation.utils';
+import {NavigationService} from 'projects/nshmp-apps/src/shared/services/navigation.service';
 
 @Component({
   imports: [
@@ -29,9 +26,6 @@ import {
   templateUrl: './app.component.html',
 })
 export class AppComponent {
-  /** Navigation list for menu */
-  navigationList = devNavigation();
-
   title = 'Hazard Applications';
 
   sections: ApplicationSections[] = [
@@ -39,10 +33,14 @@ export class AppComponent {
       gridClass: 'grid-col-10',
       sections: [
         {
-          applications: devHazardApps().map(navigation => ({navigation})),
+          applications: this.navService
+            .devHazardApps()
+            .map(navigation => ({navigation})),
           gridClass: 'grid-col-12 tablet-lg:grid-col-8 grid-offset-1',
         },
       ],
     },
   ];
+
+  constructor(public navService: NavigationService) {}
 }
diff --git a/projects/nshmp-apps/src/app/dev/hazard/dynamic-compare/app.component.html b/projects/nshmp-apps/src/app/dev/hazard/dynamic-compare/app.component.html
index e86be1762..a3ead50bc 100644
--- a/projects/nshmp-apps/src/app/dev/hazard/dynamic-compare/app.component.html
+++ b/projects/nshmp-apps/src/app/dev/hazard/dynamic-compare/app.component.html
@@ -1,4 +1,7 @@
-<nshmp-lib-ng-template [navigationList]="navigationList" [title]="title">
+<nshmp-lib-ng-template
+  [navigationList]="navService.devNavigation()"
+  [title]="title"
+>
   <nshmp-template-content-container>
     <!-- Control panel -->
     <nshmp-template-control-panel>
diff --git a/projects/nshmp-apps/src/app/dev/hazard/dynamic-compare/app.component.ts b/projects/nshmp-apps/src/app/dev/hazard/dynamic-compare/app.component.ts
index 22774c738..9dc683deb 100644
--- a/projects/nshmp-apps/src/app/dev/hazard/dynamic-compare/app.component.ts
+++ b/projects/nshmp-apps/src/app/dev/hazard/dynamic-compare/app.component.ts
@@ -8,8 +8,8 @@ import {
   NshmpTemplateMainContentComponent,
   NshmpTemplateSettingsComponent,
 } from '@ghsc/nshmp-template';
+import {NavigationService} from 'projects/nshmp-apps/src/shared/services/navigation.service';
 import {devApps} from 'projects/nshmp-apps/src/shared/utils/applications.utils';
-import {devNavigation} from 'projects/nshmp-apps/src/shared/utils/navigation.utils';
 
 import {AboutComponent} from './components/about/about.component';
 import {ContentComponent} from './components/content/content.component';
@@ -36,12 +36,13 @@ import {AppService} from './services/app.service';
   templateUrl: './app.component.html',
 })
 export class AppComponent implements OnInit {
-  /** Navigation list for menu */
-  navigationList = devNavigation();
   /** Application title */
   title = devApps().hazard.dynamicCompare.display;
 
-  constructor(public service: AppService) {}
+  constructor(
+    public service: AppService,
+    public navService: NavigationService,
+  ) {}
 
   ngOnInit(): void {
     this.service.init();
diff --git a/projects/nshmp-apps/src/app/dev/math/dashboard/app.component.html b/projects/nshmp-apps/src/app/dev/math/dashboard/app.component.html
index 755f5e99f..ce9d0b14e 100644
--- a/projects/nshmp-apps/src/app/dev/math/dashboard/app.component.html
+++ b/projects/nshmp-apps/src/app/dev/math/dashboard/app.component.html
@@ -1,6 +1,6 @@
 <nshmp-lib-ng-template
   #template
-  [navigationList]="navigationList"
+  [navigationList]="navService.devNavigation()"
   [title]="title"
 >
   <!-- Dashboard -->
diff --git a/projects/nshmp-apps/src/app/dev/math/dashboard/app.component.ts b/projects/nshmp-apps/src/app/dev/math/dashboard/app.component.ts
index 64672d4cc..1ee581804 100644
--- a/projects/nshmp-apps/src/app/dev/math/dashboard/app.component.ts
+++ b/projects/nshmp-apps/src/app/dev/math/dashboard/app.component.ts
@@ -10,10 +10,7 @@ import {
   NshmpLibNgDashboardTitleComponent,
   NshmpLibNgTemplateComponent,
 } from '@ghsc/nshmp-lib-ng/nshmp';
-import {
-  devMathApps,
-  devNavigation,
-} from 'projects/nshmp-apps/src/shared/utils/navigation.utils';
+import {NavigationService} from 'projects/nshmp-apps/src/shared/services/navigation.service';
 
 @Component({
   imports: [
@@ -29,9 +26,6 @@ import {
   templateUrl: './app.component.html',
 })
 export class AppComponent {
-  /** Navigation list for menu */
-  navigationList = devNavigation();
-
   title = 'Math Applications';
 
   sections: ApplicationSections[] = [
@@ -39,10 +33,14 @@ export class AppComponent {
       gridClass: 'grid-col-10',
       sections: [
         {
-          applications: devMathApps().map(navigation => ({navigation})),
+          applications: this.navService
+            .devMathApps()
+            .map(navigation => ({navigation})),
           gridClass: 'grid-col-12 tablet-lg:grid-col-8 grid-offset-1',
         },
       ],
     },
   ];
+
+  constructor(public navService: NavigationService) {}
 }
diff --git a/projects/nshmp-apps/src/app/dev/math/exceedance-explorer/app.component.html b/projects/nshmp-apps/src/app/dev/math/exceedance-explorer/app.component.html
index 3e40d662b..e5fc58485 100644
--- a/projects/nshmp-apps/src/app/dev/math/exceedance-explorer/app.component.html
+++ b/projects/nshmp-apps/src/app/dev/math/exceedance-explorer/app.component.html
@@ -1,4 +1,7 @@
-<nshmp-lib-ng-template [navigationList]="navigationList" [title]="title">
+<nshmp-lib-ng-template
+  [navigationList]="navService.devNavigation()"
+  [title]="title"
+>
   <nshmp-template-content-container>
     <nshmp-template-control-panel>
       <app-control-panel />
diff --git a/projects/nshmp-apps/src/app/dev/math/exceedance-explorer/app.component.ts b/projects/nshmp-apps/src/app/dev/math/exceedance-explorer/app.component.ts
index 578861498..1338aa528 100644
--- a/projects/nshmp-apps/src/app/dev/math/exceedance-explorer/app.component.ts
+++ b/projects/nshmp-apps/src/app/dev/math/exceedance-explorer/app.component.ts
@@ -7,8 +7,8 @@ import {
   NshmpTemplateMainContentComponent,
   NshmpTemplateSettingsComponent,
 } from '@ghsc/nshmp-template';
+import {NavigationService} from 'projects/nshmp-apps/src/shared/services/navigation.service';
 import {devApps} from 'projects/nshmp-apps/src/shared/utils/applications.utils';
-import {devNavigation} from 'projects/nshmp-apps/src/shared/utils/navigation.utils';
 
 import {AboutComponent} from './components/about/about.component';
 import {ControlPanelComponent} from './components/control-panel/control-panel.component';
@@ -38,8 +38,8 @@ import {PlotSettingsPanelComponent} from './components/plot-settings-panel/plot-
   templateUrl: './app.component.html',
 })
 export class AppComponent {
-  /** Navigation list for menu */
-  navigationList = devNavigation();
   /** Application title */
   title = devApps().math.exceedanceExplorer.display;
+
+  constructor(public navService: NavigationService) {}
 }
diff --git a/projects/nshmp-apps/src/app/error-pages/404/404.component.html b/projects/nshmp-apps/src/app/error-pages/404/404.component.html
index 5ab9418f4..b438476bc 100644
--- a/projects/nshmp-apps/src/app/error-pages/404/404.component.html
+++ b/projects/nshmp-apps/src/app/error-pages/404/404.component.html
@@ -1,5 +1,5 @@
 <nshmp-lib-ng-error-page
   title="404 Not Found"
   alertText="The page you requested was not found."
-  [navigationList]="navigationList"
+  [navigationList]="navService.navigationList()"
 />
diff --git a/projects/nshmp-apps/src/app/error-pages/404/404.component.ts b/projects/nshmp-apps/src/app/error-pages/404/404.component.ts
index b3403afe3..2892d860e 100644
--- a/projects/nshmp-apps/src/app/error-pages/404/404.component.ts
+++ b/projects/nshmp-apps/src/app/error-pages/404/404.component.ts
@@ -1,6 +1,6 @@
 import {Component} from '@angular/core';
 import {NshmpLibNgErrorPageComponent} from '@ghsc/nshmp-lib-ng/nshmp';
-import {navigation} from 'projects/nshmp-apps/src/shared/utils/navigation.utils';
+import {NavigationService} from 'projects/nshmp-apps/src/shared/services/navigation.service';
 
 /**
  * Error page for any 404 errors.
@@ -14,7 +14,5 @@ import {navigation} from 'projects/nshmp-apps/src/shared/utils/navigation.utils'
   templateUrl: './404.component.html',
 })
 export class Error404Component {
-  navigationList = navigation();
-
-  constructor() {}
+  constructor(public navService: NavigationService) {}
 }
diff --git a/projects/nshmp-apps/src/app/error-pages/410/410.component.html b/projects/nshmp-apps/src/app/error-pages/410/410.component.html
index 3b9643655..eff3d0d85 100644
--- a/projects/nshmp-apps/src/app/error-pages/410/410.component.html
+++ b/projects/nshmp-apps/src/app/error-pages/410/410.component.html
@@ -1,5 +1,5 @@
 <nshmp-lib-ng-error-page
   title="410 Gone"
   alertText="The page you requested no longer exists."
-  [navigationList]="navigationList"
+  [navigationList]="navService.navigationList()"
 />
diff --git a/projects/nshmp-apps/src/app/error-pages/410/410.component.ts b/projects/nshmp-apps/src/app/error-pages/410/410.component.ts
index 653e3cc6d..5eb0ce9ef 100644
--- a/projects/nshmp-apps/src/app/error-pages/410/410.component.ts
+++ b/projects/nshmp-apps/src/app/error-pages/410/410.component.ts
@@ -1,6 +1,6 @@
 import {Component} from '@angular/core';
 import {NshmpLibNgErrorPageComponent} from '@ghsc/nshmp-lib-ng/nshmp';
-import {navigation} from 'projects/nshmp-apps/src/shared/utils/navigation.utils';
+import {NavigationService} from 'projects/nshmp-apps/src/shared/services/navigation.service';
 
 /**
  * Error page for any 410 errors.
@@ -14,7 +14,5 @@ import {navigation} from 'projects/nshmp-apps/src/shared/utils/navigation.utils'
   templateUrl: './410.component.html',
 })
 export class Error410Component {
-  navigationList = navigation();
-
-  constructor() {}
+  constructor(public navService: NavigationService) {}
 }
diff --git a/projects/nshmp-apps/src/app/error-pages/500/500.component.html b/projects/nshmp-apps/src/app/error-pages/500/500.component.html
index e17fae2a9..b1dd7add9 100644
--- a/projects/nshmp-apps/src/app/error-pages/500/500.component.html
+++ b/projects/nshmp-apps/src/app/error-pages/500/500.component.html
@@ -1,5 +1,5 @@
 <nshmp-lib-ng-error-page
   title="500 Internal Server Error"
   alertText="The page you requested is temporarily unavailable."
-  [navigationList]="navigationList"
+  [navigationList]="navService.navigationList()"
 />
diff --git a/projects/nshmp-apps/src/app/error-pages/500/500.component.ts b/projects/nshmp-apps/src/app/error-pages/500/500.component.ts
index 2bdad2ef0..2f4398d71 100644
--- a/projects/nshmp-apps/src/app/error-pages/500/500.component.ts
+++ b/projects/nshmp-apps/src/app/error-pages/500/500.component.ts
@@ -1,6 +1,6 @@
 import {Component} from '@angular/core';
 import {NshmpLibNgErrorPageComponent} from '@ghsc/nshmp-lib-ng/nshmp';
-import {navigation} from 'projects/nshmp-apps/src/shared/utils/navigation.utils';
+import {NavigationService} from 'projects/nshmp-apps/src/shared/services/navigation.service';
 
 /**
  * Error page for any 500 errors.
@@ -14,7 +14,5 @@ import {navigation} from 'projects/nshmp-apps/src/shared/utils/navigation.utils'
   templateUrl: './500.component.html',
 })
 export class Error500Component {
-  navigationList = navigation();
-
-  constructor() {}
+  constructor(public navService: NavigationService) {}
 }
diff --git a/projects/nshmp-apps/src/app/gmm/dashboard/app.component.html b/projects/nshmp-apps/src/app/gmm/dashboard/app.component.html
index 8304e735c..402f91c4a 100644
--- a/projects/nshmp-apps/src/app/gmm/dashboard/app.component.html
+++ b/projects/nshmp-apps/src/app/gmm/dashboard/app.component.html
@@ -1,6 +1,6 @@
 <nshmp-lib-ng-template
   #template
-  [navigationList]="navigationList"
+  [navigationList]="navService.navigationList()"
   [title]="title"
 >
   <!-- Dashboard -->
diff --git a/projects/nshmp-apps/src/app/gmm/dashboard/app.component.ts b/projects/nshmp-apps/src/app/gmm/dashboard/app.component.ts
index d9904965c..b798e9f40 100644
--- a/projects/nshmp-apps/src/app/gmm/dashboard/app.component.ts
+++ b/projects/nshmp-apps/src/app/gmm/dashboard/app.component.ts
@@ -10,10 +10,7 @@ import {
   NshmpLibNgDashboardTitleComponent,
   NshmpLibNgTemplateComponent,
 } from '@ghsc/nshmp-lib-ng/nshmp';
-import {
-  gmmApps,
-  navigation,
-} from 'projects/nshmp-apps/src/shared/utils/navigation.utils';
+import {NavigationService} from 'projects/nshmp-apps/src/shared/services/navigation.service';
 
 @Component({
   imports: [
@@ -29,9 +26,6 @@ import {
   templateUrl: './app.component.html',
 })
 export class AppComponent {
-  /** Navigation list for menu */
-  navigationList = navigation();
-
   title = 'GMM Applications';
 
   sections: ApplicationSections[] = [
@@ -39,10 +33,14 @@ export class AppComponent {
       gridClass: 'grid-col-10',
       sections: [
         {
-          applications: gmmApps().map(navigation => ({navigation})),
+          applications: this.navService
+            .gmmApps()
+            .map(navigation => ({navigation})),
           gridClass: 'grid-col-12 tablet-lg:grid-col-8 grid-offset-1',
         },
       ],
     },
   ];
+
+  constructor(public navService: NavigationService) {}
 }
diff --git a/projects/nshmp-apps/src/app/gmm/distance/app.component.html b/projects/nshmp-apps/src/app/gmm/distance/app.component.html
index 464fe56b0..792c00dff 100644
--- a/projects/nshmp-apps/src/app/gmm/distance/app.component.html
+++ b/projects/nshmp-apps/src/app/gmm/distance/app.component.html
@@ -1,4 +1,7 @@
-<nshmp-lib-ng-template [navigationList]="navigationList" [title]="title">
+<nshmp-lib-ng-template
+  [navigationList]="navService.navigationList()"
+  [title]="title"
+>
   <nshmp-template-content-container>
     <nshmp-template-control-panel>
       <app-control-panel />
diff --git a/projects/nshmp-apps/src/app/gmm/distance/app.component.ts b/projects/nshmp-apps/src/app/gmm/distance/app.component.ts
index 92ff39db7..d8cf4e679 100644
--- a/projects/nshmp-apps/src/app/gmm/distance/app.component.ts
+++ b/projects/nshmp-apps/src/app/gmm/distance/app.component.ts
@@ -7,8 +7,8 @@ import {
   NshmpTemplateMainContentComponent,
   NshmpTemplateSettingsComponent,
 } from '@ghsc/nshmp-template';
+import {NavigationService} from 'projects/nshmp-apps/src/shared/services/navigation.service';
 import {apps} from 'projects/nshmp-apps/src/shared/utils/applications.utils';
-import {navigation} from 'projects/nshmp-apps/src/shared/utils/navigation.utils';
 
 import {AboutComponent} from './components/about/about.component';
 import {ContentComponent} from './components/content/content.component';
@@ -41,12 +41,13 @@ import {AppService} from './services/app.service';
   templateUrl: './app.component.html',
 })
 export class AppComponent implements OnInit {
-  /** Navigation list for menu */
-  navigationList = navigation();
   /** Application title */
   title = apps().gmm.distance.display;
 
-  constructor(public service: AppService) {}
+  constructor(
+    public service: AppService,
+    public navService: NavigationService,
+  ) {}
 
   ngOnInit() {
     this.service.init();
diff --git a/projects/nshmp-apps/src/app/gmm/magnitude/app.component.html b/projects/nshmp-apps/src/app/gmm/magnitude/app.component.html
index 464fe56b0..792c00dff 100644
--- a/projects/nshmp-apps/src/app/gmm/magnitude/app.component.html
+++ b/projects/nshmp-apps/src/app/gmm/magnitude/app.component.html
@@ -1,4 +1,7 @@
-<nshmp-lib-ng-template [navigationList]="navigationList" [title]="title">
+<nshmp-lib-ng-template
+  [navigationList]="navService.navigationList()"
+  [title]="title"
+>
   <nshmp-template-content-container>
     <nshmp-template-control-panel>
       <app-control-panel />
diff --git a/projects/nshmp-apps/src/app/gmm/magnitude/app.component.ts b/projects/nshmp-apps/src/app/gmm/magnitude/app.component.ts
index 1d80636ca..24916169c 100644
--- a/projects/nshmp-apps/src/app/gmm/magnitude/app.component.ts
+++ b/projects/nshmp-apps/src/app/gmm/magnitude/app.component.ts
@@ -7,8 +7,8 @@ import {
   NshmpTemplateMainContentComponent,
   NshmpTemplateSettingsComponent,
 } from '@ghsc/nshmp-template';
+import {NavigationService} from 'projects/nshmp-apps/src/shared/services/navigation.service';
 import {apps} from 'projects/nshmp-apps/src/shared/utils/applications.utils';
-import {navigation} from 'projects/nshmp-apps/src/shared/utils/navigation.utils';
 
 import {AboutComponent} from './components/about/about.component';
 import {ContentComponent} from './components/content/content.component';
@@ -41,12 +41,13 @@ import {AppService} from './services/app.service';
   templateUrl: './app.component.html',
 })
 export class AppComponent implements OnInit {
-  /** Navigation list for menu */
-  navigationList = navigation();
   /** Application title */
   title = apps().gmm.magnitude.display;
 
-  constructor(public service: AppService) {}
+  constructor(
+    public service: AppService,
+    public navService: NavigationService,
+  ) {}
 
   ngOnInit(): void {
     this.service.init();
diff --git a/projects/nshmp-apps/src/app/gmm/spectra/app.component.html b/projects/nshmp-apps/src/app/gmm/spectra/app.component.html
index 464fe56b0..792c00dff 100644
--- a/projects/nshmp-apps/src/app/gmm/spectra/app.component.html
+++ b/projects/nshmp-apps/src/app/gmm/spectra/app.component.html
@@ -1,4 +1,7 @@
-<nshmp-lib-ng-template [navigationList]="navigationList" [title]="title">
+<nshmp-lib-ng-template
+  [navigationList]="navService.navigationList()"
+  [title]="title"
+>
   <nshmp-template-content-container>
     <nshmp-template-control-panel>
       <app-control-panel />
diff --git a/projects/nshmp-apps/src/app/gmm/spectra/app.component.ts b/projects/nshmp-apps/src/app/gmm/spectra/app.component.ts
index ed3a8c451..d9ef907d2 100644
--- a/projects/nshmp-apps/src/app/gmm/spectra/app.component.ts
+++ b/projects/nshmp-apps/src/app/gmm/spectra/app.component.ts
@@ -7,8 +7,8 @@ import {
   NshmpTemplateMainContentComponent,
   NshmpTemplateSettingsComponent,
 } from '@ghsc/nshmp-template';
+import {NavigationService} from 'projects/nshmp-apps/src/shared/services/navigation.service';
 import {apps} from 'projects/nshmp-apps/src/shared/utils/applications.utils';
-import {navigation} from 'projects/nshmp-apps/src/shared/utils/navigation.utils';
 
 import {AboutComponent} from './components/about/about.component';
 import {ContentComponent} from './components/content/content.component';
@@ -41,12 +41,13 @@ import {AppService} from './services/app.service';
   templateUrl: './app.component.html',
 })
 export class AppComponent implements OnInit {
-  /** Navigation list for menu */
-  navigationList = navigation();
   /** Application title */
   title = apps().gmm.spectra.display;
 
-  constructor(public service: AppService) {}
+  constructor(
+    public service: AppService,
+    public navService: NavigationService,
+  ) {}
 
   ngOnInit(): void {
     this.service.init();
diff --git a/projects/nshmp-apps/src/app/hazard/dashboard/app.component.html b/projects/nshmp-apps/src/app/hazard/dashboard/app.component.html
index baf20fa7d..ac886b81b 100644
--- a/projects/nshmp-apps/src/app/hazard/dashboard/app.component.html
+++ b/projects/nshmp-apps/src/app/hazard/dashboard/app.component.html
@@ -1,6 +1,6 @@
 <nshmp-lib-ng-template
   #template
-  [navigationList]="navigationList"
+  [navigationList]="navService.navigationList()"
   [title]="title"
 >
   <!-- Dashboard -->
diff --git a/projects/nshmp-apps/src/app/hazard/dashboard/app.component.ts b/projects/nshmp-apps/src/app/hazard/dashboard/app.component.ts
index 03b0d8eb1..f9999d8a3 100644
--- a/projects/nshmp-apps/src/app/hazard/dashboard/app.component.ts
+++ b/projects/nshmp-apps/src/app/hazard/dashboard/app.component.ts
@@ -10,10 +10,7 @@ import {
   NshmpLibNgDashboardTitleComponent,
   NshmpLibNgTemplateComponent,
 } from '@ghsc/nshmp-lib-ng/nshmp';
-import {
-  hazardApps,
-  navigation,
-} from 'projects/nshmp-apps/src/shared/utils/navigation.utils';
+import {NavigationService} from 'projects/nshmp-apps/src/shared/services/navigation.service';
 
 @Component({
   imports: [
@@ -29,9 +26,6 @@ import {
   templateUrl: './app.component.html',
 })
 export class AppComponent {
-  /** Navigation list for menu */
-  navigationList = navigation();
-
   title = 'Hazard Applications';
 
   sections: ApplicationSections[] = [
@@ -39,10 +33,14 @@ export class AppComponent {
       gridClass: 'grid-col-10',
       sections: [
         {
-          applications: hazardApps().map(navigation => ({navigation})),
+          applications: this.navService
+            .hazardApps()
+            .map(navigation => ({navigation})),
           gridClass: 'grid-col-12 tablet-lg:grid-col-8 grid-offset-1',
         },
       ],
     },
   ];
+
+  constructor(public navService: NavigationService) {}
 }
diff --git a/projects/nshmp-apps/src/app/hazard/disagg/app.component.html b/projects/nshmp-apps/src/app/hazard/disagg/app.component.html
index 031a569dc..058bb0ae7 100644
--- a/projects/nshmp-apps/src/app/hazard/disagg/app.component.html
+++ b/projects/nshmp-apps/src/app/hazard/disagg/app.component.html
@@ -1,4 +1,7 @@
-<nshmp-lib-ng-template [navigationList]="navigationList" [title]="title">
+<nshmp-lib-ng-template
+  [navigationList]="navService.navigationList()"
+  [title]="title"
+>
   <nshmp-template-content-container [showSettingsPanel]="false">
     <nshmp-template-control-panel>
       <app-control-panel />
diff --git a/projects/nshmp-apps/src/app/hazard/disagg/app.component.ts b/projects/nshmp-apps/src/app/hazard/disagg/app.component.ts
index 8b970cb29..a4f0f5964 100644
--- a/projects/nshmp-apps/src/app/hazard/disagg/app.component.ts
+++ b/projects/nshmp-apps/src/app/hazard/disagg/app.component.ts
@@ -7,8 +7,8 @@ import {
   NshmpTemplateControlPanelComponent,
   NshmpTemplateMainContentComponent,
 } from '@ghsc/nshmp-template';
+import {NavigationService} from 'projects/nshmp-apps/src/shared/services/navigation.service';
 import {apps} from 'projects/nshmp-apps/src/shared/utils/applications.utils';
-import {navigation} from 'projects/nshmp-apps/src/shared/utils/navigation.utils';
 
 import {AboutComponent} from './components/about/about.component';
 import {ContentComponent} from './components/content/content.component';
@@ -35,12 +35,13 @@ import {AppService} from './services/app.service';
   templateUrl: './app.component.html',
 })
 export class AppComponent implements OnInit {
-  /** Navigation list for menu */
-  navigationList = navigation();
   /** Application title */
   title = apps().hazard.disagg.display;
 
-  constructor(public service: AppService) {}
+  constructor(
+    public service: AppService,
+    public navService: NavigationService,
+  ) {}
 
   ngOnInit(): void {
     this.service.init();
diff --git a/projects/nshmp-apps/src/app/hazard/dynamic/app.component.html b/projects/nshmp-apps/src/app/hazard/dynamic/app.component.html
index b7c70d9bd..e78a5ee9d 100644
--- a/projects/nshmp-apps/src/app/hazard/dynamic/app.component.html
+++ b/projects/nshmp-apps/src/app/hazard/dynamic/app.component.html
@@ -1,4 +1,7 @@
-<nshmp-lib-ng-template [navigationList]="navigationList" [title]="title">
+<nshmp-lib-ng-template
+  [navigationList]="navService.navigationList()"
+  [title]="title"
+>
   <nshmp-template-content-container>
     <nshmp-template-control-panel>
       <app-control-panel />
diff --git a/projects/nshmp-apps/src/app/hazard/dynamic/app.component.ts b/projects/nshmp-apps/src/app/hazard/dynamic/app.component.ts
index b1ea4cd94..7b9c6e747 100644
--- a/projects/nshmp-apps/src/app/hazard/dynamic/app.component.ts
+++ b/projects/nshmp-apps/src/app/hazard/dynamic/app.component.ts
@@ -8,8 +8,8 @@ import {
   NshmpTemplateMainContentComponent,
   NshmpTemplateSettingsComponent,
 } from '@ghsc/nshmp-template';
+import {NavigationService} from 'projects/nshmp-apps/src/shared/services/navigation.service';
 import {apps} from 'projects/nshmp-apps/src/shared/utils/applications.utils';
-import {navigation} from 'projects/nshmp-apps/src/shared/utils/navigation.utils';
 
 import {AboutComponent} from './components/about/about.component';
 import {ContentComponent} from './components/content/content.component';
@@ -39,12 +39,13 @@ import {AppService} from './services/app.service';
   templateUrl: './app.component.html',
 })
 export class AppComponent implements OnInit {
-  /** Navigation list for menu */
-  navigationList = navigation();
   /** Application title */
   title = apps().hazard.dynamic.display;
 
-  constructor(public service: AppService) {}
+  constructor(
+    public service: AppService,
+    public navService: NavigationService,
+  ) {}
 
   ngOnInit(): void {
     this.service.init();
diff --git a/projects/nshmp-apps/src/app/hazard/static/app.component.html b/projects/nshmp-apps/src/app/hazard/static/app.component.html
index 464fe56b0..792c00dff 100644
--- a/projects/nshmp-apps/src/app/hazard/static/app.component.html
+++ b/projects/nshmp-apps/src/app/hazard/static/app.component.html
@@ -1,4 +1,7 @@
-<nshmp-lib-ng-template [navigationList]="navigationList" [title]="title">
+<nshmp-lib-ng-template
+  [navigationList]="navService.navigationList()"
+  [title]="title"
+>
   <nshmp-template-content-container>
     <nshmp-template-control-panel>
       <app-control-panel />
diff --git a/projects/nshmp-apps/src/app/hazard/static/app.component.ts b/projects/nshmp-apps/src/app/hazard/static/app.component.ts
index 903650eab..de2f424e9 100644
--- a/projects/nshmp-apps/src/app/hazard/static/app.component.ts
+++ b/projects/nshmp-apps/src/app/hazard/static/app.component.ts
@@ -7,8 +7,8 @@ import {
   NshmpTemplateMainContentComponent,
   NshmpTemplateSettingsComponent,
 } from '@ghsc/nshmp-template';
+import {NavigationService} from 'projects/nshmp-apps/src/shared/services/navigation.service';
 import {apps} from 'projects/nshmp-apps/src/shared/utils/applications.utils';
-import {navigation} from 'projects/nshmp-apps/src/shared/utils/navigation.utils';
 
 import {AboutComponent} from './components/about/about.component';
 import {ContentComponent} from './components/content/content.component';
@@ -37,12 +37,13 @@ import {AppService} from './services/app.service';
   templateUrl: './app.component.html',
 })
 export class AppComponent implements OnInit {
-  /** Navigation list for menu */
-  navigationList = navigation();
   /** Application title */
   title = apps().hazard.static.display;
 
-  constructor(private service: AppService) {}
+  constructor(
+    private service: AppService,
+    public navService: NavigationService,
+  ) {}
 
   ngOnInit() {
     this.service.init();
diff --git a/projects/nshmp-apps/src/app/internal/aws/check-haz-jobs/app.component.html b/projects/nshmp-apps/src/app/internal/aws/check-haz-jobs/app.component.html
index e3c04045a..c4dd32052 100644
--- a/projects/nshmp-apps/src/app/internal/aws/check-haz-jobs/app.component.html
+++ b/projects/nshmp-apps/src/app/internal/aws/check-haz-jobs/app.component.html
@@ -1,4 +1,7 @@
-<nshmp-lib-ng-template [navigationList]="navigationList" [title]="title">
+<nshmp-lib-ng-template
+  [navigationList]="navService.internalNavigation()"
+  [title]="title"
+>
   <nshmp-template-content-container [showSettingsPanel]="false">
     <nshmp-template-control-panel>
       <app-control-panel />
diff --git a/projects/nshmp-apps/src/app/internal/aws/check-haz-jobs/app.component.ts b/projects/nshmp-apps/src/app/internal/aws/check-haz-jobs/app.component.ts
index 3c9c639c2..636500f8c 100644
--- a/projects/nshmp-apps/src/app/internal/aws/check-haz-jobs/app.component.ts
+++ b/projects/nshmp-apps/src/app/internal/aws/check-haz-jobs/app.component.ts
@@ -6,8 +6,8 @@ import {
   NshmpTemplateControlPanelComponent,
   NshmpTemplateMainContentComponent,
 } from '@ghsc/nshmp-template';
+import {NavigationService} from 'projects/nshmp-apps/src/shared/services/navigation.service';
 import {internalApps} from 'projects/nshmp-apps/src/shared/utils/applications.utils';
-import {internalNavigation} from 'projects/nshmp-apps/src/shared/utils/navigation.utils';
 
 import {AboutComponent} from './components/about/about.component';
 import {ContentComponent} from './components/content/content.component';
@@ -38,12 +38,13 @@ import {AppService} from './services/app.service';
   templateUrl: './app.component.html',
 })
 export class AppComponent implements OnInit {
-  /** Navigation list for menu */
-  navigationList = internalNavigation();
   /** Application title */
   title = internalApps().aws.checkHazJobs.display;
 
-  constructor(private service: AppService) {}
+  constructor(
+    private service: AppService,
+    public navService: NavigationService,
+  ) {}
 
   ngOnInit() {
     this.service.init();
diff --git a/projects/nshmp-apps/src/app/internal/aws/dashboard/app.component.html b/projects/nshmp-apps/src/app/internal/aws/dashboard/app.component.html
index d8f47ed31..06099039d 100644
--- a/projects/nshmp-apps/src/app/internal/aws/dashboard/app.component.html
+++ b/projects/nshmp-apps/src/app/internal/aws/dashboard/app.component.html
@@ -1,4 +1,8 @@
-<nshmp-lib-ng-template #template [navigationList]="navigationList" [title]="">
+<nshmp-lib-ng-template
+  #template
+  [navigationList]="navService.internalNavigation()"
+  [title]=""
+>
   <!-- Dashboard -->
   <nshmp-lib-ng-dashboard [sections]="sections">
     <nshmp-lib-ng-dashboard-title>
diff --git a/projects/nshmp-apps/src/app/internal/aws/dashboard/app.component.ts b/projects/nshmp-apps/src/app/internal/aws/dashboard/app.component.ts
index c1faedc1f..1c45918b5 100644
--- a/projects/nshmp-apps/src/app/internal/aws/dashboard/app.component.ts
+++ b/projects/nshmp-apps/src/app/internal/aws/dashboard/app.component.ts
@@ -10,10 +10,7 @@ import {
   NshmpLibNgDashboardTitleComponent,
   NshmpLibNgTemplateComponent,
 } from '@ghsc/nshmp-lib-ng/nshmp';
-import {
-  internalAwsApps,
-  internalNavigation,
-} from 'projects/nshmp-apps/src/shared/utils/navigation.utils';
+import {NavigationService} from 'projects/nshmp-apps/src/shared/services/navigation.service';
 
 @Component({
   imports: [
@@ -29,18 +26,19 @@ import {
   templateUrl: './app.component.html',
 })
 export class AppComponent {
-  /** Navigation list for menu */
-  navigationList = internalNavigation();
-
   sections: ApplicationSections[] = [
     {
       gridClass: 'grid-col-10',
       sections: [
         {
-          applications: internalAwsApps().map(navigation => ({navigation})),
+          applications: this.navService
+            .internalAwsApps()
+            .map(navigation => ({navigation})),
           gridClass: 'grid-col-12 tablet-lg:grid-col-8 grid-offset-1',
         },
       ],
     },
   ];
+
+  constructor(public navService: NavigationService) {}
 }
diff --git a/projects/nshmp-apps/src/app/internal/aws/haz-job-history/app.component.html b/projects/nshmp-apps/src/app/internal/aws/haz-job-history/app.component.html
index e3c04045a..c4dd32052 100644
--- a/projects/nshmp-apps/src/app/internal/aws/haz-job-history/app.component.html
+++ b/projects/nshmp-apps/src/app/internal/aws/haz-job-history/app.component.html
@@ -1,4 +1,7 @@
-<nshmp-lib-ng-template [navigationList]="navigationList" [title]="title">
+<nshmp-lib-ng-template
+  [navigationList]="navService.internalNavigation()"
+  [title]="title"
+>
   <nshmp-template-content-container [showSettingsPanel]="false">
     <nshmp-template-control-panel>
       <app-control-panel />
diff --git a/projects/nshmp-apps/src/app/internal/aws/haz-job-history/app.component.ts b/projects/nshmp-apps/src/app/internal/aws/haz-job-history/app.component.ts
index c40822124..da1a55da9 100644
--- a/projects/nshmp-apps/src/app/internal/aws/haz-job-history/app.component.ts
+++ b/projects/nshmp-apps/src/app/internal/aws/haz-job-history/app.component.ts
@@ -6,8 +6,8 @@ import {
   NshmpTemplateControlPanelComponent,
   NshmpTemplateMainContentComponent,
 } from '@ghsc/nshmp-template';
+import {NavigationService} from 'projects/nshmp-apps/src/shared/services/navigation.service';
 import {internalApps} from 'projects/nshmp-apps/src/shared/utils/applications.utils';
-import {internalNavigation} from 'projects/nshmp-apps/src/shared/utils/navigation.utils';
 
 import {AboutComponent} from './components/about/about.component';
 import {ContentComponent} from './components/content/content.component';
@@ -36,12 +36,13 @@ import {AppService} from './services/app.service';
   templateUrl: './app.component.html',
 })
 export class AppComponent implements OnInit {
-  /** Navigation list for menu */
-  navigationList = internalNavigation();
   /** Application title */
   title = internalApps().aws.hazJobHistory.display;
 
-  constructor(private service: AppService) {}
+  constructor(
+    private service: AppService,
+    public navService: NavigationService,
+  ) {}
 
   ngOnInit(): void {
     this.service.init();
diff --git a/projects/nshmp-apps/src/app/internal/aws/submit-haz-jobs/app.component.html b/projects/nshmp-apps/src/app/internal/aws/submit-haz-jobs/app.component.html
index 5a47eabf7..75c651b8c 100644
--- a/projects/nshmp-apps/src/app/internal/aws/submit-haz-jobs/app.component.html
+++ b/projects/nshmp-apps/src/app/internal/aws/submit-haz-jobs/app.component.html
@@ -1,4 +1,7 @@
-<nshmp-lib-ng-template [navigationList]="navigationList" [title]="title">
+<nshmp-lib-ng-template
+  [navigationList]="navService.internalNavigation()"
+  [title]="title"
+>
   <div class="app-content height-full">
     <app-content />
   </div>
diff --git a/projects/nshmp-apps/src/app/internal/aws/submit-haz-jobs/app.component.ts b/projects/nshmp-apps/src/app/internal/aws/submit-haz-jobs/app.component.ts
index c2149b8b0..1224e8dd3 100644
--- a/projects/nshmp-apps/src/app/internal/aws/submit-haz-jobs/app.component.ts
+++ b/projects/nshmp-apps/src/app/internal/aws/submit-haz-jobs/app.component.ts
@@ -1,8 +1,8 @@
 import {Component, OnInit} from '@angular/core';
 import {NshmpLibNgAboutPageComponent} from '@ghsc/nshmp-lib-ng/about';
 import {NshmpLibNgTemplateComponent} from '@ghsc/nshmp-lib-ng/nshmp';
+import {NavigationService} from 'projects/nshmp-apps/src/shared/services/navigation.service';
 import {internalApps} from 'projects/nshmp-apps/src/shared/utils/applications.utils';
-import {internalNavigation} from 'projects/nshmp-apps/src/shared/utils/navigation.utils';
 
 import {AboutComponent} from './components/about/about.component';
 import {ContentComponent} from './components/content/content.component';
@@ -27,12 +27,13 @@ import {AppService} from './services/app.service';
   templateUrl: './app.component.html',
 })
 export class AppComponent implements OnInit {
-  /** Navigation list for menu */
-  navigationList = internalNavigation();
   /** Application title */
   title = internalApps().aws.submitHazJobs.display;
 
-  constructor(private service: AppService) {}
+  constructor(
+    private service: AppService,
+    public navService: NavigationService,
+  ) {}
 
   ngOnInit(): void {
     this.service.getNshmTag();
diff --git a/projects/nshmp-apps/src/app/internal/aws/terminate-haz-jobs/app.component.html b/projects/nshmp-apps/src/app/internal/aws/terminate-haz-jobs/app.component.html
index 55a846566..751979d57 100644
--- a/projects/nshmp-apps/src/app/internal/aws/terminate-haz-jobs/app.component.html
+++ b/projects/nshmp-apps/src/app/internal/aws/terminate-haz-jobs/app.component.html
@@ -1,4 +1,7 @@
-<nshmp-lib-ng-template [navigationList]="navigationList" [title]="title">
+<nshmp-lib-ng-template
+  [navigationList]="navService.internalNavigation()"
+  [title]="title"
+>
   <div class="app-content">
     <app-content />
   </div>
diff --git a/projects/nshmp-apps/src/app/internal/aws/terminate-haz-jobs/app.component.ts b/projects/nshmp-apps/src/app/internal/aws/terminate-haz-jobs/app.component.ts
index c0d540ae6..340d11cb7 100644
--- a/projects/nshmp-apps/src/app/internal/aws/terminate-haz-jobs/app.component.ts
+++ b/projects/nshmp-apps/src/app/internal/aws/terminate-haz-jobs/app.component.ts
@@ -1,8 +1,8 @@
 import {Component, OnInit} from '@angular/core';
 import {NshmpLibNgAboutPageComponent} from '@ghsc/nshmp-lib-ng/about';
 import {NshmpLibNgTemplateComponent} from '@ghsc/nshmp-lib-ng/nshmp';
+import {NavigationService} from 'projects/nshmp-apps/src/shared/services/navigation.service';
 import {internalApps} from 'projects/nshmp-apps/src/shared/utils/applications.utils';
-import {internalNavigation} from 'projects/nshmp-apps/src/shared/utils/navigation.utils';
 
 import {AboutComponent} from './components/about/about.component';
 import {ContentComponent} from './components/content/content.component';
@@ -27,12 +27,13 @@ import {AppService} from './services/app.service';
   templateUrl: './app.component.html',
 })
 export class AppComponent implements OnInit {
-  /** Navigation list for menu */
-  navigationList = internalNavigation();
   /** Application title */
   title = internalApps().aws.terminateHazJobs.display;
 
-  constructor(private service: AppService) {}
+  constructor(
+    private service: AppService,
+    public navService: NavigationService,
+  ) {}
 
   ngOnInit(): void {
     this.service.init();
diff --git a/projects/nshmp-apps/src/app/internal/dashboard/app.component.html b/projects/nshmp-apps/src/app/internal/dashboard/app.component.html
index d4913aec9..75a1f4171 100644
--- a/projects/nshmp-apps/src/app/internal/dashboard/app.component.html
+++ b/projects/nshmp-apps/src/app/internal/dashboard/app.component.html
@@ -1,6 +1,6 @@
 <nshmp-lib-ng-template
   #template
-  [navigationList]="navigationList"
+  [navigationList]="navService.internalNavigation()"
   [title]="title"
 >
   <!-- Dashboard -->
diff --git a/projects/nshmp-apps/src/app/internal/dashboard/app.component.ts b/projects/nshmp-apps/src/app/internal/dashboard/app.component.ts
index 2158f3deb..19ed62473 100644
--- a/projects/nshmp-apps/src/app/internal/dashboard/app.component.ts
+++ b/projects/nshmp-apps/src/app/internal/dashboard/app.component.ts
@@ -10,10 +10,10 @@ import {
   NshmpLibNgDashboardTitleComponent,
   NshmpLibNgTemplateComponent,
 } from '@ghsc/nshmp-lib-ng/nshmp';
+import {NavigationService} from 'projects/nshmp-apps/src/shared/services/navigation.service';
 import {Subscription} from 'rxjs';
 
-import * as nav from '../../../shared/utils/navigation.utils';
-import {AuthService} from '../shared/services/auth.service';
+import {AuthService} from '../../../shared/services/auth.service';
 
 /**
  * Development dashboard showing links to development applications.
@@ -32,19 +32,16 @@ import {AuthService} from '../shared/services/auth.service';
   templateUrl: './app.component.html',
 })
 export class AppComponent implements OnInit, OnDestroy {
-  /** Navigation list for menu */
-  navigationList = nav.internalNavigation();
-
   title = 'Internal Applications';
 
-  /** AWS applications */
-  private awsApps = nav.internalAwsApps();
-
   sections: ApplicationSections[] = [];
 
   private sub: Subscription;
 
-  constructor(private authService: AuthService) {}
+  constructor(
+    public navService: NavigationService,
+    private authService: AuthService,
+  ) {}
 
   ngOnInit(): void {
     this.sub = this.authService.isAuthorized().subscribe(() => {
@@ -52,7 +49,9 @@ export class AppComponent implements OnInit, OnDestroy {
         {
           sections: [
             {
-              applications: this.awsApps.map(navigation => ({navigation})),
+              applications: this.navService
+                .internalAwsApps()
+                .map(navigation => ({navigation})),
             },
           ],
         },
diff --git a/projects/nshmp-apps/src/app/internal/internal.routes.ts b/projects/nshmp-apps/src/app/internal/internal.routes.ts
index 899ea06cf..ebc76efb3 100644
--- a/projects/nshmp-apps/src/app/internal/internal.routes.ts
+++ b/projects/nshmp-apps/src/app/internal/internal.routes.ts
@@ -1,7 +1,7 @@
 import {Routes} from '@angular/router';
 
+import {networkGuard} from '../../shared/guards/network.guard';
 import {devAwsRoutes} from './aws/aws.routes';
-import {networkGuard} from './shared/guards/network.guard';
 
 /**
  * Internal application routes.
diff --git a/projects/nshmp-apps/src/app/ncm/dashboard/app.component.html b/projects/nshmp-apps/src/app/ncm/dashboard/app.component.html
index 4e34e88b8..d4bfaae76 100644
--- a/projects/nshmp-apps/src/app/ncm/dashboard/app.component.html
+++ b/projects/nshmp-apps/src/app/ncm/dashboard/app.component.html
@@ -1,6 +1,6 @@
 <nshmp-lib-ng-template
   #template
-  [navigationList]="navigationList"
+  [navigationList]="navService.navigationList()"
   [title]="title"
 >
   <!-- Dashboard -->
diff --git a/projects/nshmp-apps/src/app/ncm/dashboard/app.component.ts b/projects/nshmp-apps/src/app/ncm/dashboard/app.component.ts
index 8faa370cb..19a36749d 100644
--- a/projects/nshmp-apps/src/app/ncm/dashboard/app.component.ts
+++ b/projects/nshmp-apps/src/app/ncm/dashboard/app.component.ts
@@ -10,10 +10,7 @@ import {
   NshmpLibNgDashboardTitleComponent,
   NshmpLibNgTemplateComponent,
 } from '@ghsc/nshmp-lib-ng/nshmp';
-import {
-  navigation,
-  ncmApps,
-} from 'projects/nshmp-apps/src/shared/utils/navigation.utils';
+import {NavigationService} from 'projects/nshmp-apps/src/shared/services/navigation.service';
 
 @Component({
   imports: [
@@ -29,9 +26,6 @@ import {
   templateUrl: './app.component.html',
 })
 export class AppComponent {
-  /** Navigation list for menu */
-  navigationList = navigation();
-
   title = 'NCM Applications';
 
   sections: ApplicationSections[] = [
@@ -39,10 +33,14 @@ export class AppComponent {
       gridClass: 'grid-col-10',
       sections: [
         {
-          applications: ncmApps().map(navigation => ({navigation})),
+          applications: this.navService
+            .ncmApps()
+            .map(navigation => ({navigation})),
           gridClass: 'grid-col-12 tablet-lg:grid-col-8 grid-offset-1',
         },
       ],
     },
   ];
+
+  constructor(public navService: NavigationService) {}
 }
diff --git a/projects/nshmp-apps/src/app/ncm/geophysical-profiles/app.component.html b/projects/nshmp-apps/src/app/ncm/geophysical-profiles/app.component.html
index 3f2a7bef6..02e1d8c0b 100644
--- a/projects/nshmp-apps/src/app/ncm/geophysical-profiles/app.component.html
+++ b/projects/nshmp-apps/src/app/ncm/geophysical-profiles/app.component.html
@@ -1,4 +1,7 @@
-<nshmp-lib-ng-template [navigationList]="navigationList" [title]="title">
+<nshmp-lib-ng-template
+  [navigationList]="navService.navigationList()"
+  [title]="title"
+>
   <nshmp-template-content-container>
     <nshmp-template-control-panel>
       <app-control-panel />
diff --git a/projects/nshmp-apps/src/app/ncm/geophysical-profiles/app.component.ts b/projects/nshmp-apps/src/app/ncm/geophysical-profiles/app.component.ts
index c1327eec0..cff11e600 100644
--- a/projects/nshmp-apps/src/app/ncm/geophysical-profiles/app.component.ts
+++ b/projects/nshmp-apps/src/app/ncm/geophysical-profiles/app.component.ts
@@ -7,8 +7,8 @@ import {
   NshmpTemplateMainContentComponent,
   NshmpTemplateSettingsComponent,
 } from '@ghsc/nshmp-template';
+import {NavigationService} from 'projects/nshmp-apps/src/shared/services/navigation.service';
 import {apps} from 'projects/nshmp-apps/src/shared/utils/applications.utils';
-import {navigation} from 'projects/nshmp-apps/src/shared/utils/navigation.utils';
 
 import {AboutComponent} from './components/about/about.component';
 import {ContentComponent} from './components/content/content.component';
@@ -34,13 +34,13 @@ import {AppService} from './services/app.service';
   templateUrl: './app.component.html',
 })
 export class AppComponent implements OnInit {
-  /** Navigation list for menu */
-  navigationList = navigation();
-
   /** Application title */
   title = apps().ncm.geophysicalProfiles.display;
 
-  constructor(private service: AppService) {}
+  constructor(
+    private service: AppService,
+    public navService: NavigationService,
+  ) {}
 
   ngOnInit(): void {
     this.service.init();
diff --git a/projects/nshmp-apps/src/app/source/dashboard/app.component.html b/projects/nshmp-apps/src/app/source/dashboard/app.component.html
index be11ff361..424667399 100644
--- a/projects/nshmp-apps/src/app/source/dashboard/app.component.html
+++ b/projects/nshmp-apps/src/app/source/dashboard/app.component.html
@@ -1,6 +1,6 @@
 <nshmp-lib-ng-template
   #template
-  [navigationList]="navigationList"
+  [navigationList]="navService.navigationList()"
   [title]="title"
 >
   <!-- Dashboard -->
diff --git a/projects/nshmp-apps/src/app/source/dashboard/app.component.ts b/projects/nshmp-apps/src/app/source/dashboard/app.component.ts
index 8c9fda7c6..aa77e86d0 100644
--- a/projects/nshmp-apps/src/app/source/dashboard/app.component.ts
+++ b/projects/nshmp-apps/src/app/source/dashboard/app.component.ts
@@ -10,10 +10,7 @@ import {
   NshmpLibNgDashboardTitleComponent,
   NshmpLibNgTemplateComponent,
 } from '@ghsc/nshmp-lib-ng/nshmp';
-import {
-  navigation,
-  sourceModelApps,
-} from 'projects/nshmp-apps/src/shared/utils/navigation.utils';
+import {NavigationService} from 'projects/nshmp-apps/src/shared/services/navigation.service';
 
 @Component({
   imports: [
@@ -29,9 +26,6 @@ import {
   templateUrl: './app.component.html',
 })
 export class AppComponent {
-  /** Navigation list for menu */
-  navigationList = navigation();
-
   title = 'Source Model Applications';
 
   sections: ApplicationSections[] = [
@@ -39,10 +33,14 @@ export class AppComponent {
       gridClass: 'grid-col-10',
       sections: [
         {
-          applications: sourceModelApps().map(navigation => ({navigation})),
+          applications: this.navService
+            .sourceModelApps()
+            .map(navigation => ({navigation})),
           gridClass: 'grid-col-12 tablet-lg:grid-col-8 grid-offset-1',
         },
       ],
     },
   ];
+
+  constructor(public navService: NavigationService) {}
 }
diff --git a/projects/nshmp-apps/src/app/source/mfd/app.component.html b/projects/nshmp-apps/src/app/source/mfd/app.component.html
index b7c70d9bd..e78a5ee9d 100644
--- a/projects/nshmp-apps/src/app/source/mfd/app.component.html
+++ b/projects/nshmp-apps/src/app/source/mfd/app.component.html
@@ -1,4 +1,7 @@
-<nshmp-lib-ng-template [navigationList]="navigationList" [title]="title">
+<nshmp-lib-ng-template
+  [navigationList]="navService.navigationList()"
+  [title]="title"
+>
   <nshmp-template-content-container>
     <nshmp-template-control-panel>
       <app-control-panel />
diff --git a/projects/nshmp-apps/src/app/source/mfd/app.component.ts b/projects/nshmp-apps/src/app/source/mfd/app.component.ts
index 509376c6d..1743891d7 100644
--- a/projects/nshmp-apps/src/app/source/mfd/app.component.ts
+++ b/projects/nshmp-apps/src/app/source/mfd/app.component.ts
@@ -9,8 +9,8 @@ import {
   NshmpTemplateService,
   NshmpTemplateSettingsComponent,
 } from '@ghsc/nshmp-template';
+import {NavigationService} from 'projects/nshmp-apps/src/shared/services/navigation.service';
 import {apps} from 'projects/nshmp-apps/src/shared/utils/applications.utils';
-import {navigation} from 'projects/nshmp-apps/src/shared/utils/navigation.utils';
 
 import {AboutComponent} from './components/about/about.component';
 import {ContentComponent} from './components/content/content.component';
@@ -43,14 +43,13 @@ import {AppService} from './services/app.service';
   templateUrl: './app.component.html',
 })
 export class AppComponent implements OnInit {
-  /** Navigation list for menu */
-  navigationList = navigation();
   /** Application title */
   title = apps().source.mfd.display;
 
   constructor(
     public nshmpTemplateService: NshmpTemplateService,
     public service: AppService,
+    public navService: NavigationService,
   ) {}
 
   ngOnInit(): void {
diff --git a/projects/nshmp-apps/src/app/source/model-maps/app.component.html b/projects/nshmp-apps/src/app/source/model-maps/app.component.html
index 85fc7ab01..a133f12e5 100644
--- a/projects/nshmp-apps/src/app/source/model-maps/app.component.html
+++ b/projects/nshmp-apps/src/app/source/model-maps/app.component.html
@@ -1,4 +1,7 @@
-<nshmp-lib-ng-template [navigationList]="navigationList" [title]="title">
+<nshmp-lib-ng-template
+  [navigationList]="navService.navigationList()"
+  [title]="title"
+>
   <nshmp-template-content-container>
     <nshmp-template-control-panel>
       <app-control-panel />
diff --git a/projects/nshmp-apps/src/app/source/model-maps/app.component.ts b/projects/nshmp-apps/src/app/source/model-maps/app.component.ts
index 8e75d6ec5..fdf1122c0 100644
--- a/projects/nshmp-apps/src/app/source/model-maps/app.component.ts
+++ b/projects/nshmp-apps/src/app/source/model-maps/app.component.ts
@@ -9,9 +9,8 @@ import {
   NshmpTemplateMainContentComponent,
   NshmpTemplateSettingsComponent,
 } from '@ghsc/nshmp-template';
+import {NavigationService} from 'projects/nshmp-apps/src/shared/services/navigation.service';
 import {apps} from 'projects/nshmp-apps/src/shared/utils/applications.utils';
-import {navigation} from 'projects/nshmp-apps/src/shared/utils/navigation.utils';
-import {Subscription} from 'rxjs';
 
 import {AboutComponent} from './components/about/about.component';
 import {ControlPanelComponent} from './components/control-panel/control-panel.component';
@@ -48,15 +47,12 @@ import {AppService} from './services/app.service';
   templateUrl: './app.component.html',
 })
 export class AppComponent implements OnInit {
-  /** Subscirption on controls change */
-  controlsSubscription: Subscription;
-  /** Navigation list for meny */
-  navigationList = navigation();
   /** Application title */
   title = apps().source.data.display;
 
   constructor(
     public service: AppService,
+    public navService: NavigationService,
     private headerService: HeaderService,
   ) {
     effect(() => {
diff --git a/projects/nshmp-apps/src/app/source/model-maps/services/app.service.ts b/projects/nshmp-apps/src/app/source/model-maps/services/app.service.ts
index 002eac124..296083248 100644
--- a/projects/nshmp-apps/src/app/source/model-maps/services/app.service.ts
+++ b/projects/nshmp-apps/src/app/source/model-maps/services/app.service.ts
@@ -40,7 +40,7 @@ import * as L from 'leaflet';
 import {environment} from 'projects/nshmp-apps/src/environments/environment';
 import {AppServiceModel} from 'projects/nshmp-apps/src/shared/models/app-service.model';
 import {apps} from 'projects/nshmp-apps/src/shared/utils/applications.utils';
-import {catchError, forkJoin, map, mergeMap, Observable} from 'rxjs';
+import {catchError, forkJoin, map, mergeMap, Observable, of} from 'rxjs';
 
 import {ControlForm, LatestEarthquakeTime} from '../models/control-form.model';
 import {EarthquakeFeatureProperties} from '../models/earthquake-props.model';
@@ -576,7 +576,7 @@ export class AppService implements AppServiceModel<AppState, ControlForm> {
           this.initialFormSet();
           spinnerRef.close();
           console.error(error);
-          return [];
+          return of();
         }),
       )
       .subscribe(() => {
diff --git a/projects/nshmp-apps/src/app/source/rates/app.component.html b/projects/nshmp-apps/src/app/source/rates/app.component.html
index b7c70d9bd..e78a5ee9d 100644
--- a/projects/nshmp-apps/src/app/source/rates/app.component.html
+++ b/projects/nshmp-apps/src/app/source/rates/app.component.html
@@ -1,4 +1,7 @@
-<nshmp-lib-ng-template [navigationList]="navigationList" [title]="title">
+<nshmp-lib-ng-template
+  [navigationList]="navService.navigationList()"
+  [title]="title"
+>
   <nshmp-template-content-container>
     <nshmp-template-control-panel>
       <app-control-panel />
diff --git a/projects/nshmp-apps/src/app/source/rates/app.component.ts b/projects/nshmp-apps/src/app/source/rates/app.component.ts
index 7cfe96535..2279f0162 100644
--- a/projects/nshmp-apps/src/app/source/rates/app.component.ts
+++ b/projects/nshmp-apps/src/app/source/rates/app.component.ts
@@ -8,8 +8,8 @@ import {
   NshmpTemplateMainContentComponent,
   NshmpTemplateSettingsComponent,
 } from '@ghsc/nshmp-template';
+import {NavigationService} from 'projects/nshmp-apps/src/shared/services/navigation.service';
 import {apps} from 'projects/nshmp-apps/src/shared/utils/applications.utils';
-import {navigation} from 'projects/nshmp-apps/src/shared/utils/navigation.utils';
 
 import {AboutComponent} from './components/about/about.component';
 import {ContentComponent} from './components/content/content.component';
@@ -36,12 +36,13 @@ import {AppService} from './services/app.service';
   templateUrl: './app.component.html',
 })
 export class AppComponent implements OnInit {
-  /** Navigation list for menu */
-  navigationList = navigation();
   /** Application title */
   title = apps().source.rateAndProbability.display;
 
-  constructor(public service: AppService) {}
+  constructor(
+    public service: AppService,
+    public navService: NavigationService,
+  ) {}
 
   ngOnInit(): void {
     this.service.init();
diff --git a/projects/nshmp-ws/src/app/services/components/content/content.component.ts b/projects/nshmp-ws/src/app/services/components/content/content.component.ts
index 5881897a1..ba0e9d528 100644
--- a/projects/nshmp-ws/src/app/services/components/content/content.component.ts
+++ b/projects/nshmp-ws/src/app/services/components/content/content.component.ts
@@ -21,11 +21,8 @@ import {HazardService} from '@ghsc/nshmp-lib-ng/hazard';
 import {NshmpService} from '@ghsc/nshmp-lib-ng/nshmp';
 import {NshmpTemplateService} from '@ghsc/nshmp-template';
 import {environment} from 'projects/nshmp-apps/src/environments/environment';
+import {NavigationService} from 'projects/nshmp-apps/src/shared/services/navigation.service';
 import {apps} from 'projects/nshmp-apps/src/shared/utils/applications.utils';
-import {
-  gmmApps,
-  ncmApps,
-} from 'projects/nshmp-apps/src/shared/utils/navigation.utils';
 import {map, Observable, of} from 'rxjs';
 
 import {QueryParameters} from '../../models/query-parameters.model';
@@ -160,7 +157,7 @@ export class ContentComponent implements AfterViewInit {
     },
     // Data services
     {
-      applicationsUsedIn: [...gmmApps(), APPS.source.data],
+      applicationsUsedIn: [...this.navService.gmmApps(), APPS.source.data],
       id: ServiceGroupId.NSHMP_WS,
       images: [
         {
@@ -223,7 +220,7 @@ export class ContentComponent implements AfterViewInit {
     },
     // NCM services
     {
-      applicationsUsedIn: [...ncmApps()],
+      applicationsUsedIn: [...this.navService.ncmApps()],
       id: ServiceGroupId.NCM,
       images: [
         {
@@ -275,6 +272,7 @@ export class ContentComponent implements AfterViewInit {
 
   constructor(
     public templateService: NshmpTemplateService,
+    private navService: NavigationService,
     private el: ElementRef<HTMLDivElement>,
     private route: ActivatedRoute,
     private router: Router,
-- 
GitLab


From 320ccef22ae820e51091725438be3e3e48c8859b Mon Sep 17 00:00:00 2001
From: Brandon Clayton <bclayton@usgs.gov>
Date: Tue, 18 Mar 2025 13:32:59 -0600
Subject: [PATCH 2/6] move

---
 .../shared/guards/network.guard.ts            |  0
 .../shared/services/auth.service.ts           | 28 ++++++++++++++-----
 2 files changed, 21 insertions(+), 7 deletions(-)
 rename projects/nshmp-apps/src/{app/internal => }/shared/guards/network.guard.ts (100%)
 rename projects/nshmp-apps/src/{app/internal => }/shared/services/auth.service.ts (59%)

diff --git a/projects/nshmp-apps/src/app/internal/shared/guards/network.guard.ts b/projects/nshmp-apps/src/shared/guards/network.guard.ts
similarity index 100%
rename from projects/nshmp-apps/src/app/internal/shared/guards/network.guard.ts
rename to projects/nshmp-apps/src/shared/guards/network.guard.ts
diff --git a/projects/nshmp-apps/src/app/internal/shared/services/auth.service.ts b/projects/nshmp-apps/src/shared/services/auth.service.ts
similarity index 59%
rename from projects/nshmp-apps/src/app/internal/shared/services/auth.service.ts
rename to projects/nshmp-apps/src/shared/services/auth.service.ts
index 7a39e67e4..4ad61d7f0 100644
--- a/projects/nshmp-apps/src/app/internal/shared/services/auth.service.ts
+++ b/projects/nshmp-apps/src/shared/services/auth.service.ts
@@ -1,8 +1,13 @@
 import {HttpClient} from '@angular/common/http';
 import {Injectable} from '@angular/core';
-import {NshmpService, SpinnerService} from '@ghsc/nshmp-lib-ng/nshmp';
+import {MatDialogRef} from '@angular/material/dialog';
+import {
+  NshmpLibNgSpinnerComponent,
+  NshmpService,
+  SpinnerService,
+} from '@ghsc/nshmp-lib-ng/nshmp';
 import {environment} from 'projects/nshmp-apps/src/environments/environment';
-import {catchError, map} from 'rxjs';
+import {catchError, map, Observable} from 'rxjs';
 
 interface AuthResponse {
   isAuthorized: boolean;
@@ -24,14 +29,23 @@ export class AuthService {
     private nshmpService: NshmpService,
   ) {}
 
-  isAuthorized() {
-    const ref = this.spinnerService.show('Checking USGS network ...');
+  /**
+   * Check if user is on USGS network for internal applications.
+   *
+   * @param required Whether the user must be on the network
+   */
+  isAuthorized(required = true): Observable<boolean> {
+    let ref: MatDialogRef<NshmpLibNgSpinnerComponent> | undefined = undefined;
+
+    if (required) {
+      ref = this.spinnerService.show('Checking USGS network ...');
+    }
 
     return this.http.get<AuthResponse>(this.url).pipe(
       map(response => {
-        ref.close();
+        ref?.close();
 
-        if (!response.isAuthorized) {
+        if (!response.isAuthorized && required) {
           this.nshmpService.throwError$(
             new Error(
               'Must be on USGS network to access internal applications',
@@ -42,7 +56,7 @@ export class AuthService {
         return response.isAuthorized;
       }),
       catchError((error: Error) => {
-        ref.close();
+        ref?.close();
         return this.nshmpService.throwError$(error);
       }),
     );
-- 
GitLab


From 7c165f30ce6c3be1df8b929f0afef7f4179178a9 Mon Sep 17 00:00:00 2001
From: Brandon Clayton <bclayton@usgs.gov>
Date: Tue, 18 Mar 2025 13:33:11 -0600
Subject: [PATCH 3/6] add nav service

---
 .../src/shared/services/navigation.service.ts | 216 ++++++++++++++++++
 1 file changed, 216 insertions(+)
 create mode 100644 projects/nshmp-apps/src/shared/services/navigation.service.ts

diff --git a/projects/nshmp-apps/src/shared/services/navigation.service.ts b/projects/nshmp-apps/src/shared/services/navigation.service.ts
new file mode 100644
index 000000000..70328b792
--- /dev/null
+++ b/projects/nshmp-apps/src/shared/services/navigation.service.ts
@@ -0,0 +1,216 @@
+import {Injectable, Signal, signal} from '@angular/core';
+import {Navigation, NavigationList} from '@ghsc/nshmp-template';
+import {catchError, map, of} from 'rxjs';
+
+import * as ApplicationsUtils from '../utils/applications.utils';
+import {AuthService} from './auth.service';
+
+const APPS = ApplicationsUtils.apps();
+const DEV_APPS = ApplicationsUtils.devApps();
+const INTERNAL_APPS = ApplicationsUtils.internalApps();
+
+@Injectable({
+  providedIn: 'root',
+})
+export class NavigationService {
+  private navListSignal = signal<NavigationList[]>([]);
+  private devNavListSignal = signal<NavigationList[]>(this.devNavigationList());
+  private internalNavListSignal = signal<NavigationList[]>(
+    this.internalNavigationList(),
+  );
+
+  constructor(private authService: AuthService) {
+    this.navigation();
+  }
+
+  /**
+   * Returns the list of design map application.
+   */
+  designMapApps(): Navigation[] {
+    return Object.values(APPS.designMaps) as Navigation[];
+  }
+
+  devGmmApps(): Navigation[] {
+    return Object.values(DEV_APPS.gmm) as Navigation[];
+  }
+
+  devHazardApps(): Navigation[] {
+    return Object.values(DEV_APPS.hazard) as Navigation[];
+  }
+
+  /**
+   * Returns the list development main applications.
+   */
+  devMainApps(): Navigation[] {
+    return [
+      DEV_APPS.math.exceedanceExplorer,
+      DEV_APPS.hazard.dynamicCompare,
+      DEV_APPS.gmm.hangingWallEffects,
+    ];
+  }
+
+  devMathApps(): Navigation[] {
+    return Object.values(DEV_APPS.math) as Navigation[];
+  }
+
+  /**
+   * Returns the drop down navigation menu for development applications.
+   */
+  get devNavigation(): Signal<NavigationList[]> {
+    return this.devNavListSignal.asReadonly();
+  }
+
+  /**
+   * Returns the list of ground motion model applications.
+   */
+  gmmApps(): Navigation[] {
+    return Object.values(APPS.gmm) as Navigation[];
+  }
+
+  /**
+   * Returns list of hazard applications.
+   */
+  hazardApps(): Navigation[] {
+    return Object.values(APPS.hazard) as Navigation[];
+  }
+
+  /**
+   * Returns the list of AWS applications.
+   */
+  internalAwsApps(): Navigation[] {
+    return Object.values(INTERNAL_APPS.aws) as Navigation[];
+  }
+
+  internalMainApps(): Navigation[] {
+    return this.internalAwsApps();
+  }
+
+  get internalNavigation(): Signal<NavigationList[]> {
+    return this.internalNavListSignal.asReadonly();
+  }
+
+  get navigationList(): Signal<NavigationList[]> {
+    return this.navListSignal;
+  }
+
+  /**
+   * Returns the list services apps.
+   */
+  serviceApps(): Navigation[] {
+    return [APPS.services];
+  }
+
+  /**
+   * Returns the list of NCM appliations.
+   */
+  ncmApps(): Navigation[] {
+    return Object.values(APPS.ncm) as Navigation[];
+  }
+
+  /**
+   * Returns the list of source model applicaitons.
+   */
+  sourceModelApps(): Navigation[] {
+    return Object.values(APPS.source) as Navigation[];
+  }
+
+  private devNavigationList(): NavigationList[] {
+    const devNavigation: NavigationList[] = [
+      {
+        navigation: [DEV_APPS.dashboard],
+      },
+      {
+        navigation: this.devHazardApps(),
+        subHeader: 'Hazard',
+      },
+      {
+        navigation: this.devGmmApps(),
+        subHeader: 'Ground Motion Models',
+      },
+      {
+        navigation: this.devMathApps(),
+        subHeader: 'Math',
+      },
+    ];
+
+    return devNavigation;
+  }
+
+  private internalNavigationList(): NavigationList[] {
+    const internalNavigation: NavigationList[] = [
+      {
+        navigation: [INTERNAL_APPS.dashboard],
+      },
+      {
+        navigation: this.internalAwsApps(),
+        subHeader: 'AWS',
+      },
+    ];
+
+    return [...internalNavigation];
+  }
+
+  /**
+   * Get navigation.
+   */
+  private navigation() {
+    const navigation: NavigationList[] = [
+      {
+        navigation: [APPS.dashboard],
+      },
+      {
+        navigation: this.hazardApps(),
+        subHeader: 'Hazard',
+      },
+      {
+        navigation: this.sourceModelApps(),
+        subHeader: 'Source Models',
+      },
+      {
+        navigation: this.gmmApps(),
+        subHeader: 'Ground Motion Models',
+      },
+      {
+        navigation: this.designMapApps(),
+        subHeader: 'Design Map',
+      },
+      {
+        navigation: this.ncmApps(),
+        subHeader: 'National Crustal Model',
+      },
+      {
+        navigation: [DEV_APPS.dashboard, ...this.devMainApps()],
+        subHeader: 'Development',
+      },
+    ];
+
+    this.authService
+      .isAuthorized(false)
+      .pipe(
+        map(isInternal => {
+          if (isInternal) {
+            navigation.push({
+              navigation: this.internalMainApps(),
+              subHeader: 'Internal',
+            });
+          }
+
+          navigation.push({
+            navigation: [APPS.services],
+          });
+
+          return navigation;
+        }),
+        catchError(() => {
+          navigation.push({
+            navigation: [APPS.services],
+          });
+          this.navListSignal.set(navigation);
+          return of();
+        }),
+      )
+      .subscribe(navList => {
+        this.navListSignal.set(navList);
+      });
+  }
+}
-- 
GitLab


From 67187cbc8c6471c5b8ab797a1936a1c11f44fa09 Mon Sep 17 00:00:00 2001
From: Brandon Clayton <bclayton@usgs.gov>
Date: Tue, 18 Mar 2025 13:33:17 -0600
Subject: [PATCH 4/6] remove utils

---
 .../src/shared/utils/navigation.utils.ts      | 162 ------------------
 1 file changed, 162 deletions(-)
 delete mode 100644 projects/nshmp-apps/src/shared/utils/navigation.utils.ts

diff --git a/projects/nshmp-apps/src/shared/utils/navigation.utils.ts b/projects/nshmp-apps/src/shared/utils/navigation.utils.ts
deleted file mode 100644
index bdc7a1a02..000000000
--- a/projects/nshmp-apps/src/shared/utils/navigation.utils.ts
+++ /dev/null
@@ -1,162 +0,0 @@
-import {Navigation, NavigationList} from '@ghsc/nshmp-template';
-
-import * as ApplicationsUtils from './applications.utils';
-
-const APPS = ApplicationsUtils.apps();
-const DEV_APPS = ApplicationsUtils.devApps();
-const INTERNAL_APPS = ApplicationsUtils.internalApps();
-
-/**
- * Returns the list of design map application.
- */
-export function designMapApps(): Navigation[] {
-  return Object.values(APPS.designMaps) as Navigation[];
-}
-
-export function devGmmApps(): Navigation[] {
-  return Object.values(DEV_APPS.gmm) as Navigation[];
-}
-
-export function devHazardApps(): Navigation[] {
-  return Object.values(DEV_APPS.hazard) as Navigation[];
-}
-
-/**
- * Returns the list development main applications.
- */
-export function devMainApps(): Navigation[] {
-  return [
-    DEV_APPS.math.exceedanceExplorer,
-    DEV_APPS.hazard.dynamicCompare,
-    DEV_APPS.gmm.hangingWallEffects,
-  ];
-}
-
-export function devMathApps(): Navigation[] {
-  return Object.values(DEV_APPS.math) as Navigation[];
-}
-
-/**
- * Returns the drop down navigation menu for development applications.
- */
-export function devNavigation(): NavigationList[] {
-  const devNavigation: NavigationList[] = [
-    {
-      navigation: [DEV_APPS.dashboard],
-    },
-    {
-      navigation: devHazardApps(),
-      subHeader: 'Hazard',
-    },
-    {
-      navigation: devGmmApps(),
-      subHeader: 'Ground Motion Models',
-    },
-    {
-      navigation: devMathApps(),
-      subHeader: 'Math',
-    },
-  ];
-
-  return [...devNavigation];
-}
-
-/**
- * Returns the list of ground motion model applications.
- */
-export function gmmApps(): Navigation[] {
-  return Object.values(APPS.gmm) as Navigation[];
-}
-
-/**
- * Returns list of hazard applications.
- */
-export function hazardApps(): Navigation[] {
-  return Object.values(APPS.hazard) as Navigation[];
-}
-
-/**
- * Returns the list of AWS applications.
- */
-export function internalAwsApps(): Navigation[] {
-  return Object.values(INTERNAL_APPS.aws) as Navigation[];
-}
-
-export function internalMainApps(): Navigation[] {
-  return internalAwsApps();
-}
-
-export function internalNavigation(): NavigationList[] {
-  const internalNavigation: NavigationList[] = [
-    {
-      navigation: [INTERNAL_APPS.dashboard],
-    },
-    {
-      navigation: internalAwsApps(),
-      subHeader: 'AWS',
-    },
-  ];
-
-  return [...internalNavigation];
-}
-
-/**
- * Returns the list services apps.
- */
-export function serviceApps(): Navigation[] {
-  return [APPS.services];
-}
-
-/**
- * Returns drop down navigation menu of applications.
- */
-export function navigation(): NavigationList[] {
-  const navigation: NavigationList[] = [
-    {
-      navigation: [APPS.dashboard],
-    },
-    {
-      navigation: hazardApps(),
-      subHeader: 'Hazard',
-    },
-    {
-      navigation: sourceModelApps(),
-      subHeader: 'Source Models',
-    },
-    {
-      navigation: gmmApps(),
-      subHeader: 'Ground Motion Models',
-    },
-    {
-      navigation: designMapApps(),
-      subHeader: 'Design Map',
-    },
-    {
-      navigation: ncmApps(),
-      subHeader: 'National Crustal Model',
-    },
-    {
-      navigation: [DEV_APPS.dashboard, ...devMainApps()],
-      subHeader: 'Development',
-    },
-    {
-      navigation: [APPS.services],
-    },
-  ];
-
-  return [...navigation];
-}
-
-/**
- * Returns the list of NCM appliations.
- */
-export function ncmApps(): Navigation[] {
-  return Object.values(APPS.ncm) as Navigation[];
-}
-
-/**
- * Returns the list of source model applicaitons.
- */
-export function sourceModelApps(): Navigation[] {
-  return Object.values(APPS.source) as Navigation[];
-}
-- 
GitLab


From 07bf2eaa6c0e785bb129b469ab64edc55c9deb94 Mon Sep 17 00:00:00 2001
From: Brandon Clayton <bclayton@usgs.gov>
Date: Tue, 18 Mar 2025 13:38:08 -0600
Subject: [PATCH 5/6] remove nav from test

---
 .../integration/dashboard/dashboard.spec.ts   | 15 +-----
 .../dev/dashboard/dev-dashboard.spec.ts       | 15 +-----
 .../exceedance-explorer.spec.ts               |  3 +-
 .../gmm/distance/gmm-distance.spec.ts         |  3 +-
 .../gmm/magnitude/gmm-magnitude.spec.ts       |  3 +-
 .../gmm/spectra/response-spectra.spec.ts      |  3 +-
 .../integration/hazard/disagg/disagg.spec.ts  |  3 +-
 .../hazard/dynamic/dynamic-hazard.spec.ts     |  3 +-
 .../hazard/static/static-hazard.spec.ts       |  3 +-
 .../integration/services/services.spec.ts     |  3 +-
 .../source/data/data-mapping.spec.ts          |  3 +-
 .../integration/source/mfd/mfd.spec.ts        |  3 +-
 .../cypress/utils/dashboard.utils.ts          | 38 +-------------
 .../cypress/utils/nshmp-template.utils.ts     | 50 +------------------
 14 files changed, 16 insertions(+), 132 deletions(-)

diff --git a/projects/nshmp-apps/cypress/integration/dashboard/dashboard.spec.ts b/projects/nshmp-apps/cypress/integration/dashboard/dashboard.spec.ts
index 909100aab..958fad149 100644
--- a/projects/nshmp-apps/cypress/integration/dashboard/dashboard.spec.ts
+++ b/projects/nshmp-apps/cypress/integration/dashboard/dashboard.spec.ts
@@ -1,4 +1,3 @@
-import {navigation} from '../../../src/shared/utils/navigation.utils';
 import * as utils from '../../utils';
 
 describe('Dashboard', () => {
@@ -8,20 +7,10 @@ describe('Dashboard', () => {
   });
 
   describe('Check nshmp-template', () => {
-    utils.hasNshmpTemplate(navigation());
+    utils.hasNshmpTemplate();
   });
 
   describe('Check dashboard', () => {
-    const nav = navigation().map(navItem => {
-      const list = navItem.navigation.filter(
-        app => app.display !== 'Dashboard',
-      );
-      return {
-        ...navItem,
-        navigation: list,
-      };
-    });
-
-    utils.hasDashboard(nav);
+    utils.hasDashboard();
   });
 });
diff --git a/projects/nshmp-apps/cypress/integration/dev/dashboard/dev-dashboard.spec.ts b/projects/nshmp-apps/cypress/integration/dev/dashboard/dev-dashboard.spec.ts
index 9a86dd68b..983f981bc 100644
--- a/projects/nshmp-apps/cypress/integration/dev/dashboard/dev-dashboard.spec.ts
+++ b/projects/nshmp-apps/cypress/integration/dev/dashboard/dev-dashboard.spec.ts
@@ -1,4 +1,3 @@
-import {devNavigation} from '../../../../src/shared/utils/navigation.utils';
 import * as utils from '../../../utils';
 
 describe('Development Dashboard', () => {
@@ -8,20 +7,10 @@ describe('Development Dashboard', () => {
   });
 
   describe('Check nshmp-template', () => {
-    utils.hasNshmpTemplate(devNavigation());
+    utils.hasNshmpTemplate();
   });
 
   describe('Check dev dashboard', () => {
-    const nav = devNavigation().map(navItem => {
-      const list = navItem.navigation.filter(
-        app => app.display !== 'Development Dashboard',
-      );
-      return {
-        ...navItem,
-        navigation: list,
-      };
-    });
-
-    utils.hasDashboard(nav);
+    utils.hasDashboard();
   });
 });
diff --git a/projects/nshmp-apps/cypress/integration/dev/math/exceedance-explorer/exceedance-explorer.spec.ts b/projects/nshmp-apps/cypress/integration/dev/math/exceedance-explorer/exceedance-explorer.spec.ts
index f3f644ecb..1eb300f21 100644
--- a/projects/nshmp-apps/cypress/integration/dev/math/exceedance-explorer/exceedance-explorer.spec.ts
+++ b/projects/nshmp-apps/cypress/integration/dev/math/exceedance-explorer/exceedance-explorer.spec.ts
@@ -1,4 +1,3 @@
-import {devNavigation} from '../../../../../src/shared/utils/navigation.utils';
 import * as utils from '../../../../utils';
 
 describe('Exceedance Explorer Application', () => {
@@ -8,7 +7,7 @@ describe('Exceedance Explorer Application', () => {
   });
 
   describe('Check nshmp-template', () => {
-    utils.hasNshmpTemplate(devNavigation());
+    utils.hasNshmpTemplate();
   });
 
   describe('Application', () => {
diff --git a/projects/nshmp-apps/cypress/integration/gmm/distance/gmm-distance.spec.ts b/projects/nshmp-apps/cypress/integration/gmm/distance/gmm-distance.spec.ts
index 1c1e8c40c..64c415460 100644
--- a/projects/nshmp-apps/cypress/integration/gmm/distance/gmm-distance.spec.ts
+++ b/projects/nshmp-apps/cypress/integration/gmm/distance/gmm-distance.spec.ts
@@ -1,4 +1,3 @@
-import {navigation} from '../../../../src/shared/utils/navigation.utils';
 import * as utils from '../../../utils';
 
 const url = 'https://earthquake.usgs.gov/ws/nshmp/data/gmm/distance';
@@ -12,7 +11,7 @@ describe('Ground Motion vs. Distance Application', () => {
   });
 
   describe('Check nshmp-template', () => {
-    utils.hasNshmpTemplate(navigation());
+    utils.hasNshmpTemplate();
   });
 
   describe('Application', () => {
diff --git a/projects/nshmp-apps/cypress/integration/gmm/magnitude/gmm-magnitude.spec.ts b/projects/nshmp-apps/cypress/integration/gmm/magnitude/gmm-magnitude.spec.ts
index 7e15bf380..952126527 100644
--- a/projects/nshmp-apps/cypress/integration/gmm/magnitude/gmm-magnitude.spec.ts
+++ b/projects/nshmp-apps/cypress/integration/gmm/magnitude/gmm-magnitude.spec.ts
@@ -1,4 +1,3 @@
-import {navigation} from '../../../../src/shared/utils/navigation.utils';
 import * as utils from '../../../utils';
 
 const url = 'https://earthquake.usgs.gov/ws/nshmp/data/gmm/magnitude';
@@ -12,7 +11,7 @@ describe('Ground Motion vs. Magnitude', () => {
   });
 
   describe('Check nshmp-template', () => {
-    utils.hasNshmpTemplate(navigation());
+    utils.hasNshmpTemplate();
   });
 
   describe('Application', () => {
diff --git a/projects/nshmp-apps/cypress/integration/gmm/spectra/response-spectra.spec.ts b/projects/nshmp-apps/cypress/integration/gmm/spectra/response-spectra.spec.ts
index 0d369e638..af90143f7 100644
--- a/projects/nshmp-apps/cypress/integration/gmm/spectra/response-spectra.spec.ts
+++ b/projects/nshmp-apps/cypress/integration/gmm/spectra/response-spectra.spec.ts
@@ -1,4 +1,3 @@
-import {navigation} from '../../../../src/shared/utils/navigation.utils';
 import * as utils from '../../../utils';
 
 const url = 'https://earthquake.usgs.gov/ws/nshmp/data/gmm/spectra';
@@ -12,7 +11,7 @@ describe('Response Spectra', () => {
   });
 
   describe('Check nshmp-template', () => {
-    utils.hasNshmpTemplate(navigation());
+    utils.hasNshmpTemplate();
   });
 
   describe('Application', () => {
diff --git a/projects/nshmp-apps/cypress/integration/hazard/disagg/disagg.spec.ts b/projects/nshmp-apps/cypress/integration/hazard/disagg/disagg.spec.ts
index ec8be6590..a2eed44f1 100644
--- a/projects/nshmp-apps/cypress/integration/hazard/disagg/disagg.spec.ts
+++ b/projects/nshmp-apps/cypress/integration/hazard/disagg/disagg.spec.ts
@@ -1,6 +1,5 @@
 import {DisaggTarget} from '@ghsc/nshmp-lib-ng/hazard';
 
-import {navigation} from '../../../../src/shared/utils/navigation.utils';
 import * as utils from '../../../utils';
 
 const url = 'https://earthquake.usgs.gov/ws/nshmp/*/dynamic/disagg';
@@ -14,7 +13,7 @@ describe('Disagg Application', () => {
   });
 
   describe('Check nshmp-template', () => {
-    utils.hasNshmpTemplate(navigation());
+    utils.hasNshmpTemplate();
   });
 
   describe('Application', () => {
diff --git a/projects/nshmp-apps/cypress/integration/hazard/dynamic/dynamic-hazard.spec.ts b/projects/nshmp-apps/cypress/integration/hazard/dynamic/dynamic-hazard.spec.ts
index 003919c29..73c83d629 100644
--- a/projects/nshmp-apps/cypress/integration/hazard/dynamic/dynamic-hazard.spec.ts
+++ b/projects/nshmp-apps/cypress/integration/hazard/dynamic/dynamic-hazard.spec.ts
@@ -1,4 +1,3 @@
-import {navigation} from '../../../../src/shared/utils/navigation.utils';
 import * as utils from '../../../utils';
 
 const url = 'https://earthquake.usgs.gov/ws/nshmp/*/dynamic/hazard';
@@ -12,7 +11,7 @@ describe('Dynamic Hazard Application', () => {
   });
 
   describe('Check nshmp-template', () => {
-    utils.hasNshmpTemplate(navigation());
+    utils.hasNshmpTemplate();
   });
 
   describe('Application', () => {
diff --git a/projects/nshmp-apps/cypress/integration/hazard/static/static-hazard.spec.ts b/projects/nshmp-apps/cypress/integration/hazard/static/static-hazard.spec.ts
index ef75af05c..ae5a32ce8 100644
--- a/projects/nshmp-apps/cypress/integration/hazard/static/static-hazard.spec.ts
+++ b/projects/nshmp-apps/cypress/integration/hazard/static/static-hazard.spec.ts
@@ -1,4 +1,3 @@
-import {navigation} from '../../../../src/shared/utils/navigation.utils';
 import * as utils from '../../../utils';
 
 const url = 'https://**/ws/nshmp/*/static/hazard';
@@ -12,7 +11,7 @@ describe('Static Hazard Application', () => {
   });
 
   describe('Check nshmp-template', () => {
-    utils.hasNshmpTemplate(navigation());
+    utils.hasNshmpTemplate();
   });
 
   describe('Application', () => {
diff --git a/projects/nshmp-apps/cypress/integration/services/services.spec.ts b/projects/nshmp-apps/cypress/integration/services/services.spec.ts
index 13ed0c7a4..82c7b4675 100644
--- a/projects/nshmp-apps/cypress/integration/services/services.spec.ts
+++ b/projects/nshmp-apps/cypress/integration/services/services.spec.ts
@@ -1,4 +1,3 @@
-import {navigation} from '../../../src/shared/utils/navigation.utils';
 import * as utils from '../../utils';
 
 describe('Services Application', () => {
@@ -8,7 +7,7 @@ describe('Services Application', () => {
   });
 
   describe('Check nshmp-template', () => {
-    utils.hasNshmpTemplate(navigation());
+    utils.hasNshmpTemplate();
   });
 
   describe('Application', () => {
diff --git a/projects/nshmp-apps/cypress/integration/source/data/data-mapping.spec.ts b/projects/nshmp-apps/cypress/integration/source/data/data-mapping.spec.ts
index 147f7316d..d9c7be650 100644
--- a/projects/nshmp-apps/cypress/integration/source/data/data-mapping.spec.ts
+++ b/projects/nshmp-apps/cypress/integration/source/data/data-mapping.spec.ts
@@ -1,4 +1,3 @@
-import {navigation} from '../../../../src/shared/utils/navigation.utils';
 import * as utils from '../../../utils';
 
 const url = '/ws/nshmp/data/fault-sections';
@@ -12,7 +11,7 @@ describe('Model Mapping Application', () => {
   });
 
   describe('Check nshmp-template', () => {
-    utils.hasNshmpTemplate(navigation());
+    utils.hasNshmpTemplate();
   });
 
   describe('Application', () => {
diff --git a/projects/nshmp-apps/cypress/integration/source/mfd/mfd.spec.ts b/projects/nshmp-apps/cypress/integration/source/mfd/mfd.spec.ts
index 20da7c987..7aa0c42f1 100644
--- a/projects/nshmp-apps/cypress/integration/source/mfd/mfd.spec.ts
+++ b/projects/nshmp-apps/cypress/integration/source/mfd/mfd.spec.ts
@@ -1,4 +1,3 @@
-import {navigation} from '../../../../src/shared/utils/navigation.utils';
 import * as utils from '../../../utils';
 
 const url = 'https://earthquake.usgs.gov/ws/nshmp/*/dynamic/trees';
@@ -12,7 +11,7 @@ describe('Magnitude Frequency Distribution Application', () => {
   });
 
   describe('Check nshmp-template', () => {
-    utils.hasNshmpTemplate(navigation());
+    utils.hasNshmpTemplate();
   });
 
   describe('Application', () => {
diff --git a/projects/nshmp-apps/cypress/utils/dashboard.utils.ts b/projects/nshmp-apps/cypress/utils/dashboard.utils.ts
index 3ff138217..3210c15d8 100644
--- a/projects/nshmp-apps/cypress/utils/dashboard.utils.ts
+++ b/projects/nshmp-apps/cypress/utils/dashboard.utils.ts
@@ -1,8 +1,6 @@
 import 'cypress';
 
-import {NavigationList} from '@ghsc/nshmp-template';
-
-export function hasDashboard(navList: NavigationList[]) {
+export function hasDashboard() {
   it('Has nshmp-template main', () => {
     cy.get('nshmp-template-main').should('be.visible');
   });
@@ -29,38 +27,4 @@ export function hasDashboard(navList: NavigationList[]) {
       .should('have.length.above', 0)
       .should('be.visible');
   });
-
-  navList.forEach(nav => {
-    if (nav.subHeader) {
-      it(`Has "${nav.subHeader}" application list header`, () => {
-        cy.get('.dashboard').find('.app-section').contains(nav.subHeader);
-      });
-    }
-
-    nav.navigation.forEach(app => {
-      const routerLink = app.routerLink.startsWith('/')
-        ? app.routerLink.substring(1)
-        : app.routerLink;
-
-      it(`Has "${app.display}" application`, () => {
-        if (app.routerLink.includes('/aws/')) {
-          cy.intercept(
-            'GET',
-            'https://earthquake.usgs.gov/ws/nshmp/hazard-runs/auth',
-            {
-              fixture: 'aws-auth.json',
-            },
-          );
-        }
-
-        cy.get('.dashboard')
-          .find('mat-card')
-          .contains('mat-card-title', app.display)
-          .parent()
-          .click()
-          .url()
-          .should('contain', `${Cypress.config().baseUrl}${routerLink}`);
-      });
-    });
-  });
 }
diff --git a/projects/nshmp-apps/cypress/utils/nshmp-template.utils.ts b/projects/nshmp-apps/cypress/utils/nshmp-template.utils.ts
index 18cd9977a..442b2b174 100644
--- a/projects/nshmp-apps/cypress/utils/nshmp-template.utils.ts
+++ b/projects/nshmp-apps/cypress/utils/nshmp-template.utils.ts
@@ -1,7 +1,5 @@
 import 'cypress';
 
-import {NavigationList} from '@ghsc/nshmp-template';
-
 export interface CheckPlot {
   plotClass: string;
   intercept?: boolean;
@@ -33,7 +31,7 @@ export function hasControlPanel() {
   });
 }
 
-export function hasNshmpTemplate(navList: NavigationList[]) {
+export function hasNshmpTemplate() {
   it('Has nshmp-template', () => {
     cy.get('nshmp-template').should('be.visible');
   });
@@ -70,52 +68,6 @@ export function hasNshmpTemplate(navList: NavigationList[]) {
         .find('button')
         .should('have.length.above', 0);
     });
-
-    navList.forEach(nav => {
-      if (nav.subHeader) {
-        it(`Has "${nav.subHeader}" header`, () => {
-          cy.get('nshmp-template-navigation')
-            .find('button')
-            .click()
-            .get('.mat-menu-panel')
-            .contains(nav.subHeader);
-        });
-      }
-      nav.navigation.forEach(app => {
-        const routerLink = app.routerLink.startsWith('/')
-          ? app.routerLink.substring(1)
-          : app.routerLink;
-
-        it(`Has "${app.display}" listed in navigation menu`, () => {
-          if (app.routerLink.includes('/aws/')) {
-            cy.intercept(
-              'GET',
-              'https://earthquake.usgs.gov/ws/nshmp/hazard-runs/auth',
-              {
-                fixture: 'aws-auth.json',
-              },
-            );
-          }
-
-          cy.get('nshmp-template-navigation').find('button').click();
-
-          cy.get('.mat-menu-panel')
-            .then(menu => {
-              const subMenu = menu.find(`button:contains('${nav.subHeader}')`);
-              if (subMenu.length) {
-                cy.get('.mat-menu-panel')
-                  .find(`button:contains('${nav.subHeader}')`)
-                  .trigger('mouseenter');
-              }
-            })
-            .get('.mat-menu-panel')
-            .contains('button', app.display)
-            .click()
-            .url()
-            .should('contain', `${Cypress.config().baseUrl}${routerLink}`);
-        });
-      });
-    });
   });
 }
 
-- 
GitLab


From 5717bf5b7a0721485f77045fdf092b04497d32a7 Mon Sep 17 00:00:00 2001
From: Brandon Clayton <bclayton@usgs.gov>
Date: Tue, 18 Mar 2025 14:34:56 -0600
Subject: [PATCH 6/6] add router

---
 .../src/app/error-pages/404/404.component.spec.ts          | 7 ++++++-
 .../src/app/error-pages/410/410.component.spec.ts          | 7 ++++++-
 .../src/app/error-pages/500/500.component.spec.ts          | 7 ++++++-
 3 files changed, 18 insertions(+), 3 deletions(-)

diff --git a/projects/nshmp-apps/src/app/error-pages/404/404.component.spec.ts b/projects/nshmp-apps/src/app/error-pages/404/404.component.spec.ts
index 8c85b4f25..304e4fb67 100644
--- a/projects/nshmp-apps/src/app/error-pages/404/404.component.spec.ts
+++ b/projects/nshmp-apps/src/app/error-pages/404/404.component.spec.ts
@@ -1,3 +1,4 @@
+import {provideHttpClient} from '@angular/common/http';
 import {ComponentFixture, TestBed} from '@angular/core/testing';
 import {provideNoopAnimations} from '@angular/platform-browser/animations';
 import {provideRouter} from '@angular/router';
@@ -11,7 +12,11 @@ describe('Error404Component', () => {
   beforeEach(async () => {
     await TestBed.configureTestingModule({
       imports: [Error404Component],
-      providers: [provideRouter([]), provideNoopAnimations()],
+      providers: [
+        provideRouter([]),
+        provideNoopAnimations(),
+        provideHttpClient(),
+      ],
     }).compileComponents();
   });
 
diff --git a/projects/nshmp-apps/src/app/error-pages/410/410.component.spec.ts b/projects/nshmp-apps/src/app/error-pages/410/410.component.spec.ts
index d765c32ef..587f0023e 100644
--- a/projects/nshmp-apps/src/app/error-pages/410/410.component.spec.ts
+++ b/projects/nshmp-apps/src/app/error-pages/410/410.component.spec.ts
@@ -1,3 +1,4 @@
+import {provideHttpClient} from '@angular/common/http';
 import {ComponentFixture, TestBed} from '@angular/core/testing';
 import {provideNoopAnimations} from '@angular/platform-browser/animations';
 import {provideRouter} from '@angular/router';
@@ -11,7 +12,11 @@ describe('Error410Component', () => {
   beforeEach(async () => {
     await TestBed.configureTestingModule({
       imports: [Error410Component],
-      providers: [provideRouter([]), provideNoopAnimations()],
+      providers: [
+        provideRouter([]),
+        provideNoopAnimations(),
+        provideHttpClient(),
+      ],
     }).compileComponents();
   });
 
diff --git a/projects/nshmp-apps/src/app/error-pages/500/500.component.spec.ts b/projects/nshmp-apps/src/app/error-pages/500/500.component.spec.ts
index 2512b8b74..11cf4190e 100644
--- a/projects/nshmp-apps/src/app/error-pages/500/500.component.spec.ts
+++ b/projects/nshmp-apps/src/app/error-pages/500/500.component.spec.ts
@@ -1,3 +1,4 @@
+import {provideHttpClient} from '@angular/common/http';
 import {ComponentFixture, TestBed} from '@angular/core/testing';
 import {provideNoopAnimations} from '@angular/platform-browser/animations';
 import {provideRouter} from '@angular/router';
@@ -11,7 +12,11 @@ describe('Error500Component', () => {
   beforeEach(async () => {
     await TestBed.configureTestingModule({
       imports: [Error500Component],
-      providers: [provideRouter([]), provideNoopAnimations()],
+      providers: [
+        provideRouter([]),
+        provideNoopAnimations(),
+        provideHttpClient(),
+      ],
     }).compileComponents();
   });
 
-- 
GitLab