[NIFI-12519] - deselect parameter when it is deleted. (#8166)

* [NIFI-12519] - deselect parameter when it is deleted. also, enable goto controller service linking

* Added confirmation dialog in controller service edit when the form is dirty and the user attempts to route away using a referencing component link

* Reset state when closing the summary and counter pages.

This closes #8166
This commit is contained in:
Rob Fellows 2023-12-19 10:16:50 -05:00 committed by GitHub
parent 6b7b7cccf8
commit 703948b1d6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 104 additions and 41 deletions

View File

@ -19,6 +19,7 @@ import { Component, OnDestroy, OnInit } from '@angular/core';
import { Store } from '@ngrx/store';
import { NiFiState } from '../../../state';
import { startUserPolling, stopUserPolling } from '../../../state/user/user.actions';
import { resetCounterState } from '../state/counter-listing/counter-listing.actions';
@Component({
selector: 'counters',
@ -33,6 +34,7 @@ export class Counters implements OnInit, OnDestroy {
}
ngOnDestroy(): void {
this.store.dispatch(resetCounterState());
this.store.dispatch(stopUserPolling());
}
}

View File

@ -43,3 +43,5 @@ export const resetCounterSuccess = createAction(
`${COUNTER_PREFIX} Reset Counter Success`,
props<{ response: ResetCounterSuccess }>()
);
export const resetCounterState = createAction(`${COUNTER_PREFIX} Reset Counter State`);

View File

@ -17,7 +17,7 @@
import { CounterListingState } from './index';
import { createReducer, on } from '@ngrx/store';
import { loadCounters, loadCountersSuccess, resetCounterSuccess } from './counter-listing.actions';
import { loadCounters, loadCountersSuccess, resetCounterState, resetCounterSuccess } from './counter-listing.actions';
import { parameterContextListingApiError } from '../../../parameter-contexts/state/parameter-context-listing/parameter-context-listing.actions';
import { produce } from 'immer';
@ -57,5 +57,8 @@ export const counterListingReducer = createReducer(
};
}
});
})
}),
on(resetCounterState, (state) => ({
...initialState
}))
);

View File

@ -42,6 +42,8 @@ import { Client } from '../../../../service/client.service';
import { YesNoDialog } from '../../../../ui/common/yes-no-dialog/yes-no-dialog.component';
import { EditControllerService } from '../../../../ui/common/controller-service/edit-controller-service/edit-controller-service.component';
import {
ComponentType,
ControllerServiceReferencingComponent,
EditParameterRequest,
EditParameterResponse,
InlineServiceCreationRequest,
@ -277,6 +279,13 @@ export class ControllerServicesEffects {
}
};
editDialogReference.componentInstance.goToReferencingComponent = (
component: ControllerServiceReferencingComponent
) => {
const route: string[] = this.getRouteForReference(component);
goTo(route, component.referenceType);
};
if (parameterContext != null) {
editDialogReference.componentInstance.getParameters = (sensitive: boolean) => {
return this.flowService.getParameterContext(parameterContext.id).pipe(
@ -606,4 +615,24 @@ export class ControllerServicesEffects {
),
{ dispatch: false }
);
private getRouteForReference(reference: ControllerServiceReferencingComponent): string[] {
if (reference.referenceType == 'ControllerService') {
if (reference.groupId == null) {
return ['/settings', 'management-controller-services', reference.id];
} else {
return ['/process-groups', reference.groupId, 'controller-services', reference.id];
}
} else if (reference.referenceType == 'ReportingTask') {
return ['/settings', 'reporting-tasks', reference.id];
} else if (reference.referenceType == 'Processor') {
return ['/process-groups', reference.groupId, ComponentType.Processor, reference.id];
} else if (reference.referenceType == 'FlowAnalysisRule') {
return ['/settings', 'flow-analysis-rules', reference.id];
} else if (reference.referenceType == 'ParameterProvider') {
return ['/settings', 'parameter-providers', reference.id];
} else {
return ['/settings', 'registry-clients', reference.id];
}
}
}

View File

@ -67,6 +67,7 @@ import { CreatePort } from '../../ui/canvas/items/port/create-port/create-port.c
import { EditPort } from '../../ui/canvas/items/port/edit-port/edit-port.component';
import {
ComponentType,
ControllerServiceReferencingComponent,
EditParameterRequest,
EditParameterResponse,
InlineServiceCreationRequest,

View File

@ -129,7 +129,7 @@ export class ParameterReferences {
}
getRouteForReference(reference: AffectedComponent): string[] {
if (reference.referenceType == 'ControllerService') {
if (reference.referenceType === 'CONTROLLER_SERVICE') {
if (reference.processGroupId == null) {
return ['/settings', 'management-controller-services', reference.id];
} else {

View File

@ -74,7 +74,7 @@ export class ParameterTable implements AfterViewInit, ControlValueAccessor {
displayedColumns: string[] = ['name', 'value', 'actions'];
dataSource: MatTableDataSource<ParameterItem> = new MatTableDataSource<ParameterItem>();
selectedItem!: ParameterItem;
selectedItem: ParameterItem | null = null;
isDisabled: boolean = false;
isTouched: boolean = false;
@ -280,7 +280,7 @@ export class ParameterTable implements AfterViewInit, ControlValueAccessor {
item.entity.parameter.valueRemoved = true;
item.deleted = true;
item.dirty = true;
this.selectParameter(null);
this.handleChanged();
}
}
@ -327,7 +327,7 @@ export class ParameterTable implements AfterViewInit, ControlValueAccessor {
});
}
selectParameter(item: ParameterItem): void {
selectParameter(item: ParameterItem | null): void {
this.selectedItem = item;
}

View File

@ -29,6 +29,8 @@ import { Client } from '../../../../service/client.service';
import { YesNoDialog } from '../../../../ui/common/yes-no-dialog/yes-no-dialog.component';
import { EditControllerService } from '../../../../ui/common/controller-service/edit-controller-service/edit-controller-service.component';
import {
ComponentType,
ControllerServiceReferencingComponent,
InlineServiceCreationRequest,
InlineServiceCreationResponse,
NewPropertyDialogRequest,
@ -220,12 +222,12 @@ export class ManagementControllerServicesEffects {
);
};
const goTo = (commands: string[]): void => {
const goTo = (commands: string[], destination: string): void => {
if (editDialogReference.componentInstance.editControllerServiceForm.dirty) {
const saveChangesDialogReference = this.dialog.open(YesNoDialog, {
data: {
title: 'Controller Service Configuration',
message: `Save changes before going to this Controller Service?`
message: `Save changes before going to this ${destination}?`
},
panelClass: 'small-dialog'
});
@ -246,7 +248,14 @@ export class ManagementControllerServicesEffects {
editDialogReference.componentInstance.goToService = (serviceId: string) => {
const commands: string[] = ['/settings', 'management-controller-services', serviceId];
goTo(commands);
goTo(commands, 'Controller Service');
};
editDialogReference.componentInstance.goToReferencingComponent = (
component: ControllerServiceReferencingComponent
) => {
const route: string[] = this.getRouteForReference(component);
goTo(route, component.referenceType);
};
editDialogReference.componentInstance.createNewService = (
@ -465,4 +474,24 @@ export class ManagementControllerServicesEffects {
),
{ dispatch: false }
);
private getRouteForReference(reference: ControllerServiceReferencingComponent): string[] {
if (reference.referenceType == 'ControllerService') {
if (reference.groupId == null) {
return ['/settings', 'management-controller-services', reference.id];
} else {
return ['/process-groups', reference.groupId, 'controller-services', reference.id];
}
} else if (reference.referenceType == 'ReportingTask') {
return ['/settings', 'reporting-tasks', reference.id];
} else if (reference.referenceType == 'Processor') {
return ['/process-groups', reference.groupId, ComponentType.Processor, reference.id];
} else if (reference.referenceType == 'FlowAnalysisRule') {
return ['/settings', 'flow-analysis-rules', reference.id];
} else if (reference.referenceType == 'ParameterProvider') {
return ['/settings', 'parameter-providers', reference.id];
} else {
return ['/settings', 'registry-clients', reference.id];
}
}
}

View File

@ -19,7 +19,7 @@ import { Component, OnDestroy, OnInit } from '@angular/core';
import { Store } from '@ngrx/store';
import { NiFiState } from '../../../state';
import { startUserPolling, stopUserPolling } from '../../../state/user/user.actions';
import { loadSummaryListing } from '../state/summary-listing/summary-listing.actions';
import { loadSummaryListing, resetSummaryState } from '../state/summary-listing/summary-listing.actions';
interface TabLink {
label: string;
@ -49,6 +49,7 @@ export class Summary implements OnInit, OnDestroy {
}
ngOnDestroy(): void {
this.store.dispatch(resetSummaryState());
this.store.dispatch(stopUserPolling());
}
}

View File

@ -44,3 +44,5 @@ export const navigateToViewProcessorStatusHistory = createAction(
`${SUMMARY_LISTING_PREFIX} Navigate To Processor Status History`,
props<{ id: string }>()
);
export const resetSummaryState = createAction(`${SUMMARY_LISTING_PREFIX} Reset Summary State`);

View File

@ -16,13 +16,13 @@
*/
import { createReducer, on } from '@ngrx/store';
import { ProcessGroupStatusSnapshot, ProcessorStatusSnapshotEntity, SummaryListingState } from './index';
import {
AggregateSnapshot,
ProcessGroupStatusSnapshot,
ProcessorStatusSnapshotEntity,
SummaryListingState
} from './index';
import { loadSummaryListing, loadSummaryListingSuccess, summaryListingApiError } from './summary-listing.actions';
loadSummaryListing,
loadSummaryListingSuccess,
resetSummaryState,
summaryListingApiError
} from './summary-listing.actions';
export const initialState: SummaryListingState = {
clusterSummary: null,
@ -61,6 +61,10 @@ export const summaryListingReducer = createReducer(
...state,
error,
status: 'error' as const
})),
on(resetSummaryState, (state) => ({
...initialState
}))
);

View File

@ -99,7 +99,7 @@
<ng-template #validNonService>
<div [ngClass]="getNonServiceStateIcon(reference.component)"></div>
</ng-template>
<a [routerLink]="getRouteForReference(reference.component)" mat-dialog-close="ROUTED">{{
<a (click)="goToReferencingComponentClicked($event, reference.component)">{{
reference.component.name
}}</a>
<div
@ -134,9 +134,11 @@
<ng-template #validService>
<div [ngClass]="getServiceStateIcon(service.component)"></div>
</ng-template>
<a [routerLink]="getRouteForReference(service.component)" mat-dialog-close="ROUTED">{{
service.component.name
}}</a>
<a
(click)="goToReferencingComponentClicked($event, service.component)"
mat-dialog-close="ROUTED"
>{{ service.component.name }}</a
>
<div
class="pointer fa fa-sticky-note-o"
*ngIf="hasBulletins(service)"

View File

@ -18,6 +18,7 @@
import { Component, Input } from '@angular/core';
import {
BulletinsTipInput,
ComponentType,
ControllerServiceReferencingComponent,
ControllerServiceReferencingComponentEntity,
ValidationErrorsTipInput
@ -53,6 +54,7 @@ import { MatDialogModule } from '@angular/material/dialog';
})
export class ControllerServiceReferences {
@Input() serviceReferences!: ControllerServiceReferencingComponentEntity[];
@Input() goToReferencingComponent!: (component: ControllerServiceReferencingComponent) => void;
protected readonly ValidationErrorsTip = ValidationErrorsTip;
protected readonly BulletinsTip = BulletinsTip;
@ -102,24 +104,9 @@ export class ControllerServiceReferences {
}
}
getRouteForReference(reference: ControllerServiceReferencingComponent): string[] {
if (reference.referenceType == 'ControllerService') {
if (reference.groupId == null) {
return ['/settings', 'management-controller-services', reference.id];
} else {
return ['/process-groups', reference.groupId, 'controller-services', reference.id];
}
} else if (reference.referenceType == 'ReportingTask') {
return ['/settings', 'reporting-tasks', reference.id];
} else if (reference.referenceType == 'Processor') {
return ['/process-groups', reference.groupId, 'processors', reference.id];
} else if (reference.referenceType == 'FlowAnalysisRule') {
return ['/settings', 'flow-analysis-rules', reference.id];
} else if (reference.referenceType == 'ParameterProvider') {
return ['/settings', 'parameter-providers', reference.id];
} else {
return ['/settings', 'registry-clients', reference.id];
}
goToReferencingComponentClicked(event: MouseEvent, component: ControllerServiceReferencingComponent) {
event.stopPropagation();
this.goToReferencingComponent(component);
}
hasBulletins(entity: ControllerServiceReferencingComponentEntity): boolean {

View File

@ -70,9 +70,8 @@
<div>Referencing Components</div>
<div>
<controller-service-references
[serviceReferences]="
request.controllerService.component.referencingComponents
"></controller-service-references>
[serviceReferences]="request.controllerService.component.referencingComponents"
[goToReferencingComponent]="goToReferencingComponent"></controller-service-references>
</div>
</div>
</div>

View File

@ -21,6 +21,7 @@ import { AbstractControl, FormBuilder, FormControl, FormGroup, ReactiveFormsModu
import { Client } from '../../../../service/client.service';
import {
ControllerServiceEntity,
ControllerServiceReferencingComponent,
EditControllerServiceDialogRequest,
InlineServiceCreationRequest,
InlineServiceCreationResponse,
@ -74,6 +75,7 @@ export class EditControllerService {
@Input() goToParameter!: (parameter: string) => void;
@Input() convertToParameter!: (name: string, sensitive: boolean, value: string | null) => Observable<string>;
@Input() goToService!: (serviceId: string) => void;
@Input() goToReferencingComponent!: (component: ControllerServiceReferencingComponent) => void;
@Input() saving$!: Observable<boolean>;
@Output() editControllerService: EventEmitter<UpdateControllerServiceRequest> =
new EventEmitter<UpdateControllerServiceRequest>();