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.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/flow/flow.actions.ts index c1238cb382..89eeccfd49 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.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/flow/flow.actions.ts @@ -383,6 +383,11 @@ export const openEditProcessGroupDialog = createAction( props<{ request: EditComponentDialogRequest }>() ); +export const openEditRemoteProcessGroupDialog = createAction( + `${CANVAS_PREFIX} Open Edit Remote Process Group Dialog`, + props<{ request: EditComponentDialogRequest }>() +); + export const updateComponent = createAction( `${CANVAS_PREFIX} Update Component`, props<{ request: UpdateComponentRequest }>() 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 97343047c0..eff3dba2cd 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 @@ -95,7 +95,7 @@ import { RegistryService } from '../../service/registry.service'; import { ImportFromRegistry } from '../../ui/canvas/items/flow/import-from-registry/import-from-registry.component'; import { selectCurrentUser } from '../../../../state/current-user/current-user.selectors'; import { NoRegistryClientsDialog } from '../../ui/common/no-registry-clients-dialog/no-registry-clients-dialog.component'; -import { showOkDialog } from './flow.actions'; +import { EditRemoteProcessGroup } from '../../ui/canvas/items/remote-process-group/edit-remote-process-group/edit-remote-process-group.component'; @Injectable() export class FlowEffects { @@ -348,7 +348,10 @@ export class FlowEffects { this.flowService.goToRemoteProcessGroup(request); } else { this.store.dispatch( - showOkDialog({ title: 'Remote Process Group', message: 'No target URI defined.' }) + FlowActions.showOkDialog({ + title: 'Remote Process Group', + message: 'No target URI defined.' + }) ); } }) @@ -926,6 +929,8 @@ export class FlowEffects { return of(FlowActions.openEditConnectionDialog({ request })); case ComponentType.ProcessGroup: return of(FlowActions.openEditProcessGroupDialog({ request })); + case ComponentType.RemoteProcessGroup: + return of(FlowActions.openEditRemoteProcessGroupDialog({ request })); case ComponentType.InputPort: case ComponentType.OutputPort: return of(FlowActions.openEditPortDialog({ request })); @@ -1250,6 +1255,57 @@ export class FlowEffects { { dispatch: false } ); + openEditRemoteProcessGroupDialog$ = createEffect( + () => + this.actions$.pipe( + ofType(FlowActions.openEditRemoteProcessGroupDialog), + map((action) => action.request), + tap((request) => { + const editDialogReference = this.dialog.open(EditRemoteProcessGroup, { + data: request, + panelClass: 'large-dialog' + }); + + editDialogReference.componentInstance.saving$ = this.store.select(selectSaving); + + editDialogReference.componentInstance.editRemoteProcessGroup + .pipe(takeUntil(editDialogReference.afterClosed())) + .subscribe((payload: any) => { + this.store.dispatch( + FlowActions.updateComponent({ + request: { + id: request.entity.id, + uri: request.uri, + type: request.type, + payload + } + }) + ); + }); + + editDialogReference.afterClosed().subscribe((response) => { + this.store.dispatch(FlowActions.clearFlowApiError()); + + if (response != 'ROUTED') { + this.store.dispatch( + FlowActions.selectComponents({ + request: { + components: [ + { + id: request.entity.id, + componentType: request.type + } + ] + } + }) + ); + } + }); + }) + ), + { dispatch: false } + ); + updateComponent$ = createEffect(() => this.actions$.pipe( ofType(FlowActions.updateComponent), 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/remote-process-group/create-remote-process-group/create-remote-process-group.component.spec.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/remote-process-group/create-remote-process-group/create-remote-process-group.component.spec.ts index d2ffc980de..c06555fc81 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/remote-process-group/create-remote-process-group/create-remote-process-group.component.spec.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/remote-process-group/create-remote-process-group/create-remote-process-group.component.spec.ts @@ -34,7 +34,7 @@ describe('CreateRemoteProcessGroup', () => { clientId: 'a6482293-7fe8-43b4-8ab4-ee95b3b27721', version: 0 }, - type: ComponentType.ProcessGroup, + type: ComponentType.RemoteProcessGroup, position: { x: -4, y: -698.5 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/remote-process-group/create-remote-process-group/create-remote-process-group.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/remote-process-group/create-remote-process-group/create-remote-process-group.component.ts index c8a77e22a9..a2c32b98e1 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/remote-process-group/create-remote-process-group/create-remote-process-group.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/remote-process-group/create-remote-process-group/create-remote-process-group.component.ts @@ -37,7 +37,6 @@ import { MatIconModule } from '@angular/material/icon'; import { CreateComponentRequest } from '../../../../../state/flow'; @Component({ - selector: 'create-process-group', standalone: true, imports: [ AsyncPipe, 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/remote-process-group/edit-remote-process-group/edit-remote-process-group.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/remote-process-group/edit-remote-process-group/edit-remote-process-group.component.html new file mode 100644 index 0000000000..8c0c5ccd70 --- /dev/null +++ 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/remote-process-group/edit-remote-process-group/edit-remote-process-group.component.html @@ -0,0 +1,109 @@ + + +

Edit Remote Process Group

+
+ + +
+
Name
+
{{ request.entity.component.name }}
+
+
+
Id
+
{{ request.entity.component.id }}
+
+
+
+ + URLs + + +
+
+
+
+ + Transport Protocol + + RAW + HTTP + + +
+
+ + Local Network Interface + + +
+
+
+
+ + HTTP Proxy Server Hostname + + +
+
+ + HTTP Proxy Server Port + + +
+
+
+
+ + HTTP Proxy User + + +
+
+ + HTTP Proxy Password + + +
+
+
+
+ + Communications Timeout + + +
+
+ + Yield Duration + + +
+
+
+ + + + +
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/remote-process-group/edit-remote-process-group/edit-remote-process-group.component.scss 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/remote-process-group/edit-remote-process-group/edit-remote-process-group.component.scss new file mode 100644 index 0000000000..7d270b20ae --- /dev/null +++ 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/remote-process-group/edit-remote-process-group/edit-remote-process-group.component.scss @@ -0,0 +1,26 @@ +/* + * 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. + */ + +@use '@angular/material' as mat; + +.edit-remote-process-group-form { + @include mat.button-density(-1); + + .mat-mdc-form-field { + width: 100%; + } +} 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/remote-process-group/edit-remote-process-group/edit-remote-process-group.component.spec.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/remote-process-group/edit-remote-process-group/edit-remote-process-group.component.spec.ts new file mode 100644 index 0000000000..7f3c9a7c3f --- /dev/null +++ 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/remote-process-group/edit-remote-process-group/edit-remote-process-group.component.spec.ts @@ -0,0 +1,81 @@ +/* + * 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 { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { EditRemoteProcessGroup } from './edit-remote-process-group.component'; +import { MAT_DIALOG_DATA } from '@angular/material/dialog'; +import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { ComponentType } from '../../../../../../../state/shared'; +import { provideMockStore } from '@ngrx/store/testing'; +import { initialState } from '../../../../../state/flow/flow.reducer'; + +describe('EditRemoteProcessGroup', () => { + let component: EditRemoteProcessGroup; + let fixture: ComponentFixture; + + const data: any = { + revision: { + clientId: 'a6482293-7fe8-43b4-8ab4-ee95b3b27721', + version: 0 + }, + type: ComponentType.RemoteProcessGroup, + position: { + x: -4, + y: -698.5 + }, + entity: { + component: { + activeRemoteInputPortCount: 0, + activeRemoteOutputPortCount: 0, + comments: '', + communicationsTimeout: '30 sec', + flowRefreshed: '02/10/2024 15:20:58 EST', + id: '868228e2-018d-1000-00e2-92a25d9cb363', + inactiveRemoteInputPortCount: 0, + inactiveRemoteOutputPortCount: 0, + inputPortCount: 0, + name: 'NiFi Flow', + outputPortCount: 0, + parentGroupId: '7be4b23a-018d-1000-d059-ca023539b044', + proxyHost: '', + proxyUser: '', + targetSecure: true, + targetUri: 'https://localhost:8443/nifi', + targetUris: 'https://localhost:8443/nifi', + transmitting: false, + transportProtocol: 'HTTP', + yieldDuration: '10 sec' + } + } + }; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [EditRemoteProcessGroup, BrowserAnimationsModule], + providers: [{ provide: MAT_DIALOG_DATA, useValue: data }, provideMockStore({ initialState })] + }); + fixture = TestBed.createComponent(EditRemoteProcessGroup); + component = fixture.componentInstance; + + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); 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/remote-process-group/edit-remote-process-group/edit-remote-process-group.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/remote-process-group/edit-remote-process-group/edit-remote-process-group.component.ts new file mode 100644 index 0000000000..56bccd6a2c --- /dev/null +++ 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/remote-process-group/edit-remote-process-group/edit-remote-process-group.component.ts @@ -0,0 +1,98 @@ +/* + * 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 { Component, EventEmitter, Inject, Input, Output } from '@angular/core'; +import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog'; +import { FormBuilder, FormControl, FormGroup, FormsModule, ReactiveFormsModule, Validators } from '@angular/forms'; +import { MatInputModule } from '@angular/material/input'; +import { MatCheckboxModule } from '@angular/material/checkbox'; +import { MatButtonModule } from '@angular/material/button'; +import { AsyncPipe, NgIf } from '@angular/common'; +import { MatOptionModule } from '@angular/material/core'; +import { MatSelectModule } from '@angular/material/select'; +import { Observable } from 'rxjs'; +import { Client } from '../../../../../../../service/client.service'; +import { NifiSpinnerDirective } from '../../../../../../../ui/common/spinner/nifi-spinner.directive'; +import { TextTip } from '../../../../../../../ui/common/tooltips/text-tip/text-tip.component'; +import { EditComponentDialogRequest } from '../../../../../state/flow'; +import { ErrorBanner } from '../../../../../../../ui/common/error-banner/error-banner.component'; + +@Component({ + standalone: true, + templateUrl: './edit-remote-process-group.component.html', + imports: [ + ReactiveFormsModule, + MatDialogModule, + MatInputModule, + MatCheckboxModule, + MatButtonModule, + NgIf, + MatOptionModule, + MatSelectModule, + AsyncPipe, + NifiSpinnerDirective, + FormsModule, + ErrorBanner + ], + styleUrls: ['./edit-remote-process-group.component.scss'] +}) +export class EditRemoteProcessGroup { + @Input() saving$!: Observable; + @Output() editRemoteProcessGroup: EventEmitter = new EventEmitter(); + + protected readonly TextTip = TextTip; + + editRemoteProcessGroupForm: FormGroup; + + constructor( + @Inject(MAT_DIALOG_DATA) public request: EditComponentDialogRequest, + private formBuilder: FormBuilder, + private client: Client + ) { + this.editRemoteProcessGroupForm = this.formBuilder.group({ + urls: new FormControl(request.entity.component.targetUris, Validators.required), + transportProtocol: new FormControl(request.entity.component.transportProtocol, Validators.required), + localNetworkInterface: new FormControl(request.entity.component.localNetworkInterface), + httpProxyServerHostname: new FormControl(request.entity.component.httpProxyServerHostname), + httpProxyServerPort: new FormControl(request.entity.component.httpProxyServerPort), + httpProxyUser: new FormControl(request.entity.component.httpProxyUser), + httpProxyPassword: new FormControl(request.entity.component.httpProxyPassword), + communicationsTimeout: new FormControl(request.entity.component.communicationsTimeout, Validators.required), + yieldDuration: new FormControl(request.entity.component.yieldDuration, Validators.required) + }); + } + + submitForm() { + const payload: any = { + revision: this.client.getRevision(this.request.entity), + component: { + id: this.request.entity.id, + targetUris: this.editRemoteProcessGroupForm.get('urls')?.value, + transportProtocol: this.editRemoteProcessGroupForm.get('transportProtocol')?.value, + localNetworkInterface: this.editRemoteProcessGroupForm.get('localNetworkInterface')?.value, + proxyHost: this.editRemoteProcessGroupForm.get('httpProxyServerHostname')?.value, + proxyPort: this.editRemoteProcessGroupForm.get('httpProxyServerPort')?.value, + proxyUser: this.editRemoteProcessGroupForm.get('httpProxyUser')?.value, + proxyPassword: this.editRemoteProcessGroupForm.get('httpProxyPassword')?.value, + communicationsTimeout: this.editRemoteProcessGroupForm.get('communicationsTimeout')?.value, + yieldDuration: this.editRemoteProcessGroupForm.get('yieldDuration')?.value + } + }; + + this.editRemoteProcessGroup.next(payload); + } +}