You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@nifi.apache.org by rf...@apache.org on 2024/02/09 14:37:13 UTC
(nifi) branch main updated: NIFI-12742: Error Handling in Summary, Users, and Queue Listing (#8366)
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 439c59e733 NIFI-12742: Error Handling in Summary, Users, and Queue Listing (#8366)
439c59e733 is described below
commit 439c59e73362e002e8576580e9ad3f3a696ffaae
Author: Matt Gilman <ma...@gmail.com>
AuthorDate: Fri Feb 9 09:37:07 2024 -0500
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
---
.../app/pages/queue/state/queue-listing/index.ts | 4 +-
.../state/queue-listing/queue-listing.actions.ts | 2 +
.../state/queue-listing/queue-listing.effects.ts | 103 +++++++++++++--------
.../state/queue-listing/queue-listing.reducer.ts | 48 ++++++++--
.../state/queue-listing/queue-listing.selectors.ts | 11 ++-
.../flowfile-table/flowfile-table.component.html | 1 +
.../flowfile-table.component.spec.ts | 17 +++-
.../flowfile-table/flowfile-table.component.ts | 3 +-
.../ui/queue-listing/queue-listing.component.html | 17 ++--
.../ui/queue-listing/queue-listing.component.ts | 8 +-
.../queue/ui/queue-listing/queue-listing.module.ts | 4 +-
.../summary/service/cluster-summary.service.ts | 6 +-
.../service/process-group-status.service.ts | 6 +-
.../pages/summary/state/summary-listing/index.ts | 3 +-
.../summary-listing/summary-listing.actions.ts | 5 -
.../summary-listing/summary-listing.effects.ts | 13 ++-
.../summary-listing/summary-listing.reducer.ts | 15 +--
.../app/pages/users/state/user-listing/index.ts | 3 +-
.../state/user-listing/user-listing.actions.ts | 7 +-
.../state/user-listing/user-listing.effects.ts | 63 ++++++++++---
.../state/user-listing/user-listing.reducer.ts | 10 +-
.../state/user-listing/user-listing.selectors.ts | 2 +
.../edit-tenant/edit-tenant-dialog.component.html | 1 +
.../edit-tenant-dialog.component.spec.ts | 19 +++-
.../edit-tenant/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<CanvasState>,
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,14 +25,17 @@ 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 selectStatus = createSelector(selectQueueListingState, (state: QueueListingState) => state.status);
+export const selectCompletedListingRequest = createSelector(
+ selectQueueListingState,
+ (state: QueueListingState) => state.completedListingRequest
+);
-export const selectError = createSelector(selectQueueListingState, (state: QueueListingState) => state.error);
+export const selectStatus = createSelector(selectQueueListingState, (state: QueueListingState) => state.status);
export const selectConnectionLabel = createSelector(
selectQueueListingState,
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 @@
<div class="flowfile-table h-full flex flex-col gap-y-2">
<h3 class="text-xl bold queue-listing-header">{{ connectionLabel }}</h3>
+ <error-banner></error-banner>
<div class="flex justify-between">
<div class="value">
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<FlowFileTable>;
+ @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 @@
<div class="flex flex-col gap-y-2 h-full" *ngIf="status$ | async; let status">
<div class="flex-1">
- <div class="value" *ngIf="status === 'error'; else noError">
- {{ error$ | async }}
- </div>
- <ng-template #noError>
- <ng-container *ngIf="listingRequestEntity$ | async as entity; else initialLoading">
+ <ng-container *ngIf="listingRequest$ | async as listingRequest; else initialLoading">
+ <ng-container *ngIf="about$ | async as about">
<flowfile-table
[connectionLabel]="(connectionLabel$ | async)!"
- [listingRequest]="entity.listingRequest"
+ [listingRequest]="listingRequest"
[currentUser]="(currentUser$ | async)!"
- [contentViewerAvailable]="contentViewerAvailable((about$ | async)!)"
+ [contentViewerAvailable]="contentViewerAvailable(about)"
(viewFlowFile)="viewFlowFile($event)"
(downloadContent)="downloadContent($event)"
(viewContent)="viewContent($event)"></flowfile-table>
</ng-container>
- <ng-template #initialLoading>
- <ngx-skeleton-loader count="3"></ngx-skeleton-loader>
- </ng-template>
+ </ng-container>
+ <ng-template #initialLoading>
+ <ngx-skeleton-loader count="3"></ngx-skeleton-loader>
</ng-template>
</div>
<div class="flex justify-between">
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<any> {
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<any> {
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<NiFiState>,
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<NiFiState>,
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 @@
<h2 mat-dialog-title>{{ isNew ? 'Add' : 'Edit' }} {{ isUser ? 'User' : 'User Group' }}</h2>
<form class="edit-tenant-form" [formGroup]="editTenantForm">
+ <error-banner></error-banner>
<mat-dialog-content>
<div class="mb-6">
<mat-radio-group formControlName="tenantType" (change)="tenantTypeChanged()">
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']