diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/feature/flow-designer.module.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/feature/flow-designer.module.ts index 2343c09e6a..e1fdf96d7e 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/feature/flow-designer.module.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/feature/flow-designer.module.ts @@ -27,6 +27,7 @@ import { VersionControlTip } from '../ui/common/tooltips/version-control-tip/ver import { canvasFeatureKey, reducers } from '../state'; import { MatDialogModule } from '@angular/material/dialog'; import { ControllerServicesEffects } from '../state/controller-services/controller-services.effects'; +import { ParameterEffects } from '../state/parameter/parameter.effects'; @NgModule({ declarations: [FlowDesigner, VersionControlTip], @@ -35,7 +36,7 @@ import { ControllerServicesEffects } from '../state/controller-services/controll CommonModule, FlowDesignerRoutingModule, StoreModule.forFeature(canvasFeatureKey, reducers), - EffectsModule.forFeature(FlowEffects, TransformEffects, ControllerServicesEffects), + EffectsModule.forFeature(FlowEffects, TransformEffects, ControllerServicesEffects, ParameterEffects), NgOptimizedImage, MatDialogModule ] diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/behavior/connectable-behavior.service.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/behavior/connectable-behavior.service.spec.ts index c161f9865c..770425e0c1 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/behavior/connectable-behavior.service.spec.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/behavior/connectable-behavior.service.spec.ts @@ -29,6 +29,8 @@ import { controllerServicesFeatureKey } from '../../state/controller-services'; import * as fromControllerServices from '../../state/controller-services/controller-services.reducer'; import { selectUser } from '../../../../state/user/user.selectors'; import * as fromUser from '../../../../state/user/user.reducer'; +import { parameterFeatureKey } from '../../state/parameter'; +import * as fromParameter from '../../state/parameter/parameter.reducer'; describe('ConnectableBehavior', () => { let service: ConnectableBehavior; @@ -37,7 +39,8 @@ describe('ConnectableBehavior', () => { const initialState: CanvasState = { [flowFeatureKey]: fromFlow.initialState, [transformFeatureKey]: fromTransform.initialState, - [controllerServicesFeatureKey]: fromControllerServices.initialState + [controllerServicesFeatureKey]: fromControllerServices.initialState, + [parameterFeatureKey]: fromParameter.initialState }; TestBed.configureTestingModule({ diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/behavior/draggable-behavior.service.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/behavior/draggable-behavior.service.spec.ts index 71042a1b90..4ba0463a09 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/behavior/draggable-behavior.service.spec.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/behavior/draggable-behavior.service.spec.ts @@ -30,6 +30,8 @@ import { controllerServicesFeatureKey } from '../../state/controller-services'; import * as fromControllerServices from '../../state/controller-services/controller-services.reducer'; import { selectUser } from '../../../../state/user/user.selectors'; import * as fromUser from '../../../../state/user/user.reducer'; +import { parameterFeatureKey } from '../../state/parameter'; +import * as fromParameter from '../../state/parameter/parameter.reducer'; describe('DraggableBehavior', () => { let service: DraggableBehavior; @@ -38,7 +40,8 @@ describe('DraggableBehavior', () => { const initialState: CanvasState = { [flowFeatureKey]: fromFlow.initialState, [transformFeatureKey]: fromTransform.initialState, - [controllerServicesFeatureKey]: fromControllerServices.initialState + [controllerServicesFeatureKey]: fromControllerServices.initialState, + [parameterFeatureKey]: fromParameter.initialState }; TestBed.configureTestingModule({ diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/behavior/editable-behavior.service.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/behavior/editable-behavior.service.spec.ts index 0ca41ea7ab..e4f3039d67 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/behavior/editable-behavior.service.spec.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/behavior/editable-behavior.service.spec.ts @@ -30,6 +30,8 @@ import { controllerServicesFeatureKey } from '../../state/controller-services'; import * as fromControllerServices from '../../state/controller-services/controller-services.reducer'; import { selectUser } from '../../../../state/user/user.selectors'; import * as fromUser from '../../../../state/user/user.reducer'; +import { parameterFeatureKey } from '../../state/parameter'; +import * as fromParameter from '../../state/parameter/parameter.reducer'; describe('EditableBehaviorService', () => { let service: EditableBehavior; @@ -37,7 +39,8 @@ describe('EditableBehaviorService', () => { const initialState: CanvasState = { [flowFeatureKey]: fromFlow.initialState, [transformFeatureKey]: fromTransform.initialState, - [controllerServicesFeatureKey]: fromControllerServices.initialState + [controllerServicesFeatureKey]: fromControllerServices.initialState, + [parameterFeatureKey]: fromParameter.initialState }; beforeEach(() => { diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/behavior/quick-select-behavior.service.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/behavior/quick-select-behavior.service.spec.ts index fab7e0f9b6..84db152c65 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/behavior/quick-select-behavior.service.spec.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/behavior/quick-select-behavior.service.spec.ts @@ -29,6 +29,8 @@ import { controllerServicesFeatureKey } from '../../state/controller-services'; import * as fromControllerServices from '../../state/controller-services/controller-services.reducer'; import { selectUser } from '../../../../state/user/user.selectors'; import * as fromUser from '../../../../state/user/user.reducer'; +import { parameterFeatureKey } from '../../state/parameter'; +import * as fromParameter from '../../state/parameter/parameter.reducer'; describe('QuickSelectBehavior', () => { let service: QuickSelectBehavior; @@ -37,7 +39,8 @@ describe('QuickSelectBehavior', () => { const initialState: CanvasState = { [flowFeatureKey]: fromFlow.initialState, [transformFeatureKey]: fromTransform.initialState, - [controllerServicesFeatureKey]: fromControllerServices.initialState + [controllerServicesFeatureKey]: fromControllerServices.initialState, + [parameterFeatureKey]: fromParameter.initialState }; TestBed.configureTestingModule({ diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/behavior/selectable-behavior.service.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/behavior/selectable-behavior.service.spec.ts index e0cce0e31b..4ec93666ab 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/behavior/selectable-behavior.service.spec.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/behavior/selectable-behavior.service.spec.ts @@ -28,6 +28,8 @@ import { controllerServicesFeatureKey } from '../../state/controller-services'; import * as fromControllerServices from '../../state/controller-services/controller-services.reducer'; import { selectUser } from '../../../../state/user/user.selectors'; import * as fromUser from '../../../../state/user/user.reducer'; +import { parameterFeatureKey } from '../../state/parameter'; +import * as fromParameter from '../../state/parameter/parameter.reducer'; describe('SelectableBehavior', () => { let service: SelectableBehavior; @@ -36,7 +38,8 @@ describe('SelectableBehavior', () => { const initialState: CanvasState = { [flowFeatureKey]: fromFlow.initialState, [transformFeatureKey]: fromTransform.initialState, - [controllerServicesFeatureKey]: fromControllerServices.initialState + [controllerServicesFeatureKey]: fromControllerServices.initialState, + [parameterFeatureKey]: fromParameter.initialState }; TestBed.configureTestingModule({ diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/birdseye-view.service.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/birdseye-view.service.spec.ts index 93cf794068..0c9a1ac365 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/birdseye-view.service.spec.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/birdseye-view.service.spec.ts @@ -30,6 +30,8 @@ import { controllerServicesFeatureKey } from '../state/controller-services'; import * as fromControllerServices from '../state/controller-services/controller-services.reducer'; import { selectUser } from '../../../state/user/user.selectors'; import * as fromUser from '../../../state/user/user.reducer'; +import { parameterFeatureKey } from '../state/parameter'; +import * as fromParameter from '../state/parameter/parameter.reducer'; describe('BirdseyeView', () => { let service: BirdseyeView; @@ -38,7 +40,8 @@ describe('BirdseyeView', () => { const initialState: CanvasState = { [flowFeatureKey]: fromFlow.initialState, [transformFeatureKey]: fromTransform.initialState, - [controllerServicesFeatureKey]: fromControllerServices.initialState + [controllerServicesFeatureKey]: fromControllerServices.initialState, + [parameterFeatureKey]: fromParameter.initialState }; TestBed.configureTestingModule({ diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/canvas-utils.service.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/canvas-utils.service.spec.ts index ec7fb4ad4e..0b8bace3b5 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/canvas-utils.service.spec.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/canvas-utils.service.spec.ts @@ -29,6 +29,8 @@ import { controllerServicesFeatureKey } from '../state/controller-services'; import * as fromControllerServices from '../state/controller-services/controller-services.reducer'; import { selectUser } from '../../../state/user/user.selectors'; import * as fromUser from '../../../state/user/user.reducer'; +import { parameterFeatureKey } from '../state/parameter'; +import * as fromParameter from '../state/parameter/parameter.reducer'; describe('CanvasUtils', () => { let service: CanvasUtils; @@ -37,7 +39,8 @@ describe('CanvasUtils', () => { const initialState: CanvasState = { [flowFeatureKey]: fromFlow.initialState, [transformFeatureKey]: fromTransform.initialState, - [controllerServicesFeatureKey]: fromControllerServices.initialState + [controllerServicesFeatureKey]: fromControllerServices.initialState, + [parameterFeatureKey]: fromParameter.initialState }; TestBed.configureTestingModule({ diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/canvas-view.service.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/canvas-view.service.spec.ts index 77aa95ca71..4e3065382c 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/canvas-view.service.spec.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/canvas-view.service.spec.ts @@ -30,6 +30,8 @@ import { controllerServicesFeatureKey } from '../state/controller-services'; import * as fromControllerServices from '../state/controller-services/controller-services.reducer'; import { selectUser } from '../../../state/user/user.selectors'; import * as fromUser from '../../../state/user/user.reducer'; +import { parameterFeatureKey } from '../state/parameter'; +import * as fromParameter from '../state/parameter/parameter.reducer'; describe('CanvasView', () => { let service: CanvasView; @@ -38,7 +40,8 @@ describe('CanvasView', () => { const initialState: CanvasState = { [flowFeatureKey]: fromFlow.initialState, [transformFeatureKey]: fromTransform.initialState, - [controllerServicesFeatureKey]: fromControllerServices.initialState + [controllerServicesFeatureKey]: fromControllerServices.initialState, + [parameterFeatureKey]: fromParameter.initialState }; TestBed.configureTestingModule({ diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/flow.service.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/flow.service.ts index 6d56999806..a547a7604c 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/flow.service.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/flow.service.ts @@ -64,10 +64,6 @@ export class FlowService { return this.httpClient.get(`${FlowService.API}/flow/process-groups/${processGroupId}`); } - getControllerService(id: string): Observable { - return this.httpClient.get(`${FlowService.API}/controller-services/${id}`); - } - getProcessGroupStatus(processGroupId: string = 'root', recursive: boolean = false): Observable { return this.httpClient.get(`${FlowService.API}/flow/process-groups/${processGroupId}/status`, { params: { recursive: recursive } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/connection-manager.service.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/connection-manager.service.spec.ts index 222784270e..83f79ffa7a 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/connection-manager.service.spec.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/connection-manager.service.spec.ts @@ -30,6 +30,8 @@ import { controllerServicesFeatureKey } from '../../state/controller-services'; import * as fromControllerServices from '../../state/controller-services/controller-services.reducer'; import { selectUser } from '../../../../state/user/user.selectors'; import * as fromUser from '../../../../state/user/user.reducer'; +import { parameterFeatureKey } from '../../state/parameter'; +import * as fromParameter from '../../state/parameter/parameter.reducer'; describe('ConnectionManager', () => { let service: ConnectionManager; @@ -38,7 +40,8 @@ describe('ConnectionManager', () => { const initialState: CanvasState = { [flowFeatureKey]: fromFlow.initialState, [transformFeatureKey]: fromTransform.initialState, - [controllerServicesFeatureKey]: fromControllerServices.initialState + [controllerServicesFeatureKey]: fromControllerServices.initialState, + [parameterFeatureKey]: fromParameter.initialState }; TestBed.configureTestingModule({ diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/funnel-manager.service.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/funnel-manager.service.spec.ts index eff69edad4..d5cfa55708 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/funnel-manager.service.spec.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/funnel-manager.service.spec.ts @@ -30,6 +30,8 @@ import { controllerServicesFeatureKey } from '../../state/controller-services'; import * as fromControllerServices from '../../state/controller-services/controller-services.reducer'; import { selectUser } from '../../../../state/user/user.selectors'; import * as fromUser from '../../../../state/user/user.reducer'; +import { parameterFeatureKey } from '../../state/parameter'; +import * as fromParameter from '../../state/parameter/parameter.reducer'; describe('FunnelManager', () => { let service: FunnelManager; @@ -38,7 +40,8 @@ describe('FunnelManager', () => { const initialState: CanvasState = { [flowFeatureKey]: fromFlow.initialState, [transformFeatureKey]: fromTransform.initialState, - [controllerServicesFeatureKey]: fromControllerServices.initialState + [controllerServicesFeatureKey]: fromControllerServices.initialState, + [parameterFeatureKey]: fromParameter.initialState }; TestBed.configureTestingModule({ diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/label-manager.service.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/label-manager.service.spec.ts index 8eefbc4380..f44b2b2e69 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/label-manager.service.spec.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/label-manager.service.spec.ts @@ -30,6 +30,8 @@ import { controllerServicesFeatureKey } from '../../state/controller-services'; import * as fromControllerServices from '../../state/controller-services/controller-services.reducer'; import { selectUser } from '../../../../state/user/user.selectors'; import * as fromUser from '../../../../state/user/user.reducer'; +import { parameterFeatureKey } from '../../state/parameter'; +import * as fromParameter from '../../state/parameter/parameter.reducer'; describe('LabelManager', () => { let service: LabelManager; @@ -38,7 +40,8 @@ describe('LabelManager', () => { const initialState: CanvasState = { [flowFeatureKey]: fromFlow.initialState, [transformFeatureKey]: fromTransform.initialState, - [controllerServicesFeatureKey]: fromControllerServices.initialState + [controllerServicesFeatureKey]: fromControllerServices.initialState, + [parameterFeatureKey]: fromParameter.initialState }; TestBed.configureTestingModule({ diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/port-manager.service.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/port-manager.service.spec.ts index 748122019e..cd920ea3fb 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/port-manager.service.spec.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/port-manager.service.spec.ts @@ -30,6 +30,8 @@ import { controllerServicesFeatureKey } from '../../state/controller-services'; import * as fromControllerServices from '../../state/controller-services/controller-services.reducer'; import { selectUser } from '../../../../state/user/user.selectors'; import * as fromUser from '../../../../state/user/user.reducer'; +import { parameterFeatureKey } from '../../state/parameter'; +import * as fromParameter from '../../state/parameter/parameter.reducer'; describe('PortManager', () => { let service: PortManager; @@ -38,7 +40,8 @@ describe('PortManager', () => { const initialState: CanvasState = { [flowFeatureKey]: fromFlow.initialState, [transformFeatureKey]: fromTransform.initialState, - [controllerServicesFeatureKey]: fromControllerServices.initialState + [controllerServicesFeatureKey]: fromControllerServices.initialState, + [parameterFeatureKey]: fromParameter.initialState }; TestBed.configureTestingModule({ diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/process-group-manager.service.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/process-group-manager.service.spec.ts index 52ad6b0cd5..82f35f7404 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/process-group-manager.service.spec.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/process-group-manager.service.spec.ts @@ -30,6 +30,8 @@ import { controllerServicesFeatureKey } from '../../state/controller-services'; import * as fromControllerServices from '../../state/controller-services/controller-services.reducer'; import { selectUser } from '../../../../state/user/user.selectors'; import * as fromUser from '../../../../state/user/user.reducer'; +import { parameterFeatureKey } from '../../state/parameter'; +import * as fromParameter from '../../state/parameter/parameter.reducer'; describe('ProcessGroupManager', () => { let service: ProcessGroupManager; @@ -38,7 +40,8 @@ describe('ProcessGroupManager', () => { const initialState: CanvasState = { [flowFeatureKey]: fromFlow.initialState, [transformFeatureKey]: fromTransform.initialState, - [controllerServicesFeatureKey]: fromControllerServices.initialState + [controllerServicesFeatureKey]: fromControllerServices.initialState, + [parameterFeatureKey]: fromParameter.initialState }; TestBed.configureTestingModule({ diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/processor-manager.service.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/processor-manager.service.spec.ts index bfc23d105b..483c71c118 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/processor-manager.service.spec.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/processor-manager.service.spec.ts @@ -30,6 +30,8 @@ import { controllerServicesFeatureKey } from '../../state/controller-services'; import * as fromControllerServices from '../../state/controller-services/controller-services.reducer'; import { selectUser } from '../../../../state/user/user.selectors'; import * as fromUser from '../../../../state/user/user.reducer'; +import { parameterFeatureKey } from '../../state/parameter'; +import * as fromParameter from '../../state/parameter/parameter.reducer'; describe('ProcessorManager', () => { let service: ProcessorManager; @@ -38,7 +40,8 @@ describe('ProcessorManager', () => { const initialState: CanvasState = { [flowFeatureKey]: fromFlow.initialState, [transformFeatureKey]: fromTransform.initialState, - [controllerServicesFeatureKey]: fromControllerServices.initialState + [controllerServicesFeatureKey]: fromControllerServices.initialState, + [parameterFeatureKey]: fromParameter.initialState }; TestBed.configureTestingModule({ diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/remote-process-group-manager.service.spec.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/remote-process-group-manager.service.spec.ts index 8bb03c75ef..2a885caf80 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/remote-process-group-manager.service.spec.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/manager/remote-process-group-manager.service.spec.ts @@ -30,6 +30,8 @@ import { controllerServicesFeatureKey } from '../../state/controller-services'; import * as fromControllerServices from '../../state/controller-services/controller-services.reducer'; import { selectUser } from '../../../../state/user/user.selectors'; import * as fromUser from '../../../../state/user/user.reducer'; +import { parameterFeatureKey } from '../../state/parameter'; +import * as fromParameter from '../../state/parameter/parameter.reducer'; describe('RemoteProcessGroupManager', () => { let service: RemoteProcessGroupManager; @@ -38,7 +40,8 @@ describe('RemoteProcessGroupManager', () => { const initialState: CanvasState = { [flowFeatureKey]: fromFlow.initialState, [transformFeatureKey]: fromTransform.initialState, - [controllerServicesFeatureKey]: fromControllerServices.initialState + [controllerServicesFeatureKey]: fromControllerServices.initialState, + [parameterFeatureKey]: fromParameter.initialState }; TestBed.configureTestingModule({ diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/parameter.service.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/parameter.service.ts new file mode 100644 index 0000000000..d8e1731c68 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/service/parameter.service.ts @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Injectable } from '@angular/core'; +import { Observable, throwError } from 'rxjs'; +import { HttpClient } from '@angular/common/http'; +import { NiFiCommon } from '../../../service/nifi-common.service'; +import { ParameterContextUpdateRequest, SubmitParameterContextUpdate } from '../../../state/shared'; + +@Injectable({ providedIn: 'root' }) +export class ParameterService { + private static readonly API: string = '../nifi-api'; + + constructor( + private httpClient: HttpClient, + private nifiCommon: NiFiCommon + ) {} + + /** + * The NiFi model contain the url for each component. That URL is an absolute URL. Angular CSRF handling + * does not work on absolute URLs, so we need to strip off the proto for the request header to be added. + * + * https://stackoverflow.com/a/59586462 + * + * @param url + * @private + */ + private stripProtocol(url: string): string { + return this.nifiCommon.substringAfterFirst(url, ':'); + } + + getParameterContext(id: string, includeInheritedParameters: boolean): Observable { + return this.httpClient.get(`${ParameterService.API}/parameter-contexts/${id}`, { + params: { + includeInheritedParameters + } + }); + } + + submitParameterContextUpdate(configureParameterContext: SubmitParameterContextUpdate): Observable { + return this.httpClient.post( + `${ParameterService.API}/parameter-contexts/${configureParameterContext.id}/update-requests`, + configureParameterContext.payload + ); + } + + pollParameterContextUpdate(updateRequest: ParameterContextUpdateRequest): Observable { + return this.httpClient.get(this.stripProtocol(updateRequest.uri)); + } + + deleteParameterContextUpdate(updateRequest: ParameterContextUpdateRequest): Observable { + return this.httpClient.delete(this.stripProtocol(updateRequest.uri)); + } +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/controller-services/controller-services.effects.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/controller-services/controller-services.effects.ts index e4f99be402..abab561502 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/controller-services/controller-services.effects.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/controller-services/controller-services.effects.ts @@ -21,6 +21,7 @@ import * as ControllerServicesActions from './controller-services.actions'; import { catchError, combineLatest, + filter, from, map, NEVER, @@ -28,6 +29,7 @@ import { of, switchMap, take, + takeUntil, tap, withLatestFrom } from 'rxjs'; @@ -40,18 +42,29 @@ 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 { + EditParameterRequest, + EditParameterResponse, InlineServiceCreationRequest, InlineServiceCreationResponse, NewPropertyDialogRequest, NewPropertyDialogResponse, + Parameter, + ParameterEntity, Property, - PropertyDescriptor + PropertyDescriptor, + UpdateControllerServiceRequest } from '../../../../state/shared'; import { NewPropertyDialog } from '../../../../ui/common/new-property-dialog/new-property-dialog.component'; import { Router } from '@angular/router'; import { ExtensionTypesService } from '../../../../service/extension-types.service'; import { selectCurrentProcessGroupId, selectSaving } from './controller-services.selectors'; import { ControllerServiceService } from '../../service/controller-service.service'; +import { selectCurrentParameterContext } from '../flow/flow.selectors'; +import { FlowService } from '../../service/flow.service'; +import { EditParameterDialog } from '../../../../ui/common/edit-parameter-dialog/edit-parameter-dialog.component'; +import { selectParameterSaving } from '../parameter/parameter.selectors'; +import * as ParameterActions from '../parameter/parameter.actions'; +import { ParameterService } from '../../service/parameter.service'; @Injectable() export class ControllerServicesEffects { @@ -60,6 +73,8 @@ export class ControllerServicesEffects { private store: Store, private client: Client, private controllerServiceService: ControllerServiceService, + private flowService: FlowService, + private parameterService: ParameterService, private extensionTypesService: ExtensionTypesService, private dialog: MatDialog, private router: Router @@ -190,14 +205,18 @@ export class ControllerServicesEffects { this.actions$.pipe( ofType(ControllerServicesActions.openConfigureControllerServiceDialog), map((action) => action.request), - withLatestFrom(this.store.select(selectCurrentProcessGroupId)), - tap(([request, processGroupId]) => { + withLatestFrom( + this.store.select(selectCurrentParameterContext), + this.store.select(selectCurrentProcessGroupId) + ), + tap(([request, parameterContext, processGroupId]) => { const serviceId: string = request.id; const editDialogReference = this.dialog.open(EditControllerService, { data: { controllerService: request.controllerService }, + id: serviceId, panelClass: 'large-dialog' }); @@ -234,18 +253,134 @@ export class ControllerServicesEffects { ); }; - editDialogReference.componentInstance.getServiceLink = (serviceId: string) => { - return this.controllerServiceService.getControllerService(serviceId).pipe( - take(1), - map((serviceEntity) => { - return [ + 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 ${destination}?` + }, + panelClass: 'small-dialog' + }); + + saveChangesDialogReference.componentInstance.yes.pipe(take(1)).subscribe(() => { + editDialogReference.componentInstance.submitForm(commands); + }); + + saveChangesDialogReference.componentInstance.no.pipe(take(1)).subscribe(() => { + editDialogReference.close('ROUTED'); + this.router.navigate(commands); + }); + } else { + editDialogReference.close('ROUTED'); + this.router.navigate(commands); + } + }; + + if (parameterContext != null) { + editDialogReference.componentInstance.getParameters = (sensitive: boolean) => { + return this.flowService.getParameterContext(parameterContext.id).pipe( + take(1), + map((response) => response.component.parameters), + map((parameterEntities) => { + return parameterEntities + .map((parameterEntity: ParameterEntity) => parameterEntity.parameter) + .filter((parameter: Parameter) => parameter.sensitive == sensitive); + }) + ); + }; + + editDialogReference.componentInstance.parameterContext = parameterContext; + editDialogReference.componentInstance.goToParameter = (parameter: string) => { + const commands: string[] = ['/parameter-contexts', parameterContext.id]; + goTo(commands, 'Parameter'); + }; + + editDialogReference.componentInstance.convertToParameter = ( + name: string, + sensitive: boolean, + value: string | null + ) => { + return this.parameterService.getParameterContext(parameterContext.id, false).pipe( + switchMap((parameterContextEntity) => { + const existingParameters: string[] = + parameterContextEntity.component.parameters.map( + (parameterEntity: ParameterEntity) => parameterEntity.parameter.name + ); + const convertToParameterDialogRequest: EditParameterRequest = { + parameter: { + name, + value, + sensitive, + description: '' + }, + existingParameters + }; + const convertToParameterDialogReference = this.dialog.open(EditParameterDialog, { + data: convertToParameterDialogRequest, + panelClass: 'medium-dialog' + }); + + convertToParameterDialogReference.componentInstance.saving$ = + this.store.select(selectParameterSaving); + + convertToParameterDialogReference.componentInstance.cancel.pipe( + takeUntil(convertToParameterDialogReference.afterClosed()), + tap(() => ParameterActions.stopPollingParameterContextUpdateRequest()) + ); + + return convertToParameterDialogReference.componentInstance.editParameter.pipe( + takeUntil(convertToParameterDialogReference.afterClosed()), + switchMap((dialogResponse: EditParameterResponse) => { + this.store.dispatch( + ParameterActions.submitParameterContextUpdateRequest({ + request: { + id: parameterContext.id, + payload: { + revision: this.client.getRevision(parameterContextEntity), + component: { + id: parameterContextEntity.id, + parameters: [{ parameter: dialogResponse.parameter }] + } + } + } + }) + ); + + return this.store.select(selectParameterSaving).pipe( + takeUntil(convertToParameterDialogReference.afterClosed()), + filter((parameterSaving) => parameterSaving === false), + map(() => { + convertToParameterDialogReference.close(); + return `#{${dialogResponse.parameter.name}}`; + }) + ); + }) + ); + }), + catchError((error) => { + // TODO handle error + return NEVER; + }) + ); + }; + } + + editDialogReference.componentInstance.goToService = (serviceId: string) => { + this.controllerServiceService.getControllerService(serviceId).subscribe({ + next: (serviceEntity) => { + const commands: string[] = [ '/process-groups', serviceEntity.component.parentGroupId, 'controller-services', serviceEntity.id ]; - }) - ); + goTo(commands, 'Controller Service'); + }, + error: () => { + // TODO - handle error + } + }); }; editDialogReference.componentInstance.createNewService = ( @@ -289,13 +424,13 @@ export class ControllerServicesEffects { }) .pipe( take(1), - switchMap((createReponse) => { + switchMap((createResponse) => { // dispatch an inline create service success action so the new service is in the state this.store.dispatch( ControllerServicesActions.inlineCreateControllerServiceSuccess( { response: { - controllerService: createReponse + controllerService: createResponse } } ) @@ -310,7 +445,7 @@ export class ControllerServicesEffects { createServiceDialogReference.close(); return { - value: createReponse.id, + value: createResponse.id, descriptor: descriptorResponse.propertyDescriptor }; @@ -329,14 +464,15 @@ export class ControllerServicesEffects { }; editDialogReference.componentInstance.editControllerService - .pipe(take(1)) - .subscribe((payload: any) => { + .pipe(takeUntil(editDialogReference.afterClosed())) + .subscribe((updateControllerServiceRequest: UpdateControllerServiceRequest) => { this.store.dispatch( ControllerServicesActions.configureControllerService({ request: { id: request.controllerService.id, uri: request.controllerService.uri, - payload + payload: updateControllerServiceRequest.payload, + postUpdateNavigation: updateControllerServiceRequest.postUpdateNavigation } }) ); @@ -369,7 +505,8 @@ export class ControllerServicesEffects { ControllerServicesActions.configureControllerServiceSuccess({ response: { id: request.id, - controllerService: response + controllerService: response, + postUpdateNavigation: request.postUpdateNavigation } }) ), @@ -389,8 +526,14 @@ export class ControllerServicesEffects { () => this.actions$.pipe( ofType(ControllerServicesActions.configureControllerServiceSuccess), - tap(() => { - this.dialog.closeAll(); + map((action) => action.response), + tap((response) => { + if (response.postUpdateNavigation) { + this.router.navigate(response.postUpdateNavigation); + this.dialog.getDialogById(response.id)?.close('ROUTED'); + } else { + this.dialog.closeAll(); + } }) ), { dispatch: false } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/controller-services/index.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/controller-services/index.ts index 0fc6f55c5c..b9551f7784 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/controller-services/index.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/controller-services/index.ts @@ -46,11 +46,13 @@ export interface ConfigureControllerServiceRequest { id: string; uri: string; payload: any; + postUpdateNavigation?: string[]; } export interface ConfigureControllerServiceSuccess { id: string; controllerService: ControllerServiceEntity; + postUpdateNavigation?: string[]; } export interface DeleteControllerServiceRequest { diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/flow/flow.effects.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/flow/flow.effects.ts index c7f255f941..7eef83c20e 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/flow/flow.effects.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/flow/flow.effects.ts @@ -19,6 +19,7 @@ import { Injectable } from '@angular/core'; import { FlowService } from '../../service/flow.service'; import { Actions, createEffect, ofType } from '@ngrx/effects'; import * as FlowActions from './flow.actions'; +import * as ParameterActions from '../parameter/parameter.actions'; import { asyncScheduler, catchError, @@ -46,7 +47,8 @@ import { Snippet, UpdateComponentFailure, UpdateComponentResponse, - UpdateConnectionSuccess + UpdateConnectionSuccess, + UpdateProcessorRequest } from './index'; import { Action, Store } from '@ngrx/store'; import { @@ -65,6 +67,8 @@ 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, + EditParameterRequest, + EditParameterResponse, InlineServiceCreationRequest, InlineServiceCreationResponse, NewPropertyDialogRequest, @@ -94,6 +98,10 @@ import { CreateControllerService } from '../../../../ui/common/controller-servic import * as ControllerServicesActions from '../controller-services/controller-services.actions'; import { ExtensionTypesService } from '../../../../service/extension-types.service'; import { ControllerServiceService } from '../../service/controller-service.service'; +import { YesNoDialog } from '../../../../ui/common/yes-no-dialog/yes-no-dialog.component'; +import { EditParameterDialog } from '../../../../ui/common/edit-parameter-dialog/edit-parameter-dialog.component'; +import { selectParameterSaving } from '../parameter/parameter.selectors'; +import { ParameterService } from '../../service/parameter.service'; @Injectable() export class FlowEffects { @@ -103,6 +111,7 @@ export class FlowEffects { private flowService: FlowService, private extensionTypesService: ExtensionTypesService, private controllerServiceService: ControllerServiceService, + private parameterService: ParameterService, private client: Client, private canvasUtils: CanvasUtils, private canvasView: CanvasView, @@ -771,6 +780,7 @@ export class FlowEffects { const editDialogReference = this.dialog.open(EditProcessor, { data: request, + id: processorId, panelClass: 'large-dialog' }); @@ -807,6 +817,30 @@ export class FlowEffects { ); }; + const goTo = (commands: string[], destination: string): void => { + if (editDialogReference.componentInstance.editProcessorForm.dirty) { + const saveChangesDialogReference = this.dialog.open(YesNoDialog, { + data: { + title: 'Processor Configuration', + message: `Save changes before going to this ${destination}?` + }, + panelClass: 'small-dialog' + }); + + saveChangesDialogReference.componentInstance.yes.pipe(take(1)).subscribe(() => { + editDialogReference.componentInstance.submitForm(commands); + }); + + saveChangesDialogReference.componentInstance.no.pipe(take(1)).subscribe(() => { + editDialogReference.close('ROUTED'); + this.router.navigate(commands); + }); + } else { + editDialogReference.close('ROUTED'); + this.router.navigate(commands); + } + }; + if (parameterContext != null) { editDialogReference.componentInstance.getParameters = (sensitive: boolean) => { return this.flowService.getParameterContext(parameterContext.id).pipe( @@ -819,20 +853,98 @@ export class FlowEffects { }) ); }; + + editDialogReference.componentInstance.parameterContext = parameterContext; + editDialogReference.componentInstance.goToParameter = (parameter: string) => { + const commands: string[] = ['/parameter-contexts', parameterContext.id]; + goTo(commands, 'Parameter'); + }; + + editDialogReference.componentInstance.convertToParameter = ( + name: string, + sensitive: boolean, + value: string | null + ) => { + return this.parameterService.getParameterContext(parameterContext.id, false).pipe( + switchMap((parameterContextEntity) => { + const existingParameters: string[] = + parameterContextEntity.component.parameters.map( + (parameterEntity: ParameterEntity) => parameterEntity.parameter.name + ); + const convertToParameterDialogRequest: EditParameterRequest = { + parameter: { + name, + value, + sensitive, + description: '' + }, + existingParameters + }; + const convertToParameterDialogReference = this.dialog.open(EditParameterDialog, { + data: convertToParameterDialogRequest, + panelClass: 'medium-dialog' + }); + + convertToParameterDialogReference.componentInstance.saving$ = + this.store.select(selectParameterSaving); + + convertToParameterDialogReference.componentInstance.cancel.pipe( + takeUntil(convertToParameterDialogReference.afterClosed()), + tap(() => ParameterActions.stopPollingParameterContextUpdateRequest()) + ); + + return convertToParameterDialogReference.componentInstance.editParameter.pipe( + takeUntil(convertToParameterDialogReference.afterClosed()), + switchMap((dialogResponse: EditParameterResponse) => { + this.store.dispatch( + ParameterActions.submitParameterContextUpdateRequest({ + request: { + id: parameterContext.id, + payload: { + revision: this.client.getRevision(parameterContextEntity), + component: { + id: parameterContextEntity.id, + parameters: [{ parameter: dialogResponse.parameter }] + } + } + } + }) + ); + + return this.store.select(selectParameterSaving).pipe( + takeUntil(convertToParameterDialogReference.afterClosed()), + filter((parameterSaving) => parameterSaving === false), + map(() => { + convertToParameterDialogReference.close(); + return `#{${dialogResponse.parameter.name}}`; + }) + ); + }) + ); + }), + catchError((error) => { + // TODO handle error + return NEVER; + }) + ); + }; } - editDialogReference.componentInstance.getServiceLink = (serviceId: string) => { - return this.flowService.getControllerService(serviceId).pipe( - take(1), - map((serviceEntity) => { - return [ + editDialogReference.componentInstance.goToService = (serviceId: string) => { + this.controllerServiceService.getControllerService(serviceId).subscribe({ + next: (serviceEntity) => { + const commands: string[] = [ '/process-groups', serviceEntity.component.parentGroupId, 'controller-services', serviceEntity.id ]; - }) - ); + goTo(commands, 'Controller Service'); + }, + error: () => { + // TODO - handle error + } + }); }; editDialogReference.componentInstance.createNewService = ( @@ -917,14 +1029,15 @@ export class FlowEffects { editDialogReference.componentInstance.editProcessor .pipe(takeUntil(editDialogReference.afterClosed())) - .subscribe((payload: any) => { + .subscribe((updateProcessorRequest: UpdateProcessorRequest) => { this.store.dispatch( FlowActions.updateProcessor({ request: { id: processorId, uri: request.uri, type: request.type, - payload + payload: updateProcessorRequest.payload, + postUpdateNavigation: updateProcessorRequest.postUpdateNavigation } }) ); @@ -1082,7 +1195,8 @@ export class FlowEffects { requestId: request.requestId, id: request.id, type: request.type, - response: response + postUpdateNavigation: request.postUpdateNavigation, + response }; return FlowActions.updateComponentSuccess({ response: updateComponentResponse }); }), @@ -1104,8 +1218,14 @@ export class FlowEffects { () => this.actions$.pipe( ofType(FlowActions.updateComponentSuccess), - tap(() => { - this.dialog.closeAll(); + map((action) => action.response), + tap((response) => { + if (response.postUpdateNavigation) { + this.router.navigate(response.postUpdateNavigation); + this.dialog.getDialogById(response.id)?.close('ROUTED'); + } else { + this.dialog.closeAll(); + } }) ), { dispatch: false } @@ -1130,7 +1250,8 @@ export class FlowEffects { requestId: request.requestId, id: request.id, type: request.type, - response: response + postUpdateNavigation: request.postUpdateNavigation, + response }; return FlowActions.updateProcessorSuccess({ response: updateComponentResponse }); }), @@ -1151,10 +1272,16 @@ export class FlowEffects { updateProcessorSuccess$ = createEffect(() => this.actions$.pipe( ofType(FlowActions.updateProcessorSuccess), - tap(() => { - this.dialog.closeAll(); - }), map((action) => action.response), + tap((response) => { + if (response.postUpdateNavigation) { + this.router.navigate(response.postUpdateNavigation); + this.dialog.getDialogById(response.id)?.close('ROUTED'); + } else { + this.dialog.closeAll(); + } + }), + filter((response) => response.postUpdateNavigation == null), switchMap((response) => of(FlowActions.loadConnectionsForComponent({ id: response.id }))) ) ); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/flow/index.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/flow/index.ts index 47c8f56eef..9b1bb3106d 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/flow/index.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/flow/index.ts @@ -237,6 +237,11 @@ export interface EditConnectionDialogRequest extends EditComponentDialogRequest }; } +export interface UpdateProcessorRequest { + payload: any; + postUpdateNavigation?: string[]; +} + export interface UpdateComponentRequest { requestId?: number; id: string; @@ -244,6 +249,7 @@ export interface UpdateComponentRequest { uri: string; payload: any; restoreOnFailure?: any; + postUpdateNavigation?: string[]; } export interface UpdateComponentResponse { @@ -251,6 +257,7 @@ export interface UpdateComponentResponse { id: string; type: ComponentType; response: any; + postUpdateNavigation?: string[]; } export interface UpdateComponentFailure { diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/index.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/index.ts index 037c25a007..c84ab5c131 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/index.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/index.ts @@ -26,6 +26,8 @@ import { transformReducer } from './transform/transform.reducer'; import { flowReducer } from './flow/flow.reducer'; import { controllerServicesFeatureKey, ControllerServicesState } from './controller-services'; import { controllerServicesReducer } from './controller-services/controller-services.reducer'; +import { parameterFeatureKey, ParameterState } from './parameter'; +import { parameterReducer } from './parameter/parameter.reducer'; export const canvasFeatureKey = 'canvas'; @@ -33,13 +35,15 @@ export interface CanvasState { [flowFeatureKey]: FlowState; [transformFeatureKey]: CanvasTransform; [controllerServicesFeatureKey]: ControllerServicesState; + [parameterFeatureKey]: ParameterState; } export function reducers(state: CanvasState | undefined, action: Action) { return combineReducers({ [flowFeatureKey]: flowReducer, [transformFeatureKey]: transformReducer, - [controllerServicesFeatureKey]: controllerServicesReducer + [controllerServicesFeatureKey]: controllerServicesReducer, + [parameterFeatureKey]: parameterReducer })(state, action); } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/parameter/index.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/parameter/index.ts new file mode 100644 index 0000000000..215dbda6e7 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/parameter/index.ts @@ -0,0 +1,25 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { ParameterContextUpdateRequestEntity } from '../../../../state/shared'; + +export const parameterFeatureKey = 'parameter'; + +export interface ParameterState { + updateRequestEntity: ParameterContextUpdateRequestEntity | null; + saving: boolean; +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/parameter/parameter.actions.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/parameter/parameter.actions.ts new file mode 100644 index 0000000000..faaaa89c01 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/parameter/parameter.actions.ts @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createAction, props } from '@ngrx/store'; +import { PollParameterContextUpdateSuccess, SubmitParameterContextUpdate } from '../../../../state/shared'; + +export const parameterApiError = createAction('[Parameter] Parameter Error', props<{ error: string }>()); + +export const submitParameterContextUpdateRequest = createAction( + '[Parameter] Submit Parameter Context Update Request', + props<{ request: SubmitParameterContextUpdate }>() +); + +export const submitParameterContextUpdateRequestSuccess = createAction( + '[Parameter] Submit Parameter Context Update Request Success', + props<{ response: PollParameterContextUpdateSuccess }>() +); + +export const startPollingParameterContextUpdateRequest = createAction( + '[Parameter] Start Polling Parameter Context Update Request' +); + +export const pollParameterContextUpdateRequest = createAction('[Parameter] Poll Parameter Context Update Request'); + +export const pollParameterContextUpdateRequestSuccess = createAction( + '[Parameter] Poll Parameter Context Update Request Success', + props<{ response: PollParameterContextUpdateSuccess }>() +); + +export const stopPollingParameterContextUpdateRequest = createAction( + '[Parameter] Stop Polling Parameter Context Update Request' +); + +export const deleteParameterContextUpdateRequest = createAction('[Parameter] Delete Parameter Context Update Request'); + +export const editParameterContextComplete = createAction('[Parameter] Edit Parameter Context Complete'); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/parameter/parameter.effects.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/parameter/parameter.effects.ts new file mode 100644 index 0000000000..0c94a38f66 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/parameter/parameter.effects.ts @@ -0,0 +1,163 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { Injectable } from '@angular/core'; +import { Actions, createEffect, ofType } from '@ngrx/effects'; +import * as ParameterActions from './parameter.actions'; +import { Store } from '@ngrx/store'; +import { CanvasState } from '../index'; +import { + asyncScheduler, + catchError, + from, + interval, + map, + NEVER, + of, + switchMap, + takeUntil, + tap, + withLatestFrom +} from 'rxjs'; +import { ParameterContextUpdateRequest } from '../../../../state/shared'; +import { selectUpdateRequest } from './parameter.selectors'; +import { ParameterService } from '../../service/parameter.service'; + +@Injectable() +export class ParameterEffects { + constructor( + private actions$: Actions, + private store: Store, + private parameterService: ParameterService + ) {} + + submitParameterContextUpdateRequest$ = createEffect(() => + this.actions$.pipe( + ofType(ParameterActions.submitParameterContextUpdateRequest), + map((action) => action.request), + switchMap((request) => + from(this.parameterService.submitParameterContextUpdate(request)).pipe( + map((response) => + ParameterActions.submitParameterContextUpdateRequestSuccess({ + response: { + requestEntity: response + } + }) + ), + catchError((error) => + of( + ParameterActions.parameterApiError({ + error: error.error + }) + ) + ) + ) + ) + ) + ); + + submitParameterContextUpdateRequestSuccess$ = createEffect(() => + this.actions$.pipe( + ofType(ParameterActions.submitParameterContextUpdateRequestSuccess), + map((action) => action.response), + switchMap((response) => { + const updateRequest: ParameterContextUpdateRequest = response.requestEntity.request; + if (updateRequest.complete) { + return of(ParameterActions.deleteParameterContextUpdateRequest()); + } else { + return of(ParameterActions.startPollingParameterContextUpdateRequest()); + } + }) + ) + ); + + startPollingParameterContextUpdateRequest$ = createEffect(() => + this.actions$.pipe( + ofType(ParameterActions.startPollingParameterContextUpdateRequest), + switchMap(() => + interval(2000, asyncScheduler).pipe( + takeUntil(this.actions$.pipe(ofType(ParameterActions.stopPollingParameterContextUpdateRequest))) + ) + ), + switchMap(() => of(ParameterActions.pollParameterContextUpdateRequest())) + ) + ); + + pollParameterContextUpdateRequest$ = createEffect(() => + this.actions$.pipe( + ofType(ParameterActions.pollParameterContextUpdateRequest), + withLatestFrom(this.store.select(selectUpdateRequest)), + switchMap(([action, updateRequest]) => { + if (updateRequest) { + return from(this.parameterService.pollParameterContextUpdate(updateRequest.request)).pipe( + map((response) => + ParameterActions.pollParameterContextUpdateRequestSuccess({ + response: { + requestEntity: response + } + }) + ), + catchError((error) => + of( + ParameterActions.parameterApiError({ + error: error.error + }) + ) + ) + ); + } else { + return NEVER; + } + }) + ) + ); + + pollParameterContextUpdateRequestSuccess$ = createEffect(() => + this.actions$.pipe( + ofType(ParameterActions.pollParameterContextUpdateRequestSuccess), + map((action) => action.response), + switchMap((response) => { + const updateRequest: ParameterContextUpdateRequest = response.requestEntity.request; + if (updateRequest.complete) { + return of(ParameterActions.stopPollingParameterContextUpdateRequest()); + } else { + return NEVER; + } + }) + ) + ); + + stopPollingParameterContextUpdateRequest$ = createEffect(() => + this.actions$.pipe( + ofType(ParameterActions.stopPollingParameterContextUpdateRequest), + switchMap((response) => of(ParameterActions.deleteParameterContextUpdateRequest())) + ) + ); + + deleteParameterContextUpdateRequest$ = createEffect(() => + this.actions$.pipe( + ofType(ParameterActions.deleteParameterContextUpdateRequest), + withLatestFrom(this.store.select(selectUpdateRequest)), + tap(([action, updateRequest]) => { + if (updateRequest) { + this.parameterService.deleteParameterContextUpdate(updateRequest.request).subscribe(); + } + }), + switchMap(() => of(ParameterActions.editParameterContextComplete())) + ) + ); +} diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/parameter/parameter.reducer.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/parameter/parameter.reducer.ts new file mode 100644 index 0000000000..09237efeb1 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/parameter/parameter.reducer.ts @@ -0,0 +1,47 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createReducer, on } from '@ngrx/store'; +import { ParameterState } from './index'; +import { + editParameterContextComplete, + pollParameterContextUpdateRequestSuccess, + submitParameterContextUpdateRequest, + submitParameterContextUpdateRequestSuccess +} from './parameter.actions'; + +export const initialState: ParameterState = { + updateRequestEntity: null, + saving: false +}; + +export const parameterReducer = createReducer( + initialState, + on(submitParameterContextUpdateRequest, (state, { request }) => ({ + ...state, + saving: true + })), + on(submitParameterContextUpdateRequestSuccess, pollParameterContextUpdateRequestSuccess, (state, { response }) => ({ + ...state, + updateRequestEntity: response.requestEntity + })), + on(editParameterContextComplete, (state) => ({ + ...state, + saving: false, + updateRequestEntity: null + })) +); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/parameter/parameter.selectors.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/parameter/parameter.selectors.ts new file mode 100644 index 0000000000..bec6b20708 --- /dev/null +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/state/parameter/parameter.selectors.ts @@ -0,0 +1,32 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +import { createSelector } from '@ngrx/store'; +import { CanvasState, selectCanvasState } from '../index'; +import { parameterFeatureKey, ParameterState } from './index'; + +export const selectParameterState = createSelector( + selectCanvasState, + (state: CanvasState) => state[parameterFeatureKey] +); + +export const selectUpdateRequest = createSelector( + selectParameterState, + (state: ParameterState) => state.updateRequestEntity +); + +export const selectParameterSaving = createSelector(selectParameterState, (state: ParameterState) => state.saving); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/graph-controls/operation-control/operation-control.component.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/graph-controls/operation-control/operation-control.component.ts index 1944580e2f..fe97309c46 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/graph-controls/operation-control/operation-control.component.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/graph-controls/operation-control/operation-control.component.ts @@ -20,6 +20,7 @@ import { deleteComponents, getParameterContextsAndOpenGroupComponentsDialog, navigateToEditComponent, + navigateToEditCurrentProcessGroup, setOperationCollapsed } from '../../../../state/flow/flow.actions'; import { Store } from '@ngrx/store'; @@ -174,15 +175,19 @@ export class OperationControl { } configure(selection: any): void { - const selectionData = selection.datum(); - this.store.dispatch( - navigateToEditComponent({ - request: { - type: selectionData.type, - id: selectionData.id - } - }) - ); + if (selection.empty()) { + this.store.dispatch(navigateToEditCurrentProcessGroup()); + } else { + const selectionData = selection.datum(); + this.store.dispatch( + navigateToEditComponent({ + request: { + type: selectionData.type, + id: selectionData.id + } + }) + ); + } } canManageAccess(selection: any): boolean { diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/processor/edit-processor/edit-processor.component.html b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/processor/edit-processor/edit-processor.component.html index a9d0851948..166f54860f 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/processor/edit-processor/edit-processor.component.html +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/processor/edit-processor/edit-processor.component.html @@ -153,7 +153,10 @@ [createNewProperty]="createNewProperty" [createNewService]="createNewService" [getParameters]="getParameters" - [getServiceLink]="getServiceLink" + [goToParameter]="goToParameter" + [parameterContext]="parameterContext" + [convertToParameter]="convertToParameter" + [goToService]="goToService" [supportsSensitiveDynamicProperties]=" request.entity.component.supportsSensitiveDynamicProperties "> diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/processor/edit-processor/edit-processor.component.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/processor/edit-processor/edit-processor.component.ts index b2ae3dab09..6cb5893bd7 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/processor/edit-processor/edit-processor.component.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/flow-designer/ui/canvas/items/processor/edit-processor/edit-processor.component.ts @@ -30,13 +30,14 @@ import { InlineServiceCreationRequest, InlineServiceCreationResponse, Parameter, + ParameterContextReferenceEntity, Property, SelectOption, TextTipInput } from '../../../../../../../state/shared'; import { Client } from '../../../../../../../service/client.service'; import { NiFiCommon } from '../../../../../../../service/nifi-common.service'; -import { EditComponentDialogRequest } from '../../../../../state/flow'; +import { EditComponentDialogRequest, UpdateProcessorRequest } from '../../../../../state/flow'; import { PropertyTable } from '../../../../../../../ui/common/property-table/property-table.component'; import { NifiSpinnerDirective } from '../../../../../../../ui/common/spinner/nifi-spinner.directive'; import { NifiTooltipDirective } from '../../../../../../../ui/common/tooltips/nifi-tooltip.directive'; @@ -75,9 +76,12 @@ export class EditProcessor { @Input() createNewProperty!: (existingProperties: string[], allowsSensitive: boolean) => Observable; @Input() createNewService!: (request: InlineServiceCreationRequest) => Observable; @Input() getParameters!: (sensitive: boolean) => Observable; - @Input() getServiceLink!: (serviceId: string) => Observable; + @Input() parameterContext: ParameterContextReferenceEntity | undefined; + @Input() goToParameter!: (parameter: string) => void; + @Input() convertToParameter!: (name: string, sensitive: boolean, value: string | null) => Observable; + @Input() goToService!: (serviceId: string) => void; @Input() saving$!: Observable; - @Output() editProcessor: EventEmitter = new EventEmitter(); + @Output() editProcessor: EventEmitter = new EventEmitter(); protected readonly TextTip = TextTip; @@ -275,7 +279,7 @@ export class EditProcessor { ); } - submitForm() { + submitForm(postUpdateNavigation?: string[]) { const relationshipConfiguration: RelationshipConfiguration = this.editProcessorForm.get('relationshipConfiguration')?.value; const autoTerminated: string[] = relationshipConfiguration.relationships @@ -326,6 +330,9 @@ export class EditProcessor { payload.component.config.retryCount = relationshipConfiguration.retryCount; } - this.editProcessor.next(payload); + this.editProcessor.next({ + postUpdateNavigation, + payload + }); } } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/service/parameter-contexts.service.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/service/parameter-contexts.service.ts index 01dd297cdc..d013707af0 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/service/parameter-contexts.service.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/service/parameter-contexts.service.ts @@ -21,12 +21,11 @@ import { HttpClient } from '@angular/common/http'; import { Client } from '../../../service/client.service'; import { NiFiCommon } from '../../../service/nifi-common.service'; import { - SubmitParameterContextUpdate, CreateParameterContextRequest, DeleteParameterContextRequest, - ParameterContextEntity, - ParameterContextUpdateRequest + ParameterContextEntity } from '../state/parameter-context-listing'; +import { ParameterContextUpdateRequest, SubmitParameterContextUpdate } from '../../../state/shared'; @Injectable({ providedIn: 'root' }) export class ParameterContextService { diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/state/parameter-context-listing/index.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/state/parameter-context-listing/index.ts index 143018c08f..682ed87b98 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/state/parameter-context-listing/index.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/state/parameter-context-listing/index.ts @@ -18,6 +18,7 @@ import { AffectedComponentEntity, ParameterContextReferenceEntity, + ParameterContextUpdateRequestEntity, ParameterEntity, Permissions, Revision @@ -46,15 +47,6 @@ export interface EditParameterContextRequest { parameterContext?: ParameterContextEntity; } -export interface SubmitParameterContextUpdate { - id: string; - payload: any; -} - -export interface PollParameterContextUpdateSuccess { - requestEntity: ParameterContextUpdateRequestEntity; -} - export interface DeleteParameterContextRequest { parameterContext: ParameterContextEntity; } @@ -67,23 +59,6 @@ export interface SelectParameterContextRequest { id: string; } -export interface ParameterContextUpdateRequest { - complete: boolean; - lastUpdated: string; - percentComponent: number; - referencingComponents: AffectedComponentEntity[]; - requestId: string; - state: string; - updateSteps: any[]; - uri: string; - parameterContext?: any; -} - -export interface ParameterContextUpdateRequestEntity { - parameterContextRevision: Revision; - request: ParameterContextUpdateRequest; -} - export interface ParameterContextEntity { revision: Revision; permissions: Permissions; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/state/parameter-context-listing/parameter-context-listing.actions.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/state/parameter-context-listing/parameter-context-listing.actions.ts index aaba73f277..14ccaa463d 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/state/parameter-context-listing/parameter-context-listing.actions.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/state/parameter-context-listing/parameter-context-listing.actions.ts @@ -17,7 +17,6 @@ import { createAction, props } from '@ngrx/store'; import { - SubmitParameterContextUpdate, CreateParameterContextRequest, CreateParameterContextSuccess, DeleteParameterContextRequest, @@ -25,9 +24,9 @@ import { EditParameterContextRequest, LoadParameterContextsResponse, SelectParameterContextRequest, - PollParameterContextUpdateSuccess, GetEffectiveParameterContext } from './index'; +import { PollParameterContextUpdateSuccess, SubmitParameterContextUpdate } from '../../../../state/shared'; export const loadParameterContexts = createAction('[Parameter Context Listing] Load Parameter Contexts'); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/state/parameter-context-listing/parameter-context-listing.effects.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/state/parameter-context-listing/parameter-context-listing.effects.ts index 1c9a4ff17d..1c574d9aeb 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/state/parameter-context-listing/parameter-context-listing.effects.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/state/parameter-context-listing/parameter-context-listing.effects.ts @@ -41,9 +41,13 @@ import { ParameterContextService } from '../../service/parameter-contexts.servic import { YesNoDialog } from '../../../../ui/common/yes-no-dialog/yes-no-dialog.component'; import { EditParameterContext } from '../../ui/parameter-context-listing/edit-parameter-context/edit-parameter-context.component'; import { selectParameterContexts, selectSaving, selectUpdateRequest } from './parameter-context-listing.selectors'; -import { EditParameterRequest, EditParameterResponse, Parameter } from '../../../../state/shared'; +import { + EditParameterRequest, + EditParameterResponse, + Parameter, + ParameterContextUpdateRequest +} from '../../../../state/shared'; import { EditParameterDialog } from '../../../../ui/common/edit-parameter-dialog/edit-parameter-dialog.component'; -import { ParameterContextUpdateRequest } from './index'; import { OkDialog } from '../../../../ui/common/ok-dialog/ok-dialog.component'; @Injectable() @@ -104,7 +108,7 @@ export class ParameterContextListingEffects { panelClass: 'medium-dialog' }); - newParameterDialogReference.componentInstance.saving = false; + newParameterDialogReference.componentInstance.saving$ = of(false); return newParameterDialogReference.componentInstance.editParameter.pipe( take(1), @@ -236,7 +240,7 @@ export class ParameterContextListingEffects { panelClass: 'medium-dialog' }); - newParameterDialogReference.componentInstance.saving = false; + newParameterDialogReference.componentInstance.saving$ = of(false); return newParameterDialogReference.componentInstance.editParameter.pipe( take(1), @@ -263,7 +267,7 @@ export class ParameterContextListingEffects { panelClass: 'medium-dialog' }); - editParameterDialogReference.componentInstance.saving = false; + editParameterDialogReference.componentInstance.saving$ = of(false); return editParameterDialogReference.componentInstance.editParameter.pipe( take(1), @@ -336,7 +340,14 @@ export class ParameterContextListingEffects { this.actions$.pipe( ofType(ParameterContextListingActions.submitParameterContextUpdateRequestSuccess), map((action) => action.response), - switchMap((response) => of(ParameterContextListingActions.startPollingParameterContextUpdateRequest())) + switchMap((response) => { + const updateRequest: ParameterContextUpdateRequest = response.requestEntity.request; + if (updateRequest.complete) { + return of(ParameterContextListingActions.deleteParameterContextUpdateRequest()); + } else { + return of(ParameterContextListingActions.startPollingParameterContextUpdateRequest()); + } + }) ) ); diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/state/parameter-context-listing/parameter-context-listing.reducer.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/state/parameter-context-listing/parameter-context-listing.reducer.ts index 631b909efc..8453373d19 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/state/parameter-context-listing/parameter-context-listing.reducer.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/state/parameter-context-listing/parameter-context-listing.reducer.ts @@ -16,7 +16,7 @@ */ import { createReducer, on } from '@ngrx/store'; -import { ParameterContextListingState, ParameterContextUpdateRequestEntity } from './index'; +import { ParameterContextListingState } from './index'; import { produce } from 'immer'; import { createParameterContext, @@ -30,7 +30,7 @@ import { submitParameterContextUpdateRequest, submitParameterContextUpdateRequestSuccess } from './parameter-context-listing.actions'; -import { Revision } from '../../../../state/shared'; +import { ParameterContextUpdateRequestEntity, Revision } from '../../../../state/shared'; export const initialState: ParameterContextListingState = { parameterContexts: [], @@ -74,11 +74,7 @@ export const parameterContextListingReducer = createReducer( ...state, saving: true })), - on(submitParameterContextUpdateRequestSuccess, (state, { response }) => ({ - ...state, - updateRequestEntity: response.requestEntity - })), - on(pollParameterContextUpdateRequestSuccess, (state, { response }) => ({ + on(submitParameterContextUpdateRequestSuccess, pollParameterContextUpdateRequestSuccess, (state, { response }) => ({ ...state, updateRequestEntity: response.requestEntity })), diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/ui/parameter-context-listing/edit-parameter-context/edit-parameter-context.component.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/ui/parameter-context-listing/edit-parameter-context/edit-parameter-context.component.ts index 32db6e5fc0..1e33e33927 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/ui/parameter-context-listing/edit-parameter-context/edit-parameter-context.component.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/parameter-contexts/ui/parameter-context-listing/edit-parameter-context/edit-parameter-context.component.ts @@ -25,16 +25,12 @@ import { AsyncPipe, NgForOf, NgIf } from '@angular/common'; import { MatTabsModule } from '@angular/material/tabs'; import { MatOptionModule } from '@angular/material/core'; import { MatSelectModule } from '@angular/material/select'; -import { Observable, take, tap } from 'rxjs'; -import { - EditParameterContextRequest, - ParameterContextEntity, - ParameterContextUpdateRequestEntity -} from '../../../state/parameter-context-listing'; +import { Observable } from 'rxjs'; +import { EditParameterContextRequest, ParameterContextEntity } from '../../../state/parameter-context-listing'; import { NifiSpinnerDirective } from '../../../../../ui/common/spinner/nifi-spinner.directive'; import { Client } from '../../../../../service/client.service'; import { ParameterTable } from '../parameter-table/parameter-table.component'; -import { Parameter, ParameterEntity } from '../../../../../state/shared'; +import { Parameter, ParameterContextUpdateRequestEntity, ParameterEntity } from '../../../../../state/shared'; import { ProcessGroupReferences } from '../process-group-references/process-group-references.component'; import { ParameterContextInheritance } from '../parameter-context-inheritance/parameter-context-inheritance.component'; import { ParameterReferences } from '../parameter-references/parameter-references.component'; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/management-controller-services/index.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/management-controller-services/index.ts index c950d67249..9db8417be2 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/management-controller-services/index.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/management-controller-services/index.ts @@ -38,11 +38,13 @@ export interface ConfigureControllerServiceRequest { id: string; uri: string; payload: any; + postUpdateNavigation?: string[]; } export interface ConfigureControllerServiceSuccess { id: string; controllerService: ControllerServiceEntity; + postUpdateNavigation?: string[]; } export interface DeleteControllerServiceRequest { diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/management-controller-services/management-controller-services.effects.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/management-controller-services/management-controller-services.effects.ts index c774cde2fd..9bce0382d3 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/management-controller-services/management-controller-services.effects.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/management-controller-services/management-controller-services.effects.ts @@ -34,7 +34,8 @@ import { NewPropertyDialogRequest, NewPropertyDialogResponse, Property, - PropertyDescriptor + PropertyDescriptor, + UpdateControllerServiceRequest } from '../../../../state/shared'; import { NewPropertyDialog } from '../../../../ui/common/new-property-dialog/new-property-dialog.component'; import { Router } from '@angular/router'; @@ -182,6 +183,7 @@ export class ManagementControllerServicesEffects { data: { controllerService: request.controllerService }, + id: serviceId, panelClass: 'large-dialog' }); @@ -218,8 +220,33 @@ export class ManagementControllerServicesEffects { ); }; - editDialogReference.componentInstance.getServiceLink = (serviceId: string) => { - return of(['/settings', 'management-controller-services', serviceId]); + const goTo = (commands: 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?` + }, + panelClass: 'small-dialog' + }); + + saveChangesDialogReference.componentInstance.yes.pipe(take(1)).subscribe(() => { + editDialogReference.componentInstance.submitForm(commands); + }); + + saveChangesDialogReference.componentInstance.no.pipe(take(1)).subscribe(() => { + editDialogReference.close('ROUTED'); + this.router.navigate(commands); + }); + } else { + editDialogReference.close('ROUTED'); + this.router.navigate(commands); + } + }; + + editDialogReference.componentInstance.goToService = (serviceId: string) => { + const commands: string[] = ['/settings', 'management-controller-services', serviceId]; + goTo(commands); }; editDialogReference.componentInstance.createNewService = ( @@ -303,13 +330,14 @@ export class ManagementControllerServicesEffects { editDialogReference.componentInstance.editControllerService .pipe(takeUntil(editDialogReference.afterClosed())) - .subscribe((payload: any) => { + .subscribe((updateControllerServiceRequest: UpdateControllerServiceRequest) => { this.store.dispatch( ManagementControllerServicesActions.configureControllerService({ request: { id: request.controllerService.id, uri: request.controllerService.uri, - payload + payload: updateControllerServiceRequest.payload, + postUpdateNavigation: updateControllerServiceRequest.postUpdateNavigation } }) ); @@ -341,7 +369,8 @@ export class ManagementControllerServicesEffects { ManagementControllerServicesActions.configureControllerServiceSuccess({ response: { id: request.id, - controllerService: response + controllerService: response, + postUpdateNavigation: request.postUpdateNavigation } }) ), @@ -361,8 +390,14 @@ export class ManagementControllerServicesEffects { () => this.actions$.pipe( ofType(ManagementControllerServicesActions.configureControllerServiceSuccess), - tap(() => { - this.dialog.closeAll(); + map((action) => action.response), + tap((response) => { + if (response.postUpdateNavigation) { + this.router.navigate(response.postUpdateNavigation); + this.dialog.getDialogById(response.id)?.close('ROUTED'); + } else { + this.dialog.closeAll(); + } }) ), { dispatch: false } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/registry-clients/index.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/registry-clients/index.ts index f21667e154..c7c84e93b6 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/registry-clients/index.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/registry-clients/index.ts @@ -49,11 +49,13 @@ export interface EditRegistryClientRequest { id: string; uri: string; payload: any; + postUpdateNavigation?: string[]; } export interface EditRegistryClientRequestSuccess { id: string; registryClient: RegistryClientEntity; + postUpdateNavigation?: string[]; } export interface DeleteRegistryClientRequest { diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/registry-clients/registry-clients.effects.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/registry-clients/registry-clients.effects.ts index 33133a65e1..925f473018 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/registry-clients/registry-clients.effects.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/state/registry-clients/registry-clients.effects.ts @@ -42,6 +42,7 @@ import { ExtensionTypesService } from '../../../../service/extension-types.servi import { CreateControllerService } from '../../../../ui/common/controller-service/create-controller-service/create-controller-service.component'; import { ManagementControllerServiceService } from '../../service/management-controller-service.service'; import { Client } from '../../../../service/client.service'; +import { EditRegistryClientRequest } from './index'; @Injectable() export class RegistryClientsEffects { @@ -174,6 +175,7 @@ export class RegistryClientsEffects { const editDialogReference = this.dialog.open(EditRegistryClient, { data: request, + id: registryClientId, panelClass: 'large-dialog' }); @@ -214,8 +216,30 @@ export class RegistryClientsEffects { ); }; - editDialogReference.componentInstance.getServiceLink = (serviceId: string) => { - return of(['/settings', 'management-controller-services', serviceId]); + editDialogReference.componentInstance.goToService = (serviceId: string) => { + const commands: string[] = ['/settings', 'management-controller-services', serviceId]; + + if (editDialogReference.componentInstance.editRegistryClientForm.dirty) { + const saveChangesDialogReference = this.dialog.open(YesNoDialog, { + data: { + title: 'Registry Client Configuration', + message: `Save changes before going to this Controller Service?` + }, + panelClass: 'small-dialog' + }); + + saveChangesDialogReference.componentInstance.yes.pipe(take(1)).subscribe(() => { + editDialogReference.componentInstance.submitForm(commands); + }); + + saveChangesDialogReference.componentInstance.no.pipe(take(1)).subscribe(() => { + editDialogReference.close('ROUTED'); + this.router.navigate(commands); + }); + } else { + editDialogReference.close('ROUTED'); + this.router.navigate(commands); + } }; editDialogReference.componentInstance.createNewService = ( @@ -292,14 +316,10 @@ export class RegistryClientsEffects { editDialogReference.componentInstance.editRegistryClient .pipe(takeUntil(editDialogReference.afterClosed())) - .subscribe((payload: any) => { + .subscribe((editRegistryClientRequest: EditRegistryClientRequest) => { this.store.dispatch( RegistryClientsActions.configureRegistryClient({ - request: { - id: registryClientId, - uri: request.registryClient.uri, - payload - } + request: editRegistryClientRequest }) ); }); @@ -320,7 +340,7 @@ export class RegistryClientsEffects { { dispatch: false } ); - configureControllerService$ = createEffect(() => + configureRegistryClient$ = createEffect(() => this.actions$.pipe( ofType(RegistryClientsActions.configureRegistryClient), map((action) => action.request), @@ -330,7 +350,8 @@ export class RegistryClientsEffects { RegistryClientsActions.configureRegistryClientSuccess({ response: { id: request.id, - registryClient: response + registryClient: response, + postUpdateNavigation: request.postUpdateNavigation } }) ), @@ -350,8 +371,14 @@ export class RegistryClientsEffects { () => this.actions$.pipe( ofType(RegistryClientsActions.configureRegistryClientSuccess), - tap(() => { - this.dialog.closeAll(); + map((action) => action.response), + tap((response) => { + if (response.postUpdateNavigation) { + this.router.navigate(response.postUpdateNavigation); + this.dialog.getDialogById(response.id)?.close('ROUTED'); + } else { + this.dialog.closeAll(); + } }) ), { dispatch: false } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/registry-clients/edit-registry-client/edit-registry-client.component.html b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/registry-clients/edit-registry-client/edit-registry-client.component.html index b67122c4d4..4589c687e2 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/registry-clients/edit-registry-client/edit-registry-client.component.html +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/registry-clients/edit-registry-client/edit-registry-client.component.html @@ -50,7 +50,7 @@ [createNewProperty]="createNewProperty" [createNewService]="createNewService" [getParameters]="getParameters" - [getServiceLink]="getServiceLink" + [goToService]="goToService" [supportsSensitiveDynamicProperties]=" request.registryClient.component.supportsSensitiveDynamicProperties "> @@ -64,7 +64,7 @@ [disabled]="!editRegistryClientForm.dirty || editRegistryClientForm.invalid || saving.value" type="button" color="primary" - (click)="createRegistryClientClicked()" + (click)="submitForm()" mat-raised-button> Apply diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/registry-clients/edit-registry-client/edit-registry-client.component.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/registry-clients/edit-registry-client/edit-registry-client.component.ts index ea708a2428..5e72c69ef3 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/registry-clients/edit-registry-client/edit-registry-client.component.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/pages/settings/ui/registry-clients/edit-registry-client/edit-registry-client.component.ts @@ -31,7 +31,7 @@ import { Property, TextTipInput } from '../../../../../state/shared'; -import { EditRegistryClientDialogRequest } from '../../../state/registry-clients'; +import { EditRegistryClientDialogRequest, EditRegistryClientRequest } from '../../../state/registry-clients'; import { NifiSpinnerDirective } from '../../../../../ui/common/spinner/nifi-spinner.directive'; import { Client } from '../../../../../service/client.service'; import { MatSelectModule } from '@angular/material/select'; @@ -66,9 +66,10 @@ export class EditRegistryClient { @Input() createNewProperty!: (existingProperties: string[], allowsSensitive: boolean) => Observable; @Input() createNewService!: (request: InlineServiceCreationRequest) => Observable; @Input() getParameters!: (sensitive: boolean) => Observable; - @Input() getServiceLink!: (serviceId: string) => Observable; + @Input() goToService!: (serviceId: string) => void; @Input() saving$!: Observable; - @Output() editRegistryClient: EventEmitter = new EventEmitter(); + @Output() editRegistryClient: EventEmitter = + new EventEmitter(); protected readonly TextTip = TextTip; @@ -109,7 +110,7 @@ export class EditRegistryClient { }; } - createRegistryClientClicked() { + submitForm(postUpdateNavigation?: string[]) { const payload: any = { revision: this.client.getRevision(this.request.registryClient), component: { @@ -131,6 +132,11 @@ export class EditRegistryClient { .map((property) => property.descriptor.name); } - this.editRegistryClient.next(payload); + this.editRegistryClient.next({ + id: this.request.registryClient.id, + uri: this.request.registryClient.uri, + payload, + postUpdateNavigation + }); } } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/state/shared/index.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/state/shared/index.ts index de07655740..583b564a16 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/state/shared/index.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/state/shared/index.ts @@ -58,6 +58,11 @@ export interface EditControllerServiceDialogRequest { controllerService: ControllerServiceEntity; } +export interface UpdateControllerServiceRequest { + payload: any; + postUpdateNavigation?: string[]; +} + export interface ProvenanceEventSummary { id: string; eventId: number; @@ -253,6 +258,32 @@ export interface AffectedComponent { validationErrors: string[]; } +export interface SubmitParameterContextUpdate { + id: string; + payload: any; +} + +export interface PollParameterContextUpdateSuccess { + requestEntity: ParameterContextUpdateRequestEntity; +} + +export interface ParameterContextUpdateRequest { + complete: boolean; + lastUpdated: string; + percentComponent: number; + referencingComponents: AffectedComponentEntity[]; + requestId: string; + state: string; + updateSteps: any[]; + uri: string; + parameterContext?: any; +} + +export interface ParameterContextUpdateRequestEntity { + parameterContextRevision: Revision; + request: ParameterContextUpdateRequest; +} + export interface ElFunction { name: string; description: string; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/controller-service/edit-controller-service/edit-controller-service.component.html b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/controller-service/edit-controller-service/edit-controller-service.component.html index f53d52f109..99a466e996 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/controller-service/edit-controller-service/edit-controller-service.component.html +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/controller-service/edit-controller-service/edit-controller-service.component.html @@ -84,7 +84,10 @@ [createNewProperty]="createNewProperty" [createNewService]="createNewService" [getParameters]="getParameters" - [getServiceLink]="getServiceLink" + [parameterContext]="parameterContext" + [goToParameter]="goToParameter" + [convertToParameter]="convertToParameter" + [goToService]="goToService" [supportsSensitiveDynamicProperties]=" request.controllerService.component.supportsSensitiveDynamicProperties "> diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/controller-service/edit-controller-service/edit-controller-service.component.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/controller-service/edit-controller-service/edit-controller-service.component.ts index 0e47d1b9b4..17ea43505b 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/controller-service/edit-controller-service/edit-controller-service.component.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/controller-service/edit-controller-service/edit-controller-service.component.ts @@ -25,7 +25,9 @@ import { InlineServiceCreationRequest, InlineServiceCreationResponse, Parameter, - Property + ParameterContextReferenceEntity, + Property, + UpdateControllerServiceRequest } from '../../../../state/shared'; import { MatInputModule } from '@angular/material/input'; import { MatCheckboxModule } from '@angular/material/checkbox'; @@ -68,9 +70,13 @@ export class EditControllerService { @Input() createNewProperty!: (existingProperties: string[], allowsSensitive: boolean) => Observable; @Input() createNewService!: (request: InlineServiceCreationRequest) => Observable; @Input() getParameters!: (sensitive: boolean) => Observable; - @Input() getServiceLink!: (serviceId: string) => Observable; + @Input() parameterContext: ParameterContextReferenceEntity | undefined; + @Input() goToParameter!: (parameter: string) => void; + @Input() convertToParameter!: (name: string, sensitive: boolean, value: string | null) => Observable; + @Input() goToService!: (serviceId: string) => void; @Input() saving$!: Observable; - @Output() editControllerService: EventEmitter = new EventEmitter(); + @Output() editControllerService: EventEmitter = + new EventEmitter(); editControllerServiceForm: FormGroup; @@ -130,7 +136,7 @@ export class EditControllerService { return this.nifiCommon.formatBundle(entity.component.bundle); } - submitForm() { + submitForm(postUpdateNavigation?: string[]) { const payload: any = { revision: this.client.getRevision(this.request.controllerService), component: { @@ -151,6 +157,9 @@ export class EditControllerService { .map((property) => property.descriptor.name); } - this.editControllerService.next(payload); + this.editControllerService.next({ + payload, + postUpdateNavigation + }); } } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/edit-parameter-dialog/edit-parameter-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-parameter-dialog/edit-parameter-dialog.component.html index 0724d3d2dc..21e268a8ff 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/edit-parameter-dialog/edit-parameter-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-parameter-dialog/edit-parameter-dialog.component.html @@ -48,14 +48,14 @@ - + diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/edit-parameter-dialog/edit-parameter-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-parameter-dialog/edit-parameter-dialog.component.ts index 5492a44964..bc73251a17 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/edit-parameter-dialog/edit-parameter-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-parameter-dialog/edit-parameter-dialog.component.ts @@ -35,7 +35,8 @@ import { MatInputModule } from '@angular/material/input'; import { MatRadioModule } from '@angular/material/radio'; import { MatCheckboxModule } from '@angular/material/checkbox'; import { NifiSpinnerDirective } from '../spinner/nifi-spinner.directive'; -import { NgIf } from '@angular/common'; +import { AsyncPipe, NgIf } from '@angular/common'; +import { Observable } from 'rxjs'; @Component({ selector: 'edit-parameter-dialog', @@ -50,16 +51,19 @@ import { NgIf } from '@angular/common'; MatRadioModule, MatCheckboxModule, NifiSpinnerDirective, - NgIf + NgIf, + AsyncPipe ], templateUrl: './edit-parameter-dialog.component.html', styleUrls: ['./edit-parameter-dialog.component.scss'] }) export class EditParameterDialog { - @Input() saving!: boolean; + @Input() saving$!: Observable; @Output() editParameter: EventEmitter = new EventEmitter(); + @Output() cancel: EventEmitter = new EventEmitter(); name: FormControl; + sensitive: FormControl; editParameterForm: FormGroup; isNew: boolean; @@ -67,38 +71,48 @@ export class EditParameterDialog { @Inject(MAT_DIALOG_DATA) public request: EditParameterRequest, private formBuilder: FormBuilder ) { + // get the optional parameter. when existingParameters are specified this parameter is used to + // seed the form for the new parameter. when existingParameters are not specified, this is the + // existing parameter that populates the form const parameter: Parameter | undefined = request.parameter; - if (parameter) { - this.isNew = false; - - // in edit scenarios the existing parameters shouldn't be enforced since the parameter does exist - this.name = new FormControl({ value: parameter.name, disabled: true }, Validators.required); - - this.editParameterForm = this.formBuilder.group({ - name: this.name, - value: new FormControl(parameter.value), - empty: new FormControl(parameter.value == ''), - sensitive: new FormControl({ value: parameter.sensitive, disabled: true }, Validators.required), - description: new FormControl(parameter.description) - }); - } else { + const validators: any[] = [Validators.required]; + if (request.existingParameters) { this.isNew = true; - const validators: any[] = [Validators.required]; - if (request.existingParameters) { - validators.push(this.existingParameterValidator(request.existingParameters)); - } - this.name = new FormControl('', validators); + // since there were existing parameters in the request, add the existing parameters validator because + // parameters names must be unique + validators.push(this.existingParameterValidator(request.existingParameters)); - this.editParameterForm = this.formBuilder.group({ - name: this.name, - value: new FormControl(''), - empty: new FormControl(false), - sensitive: new FormControl({ value: false, disabled: false }, Validators.required), - description: new FormControl('') - }); + this.name = new FormControl(parameter ? parameter.name : '', validators); + + // when seeding a new parameter with a sensitivity flag do not allow it to be changed + const disableSensitive: boolean = parameter != null; + this.sensitive = new FormControl( + { value: parameter ? parameter.sensitive : false, disabled: disableSensitive }, + Validators.required + ); + } else { + this.isNew = false; + + // without existingParameters, we are editing an existing parameter. in this case the name and sensitivity cannot be modified + this.name = new FormControl( + { value: parameter ? parameter.name : '', disabled: true }, + Validators.required + ); + this.sensitive = new FormControl( + { value: parameter ? parameter.sensitive : false, disabled: true }, + Validators.required + ); } + + this.editParameterForm = this.formBuilder.group({ + name: this.name, + value: new FormControl(parameter ? parameter.value : ''), + empty: new FormControl(parameter ? parameter.value == '' : false), + sensitive: this.sensitive, + description: new FormControl(parameter ? parameter.description : '') + }); } private existingParameterValidator(existingParameters: string[]): ValidatorFn { @@ -136,7 +150,11 @@ export class EditParameterDialog { } } - addProperty(): void { + cancelClicked(): void { + this.cancel.next(); + } + + okClicked(): void { const value: string = this.editParameterForm.get('value')?.value; const empty: boolean = this.editParameterForm.get('empty')?.value; diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/property-table/property-table.component.html b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/property-table/property-table.component.html index 0ce8aedc3e..020255b66f 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/property-table/property-table.component.html +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/property-table/property-table.component.html @@ -103,19 +103,26 @@
-
- +
+ *ngIf="canGoToParameter(item)" + (click)="goToParameterClicked(item)" + title="Go to Parameter">
+
Observable; @Input() createNewService!: (request: InlineServiceCreationRequest) => Observable; @Input() getParameters!: (sensitive: boolean) => Observable; - @Input() getServiceLink!: (serviceId: string) => Observable; + @Input() parameterContext: ParameterContextReferenceEntity | undefined; + @Input() goToParameter!: (parameter: string) => void; + @Input() convertToParameter!: (name: string, sensitive: boolean, value: string | null) => Observable; + @Input() goToService!: (serviceId: string) => void; @Input() supportsSensitiveDynamicProperties: boolean = false; + private static readonly PARAM_REF_REGEX: RegExp = /#{[a-zA-Z0-9-_. ]+}/; + private destroyRef = inject(DestroyRef); protected readonly NfEditor = NfEditor; @@ -264,8 +270,6 @@ export class PropertyTable implements AfterViewInit, ControlValueAccessor { : 'optional' }; - this.populateServiceLink(item); - // store the property item in a map for an efficient lookup later this.itemLookup.set(property.property, item); return item; @@ -274,16 +278,6 @@ export class PropertyTable implements AfterViewInit, ControlValueAccessor { this.setPropertyItems(propertyItems); } - private populateServiceLink(item: PropertyItem): void { - if (this.canGoTo(item) && item.value) { - this.getServiceLink(item.value) - .pipe(take(1)) - .subscribe((serviceLink: string[]) => { - item.serviceLink = serviceLink; - }); - } - } - private setPropertyItems(propertyItems: PropertyItem[]): void { this.dataSource = new MatTableDataSource(propertyItems); this.initFilter(); @@ -311,8 +305,6 @@ export class PropertyTable implements AfterViewInit, ControlValueAccessor { : 'optional' }; - this.populateServiceLink(item); - this.itemLookup.set(property.property, item); const propertyItems: PropertyItem[] = [...currentPropertyItems, item]; @@ -388,7 +380,7 @@ export class PropertyTable implements AfterViewInit, ControlValueAccessor { this.editorOpen = true; } - canGoTo(item: PropertyItem): boolean { + canGoToService(item: PropertyItem): boolean { // TODO - add Input() for supportsGoTo? currently only false in summary table const descriptor: PropertyDescriptor = item.descriptor; @@ -401,6 +393,11 @@ export class PropertyTable implements AfterViewInit, ControlValueAccessor { return false; } + goToServiceClicked(item: PropertyItem): void { + // @ts-ignore + this.goToService(item.value); + } + createNewControllerService(item: PropertyItem): void { this.createNewService({ descriptor: item.descriptor }) .pipe(take(1)) @@ -413,6 +410,48 @@ export class PropertyTable implements AfterViewInit, ControlValueAccessor { }); } + canGoToParameter(item: PropertyItem): boolean { + // TODO - currently parameter context route does not support navigating + // directly to a specific parameter so the parameter context link + // is not item specific. + if (this.parameterContext && item.value) { + return this.parameterContext.permissions.canRead && PropertyTable.PARAM_REF_REGEX.test(item.value); + } + + return false; + } + + goToParameterClicked(item: PropertyItem): void { + // @ts-ignore + this.goToParameter(item.value); + } + + canConvertToParameter(item: PropertyItem): boolean { + let canUpdateParameterContext: boolean = false; + if (this.parameterContext) { + canUpdateParameterContext = + this.parameterContext.permissions.canRead && this.parameterContext.permissions.canWrite; + } + + let propertyReferencesParameter: boolean = false; + if (canUpdateParameterContext && item.value) { + propertyReferencesParameter = PropertyTable.PARAM_REF_REGEX.test(item.value); + } + + return canUpdateParameterContext && !propertyReferencesParameter; + } + + convertToParameterClicked(item: PropertyItem): void { + this.convertToParameter(item.property, item.descriptor.sensitive, item.value) + .pipe(take(1)) + .subscribe((propertyValue) => { + item.value = propertyValue; + item.dirty = true; + + this.handleChanged(); + }); + } + deleteProperty(item: PropertyItem): void { if (!item.deleted) { item.value = null; @@ -428,8 +467,6 @@ export class PropertyTable implements AfterViewInit, ControlValueAccessor { item.value = newValue; item.dirty = true; - this.populateServiceLink(item); - this.handleChanged(); } diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/yes-no-dialog/yes-no-dialog.component.html b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/yes-no-dialog/yes-no-dialog.component.html index a3bbd74dd0..4b0445d60f 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/yes-no-dialog/yes-no-dialog.component.html +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/yes-no-dialog/yes-no-dialog.component.html @@ -20,6 +20,6 @@
{{ request.message }}
- + diff --git a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/yes-no-dialog/yes-no-dialog.component.ts b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/yes-no-dialog/yes-no-dialog.component.ts index 371461486d..6e8c5f956e 100644 --- a/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/yes-no-dialog/yes-no-dialog.component.ts +++ b/nifi-nar-bundles/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-frontend/src/main/nifi/src/app/ui/common/yes-no-dialog/yes-no-dialog.component.ts @@ -29,10 +29,15 @@ import { MatButtonModule } from '@angular/material/button'; }) export class YesNoDialog { @Output() yes: EventEmitter = new EventEmitter(); + @Output() no: EventEmitter = new EventEmitter(); constructor(@Inject(MAT_DIALOG_DATA) public request: YesNoDialogRequest) {} yesClicked(): void { this.yes.next(); } + + noClicked(): void { + this.no.next(); + } }