-
Notifications
You must be signed in to change notification settings - Fork 3k
NIFI-14777 Restore capability from NiFi 1.x to view upstream/downstre… #11582
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
03bf725
3af61e5
4c75971
3a35876
46afca4
e01ca90
2428f5c
7670301
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -53,6 +53,7 @@ import { | |
| } from 'rxjs'; | ||
| import { | ||
| ComponentEntity, | ||
| ConnectionEntity, | ||
| CreateConnectionDialogRequest, | ||
| CreateProcessGroupDialogRequest, | ||
| DeleteComponentResponse, | ||
|
|
@@ -101,6 +102,7 @@ import { CreatePort } from '../../ui/canvas/items/port/create-port/create-port.c | |
| import { EditPort } from '../../../../ui/common/component-dialogs/edit-port/edit-port.component'; | ||
| import { | ||
| BranchEntity, | ||
| BreadcrumbEntity, | ||
| BucketEntity, | ||
| DisableComponentRequest, | ||
| EnableComponentRequest, | ||
|
|
@@ -162,6 +164,7 @@ import { ChangeVersionDialog } from '../../ui/canvas/items/flow/change-version-d | |
| import { ChangeVersionProgressDialog } from '../../ui/canvas/items/flow/change-version-progress-dialog/change-version-progress-dialog'; | ||
| import { LocalChangesDialog } from '../../ui/canvas/items/flow/local-changes-dialog/local-changes-dialog'; | ||
| import { ProcessorBacklogDialog } from '../../ui/canvas/items/processor/backlog-dialog/backlog-dialog.component'; | ||
| import { ComponentConnectionsDialog } from '../../ui/canvas/component-connections-dialog/component-connections-dialog.component'; | ||
| import { ClusterConnectionService } from '../../../../service/cluster-connection.service'; | ||
| import { ExtensionTypesService } from '../../../../service/extension-types.service'; | ||
| import { ChangeComponentVersionDialog } from '../../../../ui/common/change-component-version-dialog/change-component-version-dialog'; | ||
|
|
@@ -3180,6 +3183,96 @@ export class FlowEffects { | |
| { dispatch: false } | ||
| ); | ||
|
|
||
| /** | ||
| * Loads the flow of the group that defines the requested component's connections and retains only | ||
| * the connections attached to that component in the requested direction. The group is the one on | ||
| * the canvas for most components, and the parent group for the two port cases whose connections | ||
| * cross the enclosing group's boundary. | ||
| * | ||
| * Matching goes through the canvas' own endpoint resolvers rather than comparing the raw ids. A | ||
| * connection drawn to a Process Group or Remote Process Group actually terminates at a port inside | ||
| * it, and getConnectionSourceComponentId/getConnectionDestinationComponentId are what collapse that | ||
| * port back to the group the user sees and selects. They compare against the group currently on the | ||
| * canvas, which is the right frame of reference for the parent-group searches too: a connection | ||
| * into an Input Port carries that port's own group as its destination group, so it resolves to the | ||
| * port rather than to the group. | ||
| * | ||
| * | ||
| * Both resolvers read the ids on the connection entity rather than on its component, so a | ||
| * connection the current user cannot read — the kind most worth reporting — is still matched. | ||
| */ | ||
| viewComponentConnections$ = createEffect(() => | ||
| this.actions$.pipe( | ||
| ofType(FlowActions.viewComponentConnections), | ||
| map((action) => action.request), | ||
| switchMap((request) => { | ||
| const attachedTo = (connection: ConnectionEntity): boolean => | ||
| request.direction === 'upstream' | ||
| ? this.canvasUtils.getConnectionDestinationComponentId(connection) === request.id | ||
| : this.canvasUtils.getConnectionSourceComponentId(connection) === request.id; | ||
|
|
||
| return from(this.flowService.getFlow(request.groupId)).pipe( | ||
| map((flowEntity: ProcessGroupFlowEntity) => | ||
| FlowActions.openComponentConnectionsDialog({ | ||
| request: { | ||
| componentName: request.name, | ||
| componentType: request.type, | ||
| groupId: request.groupId, | ||
| direction: request.direction, | ||
| connections: flowEntity.processGroupFlow.flow.connections.filter(attachedTo), | ||
| groupIdToName: this.buildProcessGroupIdToNameMap(flowEntity), | ||
| remoteProcessGroupIds: this.buildRemoteProcessGroupIdSet(flowEntity), | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Please fix both so CI lint stays green. |
||
| } | ||
| }) | ||
| ), | ||
| catchError((errorResponse: HttpErrorResponse) => of(this.snackBarOrFullScreenError(errorResponse))) | ||
| ); | ||
| }) | ||
| ) | ||
| ); | ||
|
|
||
| openComponentConnectionsDialog$ = createEffect( | ||
| () => | ||
| this.actions$.pipe( | ||
| ofType(FlowActions.openComponentConnectionsDialog), | ||
| map((action) => action.request), | ||
| tap((request) => { | ||
| this.dialog.open(ComponentConnectionsDialog, { | ||
| ...XL_DIALOG, | ||
| data: request | ||
| }); | ||
| }) | ||
| ), | ||
| { dispatch: false } | ||
| ); | ||
|
|
||
| private buildProcessGroupIdToNameMap(flowEntity: ProcessGroupFlowEntity): Map<string, string> { | ||
| const idToName = new Map<string, string>(); | ||
| const processGroupFlow = flowEntity.processGroupFlow; | ||
|
|
||
| let breadcrumbEntity: BreadcrumbEntity | undefined = processGroupFlow.breadcrumb; | ||
| while (breadcrumbEntity) { | ||
| if (breadcrumbEntity.permissions.canRead) { | ||
| idToName.set(breadcrumbEntity.id, breadcrumbEntity.breadcrumb.name); | ||
| } | ||
| breadcrumbEntity = breadcrumbEntity.parentBreadcrumb; | ||
| } | ||
|
|
||
| [...(processGroupFlow.flow.processGroups ?? []), ...(processGroupFlow.flow.remoteProcessGroups ?? [])].forEach( | ||
| (group) => { | ||
| if (group.permissions.canRead) { | ||
| idToName.set(group.id, group.component.name); | ||
| } | ||
| } | ||
| ); | ||
|
|
||
| return idToName; | ||
| } | ||
|
|
||
| private buildRemoteProcessGroupIdSet(flowEntity: ProcessGroupFlowEntity): Set<string> { | ||
| return new Set((flowEntity.processGroupFlow.flow.remoteProcessGroups ?? []).map((group) => group.id)); | ||
| } | ||
|
|
||
| showOkDialog$ = createEffect( | ||
| () => | ||
| this.actions$.pipe( | ||
|
|
@@ -4945,7 +5038,7 @@ export class FlowEffects { | |
| warnedIds: this.warnedPositionIds | ||
| }) | ||
| }); | ||
| const sanitizeConnection = (entity: ComponentEntity): ComponentEntity => ({ | ||
| const sanitizeConnection = (entity: ConnectionEntity): ConnectionEntity => ({ | ||
| ...entity, | ||
| position: sanitizePosition(entity.position, { | ||
| componentId: entity.id, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,6 +19,7 @@ import { flowFeatureKey, FlowState, SelectedComponent } from './index'; | |
| import { createSelector } from '@ngrx/store'; | ||
| import { CanvasState, selectCanvasState } from '../index'; | ||
| import { ComponentType, selectCurrentRoute } from '@nifi/shared'; | ||
| import { BreadcrumbEntity } from '../../../../state/shared'; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Unused |
||
| import { | ||
| detectOverlappingConnections, | ||
| OverlappingConnectionGroup | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
View Connections never appears on empty-canvas right-click.
hasUpstream/hasDownstreamrequireselection.size() === 1, so a click on the canvas (no component selected) yields an empty submenu and the parent item is hidden (context-menu.component.tskeeps a submenu only when it has visible children).Empty canvas is the current process group — the Operation panel already treats
selection.size() === 0that way (getContextType→ProcessGroup, name from breadcrumbs). Several canvas actions do the same, for example Enable/Disable All Controller Services:If the intent is to restore 1.x “view connections for the group I’m in,” allow empty selection here and, when
selection.empty(), use the current process group id (canvasUtils.getProcessGroupId()) instead ofselection.datum(). That matches how those other current-PG actions are wired.