From 47df567235aa21aaf67fb76ebb66662f5c6cb13b Mon Sep 17 00:00:00 2001 From: Freedom9339 Date: Mon, 28 Oct 2024 17:15:31 +0000 Subject: [PATCH] NIFI-3785: Moved the logic for getting process group options to an API call. Moved move dialog to ui/controller-service. --- .../api/entity/ProcessGroupOptionEntity.java | 86 + .../apache/nifi/web/NiFiServiceFacade.java | 9 - .../nifi/web/StandardNiFiServiceFacade.java | 12 +- .../web/api/ControllerServiceResource.java | 93 + .../nifi/web/api/ProcessGroupResource.java | 8 +- .../service/controller-service.service.ts | 8 +- .../flow-designer/service/flow.service.ts | 5 - .../controller-services.effects.ts | 116 +- .../controller-services.reducer.ts | 2 - .../controller-services.selectors.ts | 10 - .../state/controller-services/index.ts | 8 +- .../move-controller-service.component.html | 11 +- .../move-controller-service.component.scss | 0 .../move-controller-service.component.spec.ts | 381 ++ .../move-controller-service.component.ts | 122 + .../move-controller-service.component.spec.ts | 3462 ----------------- .../move-controller-service.component.ts | 247 -- 17 files changed, 747 insertions(+), 3833 deletions(-) create mode 100644 nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessGroupOptionEntity.java rename nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/ui/{ => controller-service}/move-controller-service/move-controller-service.component.html (92%) rename nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/ui/{ => controller-service}/move-controller-service/move-controller-service.component.scss (100%) create mode 100644 nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/ui/controller-service/move-controller-service/move-controller-service.component.spec.ts create mode 100644 nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/ui/controller-service/move-controller-service/move-controller-service.component.ts delete mode 100644 nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/ui/move-controller-service/move-controller-service.component.spec.ts delete mode 100644 nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/ui/move-controller-service/move-controller-service.component.ts diff --git a/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessGroupOptionEntity.java b/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessGroupOptionEntity.java new file mode 100644 index 000000000000..df0f6f1fd4e2 --- /dev/null +++ b/nifi-framework-bundle/nifi-framework/nifi-client-dto/src/main/java/org/apache/nifi/web/api/entity/ProcessGroupOptionEntity.java @@ -0,0 +1,86 @@ +/* + * 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. + */ +package org.apache.nifi.web.api.entity; + +import io.swagger.v3.oas.annotations.media.Schema; + +import jakarta.xml.bind.annotation.XmlRootElement; + +@XmlRootElement(name = "processGroupOptionEntity") +public class ProcessGroupOptionEntity extends Entity { + + private String text; + private String value; + private String description; + private boolean disabled; + + /** + * The name for this ProcessGroup. + * + * @return The name + */ + @Schema(description = "The name of this ProcessGroup.") + public String getText() { + return text; + } + + public void setText(String id) { + this.text = id; + } + + /** + * The id for this ProcessGroup. + * + * @return The id + */ + @Schema(description = "The id of this ProcessGroup.") + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + /** + * Text containing any conflicts for this ProcessGroup. + * + * @return The text + */ + @Schema(description = "Text containing any conflicts for this ProcessGroup.") + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + /** + * Boolean showing whether this option is disabled. + * + * @return The disabled boolean + */ + @Schema(description = "Boolean showing whether this option is disabled.") + public boolean isDisabled() { + return disabled; + } + + public void setDisabled(boolean disabled) { + this.disabled = disabled; + } +} diff --git a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java index bcfb7fd6f19d..ee44cc8edb5f 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java +++ b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/NiFiServiceFacade.java @@ -1127,15 +1127,6 @@ Set getControllerServiceTypes(final String serviceType, final */ ProcessGroupEntity getProcessGroup(String groupId); - /** - * Returns the process group. - * - * @param groupId group - * @param recurse boolean - * @return ProcessGroup transfer object - */ - ProcessGroupEntity getProcessGroup(String groupId, boolean recurse); - /** * Verifies that a Parameter Context matching the given DTO can be created * @param parameterContext the DTO that represents the Parameter Context diff --git a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java index b69ce0afd72c..7a9e0b5472fb 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java +++ b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/StandardNiFiServiceFacade.java @@ -4798,14 +4798,11 @@ public Set getOutputPorts(final String groupId) { } private ProcessGroupEntity createProcessGroupEntity(final ProcessGroup group) { - return createProcessGroupEntity(group, false); - } - private ProcessGroupEntity createProcessGroupEntity(final ProcessGroup group, final boolean recurse) { final RevisionDTO revision = dtoFactory.createRevisionDTO(revisionManager.getRevision(group.getIdentifier())); final PermissionsDTO permissions = dtoFactory.createPermissionsDto(group); final ProcessGroupStatusDTO status = dtoFactory.createConciseProcessGroupStatusDto(controllerFacade.getProcessGroupStatus(group.getIdentifier())); final List bulletins = getProcessGroupBulletins(group); - return entityFactory.createProcessGroupEntity(dtoFactory.createProcessGroupDto(group, recurse), revision, permissions, status, bulletins); + return entityFactory.createProcessGroupEntity(dtoFactory.createProcessGroupDto(group), revision, permissions, status, bulletins); } private List getProcessGroupBulletins(final ProcessGroup group) { @@ -4985,13 +4982,8 @@ public FlowBreadcrumbEntity getProcessGroupBreadcrumbs(final String groupId) { @Override public ProcessGroupEntity getProcessGroup(final String groupId) { - return getProcessGroup(groupId, false); - } - - @Override - public ProcessGroupEntity getProcessGroup(final String groupId, final boolean recurse) { final ProcessGroup processGroup = processGroupDAO.getProcessGroup(groupId); - return createProcessGroupEntity(processGroup, recurse); + return createProcessGroupEntity(processGroup); } private ControllerServiceEntity createControllerServiceEntity(final ControllerServiceNode serviceNode, final boolean includeReferencingComponents) { diff --git a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerServiceResource.java b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerServiceResource.java index 703d01dcc5c0..07a72056a0b9 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerServiceResource.java +++ b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ControllerServiceResource.java @@ -87,6 +87,7 @@ import org.apache.nifi.web.api.entity.ControllerServiceEntity; import org.apache.nifi.web.api.entity.ControllerServiceReferencingComponentsEntity; import org.apache.nifi.web.api.entity.ControllerServiceRunStatusEntity; +import org.apache.nifi.web.api.entity.ProcessGroupOptionEntity; import org.apache.nifi.web.api.entity.PropertyDescriptorEntity; import org.apache.nifi.web.api.entity.UpdateControllerServiceReferenceRequestEntity; import org.apache.nifi.web.api.entity.VerifyConfigRequestEntity; @@ -685,6 +686,98 @@ public Response updateControllerService( ); } + @GET + @Consumes(MediaType.WILDCARD) + @Produces(MediaType.APPLICATION_JSON) + @Path("{id}/move-options") + @Operation( + summary = "Gets the move options for a controller service", + responses = @ApiResponse(content = @Content(schema = @Schema(implementation = ProcessGroupOptionEntity.class))), + security = { + @SecurityRequirement(name = "Read - /flow") + } + ) + @ApiResponses( + value = { + @ApiResponse(responseCode = "400", description = "NiFi was unable to complete the request because it was invalid. The request should not be retried without modification."), + @ApiResponse(responseCode = "401", description = "Client could not be authenticated."), + @ApiResponse(responseCode = "403", description = "Client is not authorized to make this request."), + @ApiResponse(responseCode = "404", description = "The specified resource could not be found."), + @ApiResponse(responseCode = "409", description = "The request was valid but NiFi was not in the appropriate state to process it.") + } + ) + public Response getProcessGroupOptions( + @Parameter(description = "The controller service id.") + @PathParam("id") final String controllerServiceId) { + + if (controllerServiceId == null) { + throw new IllegalArgumentException("Controller service id must be specified."); + } + + List options = new ArrayList<>(); + serviceFacade.authorizeAccess(lookup -> { + final NiFiUser user = NiFiUserUtils.getNiFiUser(); + + final ComponentAuthorizable authorizableControllerService = lookup.getControllerService(controllerServiceId); + authorizableControllerService.getAuthorizable().authorize(authorizer, RequestAction.WRITE, user); + + final ControllerServiceDTO controllerServiceDTO = serviceFacade.getControllerService(controllerServiceId, true).getComponent(); + + final ProcessGroupAuthorizable authorizableProcessGroupCurrent = lookup.getProcessGroup(controllerServiceDTO.getParentGroupId()); + authorizableProcessGroupCurrent.getAuthorizable().authorize(authorizer, RequestAction.WRITE, user); + + if (authorizableProcessGroupCurrent.getProcessGroup().getParent() != null) { + final ProcessGroupAuthorizable authorizableProcessGroupParent = lookup.getProcessGroup(authorizableProcessGroupCurrent.getProcessGroup().getParent().getIdentifier()); + authorizableProcessGroupParent.getAuthorizable().authorize(authorizer, RequestAction.WRITE, user); + + options.add(generateProcessGroupOption(controllerServiceDTO, authorizableProcessGroupParent)); + } + + authorizableProcessGroupCurrent.getProcessGroup().getProcessGroups().forEach(processGroup -> { + final ProcessGroupAuthorizable authorizableProcessGroup = lookup.getProcessGroup(processGroup.getIdentifier()); + authorizableProcessGroup.getAuthorizable().authorize(authorizer, RequestAction.WRITE, user); + options.add(generateProcessGroupOption(controllerServiceDTO, authorizableProcessGroup)); + }); + }); + + return generateOkResponse(options).build(); + } + + private ProcessGroupOptionEntity generateProcessGroupOption(ControllerServiceDTO controllerServiceDTO, ProcessGroupAuthorizable processGroup) { + List conflictingComponents = new ArrayList<>(); + controllerServiceDTO.getReferencingComponents().forEach(e -> { + if (processGroup.getProcessGroup().findProcessor(e.getId()) == null + && processGroup.getProcessGroup().findControllerService(e.getId(), true, false) == null) { + conflictingComponents.add("[" + e.getComponent().getName() + "]"); + } + }); + + controllerServiceDTO.getProperties().forEach((key, value) -> { + try { + ControllerServiceEntity refControllerService = serviceFacade.getControllerService(value, false); + if (refControllerService != null) { + if (processGroup.getProcessGroup().findControllerService(value, false, true) == null) { + conflictingComponents.add("[" + refControllerService.getComponent().getName() + "]"); + } + } + } catch (Exception ignored) { } + }); + + ProcessGroupOptionEntity option = new ProcessGroupOptionEntity(); + option.setText(processGroup.getProcessGroup().getName()); + option.setValue(processGroup.getProcessGroup().getIdentifier()); + option.setDisabled(false); + + if (!conflictingComponents.isEmpty()) { + String errorMessage = "Could not move controller service because the following components would be out of scope: "; + errorMessage += String.join(" ", conflictingComponents); + option.setDescription(errorMessage); + option.setDisabled(true); + } + + return option; + } + /** * Moves the specified Controller Service to parent/child process groups. * diff --git a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessGroupResource.java b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessGroupResource.java index 2c40379ab6fc..cacd04a29879 100644 --- a/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessGroupResource.java +++ b/nifi-framework-bundle/nifi-framework/nifi-web/nifi-web-api/src/main/java/org/apache/nifi/web/api/ProcessGroupResource.java @@ -247,9 +247,7 @@ private FlowDTO populateRemainingSnippetContent(FlowDTO flow) { ) public Response getProcessGroup( @Parameter(description = "The process group id.") - @PathParam("id") final String groupId, - @QueryParam("includeContent") @DefaultValue("false") - @Parameter(description = "Include content for process group") boolean includeContent) { + @PathParam("id") final String groupId) { if (isReplicateRequest()) { return replicate(HttpMethod.GET); @@ -262,10 +260,10 @@ public Response getProcessGroup( }); // get this process group contents - final ProcessGroupEntity entity = serviceFacade.getProcessGroup(groupId, includeContent); + final ProcessGroupEntity entity = serviceFacade.getProcessGroup(groupId); populateRemainingProcessGroupEntityContent(entity); - if (entity.getComponent() != null && !includeContent) { + if (entity.getComponent() != null) { entity.getComponent().setContents(null); } diff --git a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/service/controller-service.service.ts b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/service/controller-service.service.ts index 4d0a826b8960..b6e505a7bec0 100644 --- a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/service/controller-service.service.ts +++ b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/service/controller-service.service.ts @@ -102,11 +102,17 @@ export class ControllerServiceService implements ControllerServiceCreator, Prope moveControllerService(moveControllerService: MoveControllerServiceRequest): Observable { return this.httpClient.put( - this.nifiCommon.stripProtocol(moveControllerService.controllerService.uri + '/move'), + this.nifiCommon.stripProtocol(`${moveControllerService.controllerService.uri}/move`), moveControllerService.data ); } + getMoveOptions(controllerServiceId: string): Observable { + return this.httpClient.get( + `${ControllerServiceService.API}/controller-services/${controllerServiceId}/move-options` + ); + } + deleteControllerService(deleteControllerService: DeleteControllerServiceRequest): Observable { const entity: ControllerServiceEntity = deleteControllerService.controllerService; const params = new HttpParams({ diff --git a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/service/flow.service.ts b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/service/flow.service.ts index a51c27568c9a..34ca5d26b798 100644 --- a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/service/flow.service.ts +++ b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/service/flow.service.ts @@ -118,11 +118,6 @@ export class FlowService implements PropertyDescriptorRetriever { return this.httpClient.get(`${FlowService.API}/process-groups/${id}`); } - getProcessGroupWithContent(id: string): Observable { - const params = new HttpParams().set('includeContent', true); - return this.httpClient.get(`${FlowService.API}/process-groups/${id}`, { params: params }); - } - createFunnel(processGroupId = 'root', createFunnel: CreateComponentRequest): Observable { return this.httpClient.post(`${FlowService.API}/process-groups/${processGroupId}/funnels`, { revision: createFunnel.revision, diff --git a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/state/controller-services/controller-services.effects.ts b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/state/controller-services/controller-services.effects.ts index 9d0fb807dc82..a2100de7a9fe 100644 --- a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/state/controller-services/controller-services.effects.ts +++ b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/state/controller-services/controller-services.effects.ts @@ -19,7 +19,7 @@ import { Injectable } from '@angular/core'; import { Actions, createEffect, ofType } from '@ngrx/effects'; import { concatLatestFrom } from '@ngrx/operators'; import * as ControllerServicesActions from './controller-services.actions'; -import { catchError, combineLatest, concatMap, from, map, of, switchMap, take, takeUntil, tap } from 'rxjs'; +import { catchError, combineLatest, from, map, of, switchMap, take, takeUntil, tap } from 'rxjs'; import { MatDialog } from '@angular/material/dialog'; import { Store } from '@ngrx/store'; import { NiFiState } from '../../../../state'; @@ -36,17 +36,14 @@ import { } from '../../../../state/shared'; import { Router } from '@angular/router'; import { - selectChildProcessGroupOptions, selectCurrentProcessGroupId, selectParameterContext, selectSaving, - selectStatus, - selectServices, - selectBreadcrumb + selectStatus } from './controller-services.selectors'; import { ControllerServiceService } from '../../service/controller-service.service'; import { EnableControllerService } from '../../../../ui/common/controller-service/enable-controller-service/enable-controller-service.component'; -import { MoveControllerService } from '../../ui/move-controller-service/move-controller-service.component'; +import { MoveControllerService } from '../../ui/controller-service/move-controller-service/move-controller-service.component'; import { DisableControllerService } from '../../../../ui/common/controller-service/disable-controller-service/disable-controller-service.component'; import { PropertyTableHelperService } from '../../../../service/property-table-helper.service'; import * as ErrorActions from '../../../../state/error/error.actions'; @@ -97,28 +94,17 @@ export class ControllerServicesEffects { this.controllerServiceService.getControllerServices(request.processGroupId), this.controllerServiceService.getFlow(request.processGroupId) ]).pipe( - map(([controllerServicesResponse, flowResponse]) => { - const childProcessGroupOptions: SelectOption[] = []; - flowResponse.processGroupFlow.flow.processGroups.forEach((child: ComponentEntity) => { - if (child.permissions.canRead && child.permissions.canWrite) { - childProcessGroupOptions.push({ - text: child.component.name, - value: child.component.id - }); - } - }); - - return ControllerServicesActions.loadControllerServicesSuccess({ + map(([controllerServicesResponse, flowResponse]) => + ControllerServicesActions.loadControllerServicesSuccess({ response: { processGroupId: flowResponse.processGroupFlow.id, controllerServices: controllerServicesResponse.controllerServices, loadedTimestamp: controllerServicesResponse.currentTime, breadcrumb: flowResponse.processGroupFlow.breadcrumb, - parameterContext: flowResponse.processGroupFlow.parameterContext ?? null, - childProcessGroupOptions: childProcessGroupOptions + parameterContext: flowResponse.processGroupFlow.parameterContext ?? null } - }); - }), + }) + ), catchError((errorResponse: HttpErrorResponse) => of(this.errorHelper.handleLoadingError(status, errorResponse)) ) @@ -677,60 +663,44 @@ export class ControllerServicesEffects { this.actions$.pipe( ofType(ControllerServicesActions.openMoveControllerServiceDialog), map((action) => action.request), - concatLatestFrom(() => [ - this.store.select(selectCurrentProcessGroupId), - this.store.select(selectChildProcessGroupOptions), - this.store.select(selectServices), - this.store.select(selectBreadcrumb) - ]), - concatMap( - ([request, currentProcessGroupId, childProcessGroupOptions, controllerServices, breadcrumb]) => - combineLatest([this.flowService.getProcessGroupWithContent(currentProcessGroupId)]).pipe( - map(([processGroupEntity]) => { - return { - request, - currentProcessGroupId, - childProcessGroupOptions, - processGroupEntity, - controllerServices, - breadcrumb - }; - }) - ) - ), - tap((request) => { - const moveDialogReference = this.dialog.open(MoveControllerService, { - ...LARGE_DIALOG, - data: { - id: request.request.id, - controllerService: request.request.controllerService, - childProcessGroupOptions: request.childProcessGroupOptions, - processGroupEntity: request.processGroupEntity, - parentControllerServices: request.controllerServices, - breadcrumb: request.breadcrumb - }, - id: request.request.id - }); + switchMap((request) => + from(this.controllerServiceService.getMoveOptions(request.controllerService.id)).pipe( + map((response: SelectOption[]) => { + const moveDialogReference = this.dialog.open(MoveControllerService, { + ...LARGE_DIALOG, + data: { + controllerService: request.controllerService, + options: response + } + }); - moveDialogReference.componentInstance.goToReferencingComponent = ( - component: ControllerServiceReferencingComponent - ) => { - const route: string[] = this.getRouteForReference(component); - this.router.navigate(route); - }; + moveDialogReference.componentInstance.goToReferencingComponent = ( + component: ControllerServiceReferencingComponent + ) => { + const route: string[] = this.getRouteForReference(component); + this.router.navigate(route); + }; - moveDialogReference.afterClosed().subscribe((response) => { - if (response != 'ROUTED') { - this.store.dispatch( - ControllerServicesActions.loadControllerServices({ - request: { - processGroupId: request.currentProcessGroupId - } - }) + moveDialogReference.afterClosed().subscribe((response) => { + if (response != 'ROUTED') { + this.store.dispatch( + ControllerServicesActions.loadControllerServices({ + request: { + processGroupId: request.controllerService.parentGroupId! + } + }) + ); + } + }); + }), + catchError((errorResponse: HttpErrorResponse) => { + this.dialog.closeAll(); + return of( + ErrorActions.snackBarError({ error: this.errorHelper.getErrorString(errorResponse) }) ); - } - }); - }) + }) + ) + ) ), { dispatch: false } ); diff --git a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/state/controller-services/controller-services.reducer.ts b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/state/controller-services/controller-services.reducer.ts index 46329e5aadcd..9fb773126658 100644 --- a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/state/controller-services/controller-services.reducer.ts +++ b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/state/controller-services/controller-services.reducer.ts @@ -35,7 +35,6 @@ import { ControllerServicesState } from './index'; export const initialState: ControllerServicesState = { processGroupId: 'root', - childProcessGroupOptions: [], controllerServices: [], breadcrumb: { id: '', @@ -71,7 +70,6 @@ export const controllerServicesReducer = createReducer( breadcrumb: response.breadcrumb, parameterContext: response.parameterContext, loadedTimestamp: response.loadedTimestamp, - childProcessGroupOptions: response.childProcessGroupOptions, status: 'success' as const })), on(controllerServicesBannerApiError, (state) => ({ diff --git a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/state/controller-services/controller-services.selectors.ts b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/state/controller-services/controller-services.selectors.ts index b7cad8339c4f..0ce3a1cd33be 100644 --- a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/state/controller-services/controller-services.selectors.ts +++ b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/state/controller-services/controller-services.selectors.ts @@ -41,16 +41,6 @@ export const selectCurrentProcessGroupId = createSelector( (state: ControllerServicesState) => state.processGroupId ); -export const selectChildProcessGroupOptions = createSelector( - selectControllerServicesState, - (state: ControllerServicesState) => state.childProcessGroupOptions -); - -export const selectBreadcrumb = createSelector( - selectControllerServicesState, - (state: ControllerServicesState) => state.breadcrumb -); - export const selectParameterContext = createSelector( selectControllerServicesState, (state: ControllerServicesState) => state.parameterContext diff --git a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/state/controller-services/index.ts b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/state/controller-services/index.ts index 71bce1da6743..43858487d1e1 100644 --- a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/state/controller-services/index.ts +++ b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/state/controller-services/index.ts @@ -32,7 +32,6 @@ export interface LoadControllerServicesResponse { controllerServices: ControllerServiceEntity[]; parameterContext: ParameterContextReferenceEntity | null; loadedTimestamp: string; - childProcessGroupOptions: SelectOption[]; } export interface CreateControllerServiceSuccess { @@ -60,12 +59,8 @@ export interface MoveControllerServiceDialogRequest { } export interface MoveControllerServiceDialogRequestSuccess { - id: string; controllerService: ControllerServiceEntity; - childProcessGroupOptions: SelectOption[]; - processGroupEntity: any; - parentControllerServices: ControllerServiceEntity[]; - breadcrumb: BreadcrumbEntity; + options: SelectOption[]; } export interface MoveControllerServiceRequest { @@ -97,7 +92,6 @@ export interface SelectControllerServiceRequest { export interface ControllerServicesState { processGroupId: string; - childProcessGroupOptions: SelectOption[]; breadcrumb: BreadcrumbEntity; controllerServices: ControllerServiceEntity[]; parameterContext: ParameterContextReferenceEntity | null; diff --git a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/ui/move-controller-service/move-controller-service.component.html b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/ui/controller-service/move-controller-service/move-controller-service.component.html similarity index 92% rename from nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/ui/move-controller-service/move-controller-service.component.html rename to nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/ui/controller-service/move-controller-service/move-controller-service.component.html index ff09764623bd..2d312860db4f 100644 --- a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/ui/move-controller-service/move-controller-service.component.html +++ b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/ui/controller-service/move-controller-service/move-controller-service.component.html @@ -30,7 +30,7 @@

Move Controller Service

Process Group: - @for (option of controllerServiceActionProcessGroups; track option) { + @for (option of processGroupOptions; track option) {
Move Controller Service - + diff --git a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/ui/move-controller-service/move-controller-service.component.scss b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/ui/controller-service/move-controller-service/move-controller-service.component.scss similarity index 100% rename from nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/ui/move-controller-service/move-controller-service.component.scss rename to nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/ui/controller-service/move-controller-service/move-controller-service.component.scss diff --git a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/ui/controller-service/move-controller-service/move-controller-service.component.spec.ts b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/ui/controller-service/move-controller-service/move-controller-service.component.spec.ts new file mode 100644 index 000000000000..272e02879f82 --- /dev/null +++ b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/ui/controller-service/move-controller-service/move-controller-service.component.spec.ts @@ -0,0 +1,381 @@ +/* + * 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 { MoveControllerService } from './move-controller-service.component'; +import { NoopAnimationsModule } from '@angular/platform-browser/animations'; +import { provideMockStore } from '@ngrx/store/testing'; +import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog'; +import { ComponentType } from '@nifi/shared'; +import { initialState } from '../../../state/controller-services/controller-services.reducer'; +import { MoveControllerServiceDialogRequestSuccess } from '../../../state/controller-services'; + +describe('MoveControllerService', () => { + let component: MoveControllerService; + let fixture: ComponentFixture; + + const controllerService = { + revision: { + clientId: 'b37eba61-156a-47a4-875f-945cd153b876', + version: 7 + }, + id: '92db6ee4-018c-1000-1061-e3476c3f4e9f', + uri: 'https://localhost:4200/nifi-api/controller-services/92db6ee4-018c-1000-1061-e3476c3f4e9f', + permissions: { + canRead: true, + canWrite: true + }, + bulletins: [ + { + id: 0, + groupId: 'asdf', + sourceId: 'asdf', + timestamp: '14:08:44 EST', + canRead: true, + bulletin: { + id: 0, + category: 'asdf', + groupId: 'asdf', + sourceId: 'asdf', + sourceName: 'asdf', + sourceType: ComponentType.Processor, + level: 'ERROR', + message: 'asdf', + timestamp: '14:08:44 EST' + } + } + ], + component: { + id: '92db6ee4-018c-1000-1061-e3476c3f4e9f', + name: 'AvroReader', + type: 'org.apache.nifi.avro.AvroReader', + bundle: { + group: 'org.apache.nifi', + artifact: 'nifi-record-serialization-services-nar', + version: '2.0.0-SNAPSHOT' + }, + controllerServiceApis: [ + { + type: 'org.apache.nifi.serialization.RecordReaderFactory', + bundle: { + group: 'org.apache.nifi', + artifact: 'nifi-standard-services-api-nar', + version: '2.0.0-SNAPSHOT' + } + } + ], + state: 'DISABLED', + persistsState: false, + restricted: false, + deprecated: false, + multipleVersionsAvailable: false, + supportsSensitiveDynamicProperties: false, + properties: { + 'schema-access-strategy': 'embedded-avro-schema', + 'schema-registry': null, + 'schema-name': '${schema.name}', + 'schema-version': null, + 'schema-branch': null, + 'schema-text': '${avro.schema}', + 'schema-reference-reader': null, + 'cache-size': '1000' + }, + descriptors: { + 'schema-access-strategy': { + name: 'schema-access-strategy', + displayName: 'Schema Access Strategy', + description: 'Specifies how to obtain the schema that is to be used for interpreting the data.', + defaultValue: 'embedded-avro-schema', + allowableValues: [ + { + allowableValue: { + displayName: "Use 'Schema Name' Property", + value: 'schema-name', + description: + "The name of the Schema to use is specified by the 'Schema Name' Property. The value of this property is used to lookup the Schema in the configured Schema Registry service." + }, + canRead: true + }, + { + allowableValue: { + displayName: "Use 'Schema Text' Property", + value: 'schema-text-property', + description: + "The text of the Schema itself is specified by the 'Schema Text' Property. The value of this property must be a valid Avro Schema. If Expression Language is used, the value of the 'Schema Text' property must be valid after substituting the expressions." + }, + canRead: true + }, + { + allowableValue: { + displayName: 'Schema Reference Reader', + value: 'schema-reference-reader', + description: + 'The schema reference information will be provided through a configured Schema Reference Reader service implementation.' + }, + canRead: true + }, + { + allowableValue: { + displayName: 'Use Embedded Avro Schema', + value: 'embedded-avro-schema', + description: + 'The FlowFile has the Avro Schema embedded within the content, and this schema will be used.' + }, + canRead: true + } + ], + required: true, + sensitive: false, + dynamic: false, + supportsEl: false, + expressionLanguageScope: 'Not Supported', + dependencies: [] + }, + 'schema-registry': { + name: 'schema-registry', + displayName: 'Schema Registry', + description: 'Specifies the Controller Service to use for the Schema Registry', + allowableValues: [], + required: false, + sensitive: false, + dynamic: false, + supportsEl: false, + expressionLanguageScope: 'Not Supported', + identifiesControllerService: 'org.apache.nifi.schemaregistry.services.SchemaRegistry', + identifiesControllerServiceBundle: { + group: 'org.apache.nifi', + artifact: 'nifi-standard-services-api-nar', + version: '2.0.0-SNAPSHOT' + }, + dependencies: [ + { + propertyName: 'schema-access-strategy', + dependentValues: ['schema-reference-reader', 'schema-name'] + } + ] + }, + 'schema-name': { + name: 'schema-name', + displayName: 'Schema Name', + description: 'Specifies the name of the schema to lookup in the Schema Registry property', + defaultValue: '${schema.name}', + required: false, + sensitive: false, + dynamic: false, + supportsEl: true, + expressionLanguageScope: 'Environment variables and FlowFile Attributes', + dependencies: [ + { + propertyName: 'schema-access-strategy', + dependentValues: ['schema-name'] + } + ] + }, + 'schema-version': { + name: 'schema-version', + displayName: 'Schema Version', + description: + 'Specifies the version of the schema to lookup in the Schema Registry. If not specified then the latest version of the schema will be retrieved.', + required: false, + sensitive: false, + dynamic: false, + supportsEl: true, + expressionLanguageScope: 'Environment variables and FlowFile Attributes', + dependencies: [ + { + propertyName: 'schema-access-strategy', + dependentValues: ['schema-name'] + } + ] + }, + 'schema-branch': { + name: 'schema-branch', + displayName: 'Schema Branch', + description: + 'Specifies the name of the branch to use when looking up the schema in the Schema Registry property. If the chosen Schema Registry does not support branching, this value will be ignored.', + required: false, + sensitive: false, + dynamic: false, + supportsEl: true, + expressionLanguageScope: 'Environment variables and FlowFile Attributes', + dependencies: [ + { + propertyName: 'schema-access-strategy', + dependentValues: ['schema-name'] + } + ] + }, + 'schema-text': { + name: 'schema-text', + displayName: 'Schema Text', + description: 'The text of an Avro-formatted Schema', + defaultValue: '${avro.schema}', + required: false, + sensitive: false, + dynamic: false, + supportsEl: true, + expressionLanguageScope: 'Environment variables and FlowFile Attributes', + dependencies: [ + { + propertyName: 'schema-access-strategy', + dependentValues: ['schema-text-property'] + } + ] + }, + 'schema-reference-reader': { + name: 'schema-reference-reader', + displayName: 'Schema Reference Reader', + description: + 'Service implementation responsible for reading FlowFile attributes or content to determine the Schema Reference Identifier', + allowableValues: [], + required: true, + sensitive: false, + dynamic: false, + supportsEl: false, + expressionLanguageScope: 'Not Supported', + identifiesControllerService: 'org.apache.nifi.schemaregistry.services.SchemaReferenceReader', + identifiesControllerServiceBundle: { + group: 'org.apache.nifi', + artifact: 'nifi-standard-services-api-nar', + version: '2.0.0-SNAPSHOT' + }, + dependencies: [ + { + propertyName: 'schema-access-strategy', + dependentValues: ['schema-reference-reader'] + } + ] + }, + 'cache-size': { + name: 'cache-size', + displayName: 'Cache Size', + description: 'Specifies how many Schemas should be cached', + defaultValue: '1000', + required: true, + sensitive: false, + dynamic: false, + supportsEl: false, + expressionLanguageScope: 'Not Supported', + dependencies: [] + } + }, + referencingComponents: [ + { + revision: { + clientId: 'b37eba61-156a-47a4-875f-945cd153b876', + version: 5, + lastModifier: 'admin' + }, + id: '92db918c-018c-1000-ccd5-0796caa6d463', + permissions: { + canRead: true, + canWrite: true + }, + bulletins: [ + { + id: 0, + groupId: 'asdf', + sourceId: 'asdf', + timestamp: '14:08:44 EST', + canRead: true, + bulletin: { + id: 0, + category: 'asdf', + groupId: 'asdf', + sourceId: 'asdf', + sourceName: 'asdf', + level: 'ERROR', + message: 'asdf', + timestamp: '14:08:44 EST' + } + } + ], + component: { + id: '92db918c-018c-1000-ccd5-0796caa6d463', + name: 'ReaderLookup', + type: 'ReaderLookup', + state: 'DISABLED', + validationErrors: [ + "'avro' validated against '92db6ee4-018c-1000-1061-e3476c3f4e9f' is invalid because Controller Service with ID 92db6ee4-018c-1000-1061-e3476c3f4e9f is disabled" + ], + referenceType: 'ControllerService', + referenceCycle: false, + referencingComponents: [] + }, + operatePermissions: { + canRead: false, + canWrite: false + } + } + ], + validationStatus: 'VALID', + bulletinLevel: 'WARN', + extensionMissing: false + }, + operatePermissions: { + canRead: false, + canWrite: false + }, + status: { + runStatus: 'DISABLED', + validationStatus: 'VALID' + } + }; + + const options = [ + { + text: 'pg2', + value: 'bae2ec98-0192-1000-504b-6bf6ce039f24', + description: + 'Could not move controller service because the following components would be out of scope: [FetchGridFS]', + disabled: true + }, + { + text: 'pg1', + value: 'bad208f8-0192-1000-a9b3-3bc0d208b78b', + description: + 'Could not move controller service because the following components would be out of scope: [FetchGridFS]', + disabled: true + } + ]; + + const data: MoveControllerServiceDialogRequestSuccess = { + controllerService: controllerService, + options: options + }; + + beforeEach(() => { + TestBed.configureTestingModule({ + imports: [MoveControllerService, NoopAnimationsModule, MatDialogModule], + providers: [ + provideMockStore({ initialState }), + { + provide: MAT_DIALOG_DATA, + useValue: data + }, + { provide: MatDialogRef, useValue: null } + ] + }); + fixture = TestBed.createComponent(MoveControllerService); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/ui/controller-service/move-controller-service/move-controller-service.component.ts b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/ui/controller-service/move-controller-service/move-controller-service.component.ts new file mode 100644 index 000000000000..327796de92ee --- /dev/null +++ b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/ui/controller-service/move-controller-service/move-controller-service.component.ts @@ -0,0 +1,122 @@ +/* + * 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, Inject, Input } from '@angular/core'; +import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog'; +import { FormBuilder, FormControl, FormGroup, 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, NgTemplateOutlet } from '@angular/common'; +import { MatTabsModule } from '@angular/material/tabs'; +import { MatOptionModule } from '@angular/material/core'; +import { MatSelectModule } from '@angular/material/select'; +import { TextTip, NifiTooltipDirective, SelectOption } from '@nifi/shared'; +import { Store } from '@ngrx/store'; +import { CloseOnEscapeDialog } from '@nifi/shared'; +import { NiFiState } from 'apps/nifi/src/app/state'; +import { NgIf } from '@angular/common'; +import { + ControllerServiceEntity, + ControllerServiceReferencingComponent, + ControllerServiceReferencingComponentEntity +} from 'apps/nifi/src/app/state/shared'; +import { ControllerServiceApi } from 'apps/nifi/src/app/ui/common/controller-service/controller-service-api/controller-service-api.component'; +import { ControllerServiceReferences } from 'apps/nifi/src/app/ui/common/controller-service/controller-service-references/controller-service-references.component'; +import { NifiSpinnerDirective } from 'apps/nifi/src/app/ui/common/spinner/nifi-spinner.directive'; +import { MoveControllerServiceDialogRequestSuccess } from '../../../state/controller-services'; +import { moveControllerService } from '../../../state/controller-services/controller-services.actions'; +import { BreadcrumbEntity } from '../../../state/shared'; + +@Component({ + selector: 'move-controller-service', + standalone: true, + templateUrl: './move-controller-service.component.html', + imports: [ + ReactiveFormsModule, + MatDialogModule, + MatInputModule, + MatCheckboxModule, + MatButtonModule, + MatTabsModule, + MatOptionModule, + MatSelectModule, + ControllerServiceApi, + ControllerServiceReferences, + AsyncPipe, + NifiSpinnerDirective, + NifiTooltipDirective, + NgTemplateOutlet, + NgIf + ], + styleUrls: ['./move-controller-service.component.scss'] +}) +export class MoveControllerService extends CloseOnEscapeDialog { + @Input() goToReferencingComponent!: (component: ControllerServiceReferencingComponent) => void; + protected readonly TextTip = TextTip; + protected processGroupOptions: SelectOption[] = []; + controllerService: ControllerServiceEntity; + + moveControllerServiceForm: FormGroup; + + constructor( + @Inject(MAT_DIALOG_DATA) public request: MoveControllerServiceDialogRequestSuccess, + private store: Store, + private formBuilder: FormBuilder + ) { + super(); + + this.controllerService = request.controllerService; + + // build the form + this.moveControllerServiceForm = this.formBuilder.group({ + processGroups: new FormControl('Process Group', Validators.required) + }); + + this.processGroupOptions = request.options; + + const firstEnabled = this.processGroupOptions.findIndex((pg) => !pg.disabled); + if (firstEnabled != -1) { + this.moveControllerServiceForm.controls['processGroups'].setValue( + this.processGroupOptions[firstEnabled].value + ); + } else { + this.moveControllerServiceForm.controls['processGroups'].addValidators(() => { + return { invalid: true }; + }); + } + } + + submitForm() { + this.store.dispatch( + moveControllerService({ + request: { + controllerService: this.request.controllerService, + data: { + parentGroupId: this.moveControllerServiceForm.get('processGroups')?.value, + revision: this.request.controllerService.revision + } + } + }) + ); + } + + override isDirty(): boolean { + return this.moveControllerServiceForm.dirty; + } +} diff --git a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/ui/move-controller-service/move-controller-service.component.spec.ts b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/ui/move-controller-service/move-controller-service.component.spec.ts deleted file mode 100644 index 037e6fc1cc61..000000000000 --- a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/ui/move-controller-service/move-controller-service.component.spec.ts +++ /dev/null @@ -1,3462 +0,0 @@ -/* - * 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 { ControllerServiceEntity } from './../../../../state/shared/index'; -import { MoveControllerService } from './move-controller-service.component'; -import { NoopAnimationsModule } from '@angular/platform-browser/animations'; -import { provideMockStore } from '@ngrx/store/testing'; -import { initialState } from '../../../../state/contoller-service-state/controller-service-state.reducer'; -import { MAT_DIALOG_DATA, MatDialogModule, MatDialogRef } from '@angular/material/dialog'; -import { MoveControllerServiceDialogRequestSuccess } from '../../state/controller-services'; -import { BreadcrumbEntity } from '../../state/shared'; -import { ComponentType, SelectOption } from '@nifi/shared'; - -describe('MoveControllerService', () => { - let component: MoveControllerService; - let fixture: ComponentFixture; - const breadrumb: BreadcrumbEntity = { - id: 'cc4eefda-018d-1000-35ee-194d439257e4', - permissions: { - canRead: true, - canWrite: true - }, - breadcrumb: { - id: 'cc4eefda-018d-1000-35ee-194d439257e4', - name: 'pg1' - }, - parentBreadcrumb: { - id: '96456bc3-018b-1000-05d8-51720bebae4b', - permissions: { - canRead: true, - canWrite: true - }, - breadcrumb: { - id: '96456bc3-018b-1000-05d8-51720bebae4b', - name: 'NiFi Flow' - }, - versionedFlowState: '' - }, - versionedFlowState: '' - }; - - const chldren: SelectOption[] = [ - { - text: 'pg2', - value: 'cc4f110c-018d-1000-d4b6-d933a69c9d53' - }, - { - text: 'pg2', - value: 'cc4f110c-018d-1000-d4b6-d933a69c9d53' - } - ]; - - const processGroupEntity = { - revision: { - version: 0 - }, - id: 'cc4eefda-018d-1000-35ee-194d439257e4', - uri: 'http://127.0.0.1:4200/nifi-api/process-groups/cc4eefda-018d-1000-35ee-194d439257e4', - position: { - x: 24, - y: -88 - }, - permissions: { - canRead: true, - canWrite: true - }, - bulletins: [], - component: { - id: 'cc4eefda-018d-1000-35ee-194d439257e4', - versionedComponentId: 'eadc98b0-c3b8-345f-80f4-4e92e1130b8b', - parentGroupId: '96456bc3-018b-1000-05d8-51720bebae4b', - position: { - x: 24, - y: -88 - }, - name: 'pg1', - comments: '', - flowfileConcurrency: 'UNBOUNDED', - flowfileOutboundPolicy: 'STREAM_WHEN_AVAILABLE', - defaultFlowFileExpiration: '0 sec', - defaultBackPressureObjectThreshold: 10000, - defaultBackPressureDataSizeThreshold: '1 GB', - executionEngine: 'INHERITED', - maxConcurrentTasks: 1, - statelessFlowTimeout: '1 min', - runningCount: 0, - stoppedCount: 0, - invalidCount: 3, - disabledCount: 0, - activeRemotePortCount: 0, - inactiveRemotePortCount: 0, - upToDateCount: 0, - locallyModifiedCount: 0, - staleCount: 0, - locallyModifiedAndStaleCount: 0, - syncFailureCount: 0, - localInputPortCount: 0, - localOutputPortCount: 0, - publicInputPortCount: 0, - publicOutputPortCount: 0, - statelessGroupScheduledState: 'STOPPED', - contents: { - processGroups: [ - { - id: 'cc4f110c-018d-1000-d4b6-d933a69c9d53', - versionedComponentId: '11610e12-1853-3179-9e6b-714a77c470e2', - parentGroupId: 'cc4eefda-018d-1000-35ee-194d439257e4', - position: { - x: 450.00000073872457, - y: 89.00000213800337 - }, - name: 'pg2', - comments: '', - flowfileConcurrency: 'UNBOUNDED', - flowfileOutboundPolicy: 'STREAM_WHEN_AVAILABLE', - defaultFlowFileExpiration: '0 sec', - defaultBackPressureObjectThreshold: 10000, - defaultBackPressureDataSizeThreshold: '1 GB', - executionEngine: 'INHERITED', - maxConcurrentTasks: 1, - statelessFlowTimeout: '1 min', - runningCount: 0, - stoppedCount: 0, - invalidCount: 0, - disabledCount: 0, - activeRemotePortCount: 0, - inactiveRemotePortCount: 0, - upToDateCount: 0, - locallyModifiedCount: 0, - staleCount: 0, - locallyModifiedAndStaleCount: 0, - syncFailureCount: 0, - localInputPortCount: 0, - localOutputPortCount: 0, - publicInputPortCount: 0, - publicOutputPortCount: 0, - statelessGroupScheduledState: 'STOPPED', - contents: { - processGroups: [], - remoteProcessGroups: [], - processors: [], - inputPorts: [], - outputPorts: [], - connections: [], - labels: [], - funnels: [], - controllerServices: [] - }, - inputPortCount: 0, - outputPortCount: 0 - } - ], - remoteProcessGroups: [], - processors: [ - { - id: '018e1000-93c7-1b09-09f3-8e5a070f0381', - versionedComponentId: '401e9313-5c31-3bb8-ac48-c34af331b2af', - parentGroupId: 'cc4eefda-018d-1000-35ee-194d439257e4', - position: { - x: 760, - y: 272 - }, - name: 'ConsumeKafkaRecord_2_6 t1', - type: 'org.apache.nifi.processors.kafka.pubsub.ConsumeKafkaRecord_2_6', - bundle: { - group: 'org.apache.nifi', - artifact: 'nifi-kafka-2-6-nar', - version: '2.0.0-SNAPSHOT' - }, - state: 'STOPPED', - style: {}, - relationships: [ - { - name: 'parse.failure', - description: - 'If a message from Kafka cannot be parsed using the configured Record Reader, the contents of the message will be routed to this Relationship as its own individual FlowFile.', - autoTerminate: true, - retry: false - }, - { - name: 'success', - description: - 'FlowFiles received from Kafka. Depending on demarcation strategy it is a flow file per message or a bundle of messages grouped by topic and partition.', - autoTerminate: true, - retry: false - } - ], - supportsParallelProcessing: true, - supportsBatching: false, - supportsSensitiveDynamicProperties: false, - persistsState: false, - restricted: false, - deprecated: false, - executionNodeRestricted: false, - multipleVersionsAvailable: false, - inputRequirement: 'INPUT_FORBIDDEN', - config: { - properties: { - 'bootstrap.servers': 'localhost:9092', - topic: '321', - topic_type: 'names', - 'record-reader': '9648c622-018b-1000-c78f-2ef4bc78b696', - 'record-writer': '9648dc34-018b-1000-9fb4-636b6abe9a10', - 'group.id': '2', - 'output-strategy': 'USE_VALUE', - 'header-name-regex': null, - 'key-attribute-encoding': 'utf-8', - 'key-format': 'byte-array', - 'key-record-reader': null, - 'Commit Offsets': 'true', - 'max-uncommit-offset-wait': '1 secs', - 'honor-transactions': 'true', - 'security.protocol': 'PLAINTEXT', - 'sasl.mechanism': 'GSSAPI', - 'kerberos-user-service': null, - 'sasl.kerberos.service.name': null, - 'sasl.username': null, - 'sasl.password': null, - 'sasl.token.auth': 'false', - 'aws.profile.name': null, - 'ssl.context.service': null, - 'separate-by-key': 'false', - 'auto.offset.reset': 'latest', - 'message-header-encoding': 'UTF-8', - 'max.poll.records': '10000', - 'Communications Timeout': '60 secs' - }, - descriptors: { - 'bootstrap.servers': { - name: 'bootstrap.servers', - displayName: 'Kafka Brokers', - description: 'Comma-separated list of Kafka Brokers in the format host:port', - defaultValue: 'localhost:9092', - required: true, - sensitive: false, - dynamic: false, - supportsEl: true, - expressionLanguageScope: - 'Environment variables defined at JVM level and system properties', - dependencies: [] - }, - topic: { - name: 'topic', - displayName: 'Topic Name(s)', - description: - 'The name of the Kafka Topic(s) to pull from. More than one can be supplied if comma separated.', - required: true, - sensitive: false, - dynamic: false, - supportsEl: true, - expressionLanguageScope: - 'Environment variables defined at JVM level and system properties', - dependencies: [] - }, - topic_type: { - name: 'topic_type', - displayName: 'Topic Name Format', - description: - 'Specifies whether the Topic(s) provided are a comma separated list of names or a single regular expression', - defaultValue: 'names', - allowableValues: [ - { - allowableValue: { - displayName: 'names', - value: 'names', - description: - 'Topic is a full topic name or comma separated list of names' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'pattern', - value: 'pattern', - description: 'Topic is a regex using the Java Pattern syntax' - }, - canRead: true - } - ], - required: true, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [] - }, - 'record-reader': { - name: 'record-reader', - displayName: 'Value Record Reader', - description: 'The Record Reader to use for incoming FlowFiles', - allowableValues: [ - { - allowableValue: { - displayName: 'AvroReader', - value: '9648c622-018b-1000-c78f-2ef4bc78b696' - }, - canRead: true - } - ], - required: true, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - identifiesControllerService: 'org.apache.nifi.serialization.RecordReaderFactory', - identifiesControllerServiceBundle: { - group: 'org.apache.nifi', - artifact: 'nifi-standard-services-api-nar', - version: '2.0.0-SNAPSHOT' - }, - dependencies: [] - }, - 'record-writer': { - name: 'record-writer', - displayName: 'Record Value Writer', - description: - 'The Record Writer to use in order to serialize the data before sending to Kafka', - allowableValues: [ - { - allowableValue: { - displayName: 'AvroRecordSetWriter', - value: '9648dc34-018b-1000-9fb4-636b6abe9a10' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'AvroRecordSetWriter', - value: '3c57fe11-0190-1000-9c99-9faab34f0d5e' - }, - canRead: true - } - ], - required: true, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - identifiesControllerService: 'org.apache.nifi.serialization.RecordSetWriterFactory', - identifiesControllerServiceBundle: { - group: 'org.apache.nifi', - artifact: 'nifi-standard-services-api-nar', - version: '2.0.0-SNAPSHOT' - }, - dependencies: [] - }, - 'group.id': { - name: 'group.id', - displayName: 'Group ID', - description: - "A Group ID is used to identify consumers that are within the same consumer group. Corresponds to Kafka's 'group.id' property.", - required: true, - sensitive: false, - dynamic: false, - supportsEl: true, - expressionLanguageScope: - 'Environment variables defined at JVM level and system properties', - dependencies: [] - }, - 'output-strategy': { - name: 'output-strategy', - displayName: 'Output Strategy', - description: 'The format used to output the Kafka record into a FlowFile record.', - defaultValue: 'USE_VALUE', - allowableValues: [ - { - allowableValue: { - displayName: 'Use Content as Value', - value: 'USE_VALUE', - description: 'Write only the Kafka Record value to the FlowFile record.' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'Use Wrapper', - value: 'USE_WRAPPER', - description: - 'Write the Kafka Record key, value, headers, and metadata into the FlowFile record. (See processor usage for more information.)' - }, - canRead: true - } - ], - required: true, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [] - }, - 'header-name-regex': { - name: 'header-name-regex', - displayName: 'Headers to Add as Attributes (Regex)', - description: - 'A Regular Expression that is matched against all message headers. Any message header whose name matches the regex will be added to the FlowFile as an Attribute. If not specified, no Header values will be added as FlowFile attributes. If two messages have a different value for the same header and that header is selected by the provided regex, then those two messages must be added to different FlowFiles. As a result, users should be cautious about using a regex like ".*" if messages are expected to have header values that are unique per message, such as an identifier or timestamp, because it will prevent NiFi from bundling the messages together efficiently.', - required: false, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [ - { - propertyName: 'output-strategy', - dependentValues: ['USE_VALUE'] - } - ] - }, - 'key-attribute-encoding': { - name: 'key-attribute-encoding', - displayName: 'Key Attribute Encoding', - description: - "If the property is set to true, FlowFiles that are emitted have an attribute named 'kafka.key'. This property dictates how the value of the attribute should be encoded.", - defaultValue: 'utf-8', - allowableValues: [ - { - allowableValue: { - displayName: 'UTF-8 Encoded', - value: 'utf-8', - description: 'The key is interpreted as a UTF-8 Encoded string.' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'Hex Encoded', - value: 'hex', - description: - 'The key is interpreted as arbitrary binary data and is encoded using hexadecimal characters with uppercase letters' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'Do Not Add Key as Attribute', - value: 'do-not-add', - description: 'The key will not be added as an Attribute' - }, - canRead: true - } - ], - required: true, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [ - { - propertyName: 'output-strategy', - dependentValues: ['USE_VALUE'] - } - ] - }, - 'key-format': { - name: 'key-format', - displayName: 'Key Format', - description: "Specifies how to represent the Kafka Record's Key in the output", - defaultValue: 'byte-array', - allowableValues: [ - { - allowableValue: { - displayName: 'String', - value: 'string', - description: 'Format the Kafka ConsumerRecord key as a UTF-8 string.' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'Byte Array', - value: 'byte-array', - description: 'Format the Kafka ConsumerRecord key as a byte array.' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'Record', - value: 'record', - description: 'Format the Kafka ConsumerRecord key as a record.' - }, - canRead: true - } - ], - required: true, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [ - { - propertyName: 'output-strategy', - dependentValues: ['USE_WRAPPER'] - } - ] - }, - 'key-record-reader': { - name: 'key-record-reader', - displayName: 'Key Record Reader', - description: - "The Record Reader to use for parsing the Kafka Record's key into a Record", - allowableValues: [ - { - allowableValue: { - displayName: 'AvroReader', - value: '9648c622-018b-1000-c78f-2ef4bc78b696' - }, - canRead: true - } - ], - required: false, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - identifiesControllerService: 'org.apache.nifi.serialization.RecordReaderFactory', - identifiesControllerServiceBundle: { - group: 'org.apache.nifi', - artifact: 'nifi-standard-services-api-nar', - version: '2.0.0-SNAPSHOT' - }, - dependencies: [ - { - propertyName: 'key-format', - dependentValues: ['record'] - } - ] - }, - 'Commit Offsets': { - name: 'Commit Offsets', - displayName: 'Commit Offsets', - description: - "Specifies whether or not this Processor should commit the offsets to Kafka after receiving messages. This value should be false when a PublishKafkaRecord processor is expected to commit the offsets using Exactly Once semantics, and should be reserved for dataflows that are designed to run within Stateless NiFi. See Processor's Usage / Additional Details for more information. Note that setting this value to false can lead to significant data duplication or potentially even data loss if the dataflow is not properly configured.", - defaultValue: 'true', - allowableValues: [ - { - allowableValue: { - displayName: 'true', - value: 'true' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'false', - value: 'false' - }, - canRead: true - } - ], - required: false, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [] - }, - 'max-uncommit-offset-wait': { - name: 'max-uncommit-offset-wait', - displayName: 'Max Uncommitted Time', - description: - "Specifies the maximum amount of time allowed to pass before offsets must be committed. This value impacts how often offsets will be committed. Committing offsets less often increases throughput but also increases the window of potential data duplication in the event of a rebalance or JVM restart between commits. This value is also related to maximum poll records and the use of a message demarcator. When using a message demarcator we can have far more uncommitted messages than when we're not as there is much less for us to keep track of in memory.", - defaultValue: '1 secs', - required: false, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [ - { - propertyName: 'Commit Offsets', - dependentValues: ['true'] - } - ] - }, - 'honor-transactions': { - name: 'honor-transactions', - displayName: 'Honor Transactions', - description: - 'Specifies whether or not NiFi should honor transactional guarantees when communicating with Kafka. If false, the Processor will use an "isolation level" of read_uncomitted. This means that messages will be received as soon as they are written to Kafka but will be pulled, even if the producer cancels the transactions. If this value is true, NiFi will not receive any messages for which the producer\'s transaction was canceled, but this can result in some latency since the consumer must wait for the producer to finish its entire transaction instead of pulling as the messages become available.', - defaultValue: 'true', - allowableValues: [ - { - allowableValue: { - displayName: 'true', - value: 'true' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'false', - value: 'false' - }, - canRead: true - } - ], - required: true, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [] - }, - 'security.protocol': { - name: 'security.protocol', - displayName: 'Security Protocol', - description: - 'Security protocol used to communicate with brokers. Corresponds to Kafka Client security.protocol property', - defaultValue: 'PLAINTEXT', - allowableValues: [ - { - allowableValue: { - displayName: 'PLAINTEXT', - value: 'PLAINTEXT' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'SSL', - value: 'SSL' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'SASL_PLAINTEXT', - value: 'SASL_PLAINTEXT' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'SASL_SSL', - value: 'SASL_SSL' - }, - canRead: true - } - ], - required: true, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [] - }, - 'sasl.mechanism': { - name: 'sasl.mechanism', - displayName: 'SASL Mechanism', - description: - 'SASL mechanism used for authentication. Corresponds to Kafka Client sasl.mechanism property', - defaultValue: 'GSSAPI', - allowableValues: [ - { - allowableValue: { - displayName: 'GSSAPI', - value: 'GSSAPI', - description: 'General Security Services API for Kerberos authentication' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'PLAIN', - value: 'PLAIN', - description: 'Plain username and password authentication' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'SCRAM-SHA-256', - value: 'SCRAM-SHA-256', - description: - 'Salted Challenge Response Authentication Mechanism using SHA-512 with username and password' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'SCRAM-SHA-512', - value: 'SCRAM-SHA-512', - description: - 'Salted Challenge Response Authentication Mechanism using SHA-256 with username and password' - }, - canRead: true - } - ], - required: true, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [] - }, - 'kerberos-user-service': { - name: 'kerberos-user-service', - displayName: 'Kerberos User Service', - description: 'Service supporting user authentication with Kerberos', - allowableValues: [], - required: false, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - identifiesControllerService: - 'org.apache.nifi.kerberos.SelfContainedKerberosUserService', - identifiesControllerServiceBundle: { - group: 'org.apache.nifi', - artifact: 'nifi-standard-services-api-nar', - version: '2.0.0-SNAPSHOT' - }, - dependencies: [] - }, - 'sasl.kerberos.service.name': { - name: 'sasl.kerberos.service.name', - displayName: 'Kerberos Service Name', - description: - 'The service name that matches the primary name of the Kafka server configured in the broker JAAS configuration', - required: false, - sensitive: false, - dynamic: false, - supportsEl: true, - expressionLanguageScope: - 'Environment variables defined at JVM level and system properties', - dependencies: [] - }, - 'sasl.username': { - name: 'sasl.username', - displayName: 'Username', - description: - 'Username provided with configured password when using PLAIN or SCRAM SASL Mechanisms', - required: false, - sensitive: false, - dynamic: false, - supportsEl: true, - expressionLanguageScope: - 'Environment variables defined at JVM level and system properties', - dependencies: [ - { - propertyName: 'sasl.mechanism', - dependentValues: ['PLAIN', 'SCRAM-SHA-512', 'SCRAM-SHA-256'] - } - ] - }, - 'sasl.password': { - name: 'sasl.password', - displayName: 'Password', - description: - 'Password provided with configured username when using PLAIN or SCRAM SASL Mechanisms', - required: false, - sensitive: true, - dynamic: false, - supportsEl: true, - expressionLanguageScope: - 'Environment variables defined at JVM level and system properties', - dependencies: [ - { - propertyName: 'sasl.mechanism', - dependentValues: ['PLAIN', 'SCRAM-SHA-512', 'SCRAM-SHA-256'] - } - ] - }, - 'sasl.token.auth': { - name: 'sasl.token.auth', - displayName: 'Token Authentication', - description: - 'Enables or disables Token authentication when using SCRAM SASL Mechanisms', - defaultValue: 'false', - allowableValues: [ - { - allowableValue: { - displayName: 'true', - value: 'true' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'false', - value: 'false' - }, - canRead: true - } - ], - required: false, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [ - { - propertyName: 'sasl.mechanism', - dependentValues: ['SCRAM-SHA-512', 'SCRAM-SHA-256'] - } - ] - }, - 'aws.profile.name': { - name: 'aws.profile.name', - displayName: 'AWS Profile Name', - description: - 'The Amazon Web Services Profile to select when multiple profiles are available.', - required: false, - sensitive: false, - dynamic: false, - supportsEl: true, - expressionLanguageScope: 'Environment variables and FlowFile Attributes', - dependencies: [ - { - propertyName: 'sasl.mechanism', - dependentValues: ['AWS_MSK_IAM'] - } - ] - }, - 'ssl.context.service': { - name: 'ssl.context.service', - displayName: 'SSL Context Service', - description: 'Service supporting SSL communication with Kafka brokers', - allowableValues: [ - { - allowableValue: { - displayName: 'StandardRestrictedSSLContextService', - value: 'f5bf3c0a-018d-1000-7c8e-910f220b215e' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'aal1', - value: '3c5951d8-0190-1000-0ed6-320905f27a2f' - }, - canRead: true - } - ], - required: false, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - identifiesControllerService: 'org.apache.nifi.ssl.SSLContextService', - identifiesControllerServiceBundle: { - group: 'org.apache.nifi', - artifact: 'nifi-standard-services-api-nar', - version: '2.0.0-SNAPSHOT' - }, - dependencies: [] - }, - 'separate-by-key': { - name: 'separate-by-key', - displayName: 'Separate By Key', - description: - 'If true, two Records will only be added to the same FlowFile if both of the Kafka Messages have identical keys.', - defaultValue: 'false', - allowableValues: [ - { - allowableValue: { - displayName: 'true', - value: 'true' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'false', - value: 'false' - }, - canRead: true - } - ], - required: false, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [] - }, - 'auto.offset.reset': { - name: 'auto.offset.reset', - displayName: 'Offset Reset', - description: - "Allows you to manage the condition when there is no initial offset in Kafka or if the current offset does not exist any more on the server (e.g. because that data has been deleted). Corresponds to Kafka's 'auto.offset.reset' property.", - defaultValue: 'latest', - allowableValues: [ - { - allowableValue: { - displayName: 'earliest', - value: 'earliest', - description: 'Automatically reset the offset to the earliest offset' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'latest', - value: 'latest', - description: 'Automatically reset the offset to the latest offset' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'none', - value: 'none', - description: - "Throw exception to the consumer if no previous offset is found for the consumer's group" - }, - canRead: true - } - ], - required: true, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [] - }, - 'message-header-encoding': { - name: 'message-header-encoding', - displayName: 'Message Header Encoding', - description: - 'Any message header that is found on a Kafka message will be added to the outbound FlowFile as an attribute. This property indicates the Character Encoding to use for deserializing the headers.', - defaultValue: 'UTF-8', - required: false, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [] - }, - 'max.poll.records': { - name: 'max.poll.records', - displayName: 'Max Poll Records', - description: - 'Specifies the maximum number of records Kafka should return in a single poll.', - defaultValue: '10000', - required: false, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [] - }, - 'Communications Timeout': { - name: 'Communications Timeout', - displayName: 'Communications Timeout', - description: - 'Specifies the timeout that the consumer should use when communicating with the Kafka Broker', - defaultValue: '60 secs', - required: true, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [] - } - }, - schedulingPeriod: '0 sec', - schedulingStrategy: 'TIMER_DRIVEN', - executionNode: 'ALL', - penaltyDuration: '30 sec', - yieldDuration: '1 sec', - bulletinLevel: 'WARN', - runDurationMillis: 0, - concurrentlySchedulableTaskCount: 1, - autoTerminatedRelationships: ['parse.failure', 'success'], - comments: '', - lossTolerant: false, - defaultConcurrentTasks: { - TIMER_DRIVEN: '1', - CRON_DRIVEN: '1' - }, - defaultSchedulingPeriod: { - TIMER_DRIVEN: '0 sec', - CRON_DRIVEN: '* * * * * ?' - }, - retryCount: 10, - retriedRelationships: [], - backoffMechanism: 'PENALIZE_FLOWFILE', - maxBackoffPeriod: '10 mins' - }, - validationErrors: [ - "'Value Record Reader' validated against '9648c622-018b-1000-c78f-2ef4bc78b696' is invalid because Controller Service with ID 9648c622-018b-1000-c78f-2ef4bc78b696 is disabled" - ], - validationStatus: 'INVALID', - extensionMissing: false - }, - { - id: '018e1002-93c7-1b09-913c-8102bce39edb', - versionedComponentId: '1bd9430e-e943-33bd-9eca-40fc4187c17c', - parentGroupId: 'cc4eefda-018d-1000-35ee-194d439257e4', - position: { - x: 855, - y: 655 - }, - name: 'Budokai', - type: 'org.apache.nifi.processors.kafka.pubsub.ConsumeKafkaRecord_2_6', - bundle: { - group: 'org.apache.nifi', - artifact: 'nifi-kafka-2-6-nar', - version: '2.0.0-SNAPSHOT' - }, - state: 'STOPPED', - style: {}, - relationships: [ - { - name: 'parse.failure', - description: - 'If a message from Kafka cannot be parsed using the configured Record Reader, the contents of the message will be routed to this Relationship as its own individual FlowFile.', - autoTerminate: true, - retry: false - }, - { - name: 'success', - description: - 'FlowFiles received from Kafka. Depending on demarcation strategy it is a flow file per message or a bundle of messages grouped by topic and partition.', - autoTerminate: true, - retry: false - } - ], - supportsParallelProcessing: true, - supportsBatching: false, - supportsSensitiveDynamicProperties: false, - persistsState: false, - restricted: false, - deprecated: false, - executionNodeRestricted: false, - multipleVersionsAvailable: false, - inputRequirement: 'INPUT_FORBIDDEN', - config: { - properties: { - 'bootstrap.servers': 'localhost:9092', - topic: '321', - topic_type: 'names', - 'record-reader': '9648c622-018b-1000-c78f-2ef4bc78b696', - 'record-writer': '9648dc34-018b-1000-9fb4-636b6abe9a10', - 'group.id': '2', - 'output-strategy': 'USE_VALUE', - 'header-name-regex': null, - 'key-attribute-encoding': 'utf-8', - 'key-format': 'byte-array', - 'key-record-reader': null, - 'Commit Offsets': 'true', - 'max-uncommit-offset-wait': '1 secs', - 'honor-transactions': 'true', - 'security.protocol': 'PLAINTEXT', - 'sasl.mechanism': 'GSSAPI', - 'kerberos-user-service': null, - 'sasl.kerberos.service.name': null, - 'sasl.username': null, - 'sasl.password': null, - 'sasl.token.auth': 'false', - 'aws.profile.name': null, - 'ssl.context.service': null, - 'separate-by-key': 'false', - 'auto.offset.reset': 'latest', - 'message-header-encoding': 'UTF-8', - 'max.poll.records': '10000', - 'Communications Timeout': '60 secs' - }, - descriptors: { - 'bootstrap.servers': { - name: 'bootstrap.servers', - displayName: 'Kafka Brokers', - description: 'Comma-separated list of Kafka Brokers in the format host:port', - defaultValue: 'localhost:9092', - required: true, - sensitive: false, - dynamic: false, - supportsEl: true, - expressionLanguageScope: - 'Environment variables defined at JVM level and system properties', - dependencies: [] - }, - topic: { - name: 'topic', - displayName: 'Topic Name(s)', - description: - 'The name of the Kafka Topic(s) to pull from. More than one can be supplied if comma separated.', - required: true, - sensitive: false, - dynamic: false, - supportsEl: true, - expressionLanguageScope: - 'Environment variables defined at JVM level and system properties', - dependencies: [] - }, - topic_type: { - name: 'topic_type', - displayName: 'Topic Name Format', - description: - 'Specifies whether the Topic(s) provided are a comma separated list of names or a single regular expression', - defaultValue: 'names', - allowableValues: [ - { - allowableValue: { - displayName: 'names', - value: 'names', - description: - 'Topic is a full topic name or comma separated list of names' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'pattern', - value: 'pattern', - description: 'Topic is a regex using the Java Pattern syntax' - }, - canRead: true - } - ], - required: true, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [] - }, - 'record-reader': { - name: 'record-reader', - displayName: 'Value Record Reader', - description: 'The Record Reader to use for incoming FlowFiles', - allowableValues: [ - { - allowableValue: { - displayName: 'AvroReader', - value: '9648c622-018b-1000-c78f-2ef4bc78b696' - }, - canRead: true - } - ], - required: true, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - identifiesControllerService: 'org.apache.nifi.serialization.RecordReaderFactory', - identifiesControllerServiceBundle: { - group: 'org.apache.nifi', - artifact: 'nifi-standard-services-api-nar', - version: '2.0.0-SNAPSHOT' - }, - dependencies: [] - }, - 'record-writer': { - name: 'record-writer', - displayName: 'Record Value Writer', - description: - 'The Record Writer to use in order to serialize the data before sending to Kafka', - allowableValues: [ - { - allowableValue: { - displayName: 'AvroRecordSetWriter', - value: '9648dc34-018b-1000-9fb4-636b6abe9a10' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'AvroRecordSetWriter', - value: '3c57fe11-0190-1000-9c99-9faab34f0d5e' - }, - canRead: true - } - ], - required: true, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - identifiesControllerService: 'org.apache.nifi.serialization.RecordSetWriterFactory', - identifiesControllerServiceBundle: { - group: 'org.apache.nifi', - artifact: 'nifi-standard-services-api-nar', - version: '2.0.0-SNAPSHOT' - }, - dependencies: [] - }, - 'group.id': { - name: 'group.id', - displayName: 'Group ID', - description: - "A Group ID is used to identify consumers that are within the same consumer group. Corresponds to Kafka's 'group.id' property.", - required: true, - sensitive: false, - dynamic: false, - supportsEl: true, - expressionLanguageScope: - 'Environment variables defined at JVM level and system properties', - dependencies: [] - }, - 'output-strategy': { - name: 'output-strategy', - displayName: 'Output Strategy', - description: 'The format used to output the Kafka record into a FlowFile record.', - defaultValue: 'USE_VALUE', - allowableValues: [ - { - allowableValue: { - displayName: 'Use Content as Value', - value: 'USE_VALUE', - description: 'Write only the Kafka Record value to the FlowFile record.' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'Use Wrapper', - value: 'USE_WRAPPER', - description: - 'Write the Kafka Record key, value, headers, and metadata into the FlowFile record. (See processor usage for more information.)' - }, - canRead: true - } - ], - required: true, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [] - }, - 'header-name-regex': { - name: 'header-name-regex', - displayName: 'Headers to Add as Attributes (Regex)', - description: - 'A Regular Expression that is matched against all message headers. Any message header whose name matches the regex will be added to the FlowFile as an Attribute. If not specified, no Header values will be added as FlowFile attributes. If two messages have a different value for the same header and that header is selected by the provided regex, then those two messages must be added to different FlowFiles. As a result, users should be cautious about using a regex like ".*" if messages are expected to have header values that are unique per message, such as an identifier or timestamp, because it will prevent NiFi from bundling the messages together efficiently.', - required: false, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [ - { - propertyName: 'output-strategy', - dependentValues: ['USE_VALUE'] - } - ] - }, - 'key-attribute-encoding': { - name: 'key-attribute-encoding', - displayName: 'Key Attribute Encoding', - description: - "If the property is set to true, FlowFiles that are emitted have an attribute named 'kafka.key'. This property dictates how the value of the attribute should be encoded.", - defaultValue: 'utf-8', - allowableValues: [ - { - allowableValue: { - displayName: 'UTF-8 Encoded', - value: 'utf-8', - description: 'The key is interpreted as a UTF-8 Encoded string.' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'Hex Encoded', - value: 'hex', - description: - 'The key is interpreted as arbitrary binary data and is encoded using hexadecimal characters with uppercase letters' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'Do Not Add Key as Attribute', - value: 'do-not-add', - description: 'The key will not be added as an Attribute' - }, - canRead: true - } - ], - required: true, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [ - { - propertyName: 'output-strategy', - dependentValues: ['USE_VALUE'] - } - ] - }, - 'key-format': { - name: 'key-format', - displayName: 'Key Format', - description: "Specifies how to represent the Kafka Record's Key in the output", - defaultValue: 'byte-array', - allowableValues: [ - { - allowableValue: { - displayName: 'String', - value: 'string', - description: 'Format the Kafka ConsumerRecord key as a UTF-8 string.' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'Byte Array', - value: 'byte-array', - description: 'Format the Kafka ConsumerRecord key as a byte array.' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'Record', - value: 'record', - description: 'Format the Kafka ConsumerRecord key as a record.' - }, - canRead: true - } - ], - required: true, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [ - { - propertyName: 'output-strategy', - dependentValues: ['USE_WRAPPER'] - } - ] - }, - 'key-record-reader': { - name: 'key-record-reader', - displayName: 'Key Record Reader', - description: - "The Record Reader to use for parsing the Kafka Record's key into a Record", - allowableValues: [ - { - allowableValue: { - displayName: 'AvroReader', - value: '9648c622-018b-1000-c78f-2ef4bc78b696' - }, - canRead: true - } - ], - required: false, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - identifiesControllerService: 'org.apache.nifi.serialization.RecordReaderFactory', - identifiesControllerServiceBundle: { - group: 'org.apache.nifi', - artifact: 'nifi-standard-services-api-nar', - version: '2.0.0-SNAPSHOT' - }, - dependencies: [ - { - propertyName: 'key-format', - dependentValues: ['record'] - } - ] - }, - 'Commit Offsets': { - name: 'Commit Offsets', - displayName: 'Commit Offsets', - description: - "Specifies whether or not this Processor should commit the offsets to Kafka after receiving messages. This value should be false when a PublishKafkaRecord processor is expected to commit the offsets using Exactly Once semantics, and should be reserved for dataflows that are designed to run within Stateless NiFi. See Processor's Usage / Additional Details for more information. Note that setting this value to false can lead to significant data duplication or potentially even data loss if the dataflow is not properly configured.", - defaultValue: 'true', - allowableValues: [ - { - allowableValue: { - displayName: 'true', - value: 'true' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'false', - value: 'false' - }, - canRead: true - } - ], - required: false, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [] - }, - 'max-uncommit-offset-wait': { - name: 'max-uncommit-offset-wait', - displayName: 'Max Uncommitted Time', - description: - "Specifies the maximum amount of time allowed to pass before offsets must be committed. This value impacts how often offsets will be committed. Committing offsets less often increases throughput but also increases the window of potential data duplication in the event of a rebalance or JVM restart between commits. This value is also related to maximum poll records and the use of a message demarcator. When using a message demarcator we can have far more uncommitted messages than when we're not as there is much less for us to keep track of in memory.", - defaultValue: '1 secs', - required: false, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [ - { - propertyName: 'Commit Offsets', - dependentValues: ['true'] - } - ] - }, - 'honor-transactions': { - name: 'honor-transactions', - displayName: 'Honor Transactions', - description: - 'Specifies whether or not NiFi should honor transactional guarantees when communicating with Kafka. If false, the Processor will use an "isolation level" of read_uncomitted. This means that messages will be received as soon as they are written to Kafka but will be pulled, even if the producer cancels the transactions. If this value is true, NiFi will not receive any messages for which the producer\'s transaction was canceled, but this can result in some latency since the consumer must wait for the producer to finish its entire transaction instead of pulling as the messages become available.', - defaultValue: 'true', - allowableValues: [ - { - allowableValue: { - displayName: 'true', - value: 'true' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'false', - value: 'false' - }, - canRead: true - } - ], - required: true, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [] - }, - 'security.protocol': { - name: 'security.protocol', - displayName: 'Security Protocol', - description: - 'Security protocol used to communicate with brokers. Corresponds to Kafka Client security.protocol property', - defaultValue: 'PLAINTEXT', - allowableValues: [ - { - allowableValue: { - displayName: 'PLAINTEXT', - value: 'PLAINTEXT' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'SSL', - value: 'SSL' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'SASL_PLAINTEXT', - value: 'SASL_PLAINTEXT' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'SASL_SSL', - value: 'SASL_SSL' - }, - canRead: true - } - ], - required: true, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [] - }, - 'sasl.mechanism': { - name: 'sasl.mechanism', - displayName: 'SASL Mechanism', - description: - 'SASL mechanism used for authentication. Corresponds to Kafka Client sasl.mechanism property', - defaultValue: 'GSSAPI', - allowableValues: [ - { - allowableValue: { - displayName: 'GSSAPI', - value: 'GSSAPI', - description: 'General Security Services API for Kerberos authentication' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'PLAIN', - value: 'PLAIN', - description: 'Plain username and password authentication' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'SCRAM-SHA-256', - value: 'SCRAM-SHA-256', - description: - 'Salted Challenge Response Authentication Mechanism using SHA-512 with username and password' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'SCRAM-SHA-512', - value: 'SCRAM-SHA-512', - description: - 'Salted Challenge Response Authentication Mechanism using SHA-256 with username and password' - }, - canRead: true - } - ], - required: true, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [] - }, - 'kerberos-user-service': { - name: 'kerberos-user-service', - displayName: 'Kerberos User Service', - description: 'Service supporting user authentication with Kerberos', - allowableValues: [], - required: false, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - identifiesControllerService: - 'org.apache.nifi.kerberos.SelfContainedKerberosUserService', - identifiesControllerServiceBundle: { - group: 'org.apache.nifi', - artifact: 'nifi-standard-services-api-nar', - version: '2.0.0-SNAPSHOT' - }, - dependencies: [] - }, - 'sasl.kerberos.service.name': { - name: 'sasl.kerberos.service.name', - displayName: 'Kerberos Service Name', - description: - 'The service name that matches the primary name of the Kafka server configured in the broker JAAS configuration', - required: false, - sensitive: false, - dynamic: false, - supportsEl: true, - expressionLanguageScope: - 'Environment variables defined at JVM level and system properties', - dependencies: [] - }, - 'sasl.username': { - name: 'sasl.username', - displayName: 'Username', - description: - 'Username provided with configured password when using PLAIN or SCRAM SASL Mechanisms', - required: false, - sensitive: false, - dynamic: false, - supportsEl: true, - expressionLanguageScope: - 'Environment variables defined at JVM level and system properties', - dependencies: [ - { - propertyName: 'sasl.mechanism', - dependentValues: ['PLAIN', 'SCRAM-SHA-512', 'SCRAM-SHA-256'] - } - ] - }, - 'sasl.password': { - name: 'sasl.password', - displayName: 'Password', - description: - 'Password provided with configured username when using PLAIN or SCRAM SASL Mechanisms', - required: false, - sensitive: true, - dynamic: false, - supportsEl: true, - expressionLanguageScope: - 'Environment variables defined at JVM level and system properties', - dependencies: [ - { - propertyName: 'sasl.mechanism', - dependentValues: ['PLAIN', 'SCRAM-SHA-512', 'SCRAM-SHA-256'] - } - ] - }, - 'sasl.token.auth': { - name: 'sasl.token.auth', - displayName: 'Token Authentication', - description: - 'Enables or disables Token authentication when using SCRAM SASL Mechanisms', - defaultValue: 'false', - allowableValues: [ - { - allowableValue: { - displayName: 'true', - value: 'true' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'false', - value: 'false' - }, - canRead: true - } - ], - required: false, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [ - { - propertyName: 'sasl.mechanism', - dependentValues: ['SCRAM-SHA-512', 'SCRAM-SHA-256'] - } - ] - }, - 'aws.profile.name': { - name: 'aws.profile.name', - displayName: 'AWS Profile Name', - description: - 'The Amazon Web Services Profile to select when multiple profiles are available.', - required: false, - sensitive: false, - dynamic: false, - supportsEl: true, - expressionLanguageScope: 'Environment variables and FlowFile Attributes', - dependencies: [ - { - propertyName: 'sasl.mechanism', - dependentValues: ['AWS_MSK_IAM'] - } - ] - }, - 'ssl.context.service': { - name: 'ssl.context.service', - displayName: 'SSL Context Service', - description: 'Service supporting SSL communication with Kafka brokers', - allowableValues: [ - { - allowableValue: { - displayName: 'StandardRestrictedSSLContextService', - value: 'f5bf3c0a-018d-1000-7c8e-910f220b215e' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'aal1', - value: '3c5951d8-0190-1000-0ed6-320905f27a2f' - }, - canRead: true - } - ], - required: false, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - identifiesControllerService: 'org.apache.nifi.ssl.SSLContextService', - identifiesControllerServiceBundle: { - group: 'org.apache.nifi', - artifact: 'nifi-standard-services-api-nar', - version: '2.0.0-SNAPSHOT' - }, - dependencies: [] - }, - 'separate-by-key': { - name: 'separate-by-key', - displayName: 'Separate By Key', - description: - 'If true, two Records will only be added to the same FlowFile if both of the Kafka Messages have identical keys.', - defaultValue: 'false', - allowableValues: [ - { - allowableValue: { - displayName: 'true', - value: 'true' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'false', - value: 'false' - }, - canRead: true - } - ], - required: false, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [] - }, - 'auto.offset.reset': { - name: 'auto.offset.reset', - displayName: 'Offset Reset', - description: - "Allows you to manage the condition when there is no initial offset in Kafka or if the current offset does not exist any more on the server (e.g. because that data has been deleted). Corresponds to Kafka's 'auto.offset.reset' property.", - defaultValue: 'latest', - allowableValues: [ - { - allowableValue: { - displayName: 'earliest', - value: 'earliest', - description: 'Automatically reset the offset to the earliest offset' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'latest', - value: 'latest', - description: 'Automatically reset the offset to the latest offset' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'none', - value: 'none', - description: - "Throw exception to the consumer if no previous offset is found for the consumer's group" - }, - canRead: true - } - ], - required: true, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [] - }, - 'message-header-encoding': { - name: 'message-header-encoding', - displayName: 'Message Header Encoding', - description: - 'Any message header that is found on a Kafka message will be added to the outbound FlowFile as an attribute. This property indicates the Character Encoding to use for deserializing the headers.', - defaultValue: 'UTF-8', - required: false, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [] - }, - 'max.poll.records': { - name: 'max.poll.records', - displayName: 'Max Poll Records', - description: - 'Specifies the maximum number of records Kafka should return in a single poll.', - defaultValue: '10000', - required: false, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [] - }, - 'Communications Timeout': { - name: 'Communications Timeout', - displayName: 'Communications Timeout', - description: - 'Specifies the timeout that the consumer should use when communicating with the Kafka Broker', - defaultValue: '60 secs', - required: true, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [] - } - }, - schedulingPeriod: '0 sec', - schedulingStrategy: 'TIMER_DRIVEN', - executionNode: 'ALL', - penaltyDuration: '30 sec', - yieldDuration: '1 sec', - bulletinLevel: 'WARN', - runDurationMillis: 0, - concurrentlySchedulableTaskCount: 1, - autoTerminatedRelationships: ['parse.failure', 'success'], - comments: '', - lossTolerant: false, - defaultConcurrentTasks: { - TIMER_DRIVEN: '1', - CRON_DRIVEN: '1' - }, - defaultSchedulingPeriod: { - TIMER_DRIVEN: '0 sec', - CRON_DRIVEN: '* * * * * ?' - }, - retryCount: 10, - retriedRelationships: [], - backoffMechanism: 'PENALIZE_FLOWFILE', - maxBackoffPeriod: '10 mins' - }, - validationErrors: [ - "'Value Record Reader' validated against '9648c622-018b-1000-c78f-2ef4bc78b696' is invalid because Controller Service with ID 9648c622-018b-1000-c78f-2ef4bc78b696 is disabled" - ], - validationStatus: 'INVALID', - extensionMissing: false - }, - { - id: '0b0993c7-018e-1000-34f0-eac5126a49d7', - versionedComponentId: '2f6b8ff4-218e-3a5c-8abc-8a8146852732', - parentGroupId: 'cc4eefda-018d-1000-35ee-194d439257e4', - position: { - x: 480, - y: 408 - }, - name: 'ConsumeKafkaRecord_2_6', - type: 'org.apache.nifi.processors.kafka.pubsub.ConsumeKafkaRecord_2_6', - bundle: { - group: 'org.apache.nifi', - artifact: 'nifi-kafka-2-6-nar', - version: '2.0.0-SNAPSHOT' - }, - state: 'STOPPED', - style: {}, - relationships: [ - { - name: 'parse.failure', - description: - 'If a message from Kafka cannot be parsed using the configured Record Reader, the contents of the message will be routed to this Relationship as its own individual FlowFile.', - autoTerminate: true, - retry: false - }, - { - name: 'success', - description: - 'FlowFiles received from Kafka. Depending on demarcation strategy it is a flow file per message or a bundle of messages grouped by topic and partition.', - autoTerminate: true, - retry: false - } - ], - supportsParallelProcessing: true, - supportsBatching: false, - supportsSensitiveDynamicProperties: false, - persistsState: false, - restricted: false, - deprecated: false, - executionNodeRestricted: false, - multipleVersionsAvailable: false, - inputRequirement: 'INPUT_FORBIDDEN', - config: { - properties: { - 'bootstrap.servers': 'localhost:9092', - topic: '321', - topic_type: 'names', - 'record-reader': '9648c622-018b-1000-c78f-2ef4bc78b696', - 'record-writer': '9648dc34-018b-1000-9fb4-636b6abe9a10', - 'group.id': '2', - 'output-strategy': 'USE_VALUE', - 'header-name-regex': null, - 'key-attribute-encoding': 'utf-8', - 'key-format': 'byte-array', - 'key-record-reader': null, - 'Commit Offsets': 'true', - 'max-uncommit-offset-wait': '1 secs', - 'honor-transactions': 'true', - 'security.protocol': 'PLAINTEXT', - 'sasl.mechanism': 'GSSAPI', - 'kerberos-user-service': null, - 'sasl.kerberos.service.name': null, - 'sasl.username': null, - 'sasl.password': null, - 'sasl.token.auth': 'false', - 'aws.profile.name': null, - 'ssl.context.service': null, - 'separate-by-key': 'false', - 'auto.offset.reset': 'latest', - 'message-header-encoding': 'UTF-8', - 'max.poll.records': '10000', - 'Communications Timeout': '60 secs' - }, - descriptors: { - 'bootstrap.servers': { - name: 'bootstrap.servers', - displayName: 'Kafka Brokers', - description: 'Comma-separated list of Kafka Brokers in the format host:port', - defaultValue: 'localhost:9092', - required: true, - sensitive: false, - dynamic: false, - supportsEl: true, - expressionLanguageScope: - 'Environment variables defined at JVM level and system properties', - dependencies: [] - }, - topic: { - name: 'topic', - displayName: 'Topic Name(s)', - description: - 'The name of the Kafka Topic(s) to pull from. More than one can be supplied if comma separated.', - required: true, - sensitive: false, - dynamic: false, - supportsEl: true, - expressionLanguageScope: - 'Environment variables defined at JVM level and system properties', - dependencies: [] - }, - topic_type: { - name: 'topic_type', - displayName: 'Topic Name Format', - description: - 'Specifies whether the Topic(s) provided are a comma separated list of names or a single regular expression', - defaultValue: 'names', - allowableValues: [ - { - allowableValue: { - displayName: 'names', - value: 'names', - description: - 'Topic is a full topic name or comma separated list of names' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'pattern', - value: 'pattern', - description: 'Topic is a regex using the Java Pattern syntax' - }, - canRead: true - } - ], - required: true, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [] - }, - 'record-reader': { - name: 'record-reader', - displayName: 'Value Record Reader', - description: 'The Record Reader to use for incoming FlowFiles', - allowableValues: [ - { - allowableValue: { - displayName: 'AvroReader', - value: '9648c622-018b-1000-c78f-2ef4bc78b696' - }, - canRead: true - } - ], - required: true, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - identifiesControllerService: 'org.apache.nifi.serialization.RecordReaderFactory', - identifiesControllerServiceBundle: { - group: 'org.apache.nifi', - artifact: 'nifi-standard-services-api-nar', - version: '2.0.0-SNAPSHOT' - }, - dependencies: [] - }, - 'record-writer': { - name: 'record-writer', - displayName: 'Record Value Writer', - description: - 'The Record Writer to use in order to serialize the data before sending to Kafka', - allowableValues: [ - { - allowableValue: { - displayName: 'AvroRecordSetWriter', - value: '9648dc34-018b-1000-9fb4-636b6abe9a10' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'AvroRecordSetWriter', - value: '3c57fe11-0190-1000-9c99-9faab34f0d5e' - }, - canRead: true - } - ], - required: true, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - identifiesControllerService: 'org.apache.nifi.serialization.RecordSetWriterFactory', - identifiesControllerServiceBundle: { - group: 'org.apache.nifi', - artifact: 'nifi-standard-services-api-nar', - version: '2.0.0-SNAPSHOT' - }, - dependencies: [] - }, - 'group.id': { - name: 'group.id', - displayName: 'Group ID', - description: - "A Group ID is used to identify consumers that are within the same consumer group. Corresponds to Kafka's 'group.id' property.", - required: true, - sensitive: false, - dynamic: false, - supportsEl: true, - expressionLanguageScope: - 'Environment variables defined at JVM level and system properties', - dependencies: [] - }, - 'output-strategy': { - name: 'output-strategy', - displayName: 'Output Strategy', - description: 'The format used to output the Kafka record into a FlowFile record.', - defaultValue: 'USE_VALUE', - allowableValues: [ - { - allowableValue: { - displayName: 'Use Content as Value', - value: 'USE_VALUE', - description: 'Write only the Kafka Record value to the FlowFile record.' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'Use Wrapper', - value: 'USE_WRAPPER', - description: - 'Write the Kafka Record key, value, headers, and metadata into the FlowFile record. (See processor usage for more information.)' - }, - canRead: true - } - ], - required: true, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [] - }, - 'header-name-regex': { - name: 'header-name-regex', - displayName: 'Headers to Add as Attributes (Regex)', - description: - 'A Regular Expression that is matched against all message headers. Any message header whose name matches the regex will be added to the FlowFile as an Attribute. If not specified, no Header values will be added as FlowFile attributes. If two messages have a different value for the same header and that header is selected by the provided regex, then those two messages must be added to different FlowFiles. As a result, users should be cautious about using a regex like ".*" if messages are expected to have header values that are unique per message, such as an identifier or timestamp, because it will prevent NiFi from bundling the messages together efficiently.', - required: false, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [ - { - propertyName: 'output-strategy', - dependentValues: ['USE_VALUE'] - } - ] - }, - 'key-attribute-encoding': { - name: 'key-attribute-encoding', - displayName: 'Key Attribute Encoding', - description: - "If the property is set to true, FlowFiles that are emitted have an attribute named 'kafka.key'. This property dictates how the value of the attribute should be encoded.", - defaultValue: 'utf-8', - allowableValues: [ - { - allowableValue: { - displayName: 'UTF-8 Encoded', - value: 'utf-8', - description: 'The key is interpreted as a UTF-8 Encoded string.' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'Hex Encoded', - value: 'hex', - description: - 'The key is interpreted as arbitrary binary data and is encoded using hexadecimal characters with uppercase letters' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'Do Not Add Key as Attribute', - value: 'do-not-add', - description: 'The key will not be added as an Attribute' - }, - canRead: true - } - ], - required: true, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [ - { - propertyName: 'output-strategy', - dependentValues: ['USE_VALUE'] - } - ] - }, - 'key-format': { - name: 'key-format', - displayName: 'Key Format', - description: "Specifies how to represent the Kafka Record's Key in the output", - defaultValue: 'byte-array', - allowableValues: [ - { - allowableValue: { - displayName: 'String', - value: 'string', - description: 'Format the Kafka ConsumerRecord key as a UTF-8 string.' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'Byte Array', - value: 'byte-array', - description: 'Format the Kafka ConsumerRecord key as a byte array.' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'Record', - value: 'record', - description: 'Format the Kafka ConsumerRecord key as a record.' - }, - canRead: true - } - ], - required: true, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [ - { - propertyName: 'output-strategy', - dependentValues: ['USE_WRAPPER'] - } - ] - }, - 'key-record-reader': { - name: 'key-record-reader', - displayName: 'Key Record Reader', - description: - "The Record Reader to use for parsing the Kafka Record's key into a Record", - allowableValues: [ - { - allowableValue: { - displayName: 'AvroReader', - value: '9648c622-018b-1000-c78f-2ef4bc78b696' - }, - canRead: true - } - ], - required: false, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - identifiesControllerService: 'org.apache.nifi.serialization.RecordReaderFactory', - identifiesControllerServiceBundle: { - group: 'org.apache.nifi', - artifact: 'nifi-standard-services-api-nar', - version: '2.0.0-SNAPSHOT' - }, - dependencies: [ - { - propertyName: 'key-format', - dependentValues: ['record'] - } - ] - }, - 'Commit Offsets': { - name: 'Commit Offsets', - displayName: 'Commit Offsets', - description: - "Specifies whether or not this Processor should commit the offsets to Kafka after receiving messages. This value should be false when a PublishKafkaRecord processor is expected to commit the offsets using Exactly Once semantics, and should be reserved for dataflows that are designed to run within Stateless NiFi. See Processor's Usage / Additional Details for more information. Note that setting this value to false can lead to significant data duplication or potentially even data loss if the dataflow is not properly configured.", - defaultValue: 'true', - allowableValues: [ - { - allowableValue: { - displayName: 'true', - value: 'true' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'false', - value: 'false' - }, - canRead: true - } - ], - required: false, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [] - }, - 'max-uncommit-offset-wait': { - name: 'max-uncommit-offset-wait', - displayName: 'Max Uncommitted Time', - description: - "Specifies the maximum amount of time allowed to pass before offsets must be committed. This value impacts how often offsets will be committed. Committing offsets less often increases throughput but also increases the window of potential data duplication in the event of a rebalance or JVM restart between commits. This value is also related to maximum poll records and the use of a message demarcator. When using a message demarcator we can have far more uncommitted messages than when we're not as there is much less for us to keep track of in memory.", - defaultValue: '1 secs', - required: false, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [ - { - propertyName: 'Commit Offsets', - dependentValues: ['true'] - } - ] - }, - 'honor-transactions': { - name: 'honor-transactions', - displayName: 'Honor Transactions', - description: - 'Specifies whether or not NiFi should honor transactional guarantees when communicating with Kafka. If false, the Processor will use an "isolation level" of read_uncomitted. This means that messages will be received as soon as they are written to Kafka but will be pulled, even if the producer cancels the transactions. If this value is true, NiFi will not receive any messages for which the producer\'s transaction was canceled, but this can result in some latency since the consumer must wait for the producer to finish its entire transaction instead of pulling as the messages become available.', - defaultValue: 'true', - allowableValues: [ - { - allowableValue: { - displayName: 'true', - value: 'true' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'false', - value: 'false' - }, - canRead: true - } - ], - required: true, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [] - }, - 'security.protocol': { - name: 'security.protocol', - displayName: 'Security Protocol', - description: - 'Security protocol used to communicate with brokers. Corresponds to Kafka Client security.protocol property', - defaultValue: 'PLAINTEXT', - allowableValues: [ - { - allowableValue: { - displayName: 'PLAINTEXT', - value: 'PLAINTEXT' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'SSL', - value: 'SSL' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'SASL_PLAINTEXT', - value: 'SASL_PLAINTEXT' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'SASL_SSL', - value: 'SASL_SSL' - }, - canRead: true - } - ], - required: true, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [] - }, - 'sasl.mechanism': { - name: 'sasl.mechanism', - displayName: 'SASL Mechanism', - description: - 'SASL mechanism used for authentication. Corresponds to Kafka Client sasl.mechanism property', - defaultValue: 'GSSAPI', - allowableValues: [ - { - allowableValue: { - displayName: 'GSSAPI', - value: 'GSSAPI', - description: 'General Security Services API for Kerberos authentication' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'PLAIN', - value: 'PLAIN', - description: 'Plain username and password authentication' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'SCRAM-SHA-256', - value: 'SCRAM-SHA-256', - description: - 'Salted Challenge Response Authentication Mechanism using SHA-512 with username and password' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'SCRAM-SHA-512', - value: 'SCRAM-SHA-512', - description: - 'Salted Challenge Response Authentication Mechanism using SHA-256 with username and password' - }, - canRead: true - } - ], - required: true, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [] - }, - 'kerberos-user-service': { - name: 'kerberos-user-service', - displayName: 'Kerberos User Service', - description: 'Service supporting user authentication with Kerberos', - allowableValues: [], - required: false, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - identifiesControllerService: - 'org.apache.nifi.kerberos.SelfContainedKerberosUserService', - identifiesControllerServiceBundle: { - group: 'org.apache.nifi', - artifact: 'nifi-standard-services-api-nar', - version: '2.0.0-SNAPSHOT' - }, - dependencies: [] - }, - 'sasl.kerberos.service.name': { - name: 'sasl.kerberos.service.name', - displayName: 'Kerberos Service Name', - description: - 'The service name that matches the primary name of the Kafka server configured in the broker JAAS configuration', - required: false, - sensitive: false, - dynamic: false, - supportsEl: true, - expressionLanguageScope: - 'Environment variables defined at JVM level and system properties', - dependencies: [] - }, - 'sasl.username': { - name: 'sasl.username', - displayName: 'Username', - description: - 'Username provided with configured password when using PLAIN or SCRAM SASL Mechanisms', - required: false, - sensitive: false, - dynamic: false, - supportsEl: true, - expressionLanguageScope: - 'Environment variables defined at JVM level and system properties', - dependencies: [ - { - propertyName: 'sasl.mechanism', - dependentValues: ['PLAIN', 'SCRAM-SHA-512', 'SCRAM-SHA-256'] - } - ] - }, - 'sasl.password': { - name: 'sasl.password', - displayName: 'Password', - description: - 'Password provided with configured username when using PLAIN or SCRAM SASL Mechanisms', - required: false, - sensitive: true, - dynamic: false, - supportsEl: true, - expressionLanguageScope: - 'Environment variables defined at JVM level and system properties', - dependencies: [ - { - propertyName: 'sasl.mechanism', - dependentValues: ['PLAIN', 'SCRAM-SHA-512', 'SCRAM-SHA-256'] - } - ] - }, - 'sasl.token.auth': { - name: 'sasl.token.auth', - displayName: 'Token Authentication', - description: - 'Enables or disables Token authentication when using SCRAM SASL Mechanisms', - defaultValue: 'false', - allowableValues: [ - { - allowableValue: { - displayName: 'true', - value: 'true' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'false', - value: 'false' - }, - canRead: true - } - ], - required: false, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [ - { - propertyName: 'sasl.mechanism', - dependentValues: ['SCRAM-SHA-512', 'SCRAM-SHA-256'] - } - ] - }, - 'aws.profile.name': { - name: 'aws.profile.name', - displayName: 'AWS Profile Name', - description: - 'The Amazon Web Services Profile to select when multiple profiles are available.', - required: false, - sensitive: false, - dynamic: false, - supportsEl: true, - expressionLanguageScope: 'Environment variables and FlowFile Attributes', - dependencies: [ - { - propertyName: 'sasl.mechanism', - dependentValues: ['AWS_MSK_IAM'] - } - ] - }, - 'ssl.context.service': { - name: 'ssl.context.service', - displayName: 'SSL Context Service', - description: 'Service supporting SSL communication with Kafka brokers', - allowableValues: [ - { - allowableValue: { - displayName: 'StandardRestrictedSSLContextService', - value: 'f5bf3c0a-018d-1000-7c8e-910f220b215e' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'aal1', - value: '3c5951d8-0190-1000-0ed6-320905f27a2f' - }, - canRead: true - } - ], - required: false, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - identifiesControllerService: 'org.apache.nifi.ssl.SSLContextService', - identifiesControllerServiceBundle: { - group: 'org.apache.nifi', - artifact: 'nifi-standard-services-api-nar', - version: '2.0.0-SNAPSHOT' - }, - dependencies: [] - }, - 'separate-by-key': { - name: 'separate-by-key', - displayName: 'Separate By Key', - description: - 'If true, two Records will only be added to the same FlowFile if both of the Kafka Messages have identical keys.', - defaultValue: 'false', - allowableValues: [ - { - allowableValue: { - displayName: 'true', - value: 'true' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'false', - value: 'false' - }, - canRead: true - } - ], - required: false, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [] - }, - 'auto.offset.reset': { - name: 'auto.offset.reset', - displayName: 'Offset Reset', - description: - "Allows you to manage the condition when there is no initial offset in Kafka or if the current offset does not exist any more on the server (e.g. because that data has been deleted). Corresponds to Kafka's 'auto.offset.reset' property.", - defaultValue: 'latest', - allowableValues: [ - { - allowableValue: { - displayName: 'earliest', - value: 'earliest', - description: 'Automatically reset the offset to the earliest offset' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'latest', - value: 'latest', - description: 'Automatically reset the offset to the latest offset' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'none', - value: 'none', - description: - "Throw exception to the consumer if no previous offset is found for the consumer's group" - }, - canRead: true - } - ], - required: true, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [] - }, - 'message-header-encoding': { - name: 'message-header-encoding', - displayName: 'Message Header Encoding', - description: - 'Any message header that is found on a Kafka message will be added to the outbound FlowFile as an attribute. This property indicates the Character Encoding to use for deserializing the headers.', - defaultValue: 'UTF-8', - required: false, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [] - }, - 'max.poll.records': { - name: 'max.poll.records', - displayName: 'Max Poll Records', - description: - 'Specifies the maximum number of records Kafka should return in a single poll.', - defaultValue: '10000', - required: false, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [] - }, - 'Communications Timeout': { - name: 'Communications Timeout', - displayName: 'Communications Timeout', - description: - 'Specifies the timeout that the consumer should use when communicating with the Kafka Broker', - defaultValue: '60 secs', - required: true, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [] - } - }, - schedulingPeriod: '0 sec', - schedulingStrategy: 'TIMER_DRIVEN', - executionNode: 'ALL', - penaltyDuration: '30 sec', - yieldDuration: '1 sec', - bulletinLevel: 'WARN', - runDurationMillis: 0, - concurrentlySchedulableTaskCount: 1, - autoTerminatedRelationships: ['parse.failure', 'success'], - comments: '', - lossTolerant: false, - defaultConcurrentTasks: { - TIMER_DRIVEN: '1', - CRON_DRIVEN: '1' - }, - defaultSchedulingPeriod: { - TIMER_DRIVEN: '0 sec', - CRON_DRIVEN: '* * * * * ?' - }, - retryCount: 10, - retriedRelationships: [], - backoffMechanism: 'PENALIZE_FLOWFILE', - maxBackoffPeriod: '10 mins' - }, - validationErrors: [ - "'Value Record Reader' validated against '9648c622-018b-1000-c78f-2ef4bc78b696' is invalid because Controller Service with ID 9648c622-018b-1000-c78f-2ef4bc78b696 is disabled" - ], - validationStatus: 'INVALID', - extensionMissing: false - } - ], - inputPorts: [], - outputPorts: [], - connections: [], - labels: [], - funnels: [ - { - id: '372db66f-0190-1000-85e6-3d55ebc72e3c', - versionedComponentId: 'a29524a7-2797-31d0-8362-512efaf0cebe', - parentGroupId: 'cc4eefda-018d-1000-35ee-194d439257e4', - position: { - x: 341.1209991259036, - y: 215.00003332754773 - } - } - ], - controllerServices: [] - }, - inputPortCount: 0, - outputPortCount: 0 - }, - status: { - id: 'cc4eefda-018d-1000-35ee-194d439257e4', - name: 'pg1', - statsLastRefreshed: '14:58:25 UTC', - aggregateSnapshot: { - id: 'cc4eefda-018d-1000-35ee-194d439257e4', - name: 'pg1', - statelessActiveThreadCount: 0, - flowFilesIn: 0, - bytesIn: 0, - input: '0 (0 bytes)', - flowFilesQueued: 0, - bytesQueued: 0, - queued: '0 (0 bytes)', - queuedCount: '0', - queuedSize: '0 bytes', - bytesRead: 0, - read: '0 bytes', - bytesWritten: 0, - written: '0 bytes', - flowFilesOut: 0, - bytesOut: 0, - output: '0 (0 bytes)', - flowFilesTransferred: 0, - bytesTransferred: 0, - transferred: '0 (0 bytes)', - bytesReceived: 0, - flowFilesReceived: 0, - received: '0 (0 bytes)', - bytesSent: 0, - flowFilesSent: 0, - sent: '0 (0 bytes)', - activeThreadCount: 0, - terminatedThreadCount: 0, - processingNanos: 0 - } - }, - runningCount: 0, - stoppedCount: 0, - invalidCount: 3, - disabledCount: 0, - activeRemotePortCount: 0, - inactiveRemotePortCount: 0, - upToDateCount: 0, - locallyModifiedCount: 0, - staleCount: 0, - locallyModifiedAndStaleCount: 0, - syncFailureCount: 0, - localInputPortCount: 0, - localOutputPortCount: 0, - publicInputPortCount: 0, - publicOutputPortCount: 0, - inputPortCount: 0, - outputPortCount: 0 - }; - - const parentControllerServices: ControllerServiceEntity[] = [ - { - revision: { - version: 0 - }, - id: 'f5bf3c0a-018d-1000-7c8e-910f220b215e', - uri: 'http://127.0.0.1:4200/nifi-api/controller-services/f5bf3c0a-018d-1000-7c8e-910f220b215e', - permissions: { - canRead: true, - canWrite: true - }, - bulletins: [], - parentGroupId: '96456bc3-018b-1000-05d8-51720bebae4b', - component: { - id: 'f5bf3c0a-018d-1000-7c8e-910f220b215e', - versionedComponentId: 'a42a73b5-27a6-3ee7-b740-43345b3849de', - parentGroupId: '96456bc3-018b-1000-05d8-51720bebae4b', - name: 'StandardRestrictedSSLContextService', - type: 'org.apache.nifi.ssl.StandardRestrictedSSLContextService', - bundle: { - group: 'org.apache.nifi', - artifact: 'nifi-ssl-context-service-nar', - version: '2.0.0-SNAPSHOT' - }, - controllerServiceApis: [ - { - type: 'org.apache.nifi.ssl.SSLContextService', - bundle: { - group: 'org.apache.nifi', - artifact: 'nifi-standard-services-api-nar', - version: '2.0.0-SNAPSHOT' - } - }, - { - type: 'org.apache.nifi.ssl.RestrictedSSLContextService', - bundle: { - group: 'org.apache.nifi', - artifact: 'nifi-standard-services-api-nar', - version: '2.0.0-SNAPSHOT' - } - } - ], - comments: '', - state: 'ENABLED', - persistsState: false, - restricted: false, - deprecated: false, - multipleVersionsAvailable: false, - supportsSensitiveDynamicProperties: false, - properties: { - 'Keystore Filename': '/home/user/nifi-ui/conf/certificate.p12', - 'Keystore Password': '********', - 'key-password': null, - 'Keystore Type': 'PKCS12', - 'Truststore Filename': '/home/user/nifi-ui/conf/truststore.jks', - 'Truststore Password': '********', - 'Truststore Type': 'JKS', - 'SSL Protocol': 'TLS' - }, - descriptors: { - 'Keystore Filename': { - name: 'Keystore Filename', - displayName: 'Keystore Filename', - description: 'The fully-qualified filename of the Keystore', - required: false, - sensitive: false, - dynamic: false, - supportsEl: true, - expressionLanguageScope: 'Environment variables defined at JVM level and system properties', - dependencies: [] - }, - 'Keystore Password': { - name: 'Keystore Password', - displayName: 'Keystore Password', - description: 'The password for the Keystore', - required: false, - sensitive: true, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [] - }, - 'key-password': { - name: 'key-password', - displayName: 'Key Password', - description: - 'The password for the key. If this is not specified, but the Keystore Filename, Password, and Type are specified, then the Keystore Password will be assumed to be the same as the Key Password.', - required: false, - sensitive: true, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [] - }, - 'Keystore Type': { - name: 'Keystore Type', - displayName: 'Keystore Type', - description: 'The Type of the Keystore', - allowableValues: [ - { - allowableValue: { - displayName: 'BCFKS', - value: 'BCFKS' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'PKCS12', - value: 'PKCS12' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'JKS', - value: 'JKS' - }, - canRead: true - } - ], - required: false, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [] - }, - 'Truststore Filename': { - name: 'Truststore Filename', - displayName: 'Truststore Filename', - description: 'The fully-qualified filename of the Truststore', - required: false, - sensitive: false, - dynamic: false, - supportsEl: true, - expressionLanguageScope: 'Environment variables defined at JVM level and system properties', - dependencies: [] - }, - 'Truststore Password': { - name: 'Truststore Password', - displayName: 'Truststore Password', - description: 'The password for the Truststore', - required: false, - sensitive: true, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [] - }, - 'Truststore Type': { - name: 'Truststore Type', - displayName: 'Truststore Type', - description: 'The Type of the Truststore', - allowableValues: [ - { - allowableValue: { - displayName: 'BCFKS', - value: 'BCFKS' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'PKCS12', - value: 'PKCS12' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'JKS', - value: 'JKS' - }, - canRead: true - } - ], - required: false, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [] - }, - 'SSL Protocol': { - name: 'SSL Protocol', - displayName: 'TLS Protocol', - description: - 'TLS Protocol Version for encrypted connections. Supported versions depend on the specific version of Java used.', - defaultValue: 'TLS', - allowableValues: [ - { - allowableValue: { - displayName: 'TLS', - value: 'TLS', - description: - 'Negotiate latest protocol version based on platform supported versions' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'TLSv1.3', - value: 'TLSv1.3', - description: 'Require TLSv1.3 protocol version' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'TLSv1.2', - value: 'TLSv1.2', - description: 'Require TLSv1.2 protocol version' - }, - canRead: true - } - ], - required: false, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [] - } - }, - referencingComponents: [ - { - revision: { - version: 0, - lastModifier: 'anonymous' - }, - id: '3e4d7943-018e-1000-ef14-0b244d7070d5', - permissions: { - canRead: true, - canWrite: true - }, - bulletins: [], - component: { - groupId: '96456bc3-018b-1000-05d8-51720bebae4b', - id: '3e4d7943-018e-1000-ef14-0b244d7070d5', - name: 'DeleteSQS', - type: 'DeleteSQS', - state: 'STOPPED', - validationErrors: [ - "'AWS Credentials Provider Service' validated against 'f59560b6-018d-1000-dab9-f19f7d688d65' is invalid because Controller Service with ID f59560b6-018d-1000-dab9-f19f7d688d65 is disabled" - ], - referenceType: 'Processor', - activeThreadCount: 0 - }, - operatePermissions: { - canRead: true, - canWrite: true - } - }, - { - revision: { - version: 0, - lastModifier: 'anonymous' - }, - id: 'f5c2e95c-018d-1000-9ed4-5309b99f7fc3', - permissions: { - canRead: true, - canWrite: true - }, - bulletins: [], - component: { - groupId: 'cc4f110c-018d-1000-d4b6-d933a69c9d53', - id: 'f5c2e95c-018d-1000-9ed4-5309b99f7fc3', - name: 'MongoDBControllerService', - type: 'MongoDBControllerService', - state: 'DISABLED', - validationErrors: ["'Mongo URI' is invalid because Mongo URI is required"], - referenceType: 'ControllerService', - referenceCycle: false, - referencingComponents: [] - }, - operatePermissions: { - canRead: true, - canWrite: true - } - }, - { - revision: { - version: 0, - lastModifier: 'anonymous' - }, - id: '3e08b4c2-018e-1000-9cea-5fb844cd9c0f', - permissions: { - canRead: true, - canWrite: true - }, - bulletins: [], - component: { - groupId: '96456bc3-018b-1000-05d8-51720bebae4b', - id: '3e08b4c2-018e-1000-9cea-5fb844cd9c0f', - name: 'PutSQS', - type: 'PutSQS', - state: 'STOPPED', - validationErrors: [ - "'AWS Credentials Provider Service' validated against 'f59560b6-018d-1000-dab9-f19f7d688d65' is invalid because Controller Service with ID f59560b6-018d-1000-dab9-f19f7d688d65 is disabled" - ], - referenceType: 'Processor', - activeThreadCount: 0 - }, - operatePermissions: { - canRead: true, - canWrite: true - } - }, - { - revision: { - version: 0, - lastModifier: 'anonymous' - }, - id: 'f0b8b3e3-018d-1000-23ea-400e3a621493', - permissions: { - canRead: true, - canWrite: true - }, - bulletins: [], - component: { - groupId: '96456bc3-018b-1000-05d8-51720bebae4b', - id: 'f0b8b3e3-018d-1000-23ea-400e3a621493', - name: 'PutSNS', - type: 'PutSNS', - state: 'STOPPED', - validationErrors: [ - "'AWS Credentials Provider Service' validated against 'f59560b6-018d-1000-dab9-f19f7d688d65' is invalid because Controller Service with ID f59560b6-018d-1000-dab9-f19f7d688d65 is disabled", - "'Upstream Connections' is invalid because Processor requires an upstream connection but currently has none" - ], - referenceType: 'Processor', - activeThreadCount: 0 - }, - operatePermissions: { - canRead: true, - canWrite: true - } - }, - { - revision: { - version: 0, - lastModifier: 'anonymous' - }, - id: '3e44b03b-018e-1000-2dbf-2914e599ae1a', - permissions: { - canRead: true, - canWrite: true - }, - bulletins: [], - component: { - groupId: '96456bc3-018b-1000-05d8-51720bebae4b', - id: '3e44b03b-018e-1000-2dbf-2914e599ae1a', - name: 'GetSQS', - type: 'GetSQS', - state: 'STOPPED', - validationErrors: [ - "'AWS Credentials Provider Service' validated against 'f59560b6-018d-1000-dab9-f19f7d688d65' is invalid because Controller Service with ID f59560b6-018d-1000-dab9-f19f7d688d65 is disabled" - ], - referenceType: 'Processor', - activeThreadCount: 0 - }, - operatePermissions: { - canRead: true, - canWrite: true - } - } - ], - validationStatus: 'VALID', - bulletinLevel: 'WARN', - extensionMissing: false - }, - operatePermissions: { - canRead: true, - canWrite: true - }, - status: { - runStatus: 'ENABLED', - validationStatus: 'VALID' - } - } - ]; - - const controllerService = { - revision: { - clientId: 'b37eba61-156a-47a4-875f-945cd153b876', - version: 7 - }, - id: '92db6ee4-018c-1000-1061-e3476c3f4e9f', - uri: 'https://localhost:4200/nifi-api/controller-services/92db6ee4-018c-1000-1061-e3476c3f4e9f', - permissions: { - canRead: true, - canWrite: true - }, - bulletins: [ - { - id: 0, - groupId: 'asdf', - sourceId: 'asdf', - timestamp: '14:08:44 EST', - canRead: true, - bulletin: { - id: 0, - category: 'asdf', - groupId: 'asdf', - sourceId: 'asdf', - sourceName: 'asdf', - sourceType: ComponentType.Processor, - level: 'ERROR', - message: 'asdf', - timestamp: '14:08:44 EST' - } - } - ], - component: { - id: '92db6ee4-018c-1000-1061-e3476c3f4e9f', - name: 'AvroReader', - type: 'org.apache.nifi.avro.AvroReader', - bundle: { - group: 'org.apache.nifi', - artifact: 'nifi-record-serialization-services-nar', - version: '2.0.0-SNAPSHOT' - }, - controllerServiceApis: [ - { - type: 'org.apache.nifi.serialization.RecordReaderFactory', - bundle: { - group: 'org.apache.nifi', - artifact: 'nifi-standard-services-api-nar', - version: '2.0.0-SNAPSHOT' - } - } - ], - state: 'DISABLED', - persistsState: false, - restricted: false, - deprecated: false, - multipleVersionsAvailable: false, - supportsSensitiveDynamicProperties: false, - properties: { - 'schema-access-strategy': 'embedded-avro-schema', - 'schema-registry': null, - 'schema-name': '${schema.name}', - 'schema-version': null, - 'schema-branch': null, - 'schema-text': '${avro.schema}', - 'schema-reference-reader': null, - 'cache-size': '1000' - }, - descriptors: { - 'schema-access-strategy': { - name: 'schema-access-strategy', - displayName: 'Schema Access Strategy', - description: 'Specifies how to obtain the schema that is to be used for interpreting the data.', - defaultValue: 'embedded-avro-schema', - allowableValues: [ - { - allowableValue: { - displayName: "Use 'Schema Name' Property", - value: 'schema-name', - description: - "The name of the Schema to use is specified by the 'Schema Name' Property. The value of this property is used to lookup the Schema in the configured Schema Registry service." - }, - canRead: true - }, - { - allowableValue: { - displayName: "Use 'Schema Text' Property", - value: 'schema-text-property', - description: - "The text of the Schema itself is specified by the 'Schema Text' Property. The value of this property must be a valid Avro Schema. If Expression Language is used, the value of the 'Schema Text' property must be valid after substituting the expressions." - }, - canRead: true - }, - { - allowableValue: { - displayName: 'Schema Reference Reader', - value: 'schema-reference-reader', - description: - 'The schema reference information will be provided through a configured Schema Reference Reader service implementation.' - }, - canRead: true - }, - { - allowableValue: { - displayName: 'Use Embedded Avro Schema', - value: 'embedded-avro-schema', - description: - 'The FlowFile has the Avro Schema embedded within the content, and this schema will be used.' - }, - canRead: true - } - ], - required: true, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [] - }, - 'schema-registry': { - name: 'schema-registry', - displayName: 'Schema Registry', - description: 'Specifies the Controller Service to use for the Schema Registry', - allowableValues: [], - required: false, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - identifiesControllerService: 'org.apache.nifi.schemaregistry.services.SchemaRegistry', - identifiesControllerServiceBundle: { - group: 'org.apache.nifi', - artifact: 'nifi-standard-services-api-nar', - version: '2.0.0-SNAPSHOT' - }, - dependencies: [ - { - propertyName: 'schema-access-strategy', - dependentValues: ['schema-reference-reader', 'schema-name'] - } - ] - }, - 'schema-name': { - name: 'schema-name', - displayName: 'Schema Name', - description: 'Specifies the name of the schema to lookup in the Schema Registry property', - defaultValue: '${schema.name}', - required: false, - sensitive: false, - dynamic: false, - supportsEl: true, - expressionLanguageScope: 'Environment variables and FlowFile Attributes', - dependencies: [ - { - propertyName: 'schema-access-strategy', - dependentValues: ['schema-name'] - } - ] - }, - 'schema-version': { - name: 'schema-version', - displayName: 'Schema Version', - description: - 'Specifies the version of the schema to lookup in the Schema Registry. If not specified then the latest version of the schema will be retrieved.', - required: false, - sensitive: false, - dynamic: false, - supportsEl: true, - expressionLanguageScope: 'Environment variables and FlowFile Attributes', - dependencies: [ - { - propertyName: 'schema-access-strategy', - dependentValues: ['schema-name'] - } - ] - }, - 'schema-branch': { - name: 'schema-branch', - displayName: 'Schema Branch', - description: - 'Specifies the name of the branch to use when looking up the schema in the Schema Registry property. If the chosen Schema Registry does not support branching, this value will be ignored.', - required: false, - sensitive: false, - dynamic: false, - supportsEl: true, - expressionLanguageScope: 'Environment variables and FlowFile Attributes', - dependencies: [ - { - propertyName: 'schema-access-strategy', - dependentValues: ['schema-name'] - } - ] - }, - 'schema-text': { - name: 'schema-text', - displayName: 'Schema Text', - description: 'The text of an Avro-formatted Schema', - defaultValue: '${avro.schema}', - required: false, - sensitive: false, - dynamic: false, - supportsEl: true, - expressionLanguageScope: 'Environment variables and FlowFile Attributes', - dependencies: [ - { - propertyName: 'schema-access-strategy', - dependentValues: ['schema-text-property'] - } - ] - }, - 'schema-reference-reader': { - name: 'schema-reference-reader', - displayName: 'Schema Reference Reader', - description: - 'Service implementation responsible for reading FlowFile attributes or content to determine the Schema Reference Identifier', - allowableValues: [], - required: true, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - identifiesControllerService: 'org.apache.nifi.schemaregistry.services.SchemaReferenceReader', - identifiesControllerServiceBundle: { - group: 'org.apache.nifi', - artifact: 'nifi-standard-services-api-nar', - version: '2.0.0-SNAPSHOT' - }, - dependencies: [ - { - propertyName: 'schema-access-strategy', - dependentValues: ['schema-reference-reader'] - } - ] - }, - 'cache-size': { - name: 'cache-size', - displayName: 'Cache Size', - description: 'Specifies how many Schemas should be cached', - defaultValue: '1000', - required: true, - sensitive: false, - dynamic: false, - supportsEl: false, - expressionLanguageScope: 'Not Supported', - dependencies: [] - } - }, - referencingComponents: [ - { - revision: { - clientId: 'b37eba61-156a-47a4-875f-945cd153b876', - version: 5, - lastModifier: 'admin' - }, - id: '92db918c-018c-1000-ccd5-0796caa6d463', - permissions: { - canRead: true, - canWrite: true - }, - bulletins: [ - { - id: 0, - groupId: 'asdf', - sourceId: 'asdf', - timestamp: '14:08:44 EST', - canRead: true, - bulletin: { - id: 0, - category: 'asdf', - groupId: 'asdf', - sourceId: 'asdf', - sourceName: 'asdf', - level: 'ERROR', - message: 'asdf', - timestamp: '14:08:44 EST' - } - } - ], - component: { - id: '92db918c-018c-1000-ccd5-0796caa6d463', - name: 'ReaderLookup', - type: 'ReaderLookup', - state: 'DISABLED', - validationErrors: [ - "'avro' validated against '92db6ee4-018c-1000-1061-e3476c3f4e9f' is invalid because Controller Service with ID 92db6ee4-018c-1000-1061-e3476c3f4e9f is disabled" - ], - referenceType: 'ControllerService', - referenceCycle: false, - referencingComponents: [] - }, - operatePermissions: { - canRead: false, - canWrite: false - } - } - ], - validationStatus: 'VALID', - bulletinLevel: 'WARN', - extensionMissing: false - }, - operatePermissions: { - canRead: false, - canWrite: false - }, - status: { - runStatus: 'DISABLED', - validationStatus: 'VALID' - } - }; - - const data: MoveControllerServiceDialogRequestSuccess = { - id: '92db6ee4-018c-1000-1061-e3476c3f4e9f', - breadcrumb: breadrumb, - childProcessGroupOptions: chldren, - processGroupEntity: processGroupEntity, - parentControllerServices: parentControllerServices, - controllerService: controllerService - }; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [MoveControllerService, NoopAnimationsModule, MatDialogModule], - providers: [ - provideMockStore({ initialState }), - { - provide: MAT_DIALOG_DATA, - useValue: data - }, - { provide: MatDialogRef, useValue: null } - ] - }); - fixture = TestBed.createComponent(MoveControllerService); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/ui/move-controller-service/move-controller-service.component.ts b/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/ui/move-controller-service/move-controller-service.component.ts deleted file mode 100644 index 06ac676bf459..000000000000 --- a/nifi-frontend/src/main/frontend/apps/nifi/src/app/pages/flow-designer/ui/move-controller-service/move-controller-service.component.ts +++ /dev/null @@ -1,247 +0,0 @@ -/* - * 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, Inject, Input } from '@angular/core'; -import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog'; -import { FormBuilder, FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms'; -import { - ControllerServiceEntity, - ControllerServiceReferencingComponent, - ControllerServiceReferencingComponentEntity -} from '../../../../state/shared'; -import { MatInputModule } from '@angular/material/input'; -import { MatCheckboxModule } from '@angular/material/checkbox'; -import { MatButtonModule } from '@angular/material/button'; -import { AsyncPipe, NgTemplateOutlet } from '@angular/common'; -import { MatTabsModule } from '@angular/material/tabs'; -import { MatOptionModule } from '@angular/material/core'; -import { MatSelectModule } from '@angular/material/select'; -import { ControllerServiceApi } from '../../../../ui/common/controller-service/controller-service-api/controller-service-api.component'; -import { ControllerServiceReferences } from '../../../../ui/common/controller-service/controller-service-references/controller-service-references.component'; -import { NifiSpinnerDirective } from '../../../../ui/common/spinner/nifi-spinner.directive'; -import { TextTip, NifiTooltipDirective, SelectOption } from '@nifi/shared'; -import { Store } from '@ngrx/store'; -import { CloseOnEscapeDialog } from '@nifi/shared'; -import { moveControllerService } from '../../state/controller-services/controller-services.actions'; -import { NiFiState } from 'apps/nifi/src/app/state'; -import { MoveControllerServiceDialogRequestSuccess } from '../../state/controller-services'; -import { NgIf } from '@angular/common'; -import { BreadcrumbEntity } from '../../state/shared'; - -@Component({ - selector: 'move-controller-service', - standalone: true, - templateUrl: './move-controller-service.component.html', - imports: [ - ReactiveFormsModule, - MatDialogModule, - MatInputModule, - MatCheckboxModule, - MatButtonModule, - MatTabsModule, - MatOptionModule, - MatSelectModule, - ControllerServiceApi, - ControllerServiceReferences, - AsyncPipe, - NifiSpinnerDirective, - NifiTooltipDirective, - NgTemplateOutlet, - NgIf - ], - styleUrls: ['./move-controller-service.component.scss'] -}) -export class MoveControllerService extends CloseOnEscapeDialog { - @Input() goToReferencingComponent!: (component: ControllerServiceReferencingComponent) => void; - protected readonly TextTip = TextTip; - protected controllerServiceActionProcessGroups: SelectOption[] = []; - protected disableSubmit: boolean = false; - - controllerService: ControllerServiceEntity; - - moveControllerServiceForm: FormGroup; - - constructor( - @Inject(MAT_DIALOG_DATA) public request: MoveControllerServiceDialogRequestSuccess, - private store: Store, - private formBuilder: FormBuilder - ) { - super(); - - this.controllerService = request.controllerService; - - // build the form - this.moveControllerServiceForm = this.formBuilder.group({ - processGroups: new FormControl('Process Group', Validators.required) - }); - - const parentControllerServices = request.parentControllerServices.filter( - (cs) => cs.parentGroupId != request.controllerService.parentGroupId - ); - - const processGroups: SelectOption[] = []; - this.loadParentOption(request.breadcrumb, parentControllerServices, processGroups); - - this.loadChildOptions(request.childProcessGroupOptions, request.processGroupEntity, processGroups); - this.controllerServiceActionProcessGroups = processGroups; - - const firstEnabled = processGroups.findIndex((pg) => !pg.disabled); - if (firstEnabled != -1) { - this.moveControllerServiceForm.controls['processGroups'].setValue(processGroups[firstEnabled].value); - } else { - if (processGroups.length > 0) { - this.moveControllerServiceForm.controls['processGroups'].setValue(processGroups[0].value); - } - this.disableSubmit = true; - } - } - - loadParentOption( - breadcrumb: BreadcrumbEntity, - parentControllerServices: ControllerServiceEntity[], - processGroups: SelectOption[] - ) { - if (breadcrumb.parentBreadcrumb != undefined) { - const parentBreadcrumb = breadcrumb.parentBreadcrumb; - if (parentBreadcrumb.permissions.canRead && parentBreadcrumb.permissions.canWrite) { - const option: SelectOption = { - text: parentBreadcrumb.breadcrumb.name + ' (Parent)', - value: parentBreadcrumb.breadcrumb.id - }; - - let errorMsg = ''; - const descriptors = this.controllerService.component.descriptors; - for (const descriptor in descriptors) { - if (descriptors[descriptor].identifiesControllerService != undefined) { - const controllerId = this.controllerService.component.properties[descriptors[descriptor].name]; - if ( - controllerId != null && - !parentControllerServices.some((service) => service.id == controllerId) - ) { - errorMsg += '[' + descriptors[descriptor].name + ']'; - } - } - } - - if (errorMsg != '') { - option.description = - 'The following properties reference controller services that would be out of scope for this ' + - 'process group: ' + - errorMsg; - option.disabled = true; - } else { - option.disabled = false; - } - - processGroups.push(option); - } - } - } - - loadChildOptions( - childProcessGroupOptions: SelectOption[], - currentProcessGroupEntity: any, - processGroups: SelectOption[] - ) { - const referencingComponents: ControllerServiceReferencingComponentEntity[] = - this.controllerService.component.referencingComponents; - childProcessGroupOptions.forEach((child: SelectOption) => { - const option: SelectOption = { - text: child.text, - value: child.value - }; - - const root = this.getProcessGroupById(currentProcessGroupEntity.component, child.value ?? ''); - let errorMsg = ''; - - if (root == null) { - option.description = 'Error loading process group root.'; - option.disabled = true; - processGroups.push(option); - } else { - for (const component of referencingComponents) { - if (!this.processGroupContainsComponent(root, component.component.groupId)) { - errorMsg += '[' + component.component.name + ']'; - } - } - - if (errorMsg != '') { - option.description = - 'The following components would be out of scope for this process group: ' + errorMsg; - option.disabled = true; - } else { - option.disabled = false; - } - - processGroups.push(option); - } - }); - } - - processGroupContainsComponent(processGroup: any, groupId: string): boolean { - if (processGroup.contents != undefined) { - if (processGroup.id == groupId) { - return true; - } else { - for (const pg of processGroup.contents.processGroups) { - if (this.processGroupContainsComponent(pg, groupId)) { - return true; - } - } - return false; - } - } - return false; - } - - getProcessGroupById(root: any, processGroupId: string): any { - if (root != undefined) { - if (root.id == processGroupId) { - return root; - } else { - if (root.contents != undefined) { - for (const pg of root.contents.processGroups) { - const result = this.getProcessGroupById(pg, processGroupId); - if (result != null) { - return result; - } - } - } - return null; - } - } - return null; - } - - submitForm() { - this.store.dispatch( - moveControllerService({ - request: { - controllerService: this.request.controllerService, - data: { - parentGroupId: this.moveControllerServiceForm.get('processGroups')?.value, - revision: this.request.controllerService.revision - } - } - }) - ); - } - - override isDirty(): boolean { - return this.moveControllerServiceForm.dirty; - } -}