Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
</header>
<div class="px-5 flex-1 flex flex-col gap-y-2">
<h3 class="text-xl bold primary-color">NiFi Cluster</h3>

<error-banner></error-banner>
@if (getTabLinks(); as tabs) {
<!-- Don't show the tab bar if there is only 1 tab to show -->
<div class="cluster-tabs" [class.hidden]="tabs.length === 1">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import { CurrentUser } from '../../../state/current-user';
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
import { selectCurrentRoute } from '../../../state/router/router.selectors';
import { resetSystemDiagnostics } from '../../../state/system-diagnostics/system-diagnostics.actions';
import { clearBannerErrors } from '../../../state/error/error.actions';

interface TabLink {
label: string;
Expand Down Expand Up @@ -82,6 +83,7 @@ export class Cluster implements OnInit, OnDestroy {
ngOnDestroy(): void {
this.store.dispatch(resetClusterState());
this.store.dispatch(resetSystemDiagnostics());
this.store.dispatch(clearBannerErrors());
}

refresh() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { ClusterListingEffects } from '../state/cluster-listing/cluster-listing.
import { ClusterRoutingModule } from './cluster-routing.module';
import { MatTabsModule } from '@angular/material/tabs';
import { MatIconButton } from '@angular/material/button';
import { ErrorBanner } from '../../../ui/common/error-banner/error-banner.component';

@NgModule({
declarations: [Cluster],
Expand All @@ -37,7 +38,8 @@ import { MatIconButton } from '@angular/material/button';
StoreModule.forFeature(clusterFeatureKey, reducers),
EffectsModule.forFeature(ClusterListingEffects),
MatTabsModule,
MatIconButton
MatIconButton,
ErrorBanner
]
})
export class ClusterModule {}
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,13 @@
*/

import { Injectable } from '@angular/core';
import { Actions, concatLatestFrom, createEffect, ofType } from '@ngrx/effects';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { ActionCreator, Creator, Store } from '@ngrx/store';
import { NiFiState } from '../../../../state';
import { ErrorHelper } from '../../../../service/error-helper.service';
import { Router } from '@angular/router';
import * as ClusterListingActions from './cluster-listing.actions';
import { catchError, from, map, of, switchMap, take, tap } from 'rxjs';
import { SystemDiagnosticsService } from '../../../../service/system-diagnostics.service';
import { catchError, filter, from, map, of, switchMap, take, tap } from 'rxjs';
import { HttpErrorResponse } from '@angular/common/http';
import { selectClusterListingStatus } from './cluster-listing.selectors';
import { reloadSystemDiagnostics } from '../../../../state/system-diagnostics/system-diagnostics.actions';
Expand All @@ -35,6 +34,7 @@ import { ClusterNodeDetailDialog } from '../../ui/cluster-node-listing/cluster-n
import * as ErrorActions from '../../../../state/error/error.actions';
import { SelectClusterNodeRequest } from './index';
import { selectCurrentUser } from '../../../../state/current-user/current-user.selectors';
import { concatLatestFrom } from '@ngrx/operators';

@Injectable()
export class ClusterListingEffects {
Expand All @@ -43,20 +43,13 @@ export class ClusterListingEffects {
private store: Store<NiFiState>,
private errorHelper: ErrorHelper,
private router: Router,
private systemDiagnosticsService: SystemDiagnosticsService,
private clusterService: ClusterService,
private dialog: MatDialog
) {}

loadClusterListing$ = createEffect(() =>
this.actions$.pipe(
ofType(ClusterListingActions.loadClusterListing),
concatLatestFrom(() => this.store.select(selectCurrentUser)),
tap(([, currentUser]) => {
if (currentUser.systemPermissions.canRead) {
this.store.dispatch(reloadSystemDiagnostics({ request: { nodewise: true } }));
}
}),
concatLatestFrom(() => [this.store.select(selectClusterListingStatus)]),
switchMap(([, listingStatus]) =>
from(this.clusterService.getClusterListing()).pipe(
Expand All @@ -69,6 +62,22 @@ export class ClusterListingEffects {
)
);

loadClusterListingSuccess$ = createEffect(() =>
this.actions$.pipe(
ofType(ClusterListingActions.loadClusterListingSuccess),
concatLatestFrom(() => this.store.select(selectCurrentUser)),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

concatLatestFrom is imported from the wrong package. I also noticed that systemDiagnosticsService is injected in the constructor here but is not used anymore.

filter(([, currentUser]) => currentUser.systemPermissions.canRead),
map(() =>
reloadSystemDiagnostics({
request: {
nodewise: true,
errorStrategy: 'banner'
}
})
)
)
);

confirmAndDisconnectNode$ = createEffect(
() =>
this.actions$.pipe(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,6 @@ export const setDisconnectionAcknowledged = createAction(
props<{ disconnectionAcknowledged: boolean }>()
);

export const clusterSummaryApiError = createAction(
`${CLUSTER_SUMMARY_STATE_PREFIX} Cluster Summary Api Error`,
props<{ error: string }>()
);

export const clearClusterSummaryApiError = createAction(`${CLUSTER_SUMMARY_STATE_PREFIX} Clear About Api Error`);

export const searchCluster = createAction(
`${CLUSTER_SUMMARY_STATE_PREFIX} Search Cluster`,
props<{ request: ClusterSearchRequest }>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { Injectable } from '@angular/core';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { concatLatestFrom } from '@ngrx/operators';
import * as ClusterSummaryActions from './cluster-summary.actions';
import { acknowledgeClusterConnectionChange, setDisconnectionAcknowledged } from './cluster-summary.actions';
import { asyncScheduler, catchError, delay, filter, from, interval, map, of, switchMap, takeUntil, tap } from 'rxjs';
import { ClusterService } from '../../service/cluster.service';
import { selectClusterSummary } from './cluster-summary.selectors';
Expand All @@ -27,7 +28,6 @@ import { Store } from '@ngrx/store';
import { ClusterSummary, ClusterSummaryState } from './index';
import { HttpErrorResponse } from '@angular/common/http';
import * as ErrorActions from '../error/error.actions';
import { acknowledgeClusterConnectionChange, setDisconnectionAcknowledged } from './cluster-summary.actions';
import { OkDialog } from '../../ui/common/ok-dialog/ok-dialog.component';
import { MEDIUM_DIALOG } from '../../index';
import { MatDialog } from '@angular/material/dialog';
Expand Down Expand Up @@ -66,7 +66,15 @@ export class ClusterSummaryEffects {
response
});
}),
catchError((error) => of(ClusterSummaryActions.clusterSummaryApiError({ error: error.error })))
catchError((errorResponse: HttpErrorResponse) =>
of(
ErrorActions.snackBarError({
error: `Failed to load cluster summary - [${
errorResponse.error || errorResponse.status
}]`
})
)
)
)
);
})
Expand Down Expand Up @@ -138,7 +146,13 @@ export class ClusterSummaryEffects {
})
),
catchError((errorResponse: HttpErrorResponse) =>
of(ErrorActions.snackBarError({ error: errorResponse.error }))
of(
ErrorActions.snackBarError({
error: `Failed to search cluster summary - [${
errorResponse.error || errorResponse.status
}]`
})
)
)
);
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@
import { createReducer, on } from '@ngrx/store';
import { ClusterSummaryState } from './index';
import {
clearClusterSummaryApiError,
clusterSummaryApiError,
loadClusterSummary,
loadClusterSummarySuccess,
searchClusterSuccess,
Expand All @@ -30,7 +28,6 @@ export const initialState: ClusterSummaryState = {
disconnectionAcknowledged: false,
clusterSummary: null,
searchResults: null,
error: null,
status: 'pending'
};

Expand All @@ -43,19 +40,8 @@ export const clusterSummaryReducer = createReducer(
on(loadClusterSummarySuccess, (state, { response }) => ({
...state,
clusterSummary: response.clusterSummary,
error: null,
status: 'success' as const
})),
on(clusterSummaryApiError, (state, { error }) => ({
...state,
error,
status: 'error' as const
})),
on(clearClusterSummaryApiError, (state) => ({
...state,
error: null,
status: 'pending' as const
})),
on(searchClusterSuccess, (state, { response }) => ({
...state,
searchResults: response
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,5 @@ export interface ClusterSummaryState {
disconnectionAcknowledged: boolean;
clusterSummary: ClusterSummary | null;
searchResults: ClusterSearchResults | null;
error: string | null;
status: 'pending' | 'loading' | 'error' | 'success';
status: 'pending' | 'loading' | 'success';
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,6 @@ export const loadComponentStateSuccess = createAction(

export const openComponentStateDialog = createAction(`${COMPONENT_STATE_PREFIX} Open Component State Dialog`);

export const componentStateApiError = createAction(
`${COMPONENT_STATE_PREFIX} Component State API error`,
props<{ error: string }>()
);

export const clearComponentState = createAction(`${COMPONENT_STATE_PREFIX} Clear Component State`);

export const reloadComponentState = createAction(`${COMPONENT_STATE_PREFIX} Reload Component State`);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,14 +21,16 @@ import { concatLatestFrom } from '@ngrx/operators';
import { Store } from '@ngrx/store';
import { NiFiState } from '../index';
import * as ComponentStateActions from './component-state.actions';
import { resetComponentState } from './component-state.actions';
import { catchError, from, map, of, switchMap, tap } from 'rxjs';
import { MatDialog } from '@angular/material/dialog';
import { ComponentStateService } from '../../service/component-state.service';
import { ComponentStateDialog } from '../../ui/common/component-state/component-state.component';
import { resetComponentState } from './component-state.actions';
import { selectComponentUri } from './component-state.selectors';
import { isDefinedAndNotNull } from '../shared';
import { LARGE_DIALOG } from '../../index';
import * as ErrorActions from '../error/error.actions';
import { HttpErrorResponse } from '@angular/common/http';

@Injectable()
export class ComponentStateEffects {
Expand All @@ -53,10 +55,12 @@ export class ComponentStateEffects {
}
})
),
catchError((error) =>
catchError((errorResponse: HttpErrorResponse) =>
of(
ComponentStateActions.componentStateApiError({
error: error.error
ErrorActions.snackBarError({
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be a banner when it happens following clearComponentState?

error: `Failed to get the component state for ${request.componentName}. - [${
errorResponse.error || errorResponse.status
}]`
})
)
)
Expand Down Expand Up @@ -99,10 +103,12 @@ export class ComponentStateEffects {
from(
this.componentStateService.clearComponentState({ componentUri }).pipe(
map(() => ComponentStateActions.reloadComponentState()),
catchError((error) =>
catchError((errorResponse: HttpErrorResponse) =>
of(
ComponentStateActions.componentStateApiError({
error: error.error
ErrorActions.addBannerError({
error: `Failed to clear the component state. - [${
errorResponse.error || errorResponse.status
}]`
})
)
)
Expand All @@ -126,10 +132,12 @@ export class ComponentStateEffects {
}
})
),
catchError((error) =>
catchError((errorResponse: HttpErrorResponse) =>
of(
ComponentStateActions.componentStateApiError({
error: error.error
ErrorActions.addBannerError({
error: `Failed to reload the component state. - [${
errorResponse.error || errorResponse.status
}]`
})
)
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,20 +18,18 @@
import { ComponentStateState } from './index';
import { createReducer, on } from '@ngrx/store';
import {
resetComponentState,
loadComponentStateSuccess,
componentStateApiError,
getComponentStateAndOpenDialog,
reloadComponentStateSuccess
loadComponentStateSuccess,
reloadComponentStateSuccess,
resetComponentState
} from './component-state.actions';

export const initialState: ComponentStateState = {
componentName: null,
componentUri: null,
componentState: null,
canClear: null,
status: 'pending',
error: null
status: 'pending'
};

export const componentStateReducer = createReducer(
Expand All @@ -45,15 +43,9 @@ export const componentStateReducer = createReducer(
})),
on(loadComponentStateSuccess, reloadComponentStateSuccess, (state, { response }) => ({
...state,
error: null,
status: 'success' as const,
componentState: response.componentState
})),
on(componentStateApiError, (state, { error }) => ({
...state,
error,
status: 'error' as const
})),
on(resetComponentState, () => ({
...initialState
}))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,5 @@ export interface ComponentStateState {
componentUri: string | null;
componentState: ComponentState | null;
canClear: boolean | null;
error: string | null;
status: 'pending' | 'loading' | 'error' | 'success';
status: 'pending' | 'loading' | 'success';
}
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,6 @@ export const loadCurrentUserSuccess = createAction(
props<{ response: LoadCurrentUserResponse }>()
);

export const currentUserApiError = createAction('[Current User] Current User Api Error', props<{ error: string }>());

export const clearCurrentUserApiError = createAction('[Current User] Clear Current User Api Error');

export const startCurrentUserPolling = createAction('[Current User] Start Current User Polling');

export const stopCurrentUserPolling = createAction('[Current User] Stop Current User Polling');
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,14 @@ import { Actions, createEffect, ofType } from '@ngrx/effects';
import * as UserActions from './current-user.actions';
import { asyncScheduler, catchError, from, interval, map, of, switchMap, takeUntil } from 'rxjs';
import { CurrentUserService } from '../../service/current-user.service';
import { ErrorHelper } from '../../service/error-helper.service';

@Injectable()
export class CurrentUserEffects {
constructor(
private actions$: Actions,
private userService: CurrentUserService
private userService: CurrentUserService,
private errorHelper: ErrorHelper
) {}

loadCurrentUser$ = createEffect(() =>
Expand All @@ -41,7 +43,7 @@ export class CurrentUserEffects {
}
})
),
catchError((error) => of(UserActions.currentUserApiError({ error: error.error })))
catchError((error) => of(this.errorHelper.fullScreenError(error)))
)
);
})
Expand Down
Loading