This is an automated email from the ASF dual-hosted git repository.

rfellows pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/nifi.git


The following commit(s) were added to refs/heads/main by this push:
     new 8e0c68e5cc NIFI-12663: Error Handling in CS Listing (#8305)
8e0c68e5cc is described below

commit 8e0c68e5cc8e39b544ed44a7885d1f04f7ae6f42
Author: Matt Gilman <matt.c.gil...@gmail.com>
AuthorDate: Mon Jan 29 15:49:59 2024 -0500

    NIFI-12663: Error Handling in CS Listing (#8305)
    
    * NIFI-12663:
    - Handling API error responses in the Management Controller Services page.
    
    * NIFI-12679:
    - Renaming components based on review feedback.
    - Using ng-content in page-content component.
    - Removing the problematic route when navigating to the error page.
    - Fixing logic when handling service loading errors.
    - Handling errors in the Property Table Helper service.
    
    * NIFI-12679:
    - Addressing review feedback.
---
 .../src/main/nifi/src/app/app-routing.module.ts    |  4 ++
 .../src/main/nifi/src/app/app.module.ts            |  6 +-
 .../feature/error-routing.module.ts}               | 19 ++---
 .../feature/error.component.html}                  | 13 +++-
 .../feature/error.component.scss}                  |  6 +-
 .../feature/error.component.spec.ts}               | 23 ++++--
 .../error/feature/error.component.ts}              | 27 ++++---
 .../error/feature/error.module.ts}                 | 26 +++----
 .../pages/flow-designer/service/flow.service.ts    |  4 --
 .../port/create-port/create-port.component.html    |  2 +-
 .../port/create-port/create-port.component.ts      |  4 +-
 .../items/port/edit-port/edit-port.component.html  |  2 +-
 .../items/port/edit-port/edit-port.component.ts    |  8 +--
 .../create-process-group.component.html            |  1 +
 .../create-process-group.component.ts              |  4 +-
 .../group-components/group-components.component.ts |  2 -
 .../edit-processor/edit-processor.component.html   |  1 +
 .../edit-processor.component.spec.ts               | 19 ++++-
 .../edit-processor/edit-processor.component.ts     |  4 +-
 .../app/pages/login/feature/login.component.html   | 16 +++--
 .../src/app/pages/login/feature/login.module.ts    |  7 +-
 .../login/ui/login-form/login-form.component.html  |  2 +-
 .../state/management-controller-services/index.ts  |  3 +-
 .../management-controller-services.actions.ts      |  4 +-
 .../management-controller-services.effects.ts      | 84 ++++++++++++----------
 .../management-controller-services.reducer.ts      | 10 +--
 .../management-controller-services.selectors.ts    |  5 ++
 .../management-controller-services.module.ts       |  3 +-
 .../nifi/src/app/service/error-helper.service.ts   | 69 ++++++++++++++++++
 .../src/app/service/extension-types.service.ts     |  2 +-
 .../src/app/service/guard/authentication.guard.ts  |  8 +--
 .../service/interceptors/auth.interceptor.spec.ts  | 10 ++-
 .../app/service/interceptors/auth.interceptor.ts   | 47 +++++++++---
 .../app/service/property-table-helper.service.ts   | 53 +++++++++++---
 .../error/error.actions.ts}                        | 20 +++---
 .../main/nifi/src/app/state/error/error.effects.ts | 55 ++++++++++++++
 .../main/nifi/src/app/state/error/error.reducer.ts | 50 +++++++++++++
 .../error/error.selectors.ts}                      | 18 ++---
 .../error/index.ts}                                | 17 +++--
 .../src/main/nifi/src/app/state/index.ts           |  4 ++
 .../edit-controller-service.component.html         |  1 +
 .../edit-controller-service.component.spec.ts      | 19 ++++-
 .../edit-controller-service.component.ts           |  4 +-
 .../error-banner/error-banner.component.html}      | 21 +++---
 .../error-banner/error-banner.component.scss}      | 14 ++--
 .../error-banner/error-banner.component.spec.ts}   | 14 ++--
 .../common/error-banner/error-banner.component.ts} | 33 ++++-----
 .../page-content/page-content.component.html}      | 10 +--
 .../page-content/page-content.component.scss}      |  4 +-
 .../page-content/page-content.component.spec.ts}   | 13 ++--
 .../common/page-content/page-content.component.ts} | 17 +++--
 51 files changed, 564 insertions(+), 248 deletions(-)

diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/app-routing.module.ts
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/app-routing.module.ts
index 3a70a49d5b..704d6df973 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/app-routing.module.ts
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/app-routing.module.ts
@@ -24,6 +24,10 @@ const routes: Routes = [
         path: 'login',
         loadChildren: () => 
import('./pages/login/feature/login.module').then((m) => m.LoginModule)
     },
+    {
+        path: 'error',
+        loadChildren: () => 
import('./pages/error/feature/error.module').then((m) => m.ErrorModule)
+    },
     {
         path: 'settings',
         canMatch: [authenticationGuard],
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/app.module.ts
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/app.module.ts
index 749a8dda7a..56c94fe9c4 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/app.module.ts
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/app.module.ts
@@ -42,6 +42,8 @@ import { ControllerServiceStateEffects } from 
'./state/contoller-service-state/c
 import { SystemDiagnosticsEffects } from 
'./state/system-diagnostics/system-diagnostics.effects';
 import { FlowConfigurationEffects } from 
'./state/flow-configuration/flow-configuration.effects';
 import { ComponentStateEffects } from 
'./state/component-state/component-state.effects';
+import { ErrorEffects } from './state/error/error.effects';
+import { MatSnackBarModule } from '@angular/material/snack-bar';
 
 @NgModule({
     declarations: [AppComponent],
@@ -60,6 +62,7 @@ import { ComponentStateEffects } from 
'./state/component-state/component-state.e
             navigationActionTiming: NavigationActionTiming.PostActivation
         }),
         EffectsModule.forRoot(
+            ErrorEffects,
             CurrentUserEffects,
             ExtensionTypesEffects,
             AboutEffects,
@@ -76,7 +79,8 @@ import { ComponentStateEffects } from 
'./state/component-state/component-state.e
         }),
         MatProgressSpinnerModule,
         MatNativeDateModule,
-        MatDialogModule
+        MatDialogModule,
+        MatSnackBarModule
     ],
     providers: [
         {
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/login/ui/login-message/login-message.component.scss
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/error/feature/error-routing.module.ts
similarity index 71%
copy from 
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/login/ui/login-message/login-message.component.scss
copy to 
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/error/feature/error-routing.module.ts
index 60e6952ab4..110e54ca8c 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/login/ui/login-message/login-message.component.scss
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/error/feature/error-routing.module.ts
@@ -15,11 +15,14 @@
  * limitations under the License.
  */
 
-.login-message {
-    .login-title {
-        font-size: 18px;
-        font-weight: 600;
-        font-family: Roboto Slab;
-        color: #728e9b;
-    }
-}
+import { NgModule } from '@angular/core';
+import { RouterModule, Routes } from '@angular/router';
+import { Error } from './error.component';
+
+const routes: Routes = [{ path: '', component: Error }];
+
+@NgModule({
+    imports: [RouterModule.forChild(routes)],
+    exports: [RouterModule]
+})
+export class ErrorRoutingModule {}
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/common/banner/banner.component.html
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/error/feature/error.component.html
similarity index 61%
rename from 
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/common/banner/banner.component.html
rename to 
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/error/feature/error.component.html
index 7fa5559faf..2dcd49203f 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/common/banner/banner.component.html
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/error/feature/error.component.html
@@ -15,4 +15,15 @@
   ~ limitations under the License.
   -->
 
-<div *ngIf="message" [ngClass]="{ error: severity == 'alert' }" class="p-2 
text-center text-sm">{{ message }}</div>
+<div class="error-background pt-24 pl-24 h-screen">
+    <ng-container *ngIf="errorDetail$ | async; let errorDetail; else: 
noErrorDetails">
+        <page-content [title]="errorDetail.title">
+            <div class="text-sm">{{ errorDetail.message }}</div>
+        </page-content>
+    </ng-container>
+    <ng-template #noErrorDetails>
+        <page-content title="Error">
+            <div class="text-sm">Please check the logs or navigate home and 
try again.</div>
+        </page-content>
+    </ng-template>
+</div>
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/common/banner/banner.component.scss
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/error/feature/error.component.scss
similarity index 88%
rename from 
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/common/banner/banner.component.scss
rename to 
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/error/feature/error.component.scss
index d6751e31d6..ed2e32658f 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/common/banner/banner.component.scss
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/error/feature/error.component.scss
@@ -15,8 +15,6 @@
  * limitations under the License.
  */
 
-div {
-    &.error {
-        background-color: #ffcdd2;
-    }
+.error-background {
+    background: #fff url(../../../../assets/icons/bg-error.png) left top 
no-repeat;
 }
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/common/banner/banner.component.spec.ts
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/error/feature/error.component.spec.ts
similarity index 70%
copy from 
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/common/banner/banner.component.spec.ts
copy to 
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/error/feature/error.component.spec.ts
index b5c0823056..795a953ec6 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/common/banner/banner.component.spec.ts
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/error/feature/error.component.spec.ts
@@ -17,20 +17,29 @@
 
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 
-import { Banner } from './banner.component';
+import { Error } from './error.component';
 import { provideMockStore } from '@ngrx/store/testing';
-import { initialState } from '../../../state/flow/flow.reducer';
+import { initialState } from 
'../../../state/current-user/current-user.reducer';
+import { Component } from '@angular/core';
 
-describe('Banner', () => {
-    let component: Banner;
-    let fixture: ComponentFixture<Banner>;
+describe('Error', () => {
+    let component: Error;
+    let fixture: ComponentFixture<Error>;
+
+    @Component({
+        selector: 'page-content',
+        standalone: true,
+        template: ''
+    })
+    class MockPageContent {}
 
     beforeEach(() => {
         TestBed.configureTestingModule({
-            imports: [Banner],
+            declarations: [Error],
+            imports: [MockPageContent],
             providers: [provideMockStore({ initialState })]
         });
-        fixture = TestBed.createComponent(Banner);
+        fixture = TestBed.createComponent(Error);
         component = fixture.componentInstance;
         fixture.detectChanges();
     });
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/service/interceptors/auth.interceptor.spec.ts
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/error/feature/error.component.ts
similarity index 63%
copy from 
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/service/interceptors/auth.interceptor.spec.ts
copy to 
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/error/feature/error.component.ts
index 2f45628ff9..2bfa544afd 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/service/interceptors/auth.interceptor.spec.ts
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/error/feature/error.component.ts
@@ -15,19 +15,18 @@
  * limitations under the License.
  */
 
-import { TestBed } from '@angular/core/testing';
+import { Component } from '@angular/core';
+import { Store } from '@ngrx/store';
+import { selectFullScreenError } from '../../../state/error/error.selectors';
+import { NiFiState } from '../../../state';
 
-import { AuthInterceptor } from './auth.interceptor';
+@Component({
+    selector: 'error',
+    templateUrl: './error.component.html',
+    styleUrls: ['./error.component.scss']
+})
+export class Error {
+    errorDetail$ = this.store.select(selectFullScreenError);
 
-describe('AuthInterceptor', () => {
-    let service: AuthInterceptor;
-
-    beforeEach(() => {
-        TestBed.configureTestingModule({});
-        service = TestBed.inject(AuthInterceptor);
-    });
-
-    it('should be created', () => {
-        expect(service).toBeTruthy();
-    });
-});
+    constructor(private store: Store<NiFiState>) {}
+}
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/service/interceptors/auth.interceptor.spec.ts
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/error/feature/error.module.ts
similarity index 64%
copy from 
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/service/interceptors/auth.interceptor.spec.ts
copy to 
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/error/feature/error.module.ts
index 2f45628ff9..2e1fb41518 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/service/interceptors/auth.interceptor.spec.ts
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/error/feature/error.module.ts
@@ -15,19 +15,15 @@
  * limitations under the License.
  */
 
-import { TestBed } from '@angular/core/testing';
+import { NgModule } from '@angular/core';
+import { CommonModule } from '@angular/common';
+import { Error } from './error.component';
+import { ErrorRoutingModule } from './error-routing.module';
+import { PageContent } from 
'../../../ui/common/page-content/page-content.component';
 
-import { AuthInterceptor } from './auth.interceptor';
-
-describe('AuthInterceptor', () => {
-    let service: AuthInterceptor;
-
-    beforeEach(() => {
-        TestBed.configureTestingModule({});
-        service = TestBed.inject(AuthInterceptor);
-    });
-
-    it('should be created', () => {
-        expect(service).toBeTruthy();
-    });
-});
+@NgModule({
+    declarations: [Error],
+    exports: [Error],
+    imports: [CommonModule, ErrorRoutingModule, PageContent]
+})
+export class ErrorModule {}
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/flow.service.ts
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/flow.service.ts
index 8d841d986c..818e802663 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/flow.service.ts
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/flow.service.ts
@@ -18,7 +18,6 @@
 import { Injectable } from '@angular/core';
 import { Observable } from 'rxjs';
 import { HttpClient } from '@angular/common/http';
-import { CanvasUtils } from './canvas-utils.service';
 import {
     ComponentRunStatusRequest,
     CreateComponentRequest,
@@ -48,7 +47,6 @@ export class FlowService implements 
PropertyDescriptorRetriever {
 
     constructor(
         private httpClient: HttpClient,
-        private canvasUtils: CanvasUtils,
         private client: Client,
         private nifiCommon: NiFiCommon
     ) {}
@@ -198,12 +196,10 @@ export class FlowService implements 
PropertyDescriptorRetriever {
     }
 
     updateComponent(updateComponent: UpdateComponentRequest): Observable<any> {
-        // return throwError('API Error');
         return 
this.httpClient.put(this.nifiCommon.stripProtocol(updateComponent.uri), 
updateComponent.payload);
     }
 
     deleteComponent(deleteComponent: DeleteComponentRequest): Observable<any> {
-        // return throwError('API Error');
         const revision: any = this.client.getRevision(deleteComponent.entity);
         return 
this.httpClient.delete(this.nifiCommon.stripProtocol(deleteComponent.uri), { 
params: revision });
     }
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/port/create-port/create-port.component.html
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/port/create-port/create-port.component.html
index 04feabd8f9..b214a166d2 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/port/create-port/create-port.component.html
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/port/create-port/create-port.component.html
@@ -17,7 +17,7 @@
 
 <h2 mat-dialog-title>Create New {{ portTypeLabel }}</h2>
 <form class="create-port-form" [formGroup]="createPortForm">
-    <banner></banner>
+    <error-banner></error-banner>
     <mat-dialog-content>
         <mat-form-field>
             <mat-label>{{ portTypeLabel }} Name</mat-label>
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/port/create-port/create-port.component.ts
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/port/create-port/create-port.component.ts
index eb7a38c31f..926aa98daa 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/port/create-port/create-port.component.ts
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/port/create-port/create-port.component.ts
@@ -28,7 +28,7 @@ import { ComponentType, SelectOption, TextTipInput } from 
'../../../../../../../
 import { MatInputModule } from '@angular/material/input';
 import { MatSelectModule } from '@angular/material/select';
 import { MatTooltipModule } from '@angular/material/tooltip';
-import { Banner } from '../../../../common/banner/banner.component';
+import { ErrorBanner } from 
'../../../../../../../ui/common/error-banner/error-banner.component';
 import { AsyncPipe, NgForOf, NgIf } from '@angular/common';
 import { MatButtonModule } from '@angular/material/button';
 import { NifiSpinnerDirective } from 
'../../../../../../../ui/common/spinner/nifi-spinner.directive';
@@ -44,7 +44,7 @@ import { NifiTooltipDirective } from 
'../../../../../../../ui/common/tooltips/ni
         MatInputModule,
         MatSelectModule,
         MatTooltipModule,
-        Banner,
+        ErrorBanner,
         NgIf,
         NgForOf,
         MatButtonModule,
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/port/edit-port/edit-port.component.html
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/port/edit-port/edit-port.component.html
index 9bb3faf242..2742b7170c 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/port/edit-port/edit-port.component.html
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/port/edit-port/edit-port.component.html
@@ -17,7 +17,7 @@
 
 <h2 mat-dialog-title>Edit {{ portTypeLabel }}</h2>
 <form class="edit-port-form" [formGroup]="editPortForm">
-    <banner></banner>
+    <error-banner></error-banner>
     <mat-dialog-content>
         <div>
             <mat-form-field>
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/port/edit-port/edit-port.component.ts
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/port/edit-port/edit-port.component.ts
index 94b68953d1..2fbe452dc4 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/port/edit-port/edit-port.component.ts
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/port/edit-port/edit-port.component.ts
@@ -24,7 +24,7 @@ import { updateComponent } from 
'../../../../../state/flow/flow.actions';
 import { Client } from '../../../../../../../service/client.service';
 import { EditComponentDialogRequest } from '../../../../../state/flow';
 import { ComponentType } from '../../../../../../../state/shared';
-import { Banner } from '../../../../common/banner/banner.component';
+import { ErrorBanner } from 
'../../../../../../../ui/common/error-banner/error-banner.component';
 import { MatInputModule } from '@angular/material/input';
 import { MatCheckboxModule } from '@angular/material/checkbox';
 import { MatButtonModule } from '@angular/material/button';
@@ -38,7 +38,7 @@ import { NifiSpinnerDirective } from 
'../../../../../../../ui/common/spinner/nif
     templateUrl: './edit-port.component.html',
     imports: [
         ReactiveFormsModule,
-        Banner,
+        ErrorBanner,
         MatDialogModule,
         MatInputModule,
         MatCheckboxModule,
@@ -68,10 +68,6 @@ export class EditPort {
             this.portTypeLabel = 'Output Port';
         }
 
-        // TODO - consider updating the request to only provide the id of the 
port and selecting that item
-        // from the store. this would also allow us to be informed when 
another client has submitted an
-        // update to the same port which this editing is happening
-
         // build the form
         this.editPortForm = this.formBuilder.group({
             name: new FormControl(request.entity.component.name, 
Validators.required),
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/process-group/create-process-group/create-process-group.component.html
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/process-group/create-process-group/create-process-group.component.html
index 6ce3fb0f78..965492caca 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/process-group/create-process-group/create-process-group.component.html
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/process-group/create-process-group/create-process-group.component.html
@@ -17,6 +17,7 @@
 
 <h2 mat-dialog-title>Create Process Group</h2>
 <form class="create-process-group-form" [formGroup]="createProcessGroupForm">
+    <error-banner></error-banner>
     <mat-dialog-content>
         <mat-form-field>
             <mat-label>Name</mat-label>
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/process-group/create-process-group/create-process-group.component.ts
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/process-group/create-process-group/create-process-group.component.ts
index 74b8865aed..2caa01168e 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/process-group/create-process-group/create-process-group.component.ts
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/process-group/create-process-group/create-process-group.component.ts
@@ -24,7 +24,7 @@ import { createProcessGroup, uploadProcessGroup } from 
'../../../../../state/flo
 import { SelectOption, TextTipInput } from '../../../../../../../state/shared';
 import { selectSaving } from '../../../../../state/flow/flow.selectors';
 import { AsyncPipe, NgForOf, NgIf } from '@angular/common';
-import { Banner } from '../../../../common/banner/banner.component';
+import { ErrorBanner } from 
'../../../../../../../ui/common/error-banner/error-banner.component';
 import { MatButtonModule } from '@angular/material/button';
 import { MatFormFieldModule } from '@angular/material/form-field';
 import { MatInputModule } from '@angular/material/input';
@@ -42,7 +42,7 @@ import { NiFiCommon } from 
'../../../../../../../service/nifi-common.service';
     standalone: true,
     imports: [
         AsyncPipe,
-        Banner,
+        ErrorBanner,
         MatButtonModule,
         MatDialogModule,
         MatFormFieldModule,
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/process-group/group-components/group-components.component.ts
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/process-group/group-components/group-components.component.ts
index 690f03f3e4..84bd09f637 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/process-group/group-components/group-components.component.ts
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/process-group/group-components/group-components.component.ts
@@ -24,7 +24,6 @@ import { groupComponents } from 
'../../../../../state/flow/flow.actions';
 import { ComponentType, SelectOption, TextTipInput } from 
'../../../../../../../state/shared';
 import { selectSaving } from '../../../../../state/flow/flow.selectors';
 import { AsyncPipe, NgForOf, NgIf } from '@angular/common';
-import { Banner } from '../../../../common/banner/banner.component';
 import { MatButtonModule } from '@angular/material/button';
 import { MatFormFieldModule } from '@angular/material/form-field';
 import { MatInputModule } from '@angular/material/input';
@@ -42,7 +41,6 @@ import { Client } from 
'../../../../../../../service/client.service';
     standalone: true,
     imports: [
         AsyncPipe,
-        Banner,
         MatButtonModule,
         MatDialogModule,
         MatFormFieldModule,
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/processor/edit-processor/edit-processor.component.html
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/processor/edit-processor/edit-processor.component.html
index 166f54860f..8a67cb245a 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/processor/edit-processor/edit-processor.component.html
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/processor/edit-processor/edit-processor.component.html
@@ -17,6 +17,7 @@
 
 <h2 mat-dialog-title>Edit Processor</h2>
 <form class="processor-edit-form" [formGroup]="editProcessorForm">
+    <error-banner></error-banner>
     <!-- TODO - Stop & Configure -->
     <mat-dialog-content>
         <mat-tab-group>
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/processor/edit-processor/edit-processor.component.spec.ts
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/processor/edit-processor/edit-processor.component.spec.ts
index 18db2e5513..c181d773a3 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/processor/edit-processor/edit-processor.component.spec.ts
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/processor/edit-processor/edit-processor.component.spec.ts
@@ -22,6 +22,9 @@ import { EditComponentDialogRequest } from 
'../../../../../state/flow';
 import { MAT_DIALOG_DATA } from '@angular/material/dialog';
 import { ComponentType } from '../../../../../../../state/shared';
 import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { Component } from '@angular/core';
+import { provideMockStore } from '@ngrx/store/testing';
+import { initialState } from '../../../../../../../state/error/error.reducer';
 
 describe('EditProcessor', () => {
     let component: EditProcessor;
@@ -719,10 +722,22 @@ describe('EditProcessor', () => {
         }
     };
 
+    @Component({
+        selector: 'error-banner',
+        standalone: true,
+        template: ''
+    })
+    class MockErrorBanner {}
+
     beforeEach(() => {
         TestBed.configureTestingModule({
-            imports: [EditProcessor, BrowserAnimationsModule],
-            providers: [{ provide: MAT_DIALOG_DATA, useValue: data }]
+            imports: [EditProcessor, MockErrorBanner, BrowserAnimationsModule],
+            providers: [
+                { provide: MAT_DIALOG_DATA, useValue: data },
+                provideMockStore({
+                    initialState
+                })
+            ]
         });
         fixture = TestBed.createComponent(EditProcessor);
         component = fixture.componentInstance;
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/processor/edit-processor/edit-processor.component.ts
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/processor/edit-processor/edit-processor.component.ts
index 6cb5893bd7..c494728d35 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/processor/edit-processor/edit-processor.component.ts
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/processor/edit-processor/edit-processor.component.ts
@@ -47,6 +47,7 @@ import {
     RelationshipConfiguration,
     RelationshipSettings
 } from './relationship-settings/relationship-settings.component';
+import { ErrorBanner } from 
'../../../../../../../ui/common/error-banner/error-banner.component';
 
 @Component({
     selector: 'edit-processor',
@@ -68,7 +69,8 @@ import {
         NifiSpinnerDirective,
         NifiTooltipDirective,
         RunDurationSlider,
-        RelationshipSettings
+        RelationshipSettings,
+        ErrorBanner
     ],
     styleUrls: ['./edit-processor.component.scss']
 })
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/login/feature/login.component.html
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/login/feature/login.component.html
index 81fb3394e3..3f6d3a7f34 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/login/feature/login.component.html
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/login/feature/login.component.html
@@ -23,12 +23,16 @@
 
         <ng-template #loaded>
             <ng-container *ngIf="access.error; else noErrors">
-                <login-message [title]="access.error.title" 
[message]="access.error.message"></login-message>
+                <page-content [title]="access.error.title">
+                    <div class="text-sm">{{ access.error.message }}</div>
+                </page-content>
             </ng-container>
 
             <ng-template #noErrors>
                 <ng-container *ngIf="access.accessStatus.status === 'ACTIVE'; 
else needsLogin">
-                    <login-message [title]="'Success'" 
[message]="access.accessStatus.message"></login-message>
+                    <page-content [title]="'Success'">
+                        <div class="text-sm">{{ access.accessStatus.message 
}}</div>
+                    </page-content>
                 </ng-container>
                 <ng-template #needsLogin>
                     <ng-container *ngIf="access.accessConfig.supportsLogin; 
else loginNotSupported">
@@ -36,11 +40,9 @@
                     </ng-container>
 
                     <ng-template #loginNotSupported>
-                        <login-message
-                            [title]="'Access Denied'"
-                            [message]="
-                                'This NiFi is not configured to support 
username/password logins.'
-                            "></login-message>
+                        <page-content [title]="'Access Denied'">
+                            <div class="text-sm">This NiFi is not configured 
to support username/password logins.</div>
+                        </page-content>
                     </ng-template>
                 </ng-template>
             </ng-template>
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/login/feature/login.module.ts
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/login/feature/login.module.ts
index 339c933ede..9d317caa47 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/login/feature/login.module.ts
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/login/feature/login.module.ts
@@ -28,11 +28,11 @@ import { EffectsModule } from '@ngrx/effects';
 import { loginFeatureKey, reducers } from '../state';
 import { AccessEffects } from '../state/access/access.effects';
 import { LoginForm } from '../ui/login-form/login-form.component';
-import { LoginMessage } from '../ui/login-message/login-message.component';
+import { PageContent } from 
'../../../ui/common/page-content/page-content.component';
 import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
 
 @NgModule({
-    declarations: [Login, LoginForm, LoginMessage],
+    declarations: [Login, LoginForm],
     exports: [Login],
     imports: [
         CommonModule,
@@ -44,7 +44,8 @@ import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
         MatFormFieldModule,
         MatInputModule,
         MatButtonModule,
-        NgxSkeletonLoaderModule
+        NgxSkeletonLoaderModule,
+        PageContent
     ]
 })
 export class LoginModule {}
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/login/ui/login-form/login-form.component.html
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/login/ui/login-form/login-form.component.html
index bad2efb042..7f5d6dc18e 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/login/ui/login-form/login-form.component.html
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/login/ui/login-form/login-form.component.html
@@ -15,7 +15,7 @@
   ~ limitations under the License.
   -->
 
-<div class="login-form w-96 flex flex-col gap-y-3">
+<div class="login-form w-96 flex flex-col gap-y-5">
     <div class="flex justify-between items-center">
         <div class="login-title">Log In</div>
         <div class="flex gap-x-2">
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/management-controller-services/index.ts
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/management-controller-services/index.ts
index b1725d338c..6c1be51d41 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/management-controller-services/index.ts
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/management-controller-services/index.ts
@@ -57,6 +57,5 @@ export interface ManagementControllerServicesState {
     controllerServices: ControllerServiceEntity[];
     saving: boolean;
     loadedTimestamp: string;
-    error: string | null;
-    status: 'pending' | 'loading' | 'error' | 'success';
+    status: 'pending' | 'loading' | 'success';
 }
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/management-controller-services/management-controller-services.actions.ts
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/management-controller-services/management-controller-services.actions.ts
index 0ecaca9f51..483b481bf4 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/management-controller-services/management-controller-services.actions.ts
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/management-controller-services/management-controller-services.actions.ts
@@ -45,8 +45,8 @@ export const loadManagementControllerServicesSuccess = 
createAction(
     props<{ response: LoadManagementControllerServicesResponse }>()
 );
 
-export const managementControllerServicesApiError = createAction(
-    '[Management Controller Services] Load Management Controller Services 
Error',
+export const managementControllerServicesBannerApiError = createAction(
+    '[Management Controller Services] Management Controller Services Banner 
Api Error',
     props<{ error: string }>()
 );
 
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/management-controller-services/management-controller-services.effects.ts
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/management-controller-services/management-controller-services.effects.ts
index 62abf521cb..b94109c269 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/management-controller-services/management-controller-services.effects.ts
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/management-controller-services/management-controller-services.effects.ts
@@ -18,7 +18,8 @@
 import { Injectable } from '@angular/core';
 import { Actions, concatLatestFrom, createEffect, ofType } from 
'@ngrx/effects';
 import * as ManagementControllerServicesActions from 
'./management-controller-services.actions';
-import { catchError, from, map, NEVER, Observable, of, switchMap, take, 
takeUntil, tap } from 'rxjs';
+import * as ErrorActions from '../../../../state/error/error.actions';
+import { catchError, from, map, of, switchMap, take, takeUntil, tap } from 
'rxjs';
 import { MatDialog } from '@angular/material/dialog';
 import { ManagementControllerServiceService } from 
'../../service/management-controller-service.service';
 import { Store } from '@ngrx/store';
@@ -31,17 +32,15 @@ import { EditControllerService } from 
'../../../../ui/common/controller-service/
 import {
     ComponentType,
     ControllerServiceReferencingComponent,
-    InlineServiceCreationRequest,
-    InlineServiceCreationResponse,
-    PropertyDescriptor,
     UpdateControllerServiceRequest
 } from '../../../../state/shared';
 import { Router } from '@angular/router';
-import { ExtensionTypesService } from 
'../../../../service/extension-types.service';
-import { selectSaving } from './management-controller-services.selectors';
+import { selectSaving, selectStatus } from 
'./management-controller-services.selectors';
 import { EnableControllerService } from 
'../../../../ui/common/controller-service/enable-controller-service/enable-controller-service.component';
 import { DisableControllerService } from 
'../../../../ui/common/controller-service/disable-controller-service/disable-controller-service.component';
 import { PropertyTableHelperService } from 
'../../../../service/property-table-helper.service';
+import { HttpErrorResponse } from '@angular/common/http';
+import { ErrorHelper } from '../../../../service/error-helper.service';
 
 @Injectable()
 export class ManagementControllerServicesEffects {
@@ -50,7 +49,7 @@ export class ManagementControllerServicesEffects {
         private store: Store<NiFiState>,
         private client: Client,
         private managementControllerServiceService: 
ManagementControllerServiceService,
-        private extensionTypesService: ExtensionTypesService,
+        private errorHelper: ErrorHelper,
         private dialog: MatDialog,
         private router: Router,
         private propertyTableHelperService: PropertyTableHelperService
@@ -59,7 +58,8 @@ export class ManagementControllerServicesEffects {
     loadManagementControllerServices$ = createEffect(() =>
         this.actions$.pipe(
             
ofType(ManagementControllerServicesActions.loadManagementControllerServices),
-            switchMap(() =>
+            concatLatestFrom(() => this.store.select(selectStatus)),
+            switchMap(([action, status]) =>
                 
from(this.managementControllerServiceService.getControllerServices()).pipe(
                     map((response) =>
                         
ManagementControllerServicesActions.loadManagementControllerServicesSuccess({
@@ -69,13 +69,17 @@ export class ManagementControllerServicesEffects {
                             }
                         })
                     ),
-                    catchError((error) =>
-                        of(
-                            
ManagementControllerServicesActions.managementControllerServicesApiError({
-                                error: error.error
-                            })
-                        )
-                    )
+                    catchError((errorResponse: HttpErrorResponse) => {
+                        if (status === 'success') {
+                            if 
(this.errorHelper.showErrorInContext(errorResponse.status)) {
+                                return of(ErrorActions.snackBarError({ error: 
errorResponse.error }));
+                            } else {
+                                return 
of(this.errorHelper.fullScreenError(errorResponse));
+                            }
+                        } else {
+                            return 
of(this.errorHelper.fullScreenError(errorResponse));
+                        }
+                    })
                 )
             )
         )
@@ -130,13 +134,10 @@ export class ManagementControllerServicesEffects {
                             }
                         })
                     ),
-                    catchError((error) =>
-                        of(
-                            
ManagementControllerServicesActions.managementControllerServicesApiError({
-                                error: error.error
-                            })
-                        )
-                    )
+                    catchError((errorResponse: HttpErrorResponse) => {
+                        this.dialog.closeAll();
+                        return of(ErrorActions.snackBarError({ error: 
errorResponse.error }));
+                    })
                 )
             )
         )
@@ -265,6 +266,8 @@ export class ManagementControllerServicesEffects {
                         });
 
                     editDialogReference.afterClosed().subscribe((response) => {
+                        this.store.dispatch(ErrorActions.clearBannerErrors());
+
                         if (response != 'ROUTED') {
                             this.store.dispatch(
                                 
ManagementControllerServicesActions.selectControllerService({
@@ -295,18 +298,31 @@ export class ManagementControllerServicesEffects {
                             }
                         })
                     ),
-                    catchError((error) =>
-                        of(
-                            
ManagementControllerServicesActions.managementControllerServicesApiError({
-                                error: error.error
-                            })
-                        )
-                    )
+                    catchError((errorResponse: HttpErrorResponse) => {
+                        if 
(this.errorHelper.showErrorInContext(errorResponse.status)) {
+                            return of(
+                                
ManagementControllerServicesActions.managementControllerServicesBannerApiError({
+                                    error: errorResponse.error
+                                })
+                            );
+                        } else {
+                            
this.dialog.getDialogById(request.id)?.close('ROUTED');
+                            return 
of(this.errorHelper.fullScreenError(errorResponse));
+                        }
+                    })
                 )
             )
         )
     );
 
+    managementControllerServicesBannerApiError$ = createEffect(() =>
+        this.actions$.pipe(
+            
ofType(ManagementControllerServicesActions.managementControllerServicesBannerApiError),
+            map((action) => action.error),
+            switchMap((error) => of(ErrorActions.addBannerError({ error })))
+        )
+    );
+
     configureControllerServiceSuccess$ = createEffect(
         () =>
             this.actions$.pipe(
@@ -425,13 +441,9 @@ export class ManagementControllerServicesEffects {
                             }
                         })
                     ),
-                    catchError((error) =>
-                        of(
-                            
ManagementControllerServicesActions.managementControllerServicesApiError({
-                                error: error.error
-                            })
-                        )
-                    )
+                    catchError((errorResponse: HttpErrorResponse) => {
+                        return of(ErrorActions.snackBarError({ error: 
errorResponse.error }));
+                    })
                 )
             )
         )
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/management-controller-services/management-controller-services.reducer.ts
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/management-controller-services/management-controller-services.reducer.ts
index c23194a49b..f276f37632 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/management-controller-services/management-controller-services.reducer.ts
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/management-controller-services/management-controller-services.reducer.ts
@@ -27,7 +27,7 @@ import {
     inlineCreateControllerServiceSuccess,
     loadManagementControllerServices,
     loadManagementControllerServicesSuccess,
-    managementControllerServicesApiError,
+    managementControllerServicesBannerApiError,
     resetManagementControllerServicesState
 } from './management-controller-services.actions';
 import { produce } from 'immer';
@@ -36,7 +36,6 @@ export const initialState: ManagementControllerServicesState 
= {
     controllerServices: [],
     saving: false,
     loadedTimestamp: '',
-    error: null,
     status: 'pending'
 };
 
@@ -53,14 +52,11 @@ export const managementControllerServicesReducer = 
createReducer(
         ...state,
         controllerServices: response.controllerServices,
         loadedTimestamp: response.loadedTimestamp,
-        error: null,
         status: 'success' as const
     })),
-    on(managementControllerServicesApiError, (state, { error }) => ({
+    on(managementControllerServicesBannerApiError, (state, { error }) => ({
         ...state,
-        saving: false,
-        error,
-        status: 'error' as const
+        saving: false
     })),
     on(createControllerService, configureControllerService, 
deleteControllerService, (state, { request }) => ({
         ...state,
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/management-controller-services/management-controller-services.selectors.ts
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/management-controller-services/management-controller-services.selectors.ts
index 38a6849574..dccee8af0b 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/management-controller-services/management-controller-services.selectors.ts
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/management-controller-services/management-controller-services.selectors.ts
@@ -31,6 +31,11 @@ export const selectSaving = createSelector(
     (state: ManagementControllerServicesState) => state.saving
 );
 
+export const selectStatus = createSelector(
+    selectManagementControllerServicesState,
+    (state: ManagementControllerServicesState) => state.status
+);
+
 export const selectControllerServiceIdFromRoute = 
createSelector(selectCurrentRoute, (route) => {
     if (route) {
         // always select the controller service from the route
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/management-controller-services/management-controller-services.module.ts
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/management-controller-services/management-controller-services.module.ts
index 15fc85f780..815f85abb2 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/management-controller-services/management-controller-services.module.ts
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/management-controller-services/management-controller-services.module.ts
@@ -20,10 +20,11 @@ import { CommonModule } from '@angular/common';
 import { ManagementControllerServices } from 
'./management-controller-services.component';
 import { NgxSkeletonLoaderModule } from 'ngx-skeleton-loader';
 import { ControllerServiceTable } from 
'../../../../ui/common/controller-service/controller-service-table/controller-service-table.component';
+import { ErrorBanner } from 
'../../../../ui/common/error-banner/error-banner.component';
 
 @NgModule({
     declarations: [ManagementControllerServices],
     exports: [ManagementControllerServices],
-    imports: [CommonModule, NgxSkeletonLoaderModule, ControllerServiceTable]
+    imports: [CommonModule, NgxSkeletonLoaderModule, ControllerServiceTable, 
ErrorBanner]
 })
 export class ManagementControllerServicesModule {}
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/service/error-helper.service.ts
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/service/error-helper.service.ts
new file mode 100644
index 0000000000..3b1ef875b1
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/service/error-helper.service.ts
@@ -0,0 +1,69 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { Injectable } from '@angular/core';
+import { HttpErrorResponse } from '@angular/common/http';
+import * as ErrorDetailActions from '../state/error/error.actions';
+import { Action } from '@ngrx/store';
+import { NiFiCommon } from './nifi-common.service';
+
+@Injectable({ providedIn: 'root' })
+export class ErrorHelper {
+    constructor(private nifiCommon: NiFiCommon) {}
+
+    fullScreenError(errorResponse: HttpErrorResponse): Action {
+        let title: string;
+        let message: string;
+
+        switch (errorResponse.status) {
+            case 401:
+                title = 'Unauthorized';
+                break;
+            case 403:
+                title = 'Insufficient Permissions';
+                break;
+            case 409:
+                title = 'Invalid State';
+                break;
+            case 413:
+                title = 'Payload Too Large';
+                break;
+            case 503:
+            default:
+                title = 'An unexpected error has occurred';
+                break;
+        }
+
+        if (this.nifiCommon.isBlank(errorResponse.error)) {
+            message =
+                'An error occurred communicating with NiFi. Please check the 
logs and fix any configuration issues before restarting.';
+        } else {
+            message = errorResponse.error;
+        }
+
+        return ErrorDetailActions.fullScreenError({
+            errorDetail: {
+                title,
+                message
+            }
+        });
+    }
+
+    showErrorInContext(status: number): boolean {
+        return [400, 403, 404, 409, 413, 503].includes(status);
+    }
+}
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/service/extension-types.service.ts
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/service/extension-types.service.ts
index 2eced9f549..5fbc01928a 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/service/extension-types.service.ts
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/service/extension-types.service.ts
@@ -16,7 +16,7 @@
  */
 
 import { Injectable } from '@angular/core';
-import { Observable, throwError } from 'rxjs';
+import { Observable } from 'rxjs';
 import { HttpClient } from '@angular/common/http';
 import { Bundle } from '../state/shared';
 
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/service/guard/authentication.guard.ts
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/service/guard/authentication.guard.ts
index 7cf5227f6c..bdd3a16388 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/service/guard/authentication.guard.ts
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/service/guard/authentication.guard.ts
@@ -80,7 +80,9 @@ export const authenticationGuard: CanMatchFn = (route, state) 
=> {
                 .select(selectCurrentUserState)
                 .pipe(take(1))
                 .subscribe((userState) => {
-                    if (userState.status == 'pending') {
+                    if (userState.status == 'success') {
+                        resolve(true);
+                    } else {
                         userService
                             .getUser()
                             .pipe(take(1))
@@ -118,7 +120,7 @@ export const authenticationGuard: CanMatchFn = (route, 
state) => {
                                     }
                                 },
                                 error: (error) => {
-                                    // there is no anonymous access and we 
don't know this user - open the login page which handles login/registration/etc
+                                    // there is no anonymous access and we 
don't know this user - open the login page which handles login
                                     if (error.status === 401) {
                                         authStorage.removeToken();
                                         window.location.href = './login';
@@ -126,8 +128,6 @@ export const authenticationGuard: CanMatchFn = (route, 
state) => {
                                     resolve(false);
                                 }
                             });
-                    } else {
-                        resolve(true);
                     }
                 });
         });
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/service/interceptors/auth.interceptor.spec.ts
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/service/interceptors/auth.interceptor.spec.ts
index 2f45628ff9..1ce007609f 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/service/interceptors/auth.interceptor.spec.ts
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/service/interceptors/auth.interceptor.spec.ts
@@ -18,12 +18,20 @@
 import { TestBed } from '@angular/core/testing';
 
 import { AuthInterceptor } from './auth.interceptor';
+import { provideMockStore } from '@ngrx/store/testing';
+import { initialState } from '../../state/error/error.reducer';
 
 describe('AuthInterceptor', () => {
     let service: AuthInterceptor;
 
     beforeEach(() => {
-        TestBed.configureTestingModule({});
+        TestBed.configureTestingModule({
+            providers: [
+                provideMockStore({
+                    initialState
+                })
+            ]
+        });
         service = TestBed.inject(AuthInterceptor);
     });
 
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/service/interceptors/auth.interceptor.ts
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/service/interceptors/auth.interceptor.ts
index bc07793436..7c7620ca33 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/service/interceptors/auth.interceptor.ts
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/service/interceptors/auth.interceptor.ts
@@ -19,25 +19,54 @@ import { Injectable } from '@angular/core';
 import { HttpErrorResponse, HttpEvent, HttpHandler, HttpInterceptor, 
HttpRequest } from '@angular/common/http';
 import { Observable, tap } from 'rxjs';
 import { AuthStorage } from '../auth-storage.service';
+import { Store } from '@ngrx/store';
+import { NiFiState } from '../../state';
+import { fullScreenError } from '../../state/error/error.actions';
+import { NiFiCommon } from '../nifi-common.service';
 
 @Injectable({
     providedIn: 'root'
 })
 export class AuthInterceptor implements HttpInterceptor {
-    constructor(private authStorage: AuthStorage) {}
+    routedToFullScreenError: boolean = false;
+
+    constructor(
+        private authStorage: AuthStorage,
+        private store: Store<NiFiState>,
+        private nifiCommon: NiFiCommon
+    ) {}
 
     intercept(request: HttpRequest<any>, next: HttpHandler): 
Observable<HttpEvent<any>> {
         return next.handle(request).pipe(
             tap({
-                error: (error) => {
-                    if (error instanceof HttpErrorResponse) {
-                        if (error.status === 401) {
-                            this.authStorage.removeToken();
+                error: (errorResponse) => {
+                    if (errorResponse instanceof HttpErrorResponse) {
+                        if (errorResponse.status === 401) {
+                            if (this.authStorage.hasToken()) {
+                                this.authStorage.removeToken();
+
+                                let message: string = errorResponse.error;
+                                if (this.nifiCommon.isBlank(message)) {
+                                    message = 'Your session has expired. 
Please navigate home to log in again.';
+                                } else {
+                                    message += '. Please navigate home to log 
in again.';
+                                }
+
+                                this.routedToFullScreenError = true;
 
-                            // navigate to the root of the app which will 
handle redirection to the
-                            // login form if appropriate... TODO - replace 
with logout complete page?
-                            window.location.href = './login';
-                        } // TODO handle others (403)
+                                this.store.dispatch(
+                                    fullScreenError({
+                                        errorDetail: {
+                                            title: 'Unauthorized',
+                                            message
+                                        }
+                                    })
+                                );
+                            } else if (!this.routedToFullScreenError) {
+                                // the user has never logged in, redirect them 
to do so
+                                window.location.href = './login';
+                            }
+                        }
                     }
                 }
             })
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/service/property-table-helper.service.ts
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/service/property-table-helper.service.ts
index c359980e6f..d46068ca9f 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/service/property-table-helper.service.ts
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/service/property-table-helper.service.ts
@@ -17,7 +17,7 @@
 
 import { Injectable } from '@angular/core';
 import { MatDialog } from '@angular/material/dialog';
-import { catchError, map, NEVER, Observable, switchMap, take } from 'rxjs';
+import { catchError, EMPTY, map, Observable, switchMap, take, takeUntil, tap } 
from 'rxjs';
 import {
     ControllerServiceCreator,
     ControllerServiceEntity,
@@ -32,9 +32,12 @@ import {
 } from '../state/shared';
 import { NewPropertyDialog } from 
'../ui/common/new-property-dialog/new-property-dialog.component';
 import { CreateControllerService } from 
'../ui/common/controller-service/create-controller-service/create-controller-service.component';
-import { ManagementControllerServiceService } from 
'../pages/settings/service/management-controller-service.service';
 import { ExtensionTypesService } from './extension-types.service';
 import { Client } from './client.service';
+import { NiFiState } from '../state';
+import { Store } from '@ngrx/store';
+import { snackBarError } from '../state/error/error.actions';
+import { HttpErrorResponse } from '@angular/common/http';
 
 @Injectable({
     providedIn: 'root'
@@ -42,6 +45,7 @@ import { Client } from './client.service';
 export class PropertyTableHelperService {
     constructor(
         private dialog: MatDialog,
+        private store: Store<NiFiState>,
         private extensionTypesService: ExtensionTypesService,
         private client: Client
     ) {}
@@ -63,12 +67,19 @@ export class PropertyTableHelperService {
             });
 
             return 
newPropertyDialogReference.componentInstance.newProperty.pipe(
-                take(1),
+                takeUntil(newPropertyDialogReference.afterClosed()),
                 switchMap((dialogResponse: NewPropertyDialogResponse) => {
                     return propertyDescriptorService
                         .getPropertyDescriptor(id, dialogResponse.name, 
dialogResponse.sensitive)
                         .pipe(
                             take(1),
+                            catchError((errorResponse: HttpErrorResponse) => {
+                                this.store.dispatch(snackBarError({ error: 
errorResponse.error }));
+
+                                // handle the error here to keep the 
observable alive so the
+                                // user can attempt to create the property 
again
+                                return EMPTY;
+                            }),
                             map((response) => {
                                 newPropertyDialogReference.close();
 
@@ -112,6 +123,11 @@ export class PropertyTableHelperService {
                 )
                 .pipe(
                     take(1),
+                    tap({
+                        error: (errorResponse: HttpErrorResponse) => {
+                            this.store.dispatch(snackBarError({ error: 
errorResponse.error }));
+                        }
+                    }),
                     switchMap((implementingTypesResponse) => {
                         // show the create controller service dialog with the 
types that implemented the interface
                         const createServiceDialogReference = 
this.dialog.open(CreateControllerService, {
@@ -122,7 +138,7 @@ export class PropertyTableHelperService {
                         });
 
                         return 
createServiceDialogReference.componentInstance.createControllerService.pipe(
-                            take(1),
+                            
takeUntil(createServiceDialogReference.afterClosed()),
                             switchMap((controllerServiceType) => {
                                 // typically this sequence would be 
implemented with ngrx actions, however we are
                                 // currently in an edit session, and we need 
to return both the value (new service id)
@@ -142,6 +158,17 @@ export class PropertyTableHelperService {
 
                                 return 
controllerServiceCreator.createControllerService(payload).pipe(
                                     take(1),
+                                    catchError((errorResponse: 
HttpErrorResponse) => {
+                                        this.store.dispatch(
+                                            snackBarError({
+                                                error: `Unable to create new 
Service: ${errorResponse.error}`
+                                            })
+                                        );
+
+                                        // handle the error here to keep the 
observable alive so the
+                                        // user can attempt to create the 
service again
+                                        return EMPTY;
+                                    }),
                                     switchMap((createResponse) => {
                                         // if provided, call the callback 
function
                                         if (afterServiceCreated) {
@@ -153,6 +180,20 @@ export class PropertyTableHelperService {
                                             .getPropertyDescriptor(id, 
descriptor.name, false)
                                             .pipe(
                                                 take(1),
+                                                tap({
+                                                    error: (errorResponse: 
HttpErrorResponse) => {
+                                                        // we've errored 
getting the descriptor but since the service
+                                                        // was already 
created, we should close the create service dialog
+                                                        // so multiple service 
instances are not inadvertently created
+                                                        
createServiceDialogReference.close();
+
+                                                        this.store.dispatch(
+                                                            snackBarError({
+                                                                error: 
`Service created but unable to reload Property Descriptor: 
${errorResponse.error}`
+                                                            })
+                                                        );
+                                                    }
+                                                }),
                                                 map((descriptorResponse) => {
                                                     
createServiceDialogReference.close();
 
@@ -162,10 +203,6 @@ export class PropertyTableHelperService {
                                                     };
                                                 })
                                             );
-                                    }),
-                                    catchError((error) => {
-                                        // TODO - show error
-                                        return NEVER;
                                     })
                                 );
                             })
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/service/interceptors/auth.interceptor.spec.ts
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/state/error/error.actions.ts
similarity index 59%
copy from 
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/service/interceptors/auth.interceptor.spec.ts
copy to 
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/state/error/error.actions.ts
index 2f45628ff9..6278eb92fc 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/service/interceptors/auth.interceptor.spec.ts
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/state/error/error.actions.ts
@@ -15,19 +15,15 @@
  * limitations under the License.
  */
 
-import { TestBed } from '@angular/core/testing';
+import { createAction, props } from '@ngrx/store';
+import { ErrorDetail } from './index';
 
-import { AuthInterceptor } from './auth.interceptor';
+export const fullScreenError = createAction('[Error] Full Screen Error', 
props<{ errorDetail: ErrorDetail }>());
 
-describe('AuthInterceptor', () => {
-    let service: AuthInterceptor;
+export const snackBarError = createAction('[Error] Snackbar Error', props<{ 
error: string }>());
 
-    beforeEach(() => {
-        TestBed.configureTestingModule({});
-        service = TestBed.inject(AuthInterceptor);
-    });
+export const addBannerError = createAction('[Error] Add Banner Error', props<{ 
error: string }>());
 
-    it('should be created', () => {
-        expect(service).toBeTruthy();
-    });
-});
+export const clearBannerErrors = createAction('[Error] Clear Banner Errors');
+
+export const resetErrorState = createAction('[Error] Reset Error State');
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/state/error/error.effects.ts
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/state/error/error.effects.ts
new file mode 100644
index 0000000000..4a4d48e3a1
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/state/error/error.effects.ts
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { Injectable } from '@angular/core';
+import { Actions, createEffect, ofType } from '@ngrx/effects';
+import * as ErrorActions from './error.actions';
+import { map, tap } from 'rxjs';
+import { Router } from '@angular/router';
+import { MatSnackBar } from '@angular/material/snack-bar';
+
+@Injectable()
+export class ErrorEffects {
+    constructor(
+        private actions$: Actions,
+        private router: Router,
+        private snackBar: MatSnackBar
+    ) {}
+
+    fullScreenError$ = createEffect(
+        () =>
+            this.actions$.pipe(
+                ofType(ErrorActions.fullScreenError),
+                tap(() => {
+                    this.router.navigate(['/error'], { replaceUrl: true });
+                })
+            ),
+        { dispatch: false }
+    );
+
+    snackBarError$ = createEffect(
+        () =>
+            this.actions$.pipe(
+                ofType(ErrorActions.snackBarError),
+                map((action) => action.error),
+                tap((error) => {
+                    this.snackBar.open(error, 'Dismiss', { duration: 30000 });
+                })
+            ),
+        { dispatch: false }
+    );
+}
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/state/error/error.reducer.ts
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/state/error/error.reducer.ts
new file mode 100644
index 0000000000..939be0688d
--- /dev/null
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/state/error/error.reducer.ts
@@ -0,0 +1,50 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import { createReducer, on } from '@ngrx/store';
+import { ErrorState } from './index';
+import { resetErrorState, fullScreenError, addBannerError, clearBannerErrors } 
from './error.actions';
+import { produce } from 'immer';
+
+export const initialState: ErrorState = {
+    bannerErrors: null,
+    fullScreenError: null
+};
+
+export const errorReducer = createReducer(
+    initialState,
+    on(fullScreenError, (state, { errorDetail }) => ({
+        ...state,
+        fullScreenError: errorDetail
+    })),
+    on(addBannerError, (state, { error }) => {
+        return produce(state, (draftState) => {
+            if (draftState.bannerErrors === null) {
+                draftState.bannerErrors = [];
+            }
+
+            draftState.bannerErrors.push(error);
+        });
+    }),
+    on(clearBannerErrors, (state) => ({
+        ...state,
+        bannerErrors: null
+    })),
+    on(resetErrorState, (state) => ({
+        ...initialState
+    }))
+);
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/service/interceptors/auth.interceptor.spec.ts
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/state/error/error.selectors.ts
similarity index 64%
copy from 
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/service/interceptors/auth.interceptor.spec.ts
copy to 
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/state/error/error.selectors.ts
index 2f45628ff9..0887a5d3de 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/service/interceptors/auth.interceptor.spec.ts
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/state/error/error.selectors.ts
@@ -15,19 +15,11 @@
  * limitations under the License.
  */
 
-import { TestBed } from '@angular/core/testing';
+import { createFeatureSelector, createSelector } from '@ngrx/store';
+import { errorFeatureKey, ErrorState } from './index';
 
-import { AuthInterceptor } from './auth.interceptor';
+export const selectErrorState = 
createFeatureSelector<ErrorState>(errorFeatureKey);
 
-describe('AuthInterceptor', () => {
-    let service: AuthInterceptor;
+export const selectFullScreenError = createSelector(selectErrorState, (state: 
ErrorState) => state.fullScreenError);
 
-    beforeEach(() => {
-        TestBed.configureTestingModule({});
-        service = TestBed.inject(AuthInterceptor);
-    });
-
-    it('should be created', () => {
-        expect(service).toBeTruthy();
-    });
-});
+export const selectBannerErrors = createSelector(selectErrorState, (state: 
ErrorState) => state.bannerErrors);
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/login/ui/login-message/login-message.component.scss
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/state/error/index.ts
similarity index 78%
copy from 
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/login/ui/login-message/login-message.component.scss
copy to 
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/state/error/index.ts
index 60e6952ab4..b4febc851b 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/login/ui/login-message/login-message.component.scss
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/state/error/index.ts
@@ -15,11 +15,14 @@
  * limitations under the License.
  */
 
-.login-message {
-    .login-title {
-        font-size: 18px;
-        font-weight: 600;
-        font-family: Roboto Slab;
-        color: #728e9b;
-    }
+export const errorFeatureKey = 'error';
+
+export interface ErrorDetail {
+    title: string;
+    message: string;
+}
+
+export interface ErrorState {
+    bannerErrors: string[] | null;
+    fullScreenError: ErrorDetail | null;
 }
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/state/index.ts
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/state/index.ts
index 4ae6619448..ed546d4a04 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/state/index.ts
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/state/index.ts
@@ -33,9 +33,12 @@ import { flowConfigurationFeatureKey, FlowConfigurationState 
} from './flow-conf
 import { flowConfigurationReducer } from 
'./flow-configuration/flow-configuration.reducer';
 import { componentStateFeatureKey, ComponentStateState } from 
'./component-state';
 import { componentStateReducer } from 
'./component-state/component-state.reducer';
+import { errorFeatureKey, ErrorState } from './error';
+import { errorReducer } from './error/error.reducer';
 
 export interface NiFiState {
     router: RouterReducerState;
+    [errorFeatureKey]: ErrorState;
     [currentUserFeatureKey]: CurrentUserState;
     [extensionTypesFeatureKey]: ExtensionTypesState;
     [aboutFeatureKey]: AboutState;
@@ -48,6 +51,7 @@ export interface NiFiState {
 
 export const rootReducers: ActionReducerMap<NiFiState> = {
     router: routerReducer,
+    [errorFeatureKey]: errorReducer,
     [currentUserFeatureKey]: currentUserReducer,
     [extensionTypesFeatureKey]: extensionTypesReducer,
     [aboutFeatureKey]: aboutReducer,
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/controller-service/edit-controller-service/edit-controller-service.component.html
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/controller-service/edit-controller-service/edit-controller-service.component.html
index b507ec9201..b30e3f85fa 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/controller-service/edit-controller-service/edit-controller-service.component.html
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/controller-service/edit-controller-service/edit-controller-service.component.html
@@ -17,6 +17,7 @@
 
 <h2 mat-dialog-title>Edit Controller Service</h2>
 <form class="controller-service-edit-form" 
[formGroup]="editControllerServiceForm">
+    <error-banner></error-banner>
     <mat-dialog-content>
         <mat-tab-group>
             <mat-tab label="Settings">
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/controller-service/edit-controller-service/edit-controller-service.component.spec.ts
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/controller-service/edit-controller-service/edit-controller-service.component.spec.ts
index d9f5385b2f..750f179e34 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/controller-service/edit-controller-service/edit-controller-service.component.spec.ts
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/controller-service/edit-controller-service/edit-controller-service.component.spec.ts
@@ -21,6 +21,9 @@ import { EditControllerService } from 
'./edit-controller-service.component';
 import { EditControllerServiceDialogRequest } from '../../../../state/shared';
 import { MAT_DIALOG_DATA } from '@angular/material/dialog';
 import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { Component } from '@angular/core';
+import { provideMockStore } from '@ngrx/store/testing';
+import { initialState } from '../../../../state/error/error.reducer';
 
 describe('EditControllerService', () => {
     let component: EditControllerService;
@@ -541,10 +544,22 @@ describe('EditControllerService', () => {
         }
     };
 
+    @Component({
+        selector: 'error-banner',
+        standalone: true,
+        template: ''
+    })
+    class MockErrorBanner {}
+
     beforeEach(() => {
         TestBed.configureTestingModule({
-            imports: [EditControllerService, BrowserAnimationsModule],
-            providers: [{ provide: MAT_DIALOG_DATA, useValue: data }]
+            imports: [EditControllerService, MockErrorBanner, 
BrowserAnimationsModule],
+            providers: [
+                { provide: MAT_DIALOG_DATA, useValue: data },
+                provideMockStore({
+                    initialState
+                })
+            ]
         });
         fixture = TestBed.createComponent(EditControllerService);
         component = fixture.componentInstance;
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/controller-service/edit-controller-service/edit-controller-service.component.ts
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/controller-service/edit-controller-service/edit-controller-service.component.ts
index 08173288e6..347ace63ee 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/controller-service/edit-controller-service/edit-controller-service.component.ts
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/controller-service/edit-controller-service/edit-controller-service.component.ts
@@ -43,6 +43,7 @@ import { ControllerServiceApi } from 
'../controller-service-api/controller-servi
 import { Observable } from 'rxjs';
 import { ControllerServiceReferences } from 
'../controller-service-references/controller-service-references.component';
 import { NifiSpinnerDirective } from '../../spinner/nifi-spinner.directive';
+import { ErrorBanner } from '../../error-banner/error-banner.component';
 
 @Component({
     selector: 'edit-controller-service',
@@ -63,7 +64,8 @@ import { NifiSpinnerDirective } from 
'../../spinner/nifi-spinner.directive';
         ControllerServiceApi,
         ControllerServiceReferences,
         AsyncPipe,
-        NifiSpinnerDirective
+        NifiSpinnerDirective,
+        ErrorBanner
     ],
     styleUrls: ['./edit-controller-service.component.scss']
 })
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/login/ui/login-message/login-message.component.html
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/error-banner/error-banner.component.html
similarity index 58%
copy from 
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/login/ui/login-message/login-message.component.html
copy to 
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/error-banner/error-banner.component.html
index 98ff4032ed..ef9cb6a0d7 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/login/ui/login-message/login-message.component.html
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/error-banner/error-banner.component.html
@@ -15,13 +15,18 @@
   ~ limitations under the License.
   -->
 
-<div class="login-message w-96 flex flex-col gap-y-3">
-    <div class="flex justify-between items-center">
-        <div class="login-title">{{ title }}</div>
-        <div class="flex gap-x-3">
-            <a (click)="logout()" *ngIf="hasToken()">log out</a>
-            <a [routerLink]="['/']">home</a>
+<ng-container *ngIf="(messages$ | async)!; let messages">
+    <div class="banner-container border-t border-b px-6 py-3 flex 
justify-between items-center">
+        <ng-container *ngIf="messages.length === 1; else multipleMessages">
+            <div>{{ messages[0] }}</div>
+        </ng-container>
+        <ng-template #multipleMessages>
+            <ul>
+                <li *ngFor="let message of messages">{{ message }}</li>
+            </ul>
+        </ng-template>
+        <div class="flex flex-col mt-auto">
+            <button mat-stroked-button (click)="dismiss()">Dismiss</button>
         </div>
     </div>
-    <div class="text-sm">{{ message }}</div>
-</div>
+</ng-container>
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/login/ui/login-message/login-message.component.scss
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/error-banner/error-banner.component.scss
similarity index 82%
copy from 
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/login/ui/login-message/login-message.component.scss
copy to 
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/error-banner/error-banner.component.scss
index 60e6952ab4..6f854b7380 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/login/ui/login-message/login-message.component.scss
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/error-banner/error-banner.component.scss
@@ -15,11 +15,13 @@
  * limitations under the License.
  */
 
-.login-message {
-    .login-title {
-        font-size: 18px;
-        font-weight: 600;
-        font-family: Roboto Slab;
-        color: #728e9b;
+@use '@angular/material' as mat;
+
+.banner-container {
+    @include mat.button-density(-1);
+
+    ul {
+        list-style-type: disc;
+        list-style-position: inside;
     }
 }
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/common/banner/banner.component.spec.ts
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/error-banner/error-banner.component.spec.ts
similarity index 79%
rename from 
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/common/banner/banner.component.spec.ts
rename to 
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/error-banner/error-banner.component.spec.ts
index b5c0823056..b660e829d3 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/common/banner/banner.component.spec.ts
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/error-banner/error-banner.component.spec.ts
@@ -17,20 +17,20 @@
 
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 
-import { Banner } from './banner.component';
+import { ErrorBanner } from './error-banner.component';
 import { provideMockStore } from '@ngrx/store/testing';
-import { initialState } from '../../../state/flow/flow.reducer';
+import { initialState } from '../../../state/error/error.reducer';
 
-describe('Banner', () => {
-    let component: Banner;
-    let fixture: ComponentFixture<Banner>;
+describe('ErrorBanner', () => {
+    let component: ErrorBanner;
+    let fixture: ComponentFixture<ErrorBanner>;
 
     beforeEach(() => {
         TestBed.configureTestingModule({
-            imports: [Banner],
+            imports: [ErrorBanner],
             providers: [provideMockStore({ initialState })]
         });
-        fixture = TestBed.createComponent(Banner);
+        fixture = TestBed.createComponent(ErrorBanner);
         component = fixture.componentInstance;
         fixture.detectChanges();
     });
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/common/banner/banner.component.ts
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/error-banner/error-banner.component.ts
similarity index 56%
rename from 
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/common/banner/banner.component.ts
rename to 
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/error-banner/error-banner.component.ts
index cb42788943..27b0672866 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/common/banner/banner.component.ts
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/error-banner/error-banner.component.ts
@@ -17,28 +17,25 @@
 
 import { Component } from '@angular/core';
 import { Store } from '@ngrx/store';
-import { CanvasState } from '../../../state';
-import { selectApiError } from '../../../state/flow/flow.selectors';
-import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
-import { NgClass, NgIf } from '@angular/common';
+import { AsyncPipe, NgForOf, NgIf } from '@angular/common';
+import { MatButtonModule } from '@angular/material/button';
+import { NiFiState } from '../../../state';
+import { selectBannerErrors } from '../../../state/error/error.selectors';
+import { clearBannerErrors } from '../../../state/error/error.actions';
 
 @Component({
-    selector: 'banner',
+    selector: 'error-banner',
     standalone: true,
-    imports: [NgClass, NgIf],
-    templateUrl: './banner.component.html',
-    styleUrls: ['./banner.component.scss']
+    imports: [NgIf, NgForOf, MatButtonModule, AsyncPipe],
+    templateUrl: './error-banner.component.html',
+    styleUrls: ['./error-banner.component.scss']
 })
-export class Banner {
-    message: string | null = '';
-    severity: string = 'alert';
+export class ErrorBanner {
+    messages$ = this.store.select(selectBannerErrors);
 
-    constructor(private store: Store<CanvasState>) {
-        this.store
-            .select(selectApiError)
-            .pipe(takeUntilDestroyed())
-            .subscribe((message) => {
-                this.message = message;
-            });
+    constructor(private store: Store<NiFiState>) {}
+
+    dismiss(): void {
+        this.store.dispatch(clearBannerErrors());
     }
 }
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/login/ui/login-message/login-message.component.html
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/page-content/page-content.component.html
similarity index 73%
rename from 
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/login/ui/login-message/login-message.component.html
rename to 
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/page-content/page-content.component.html
index 98ff4032ed..594b0d3c31 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/login/ui/login-message/login-message.component.html
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/page-content/page-content.component.html
@@ -15,13 +15,13 @@
   ~ limitations under the License.
   -->
 
-<div class="login-message w-96 flex flex-col gap-y-3">
-    <div class="flex justify-between items-center">
-        <div class="login-title">{{ title }}</div>
+<div class="page-content w-1/2 flex flex-col gap-y-5">
+    <div class="flex justify-between items-center gap-x-3">
+        <div class="title whitespace-nowrap overflow-hidden text-ellipsis" 
[title]="title">{{ title }}</div>
         <div class="flex gap-x-3">
-            <a (click)="logout()" *ngIf="hasToken()">log out</a>
+            <a (click)="logout()" *ngIf="hasToken()" 
class="whitespace-nowrap">log out</a>
             <a [routerLink]="['/']">home</a>
         </div>
     </div>
-    <div class="text-sm">{{ message }}</div>
+    <ng-content></ng-content>
 </div>
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/login/ui/login-message/login-message.component.scss
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/page-content/page-content.component.scss
similarity index 96%
rename from 
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/login/ui/login-message/login-message.component.scss
rename to 
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/page-content/page-content.component.scss
index 60e6952ab4..634d984516 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/login/ui/login-message/login-message.component.scss
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/page-content/page-content.component.scss
@@ -15,8 +15,8 @@
  * limitations under the License.
  */
 
-.login-message {
-    .login-title {
+.page-content {
+    .title {
         font-size: 18px;
         font-weight: 600;
         font-family: Roboto Slab;
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/login/ui/login-message/login-message.component.spec.ts
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/page-content/page-content.component.spec.ts
similarity index 78%
rename from 
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/login/ui/login-message/login-message.component.spec.ts
rename to 
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/page-content/page-content.component.spec.ts
index 938d6f4b31..b61aeaa042 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/login/ui/login-message/login-message.component.spec.ts
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/page-content/page-content.component.spec.ts
@@ -17,21 +17,20 @@
 
 import { ComponentFixture, TestBed } from '@angular/core/testing';
 
-import { LoginMessage } from './login-message.component';
+import { PageContent } from './page-content.component';
 import { HttpClientTestingModule } from '@angular/common/http/testing';
 import { RouterModule } from '@angular/router';
 import { RouterTestingModule } from '@angular/router/testing';
 
-describe('LoginMessage', () => {
-    let component: LoginMessage;
-    let fixture: ComponentFixture<LoginMessage>;
+describe('PageContent', () => {
+    let component: PageContent;
+    let fixture: ComponentFixture<PageContent>;
 
     beforeEach(() => {
         TestBed.configureTestingModule({
-            declarations: [LoginMessage],
-            imports: [HttpClientTestingModule, RouterModule, 
RouterTestingModule]
+            imports: [PageContent, HttpClientTestingModule, RouterModule, 
RouterTestingModule]
         });
-        fixture = TestBed.createComponent(LoginMessage);
+        fixture = TestBed.createComponent(PageContent);
         component = fixture.componentInstance;
         fixture.detectChanges();
     });
diff --git 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/login/ui/login-message/login-message.component.ts
 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/page-content/page-content.component.ts
similarity index 73%
rename from 
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/login/ui/login-message/login-message.component.ts
rename to 
nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/page-content/page-content.component.ts
index 3468db13f5..d0c965f77a 100644
--- 
a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/login/ui/login-message/login-message.component.ts
+++ 
b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/page-content/page-content.component.ts
@@ -16,17 +16,20 @@
  */
 
 import { Component, Input } from '@angular/core';
-import { AuthStorage } from '../../../../service/auth-storage.service';
-import { AuthService } from '../../../../service/auth.service';
+import { AuthStorage } from '../../../service/auth-storage.service';
+import { AuthService } from '../../../service/auth.service';
+import { RouterLink } from '@angular/router';
+import { NgIf } from '@angular/common';
 
 @Component({
-    selector: 'login-message',
-    templateUrl: './login-message.component.html',
-    styleUrls: ['./login-message.component.scss']
+    selector: 'page-content',
+    standalone: true,
+    templateUrl: './page-content.component.html',
+    imports: [RouterLink, NgIf],
+    styleUrls: ['./page-content.component.scss']
 })
-export class LoginMessage {
+export class PageContent {
     @Input() title: string = '';
-    @Input() message: string = '';
 
     constructor(
         private authStorage: AuthStorage,

Reply via email to