From 439c59e73362e002e8576580e9ad3f3a696ffaae Mon Sep 17 00:00:00 2001 From: Matt Gilman Date: Fri, 9 Feb 2024 09:37:07 -0500 Subject: [PATCH] NIFI-12742: Error Handling in Summary, Users, and Queue Listing (#8366) - Error handling in Users. - Error handling in Summary. - Error handling in Queue Listing. - Addressing review feedback. - Dispatching delete success to ensure the active request is reset upon completion. This closes #8366 --- .../pages/queue/state/queue-listing/index.ts | 4 +- .../queue-listing/queue-listing.actions.ts | 2 + .../queue-listing/queue-listing.effects.ts | 103 +++++++++++------- .../queue-listing/queue-listing.reducer.ts | 48 ++++++-- .../queue-listing/queue-listing.selectors.ts | 11 +- .../flowfile-table.component.html | 1 + .../flowfile-table.component.spec.ts | 17 ++- .../flowfile-table.component.ts | 3 +- .../queue-listing.component.html | 17 ++- .../queue-listing/queue-listing.component.ts | 8 +- .../ui/queue-listing/queue-listing.module.ts | 4 +- .../service/cluster-summary.service.ts | 6 +- .../service/process-group-status.service.ts | 6 +- .../summary/state/summary-listing/index.ts | 3 +- .../summary-listing.actions.ts | 5 - .../summary-listing.effects.ts | 13 ++- .../summary-listing.reducer.ts | 15 +-- .../pages/users/state/user-listing/index.ts | 3 +- .../user-listing/user-listing.actions.ts | 7 +- .../user-listing/user-listing.effects.ts | 63 ++++++++--- .../user-listing/user-listing.reducer.ts | 10 +- .../user-listing/user-listing.selectors.ts | 2 + .../edit-tenant-dialog.component.html | 1 + .../edit-tenant-dialog.component.spec.ts | 19 +++- .../edit-tenant-dialog.component.ts | 4 +- 25 files changed, 244 insertions(+), 131 deletions(-) diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/state/queue-listing/index.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/state/queue-listing/index.ts index 0ce0492f81..b5de716db7 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/state/queue-listing/index.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/state/queue-listing/index.ts @@ -101,9 +101,9 @@ export interface FlowFileDialogRequest { } export interface QueueListingState { - requestEntity: ListingRequestEntity | null; + activeListingRequest: ListingRequest | null; + completedListingRequest: ListingRequest | null; connectionLabel: string; loadedTimestamp: string; - error: string | null; status: 'pending' | 'loading' | 'error' | 'success'; } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/state/queue-listing/queue-listing.actions.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/state/queue-listing/queue-listing.actions.ts index 52c4200dba..b4ff565d1d 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/state/queue-listing/queue-listing.actions.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/state/queue-listing/queue-listing.actions.ts @@ -68,6 +68,8 @@ export const stopPollingQueueListingRequest = createAction(`${QUEUE_PREFIX} Stop export const deleteQueueListingRequest = createAction(`${QUEUE_PREFIX} Delete Queue Listing Request`); +export const deleteQueueListingRequestSuccess = createAction(`${QUEUE_PREFIX} Delete Queue Listing Request Success`); + export const viewFlowFile = createAction(`${QUEUE_PREFIX} View FlowFile`, props<{ request: ViewFlowFileRequest }>()); export const openFlowFileDialog = createAction( diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/state/queue-listing/queue-listing.effects.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/state/queue-listing/queue-listing.effects.ts index 2d9eba388d..00564e1657 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/state/queue-listing/queue-listing.effects.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/state/queue-listing/queue-listing.effects.ts @@ -21,7 +21,7 @@ import * as QueueListingActions from './queue-listing.actions'; import { Store } from '@ngrx/store'; import { CanvasState } from '../../../flow-designer/state'; import { asyncScheduler, catchError, filter, from, interval, map, of, switchMap, take, takeUntil, tap } from 'rxjs'; -import { selectConnectionIdFromRoute, selectListingRequestEntity } from './queue-listing.selectors'; +import { selectConnectionIdFromRoute, selectActiveListingRequest } from './queue-listing.selectors'; import { QueueService } from '../../service/queue.service'; import { ListingRequest } from './index'; import { CancelDialog } from '../../../../ui/common/cancel-dialog/cancel-dialog.component'; @@ -30,6 +30,10 @@ import { selectAbout } from '../../../../state/about/about.selectors'; import { FlowFileDialog } from '../../ui/queue-listing/flowfile-dialog/flowfile-dialog.component'; import { NiFiCommon } from '../../../../service/nifi-common.service'; import { isDefinedAndNotNull } from '../../../../state/shared'; +import { HttpErrorResponse } from '@angular/common/http'; +import * as ErrorActions from '../../../../state/error/error.actions'; +import { ErrorHelper } from '../../../../service/error-helper.service'; +import { stopPollingQueueListingRequest } from './queue-listing.actions'; @Injectable() export class QueueListingEffects { @@ -37,6 +41,7 @@ export class QueueListingEffects { private actions$: Actions, private store: Store, private queueService: QueueService, + private errorHelper: ErrorHelper, private dialog: MatDialog, private nifiCommon: NiFiCommon ) {} @@ -103,13 +108,19 @@ export class QueueListingEffects { } }) ), - catchError((error) => - of( - QueueListingActions.queueListingApiError({ - error: error.error - }) - ) - ) + catchError((errorResponse: HttpErrorResponse) => { + if (this.errorHelper.showErrorInContext(errorResponse.status)) { + return of( + QueueListingActions.queueListingApiError({ + error: errorResponse.error + }) + ); + } else { + this.store.dispatch(stopPollingQueueListingRequest()); + + return of(this.errorHelper.fullScreenError(errorResponse)); + } + }) ); }) ) @@ -155,9 +166,9 @@ export class QueueListingEffects { pollQueueListingRequest$ = createEffect(() => this.actions$.pipe( ofType(QueueListingActions.pollQueueListingRequest), - concatLatestFrom(() => this.store.select(selectListingRequestEntity).pipe(isDefinedAndNotNull())), - switchMap(([, requestEntity]) => { - return from(this.queueService.pollQueueListingRequest(requestEntity.listingRequest)).pipe( + concatLatestFrom(() => this.store.select(selectActiveListingRequest).pipe(isDefinedAndNotNull())), + switchMap(([, listingRequest]) => { + return from(this.queueService.pollQueueListingRequest(listingRequest)).pipe( map((response) => QueueListingActions.pollQueueListingRequestSuccess({ response: { @@ -165,13 +176,19 @@ export class QueueListingEffects { } }) ), - catchError((error) => - of( - QueueListingActions.queueListingApiError({ - error: error.error - }) - ) - ) + catchError((errorResponse: HttpErrorResponse) => { + if (this.errorHelper.showErrorInContext(errorResponse.status)) { + return of( + QueueListingActions.queueListingApiError({ + error: errorResponse.error + }) + ); + } else { + this.store.dispatch(stopPollingQueueListingRequest()); + + return of(this.errorHelper.fullScreenError(errorResponse)); + } + }) ); }) ) @@ -193,20 +210,23 @@ export class QueueListingEffects { ) ); - deleteQueueListingRequest$ = createEffect( - () => - this.actions$.pipe( - ofType(QueueListingActions.deleteQueueListingRequest), - concatLatestFrom(() => this.store.select(selectListingRequestEntity)), - tap(([, requestEntity]) => { - this.dialog.closeAll(); + deleteQueueListingRequest$ = createEffect(() => + this.actions$.pipe( + ofType(QueueListingActions.deleteQueueListingRequest), + concatLatestFrom(() => this.store.select(selectActiveListingRequest)), + tap(([, listingRequest]) => { + this.dialog.closeAll(); - if (requestEntity) { - this.queueService.deleteQueueListingRequest(requestEntity.listingRequest).subscribe(); - } - }) - ), - { dispatch: false } + if (listingRequest) { + this.queueService.deleteQueueListingRequest(listingRequest).subscribe({ + error: (errorResponse: HttpErrorResponse) => { + this.store.dispatch(ErrorActions.snackBarError({ error: errorResponse.error })); + } + }); + } + }), + switchMap(() => of(QueueListingActions.deleteQueueListingRequestSuccess())) + ) ); viewFlowFile$ = createEffect(() => @@ -222,10 +242,10 @@ export class QueueListingEffects { } }) ), - catchError((error) => + catchError((errorResponse: HttpErrorResponse) => of( - QueueListingActions.queueListingApiError({ - error: error.error + ErrorActions.snackBarError({ + error: errorResponse.error }) ) ) @@ -298,12 +318,13 @@ export class QueueListingEffects { { dispatch: false } ); - queueListingApiError$ = createEffect( - () => - this.actions$.pipe( - ofType(QueueListingActions.queueListingApiError), - tap(() => this.dialog.closeAll()) - ), - { dispatch: false } + queueListingApiError$ = createEffect(() => + this.actions$.pipe( + ofType(QueueListingActions.queueListingApiError), + tap(() => { + this.store.dispatch(QueueListingActions.stopPollingQueueListingRequest()); + }), + switchMap(({ error }) => of(ErrorActions.addBannerError({ error }))) + ) ); } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/state/queue-listing/queue-listing.reducer.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/state/queue-listing/queue-listing.reducer.ts index 27f7fde081..28749d0657 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/state/queue-listing/queue-listing.reducer.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/state/queue-listing/queue-listing.reducer.ts @@ -23,14 +23,33 @@ import { submitQueueListingRequestSuccess, resetQueueListingState, queueListingApiError, - loadConnectionLabelSuccess + loadConnectionLabelSuccess, + deleteQueueListingRequestSuccess } from './queue-listing.actions'; +import { produce } from 'immer'; export const initialState: QueueListingState = { - requestEntity: null, + activeListingRequest: null, + completedListingRequest: { + id: '', + uri: '', + submissionTime: '', + lastUpdated: '', + percentCompleted: 100, + finished: true, + failureReason: '', + maxResults: 0, + sourceRunning: false, + destinationRunning: false, + state: '', + queueSize: { + objectCount: 0, + byteCount: 0 + }, + flowFileSummaries: [] + }, connectionLabel: 'Connection', loadedTimestamp: 'N/A', - error: null, status: 'pending' }; @@ -44,16 +63,25 @@ export const queueListingReducer = createReducer( ...state, status: 'loading' as const })), - on(submitQueueListingRequestSuccess, pollQueueListingRequestSuccess, (state, { response }) => ({ + on(submitQueueListingRequestSuccess, pollQueueListingRequestSuccess, (state, { response }) => { + return produce(state, (draftState) => { + const listingRequest = response.requestEntity.listingRequest; + + if (listingRequest.finished) { + draftState.completedListingRequest = listingRequest; + draftState.loadedTimestamp = listingRequest.lastUpdated; + draftState.status = 'success' as const; + } else { + draftState.activeListingRequest = listingRequest; + } + }); + }), + on(deleteQueueListingRequestSuccess, (state) => ({ ...state, - requestEntity: response.requestEntity, - loadedTimestamp: response.requestEntity.listingRequest.lastUpdated, - error: null, - status: 'success' as const + activeListingRequest: null })), - on(queueListingApiError, (state, { error }) => ({ + on(queueListingApiError, (state) => ({ ...state, - error, status: 'error' as const })), on(resetQueueListingState, () => ({ diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/state/queue-listing/queue-listing.selectors.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/state/queue-listing/queue-listing.selectors.ts index 01f3e8af39..a43fe859e0 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/state/queue-listing/queue-listing.selectors.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/state/queue-listing/queue-listing.selectors.ts @@ -25,15 +25,18 @@ export const selectQueueListingState = createSelector( (state: QueueState) => state[queueListingFeatureKey] ); -export const selectListingRequestEntity = createSelector( +export const selectActiveListingRequest = createSelector( selectQueueListingState, - (state: QueueListingState) => state.requestEntity + (state: QueueListingState) => state.activeListingRequest +); + +export const selectCompletedListingRequest = createSelector( + selectQueueListingState, + (state: QueueListingState) => state.completedListingRequest ); export const selectStatus = createSelector(selectQueueListingState, (state: QueueListingState) => state.status); -export const selectError = createSelector(selectQueueListingState, (state: QueueListingState) => state.error); - export const selectConnectionLabel = createSelector( selectQueueListingState, (state: QueueListingState) => state.connectionLabel diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/flowfile-table/flowfile-table.component.html b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/flowfile-table/flowfile-table.component.html index 2b0f76c870..ddef523062 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/flowfile-table/flowfile-table.component.html +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/flowfile-table/flowfile-table.component.html @@ -17,6 +17,7 @@

{{ connectionLabel }}

+
Display {{ displayObjectCount }} of {{ formatCount(queueSizeObjectCount) }} ({{ diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/flowfile-table/flowfile-table.component.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/flowfile-table/flowfile-table.component.spec.ts index fd491f6d65..7e66b66c9a 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/flowfile-table/flowfile-table.component.spec.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/flowfile-table/flowfile-table.component.spec.ts @@ -20,14 +20,29 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; import { FlowFileTable } from './flowfile-table.component'; import { MatTableModule } from '@angular/material/table'; 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('FlowFileTable', () => { let component: FlowFileTable; let fixture: ComponentFixture; + @Component({ + selector: 'error-banner', + standalone: true, + template: '' + }) + class MockErrorBanner {} + beforeEach(() => { TestBed.configureTestingModule({ - imports: [FlowFileTable, MatTableModule, BrowserAnimationsModule] + imports: [FlowFileTable, MockErrorBanner, MatTableModule, BrowserAnimationsModule], + providers: [ + provideMockStore({ + initialState + }) + ] }); fixture = TestBed.createComponent(FlowFileTable); 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/queue/ui/queue-listing/flowfile-table/flowfile-table.component.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/flowfile-table/flowfile-table.component.ts index be07533874..2404537651 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/flowfile-table/flowfile-table.component.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/flowfile-table/flowfile-table.component.ts @@ -25,12 +25,13 @@ import { NgForOf, NgIf } from '@angular/common'; import { RouterLink } from '@angular/router'; import { FlowFileSummary, ListingRequest } from '../../../state/queue-listing'; import { CurrentUser } from '../../../../../state/current-user'; +import { ErrorBanner } from '../../../../../ui/common/error-banner/error-banner.component'; @Component({ selector: 'flowfile-table', standalone: true, templateUrl: './flowfile-table.component.html', - imports: [MatTableModule, NgForOf, NgIf, RouterLink], + imports: [MatTableModule, NgForOf, NgIf, RouterLink, ErrorBanner], styleUrls: ['./flowfile-table.component.scss'] }) export class FlowFileTable { diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/queue-listing.component.html b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/queue-listing.component.html index c5824e47dc..7ade9f96e0 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/queue-listing.component.html +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/queue-listing.component.html @@ -17,23 +17,20 @@
-
- {{ error$ | async }} -
- - + + - - - + + +
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/queue-listing.component.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/queue-listing.component.ts index 2f48c84425..b340c24fcb 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/queue-listing.component.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/queue-listing.component.ts @@ -21,8 +21,7 @@ import { distinctUntilChanged, filter } from 'rxjs'; import { selectConnectionIdFromRoute, selectConnectionLabel, - selectError, - selectListingRequestEntity, + selectCompletedListingRequest, selectLoadedTimestamp, selectStatus } from '../../state/queue-listing/queue-listing.selectors'; @@ -41,6 +40,7 @@ import { NiFiState } from '../../../../state'; import { selectAbout } from '../../../../state/about/about.selectors'; import { About } from '../../../../state/about'; import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; +import { clearBannerErrors } from '../../../../state/error/error.actions'; @Component({ selector: 'queue-listing', @@ -49,10 +49,9 @@ import { takeUntilDestroyed } from '@angular/core/rxjs-interop'; }) export class QueueListing implements OnDestroy { status$ = this.store.select(selectStatus); - error$ = this.store.select(selectError); connectionLabel$ = this.store.select(selectConnectionLabel); loadedTimestamp$ = this.store.select(selectLoadedTimestamp); - listingRequestEntity$ = this.store.select(selectListingRequestEntity); + listingRequest$ = this.store.select(selectCompletedListingRequest); currentUser$ = this.store.select(selectCurrentUser); about$ = this.store.select(selectAbout); @@ -104,5 +103,6 @@ export class QueueListing implements OnDestroy { ngOnDestroy(): void { this.store.dispatch(resetQueueListingState()); + 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/queue/ui/queue-listing/queue-listing.module.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/queue-listing.module.ts index a35f591f7f..5e77a8f6ab 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/queue-listing.module.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/queue/ui/queue-listing/queue-listing.module.ts @@ -26,6 +26,7 @@ import { StoreModule } from '@ngrx/store'; import { EffectsModule } from '@ngrx/effects'; import { queueFeatureKey, reducers } from '../../state'; import { QueueListingEffects } from '../../state/queue-listing/queue-listing.effects'; +import { ErrorBanner } from '../../../../ui/common/error-banner/error-banner.component'; @NgModule({ declarations: [QueueListing], @@ -37,7 +38,8 @@ import { QueueListingEffects } from '../../state/queue-listing/queue-listing.eff NifiTooltipDirective, FlowFileTable, StoreModule.forFeature(queueFeatureKey, reducers), - EffectsModule.forFeature(QueueListingEffects) + EffectsModule.forFeature(QueueListingEffects), + ErrorBanner ] }) export class QueueListingModule {} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/summary/service/cluster-summary.service.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/summary/service/cluster-summary.service.ts index 476e999fd0..fab47aebf3 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/summary/service/cluster-summary.service.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/summary/service/cluster-summary.service.ts @@ -17,17 +17,13 @@ import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; -import { Client } from '../../../service/client.service'; import { Observable } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class ClusterSummaryService { private static readonly API: string = '../nifi-api'; - constructor( - private httpClient: HttpClient, - private client: Client - ) {} + constructor(private httpClient: HttpClient) {} getClusterSummary(): Observable { return this.httpClient.get(`${ClusterSummaryService.API}/flow/cluster/summary`); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/summary/service/process-group-status.service.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/summary/service/process-group-status.service.ts index 6d9818d6b5..e9d6618d93 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/summary/service/process-group-status.service.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/summary/service/process-group-status.service.ts @@ -17,17 +17,13 @@ import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; -import { Client } from '../../../service/client.service'; import { Observable } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class ProcessGroupStatusService { private static readonly API: string = '../nifi-api'; - constructor( - private httpClient: HttpClient, - private client: Client - ) {} + constructor(private httpClient: HttpClient) {} getProcessGroupsStatus(recursive?: boolean): Observable { if (recursive) { diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/summary/state/summary-listing/index.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/summary/state/summary-listing/index.ts index f1b1aefafa..cecb59c9de 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/summary/state/summary-listing/index.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/summary/state/summary-listing/index.ts @@ -199,6 +199,5 @@ export interface SummaryListingState { connectionStatusSnapshots: ConnectionStatusSnapshotEntity[]; remoteProcessGroupStatusSnapshots: RemoteProcessGroupStatusSnapshotEntity[]; 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/summary/state/summary-listing/summary-listing.actions.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/summary/state/summary-listing/summary-listing.actions.ts index c531bc1426..5b79d7b453 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/summary/state/summary-listing/summary-listing.actions.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/summary/state/summary-listing/summary-listing.actions.ts @@ -37,11 +37,6 @@ export const loadSummaryListingSuccess = createAction( props<{ response: SummaryListingResponse }>() ); -export const summaryListingApiError = createAction( - `${SUMMARY_LISTING_PREFIX} Load Summary Listing error`, - props<{ error: string }>() -); - export const selectProcessorStatus = createAction( `${SUMMARY_LISTING_PREFIX} Select Processor Status`, props<{ request: SelectProcessorStatusRequest }>() diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/summary/state/summary-listing/summary-listing.effects.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/summary/state/summary-listing/summary-listing.effects.ts index fe41f8aca5..ccf143ebe5 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/summary/state/summary-listing/summary-listing.effects.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/summary/state/summary-listing/summary-listing.effects.ts @@ -16,7 +16,7 @@ */ import { Injectable } from '@angular/core'; -import { Actions, createEffect, ofType } from '@ngrx/effects'; +import { Actions, concatLatestFrom, createEffect, ofType } from '@ngrx/effects'; import { Store } from '@ngrx/store'; import { NiFiState } from '../../../../state'; import { ClusterSummaryService } from '../../service/cluster-summary.service'; @@ -27,6 +27,9 @@ import * as StatusHistoryActions from '../../../../state/status-history/status-h import { catchError, combineLatest, filter, map, of, switchMap, tap } from 'rxjs'; import { Router } from '@angular/router'; import { ComponentType } from '../../../../state/shared'; +import { ErrorHelper } from '../../../../service/error-helper.service'; +import { HttpErrorResponse } from '@angular/common/http'; +import { selectSummaryListingStatus } from './summary-listing.selectors'; @Injectable() export class SummaryListingEffects { @@ -35,6 +38,7 @@ export class SummaryListingEffects { private store: Store, private clusterSummaryService: ClusterSummaryService, private pgStatusService: ProcessGroupStatusService, + private errorHelper: ErrorHelper, private router: Router ) {} @@ -42,7 +46,8 @@ export class SummaryListingEffects { this.actions$.pipe( ofType(SummaryListingActions.loadSummaryListing), map((action) => action.recursive), - switchMap((recursive) => + concatLatestFrom(() => this.store.select(selectSummaryListingStatus)), + switchMap(([recursive, listingStatus]) => combineLatest([ this.clusterSummaryService.getClusterSummary(), this.pgStatusService.getProcessGroupsStatus(recursive) @@ -55,7 +60,9 @@ export class SummaryListingEffects { } }) ), - catchError((error) => of(SummaryListingActions.summaryListingApiError({ error: error.error }))) + catchError((errorResponse: HttpErrorResponse) => + of(this.errorHelper.handleLoadingError(listingStatus, errorResponse)) + ) ) ) ) diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/summary/state/summary-listing/summary-listing.reducer.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/summary/state/summary-listing/summary-listing.reducer.ts index d8c0a94c66..b3a19d533a 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/summary/state/summary-listing/summary-listing.reducer.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/summary/state/summary-listing/summary-listing.reducer.ts @@ -25,12 +25,7 @@ import { RemoteProcessGroupStatusSnapshotEntity, SummaryListingState } from './index'; -import { - loadSummaryListing, - loadSummaryListingSuccess, - resetSummaryState, - summaryListingApiError -} from './summary-listing.actions'; +import { loadSummaryListing, loadSummaryListingSuccess, resetSummaryState } from './summary-listing.actions'; export const initialState: SummaryListingState = { clusterSummary: null, @@ -42,7 +37,6 @@ export const initialState: SummaryListingState = { connectionStatusSnapshots: [], remoteProcessGroupStatusSnapshots: [], status: 'pending', - error: null, loadedTimestamp: '' }; @@ -85,7 +79,6 @@ export const summaryListingReducer = createReducer( return { ...state, - error: null, status: 'success' as const, loadedTimestamp: response.status.processGroupStatus.statsLastRefreshed, processGroupStatus: response.status, @@ -99,12 +92,6 @@ export const summaryListingReducer = createReducer( }; }), - on(summaryListingApiError, (state, { error }) => ({ - ...state, - error, - status: 'error' as const - })), - on(resetSummaryState, () => ({ ...initialState })) diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/users/state/user-listing/index.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/users/state/user-listing/index.ts index b88ea61c4f..ec9bdf9529 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/users/state/user-listing/index.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/users/state/user-listing/index.ts @@ -116,6 +116,5 @@ export interface UserListingState { userGroups: UserGroupEntity[]; 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/users/state/user-listing/user-listing.actions.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/users/state/user-listing/user-listing.actions.ts index 0e33230507..32d8cfeada 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/users/state/user-listing/user-listing.actions.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/users/state/user-listing/user-listing.actions.ts @@ -44,7 +44,12 @@ export const loadTenantsSuccess = createAction( props<{ response: LoadTenantsSuccess }>() ); -export const usersApiError = createAction(`${USER_PREFIX} Users Api Error`, props<{ error: string }>()); +export const usersApiSnackbarError = createAction( + `${USER_PREFIX} Users Api Snackbar Error`, + props<{ error: string }>() +); + +export const usersApiBannerError = createAction(`${USER_PREFIX} Users Api Banner Error`, props<{ error: string }>()); export const openCreateTenantDialog = createAction(`${USER_PREFIX} Open Create Tenant Dialog`); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/users/state/user-listing/user-listing.effects.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/users/state/user-listing/user-listing.effects.ts index c134684d79..04baf2b6c4 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/users/state/user-listing/user-listing.effects.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/users/state/user-listing/user-listing.effects.ts @@ -26,12 +26,15 @@ import { MatDialog } from '@angular/material/dialog'; import { UsersService } from '../../service/users.service'; import { YesNoDialog } from '../../../../ui/common/yes-no-dialog/yes-no-dialog.component'; import { EditTenantDialog } from '../../../../ui/common/edit-tenant/edit-tenant-dialog.component'; -import { selectSaving, selectUserGroups, selectUsers } from './user-listing.selectors'; +import { selectSaving, selectStatus, selectUserGroups, selectUsers } from './user-listing.selectors'; import { EditTenantRequest, UserGroupEntity } from '../../../../state/shared'; import { selectTenant } from './user-listing.actions'; import { Client } from '../../../../service/client.service'; import { NiFiCommon } from '../../../../service/nifi-common.service'; import { UserAccessPolicies } from '../../ui/user-listing/user-access-policies/user-access-policies.component'; +import * as ErrorActions from '../../../../state/error/error.actions'; +import { ErrorHelper } from '../../../../service/error-helper.service'; +import { HttpErrorResponse } from '@angular/common/http'; @Injectable() export class UserListingEffects { @@ -44,13 +47,15 @@ export class UserListingEffects { private store: Store, private router: Router, private usersService: UsersService, + private errorHelper: ErrorHelper, private dialog: MatDialog ) {} loadTenants$ = createEffect(() => this.actions$.pipe( ofType(UserListingActions.loadTenants), - switchMap(() => + concatLatestFrom(() => this.store.select(selectStatus)), + switchMap(([, status]) => combineLatest([this.usersService.getUsers(), this.usersService.getUserGroups()]).pipe( map(([usersResponse, userGroupsResponse]) => UserListingActions.loadTenantsSuccess({ @@ -61,12 +66,8 @@ export class UserListingEffects { } }) ), - catchError((error) => - of( - UserListingActions.usersApiError({ - error: error.error - }) - ) + catchError((errorResponse: HttpErrorResponse) => + of(this.errorHelper.handleLoadingError(status, errorResponse)) ) ) ) @@ -155,7 +156,10 @@ export class UserListingEffects { } }) ), - catchError((error) => of(UserListingActions.usersApiError({ error: error.error }))) + catchError((errorResponse: HttpErrorResponse) => { + this.dialog.closeAll(); + return of(UserListingActions.usersApiSnackbarError({ error: errorResponse.error })); + }) ) ) ) @@ -219,6 +223,22 @@ export class UserListingEffects { ) ); + usersApiBannerError$ = createEffect(() => + this.actions$.pipe( + ofType(UserListingActions.usersApiBannerError), + map((action) => action.error), + switchMap((error) => of(ErrorActions.addBannerError({ error }))) + ) + ); + + usersApiSnackbarError$ = createEffect(() => + this.actions$.pipe( + ofType(UserListingActions.usersApiSnackbarError), + map((action) => action.error), + switchMap((error) => of(ErrorActions.snackBarError({ error }))) + ) + ); + awaitUpdateUserGroupsForCreateUser$ = createEffect(() => this.actions$.pipe( ofType(UserListingActions.createUserSuccess), @@ -263,7 +283,10 @@ export class UserListingEffects { } }) ), - catchError((error) => of(UserListingActions.usersApiError({ error: error.error }))) + catchError((errorResponse: HttpErrorResponse) => { + this.dialog.closeAll(); + return of(UserListingActions.usersApiSnackbarError({ error: errorResponse.error })); + }) ) ) ) @@ -360,6 +383,8 @@ export class UserListingEffects { }); dialogReference.afterClosed().subscribe(() => { + this.store.dispatch(ErrorActions.clearBannerErrors()); + this.store.dispatch( selectTenant({ id: request.user.id @@ -385,7 +410,9 @@ export class UserListingEffects { } }) ), - catchError((error) => of(UserListingActions.usersApiError({ error: error.error }))) + catchError((errorResponse: HttpErrorResponse) => + of(UserListingActions.usersApiBannerError({ error: errorResponse.error })) + ) ) ) ) @@ -560,6 +587,8 @@ export class UserListingEffects { }); dialogReference.afterClosed().subscribe(() => { + this.store.dispatch(ErrorActions.clearBannerErrors()); + this.store.dispatch( selectTenant({ id: request.userGroup.id @@ -585,7 +614,9 @@ export class UserListingEffects { } }) ), - catchError((error) => of(UserListingActions.usersApiError({ error: error.error }))) + catchError((errorResponse: HttpErrorResponse) => + of(UserListingActions.usersApiBannerError({ error: errorResponse.error })) + ) ) ) ) @@ -674,7 +705,9 @@ export class UserListingEffects { switchMap((request) => from(this.usersService.deleteUser(request.user)).pipe( map(() => UserListingActions.loadTenants()), - catchError((error) => of(UserListingActions.usersApiError({ error: error.error }))) + catchError((errorResponse: HttpErrorResponse) => + of(UserListingActions.usersApiSnackbarError({ error: errorResponse.error })) + ) ) ) ) @@ -713,7 +746,9 @@ export class UserListingEffects { switchMap((request) => from(this.usersService.deleteUserGroup(request.userGroup)).pipe( map(() => UserListingActions.loadTenants()), - catchError((error) => of(UserListingActions.usersApiError({ error: error.error }))) + catchError((errorResponse: HttpErrorResponse) => + of(UserListingActions.usersApiSnackbarError({ 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/users/state/user-listing/user-listing.reducer.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/users/state/user-listing/user-listing.reducer.ts index 7602d059fe..80b37a2b27 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/users/state/user-listing/user-listing.reducer.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/users/state/user-listing/user-listing.reducer.ts @@ -28,7 +28,9 @@ import { updateUser, updateUserComplete, updateUserGroup, - updateUserGroupSuccess + updateUserGroupSuccess, + usersApiBannerError, + usersApiSnackbarError } from './user-listing.actions'; export const initialState: UserListingState = { @@ -36,7 +38,6 @@ export const initialState: UserListingState = { userGroups: [], saving: false, loadedTimestamp: '', - error: null, status: 'pending' }; @@ -54,7 +55,6 @@ export const userListingReducer = createReducer( users: response.users, userGroups: response.userGroups, loadedTimestamp: response.loadedTimestamp, - error: null, status: 'success' as const })), on(createUser, updateUser, createUserGroup, updateUserGroup, (state) => ({ @@ -76,5 +76,9 @@ export const userListingReducer = createReducer( on(updateUserGroupSuccess, (state, { response }) => ({ ...state, saving: response.requestId == null ? false : state.saving + })), + on(usersApiSnackbarError, usersApiBannerError, (state) => ({ + ...state, + saving: false })) ); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/users/state/user-listing/user-listing.selectors.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/users/state/user-listing/user-listing.selectors.ts index 632381dbbe..b84caa15ca 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/users/state/user-listing/user-listing.selectors.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/users/state/user-listing/user-listing.selectors.ts @@ -24,6 +24,8 @@ export const selectUserListingState = createSelector(selectUserState, (state: Us export const selectSaving = createSelector(selectUserListingState, (state: UserListingState) => state.saving); +export const selectStatus = createSelector(selectUserListingState, (state: UserListingState) => state.status); + export const selectUsers = createSelector(selectUserListingState, (state: UserListingState) => state.users); export const selectUserGroups = createSelector(selectUserListingState, (state: UserListingState) => state.userGroups); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/edit-tenant/edit-tenant-dialog.component.html b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/edit-tenant/edit-tenant-dialog.component.html index 67b6cc27d7..2bf6307f68 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/edit-tenant/edit-tenant-dialog.component.html +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/edit-tenant/edit-tenant-dialog.component.html @@ -17,6 +17,7 @@

{{ isNew ? 'Add' : 'Edit' }} {{ isUser ? 'User' : 'User Group' }}

+
diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/edit-tenant/edit-tenant-dialog.component.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/edit-tenant/edit-tenant-dialog.component.spec.ts index c23f18a12b..50d88a8255 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/edit-tenant/edit-tenant-dialog.component.spec.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/edit-tenant/edit-tenant-dialog.component.spec.ts @@ -21,6 +21,9 @@ import { EditTenantDialog } from './edit-tenant-dialog.component'; import { EditTenantRequest } 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('EditTenantDialog', () => { let component: EditTenantDialog; @@ -782,10 +785,22 @@ describe('EditTenantDialog', () => { ] }; + @Component({ + selector: 'error-banner', + standalone: true, + template: '' + }) + class MockErrorBanner {} + beforeEach(() => { TestBed.configureTestingModule({ - imports: [EditTenantDialog, BrowserAnimationsModule], - providers: [{ provide: MAT_DIALOG_DATA, useValue: data }] + imports: [EditTenantDialog, MockErrorBanner, BrowserAnimationsModule], + providers: [ + { provide: MAT_DIALOG_DATA, useValue: data }, + provideMockStore({ + initialState + }) + ] }); fixture = TestBed.createComponent(EditTenantDialog); 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/edit-tenant/edit-tenant-dialog.component.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/edit-tenant/edit-tenant-dialog.component.ts index 2d34ba51de..0e2b5a94f5 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/edit-tenant/edit-tenant-dialog.component.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/edit-tenant/edit-tenant-dialog.component.ts @@ -40,6 +40,7 @@ import { Observable } from 'rxjs'; import { MatListModule } from '@angular/material/list'; import { Client } from '../../../service/client.service'; import { NiFiCommon } from '../../../service/nifi-common.service'; +import { ErrorBanner } from '../error-banner/error-banner.component'; @Component({ selector: 'edit-tenant-dialog', @@ -57,7 +58,8 @@ import { NiFiCommon } from '../../../service/nifi-common.service'; NgIf, AsyncPipe, MatListModule, - NgForOf + NgForOf, + ErrorBanner ], templateUrl: './edit-tenant-dialog.component.html', styleUrls: ['./edit-tenant-dialog.component.scss']