Skip to content

NIFI-16488 Add component creation and deletion to the Connector canvas - #11900

Merged
rfellows merged 2 commits into
apache:mainfrom
mcgilman:NIFI-16488
Nov 10, 2026
Merged

rfellows merged 2 commits into
apache:mainfrom
mcgilman:NIFI-16488

Conversation

@mcgilman

@mcgilman mcgilman commented Nov 9, 2026

Copy link
Copy Markdown
Contributor
  • create processors, ports, process groups, remote process groups, funnels, labels, and connections on the Connector canvas while the Connector is in Troubleshooting and writable
  • delete the selection from the context menu or the Delete key, skipping components that cannot be deleted and removing outgoing connections of deleted components
  • reload the endpoints of a connection after it is created, deleted, or moved to a new destination
  • reconcile created components with any copy a poll already added
  • enable canvas editing from the Connector's current Troubleshooting state
  • move the new canvas item chip to ui/common so it emits outputs, and update the flow designer header to use it
  • extract the Connector canvas context menu into a service
  • keep selection and double-click ahead of drag on funnels, ports, process groups, remote process groups, and connection labels
  • keep a connection label on the same bend point when bend points are added or removed, and attach the label drag once so it works after the label is selected
  • validate dynamic path segments in create and delete requests

Summary

NIFI-16488

Adds component creation and deletion to the Connector canvas. When a Connector is in Troubleshooting and the user has write permission, the canvas supports the same create and delete interactions as the flow designer.

Creation

  • Processors, input and output ports, process groups, remote process groups, funnels, and labels can be dragged from the canvas palette onto the Connector canvas.
  • Connections can be drawn between components, and the create connection dialog is reused.
  • The new canvas item chip moved to ui/common and now emits outputs instead of dispatching flow designer actions. The flow designer header uses the relocated chip.
  • Created components and connections are reconciled with any copy a poll already added, so a component is never shown twice.

Deletion

  • The current selection can be deleted from the context menu or with the Delete key.
  • Components that cannot be deleted are skipped, using new pure deletion.utils helpers.
  • Deleting a component removes its outgoing connections from state.
  • The endpoints of a connection are reloaded after it is created, deleted, or moved to a new destination.

Canvas interaction

  • The Connector canvas context menu was extracted into ConnectorCanvasContextMenuService, and the Delete command was added to it.
  • Canvas editing is enabled from the Connector's current Troubleshooting state.
  • On funnels, ports, process groups, remote process groups, and connection labels, selection and double-click are bound once on entered elements. They keep firing ahead of the drag behavior after a re-render.
  • A connection label stays on the same bend point when bend points are added or removed.
  • The connection label drag is attached once, and its handlers read the bound connection datum. The label can be dragged after it is selected and after connections are added or removed.

Security

  • Every dynamic path segment in create and delete requests is validated with safeApiPath.

Testing

  • npx nx test nifi: 357 test files, 3,556 tests passing
  • New or expanded specs for ConnectorEditService, the Connector canvas actions, reducer, selectors, and effects, the context menu and commands services, the Connector canvas component, the canvas component (label anchoring on bend points), the funnel, port, process group, remote process group, and connection renderers, deletion.utils, the relocated new canvas item chip, and the flow designer header
  • Type-check, ESLint, and Prettier pass for the changed files

Tracking

Please complete the following tracking steps prior to pull request creation.

Issue Tracking

Pull Request Tracking

  • Pull Request title starts with Apache NiFi Jira issue number, such as NIFI-00000
  • Pull Request commit message starts with Apache NiFi Jira issue number, as such NIFI-00000
  • Pull request contains commits signed with a registered key indicating Verified status

Pull Request Formatting

  • Pull Request based on current revision of the main branch
  • Pull Request refers to a feature branch with one commit containing changes

Verification

Please indicate the verification steps performed prior to pull request creation.

Build

  • Build completed using ./mvnw clean install -P contrib-check
    • JDK 21
    • JDK 25

Licensing

  • New dependencies are compatible with the Apache License 2.0 according to the License Policy
  • New dependencies are documented in applicable LICENSE and NOTICE files

Documentation

  • Documentation formatting appears as expected in rendered files

- create processors, ports, process groups, remote process groups, funnels, labels, and connections on the Connector canvas while the Connector is in Troubleshooting and writable
- delete the selection from the context menu or the Delete key, skipping components that cannot be deleted and removing outgoing connections of deleted components
- reload the endpoints of a connection after it is created, deleted, or moved to a new destination
- reconcile created components with any copy a poll already added
- enable canvas editing from the Connector's current Troubleshooting state
- move the new canvas item chip to ui/common so it emits outputs, and update the flow designer header to use it
- extract the Connector canvas context menu into a service
- keep selection and double-click ahead of drag on funnels, ports, process groups, remote process groups, and connection labels
- keep a connection label on the same bend point when bend points are added or removed, and attach the label drag once so it works after the label is selected
- validate dynamic path segments in create and delete requests
@rfellows

rfellows commented Nov 9, 2026

Copy link
Copy Markdown
Contributor

reviewing...

@rfellows rfellows left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks Matt, this is a really implementation. The state reconciliation, the outgoing-connection cleanup on delete, and the move of the new canvas item chip to ui/common all look good. The specs are thorough as well.

A few suggestions inline. The first one (canEdit and write permission) is the only one I'd consider important. I ran nx test nifi locally at e8ceec2, and all 3,556 tests passed.

]),
filter(([, connectorEntity]) => connectorEntity !== null),
map(([, connectorEntity, features]) => ({
canEdit: connectorEntity!.component.state === 'TROUBLESHOOTING',

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

canEdit here is set from state === 'TROUBLESHOOTING' alone. The palette, the Delete context-menu item and the Delete key all gate on ConnectorCanvasContextMenu.canEdit (connector-canvas-context-menu.service.ts:78), which also requires canvasPermissions()?.canWrite.

This canvas feature flag is what enables component drag and the connection-drawing handles. So a user who can read but not write the flow can still start a drag or draw a connection during Troubleshooting. The server rejects it, but the user sees an error banner and the component snaps back.

Could this use the same condition as the context menu? It would also be worth adding a spec for "in Troubleshooting but not writable".

createProcessor(processGroupId: string, request: CreateProcessorRequest): Observable<ProcessorEntity> {
return defer(() =>
this.httpClient.post<ProcessorEntity>(
`${ConnectorEditService.API}/process-groups/${safeApiPath(processGroupId)}/processors`,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new create, get and delete calls in this service go through safeApiPath, but two raw segments remain earlier in the file (outside this diff):

  • updateComponent (line 71): ${path}/${request.id}
  • createConnection (line 75): process-groups/${processGroupId}/connections

The PR description says every dynamic path segment in create and delete requests is validated, and createConnection is a create. Could both be wrapped the same way as these new methods (safeApiPath(...) inside defer)?

() =>
this.actions$.pipe(
ofType(ConnectorCanvasActions.createCanvasComponentSuccess),
tap(() => this.dialog.closeAll())

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The flow designer selects a newly created component (createComponentComplete$), and this PR already selects new connections. Processors, ports, funnels, labels and process groups created here aren't selected, though.

Would it make sense to dispatch selectComponents for response.payload.id / response.type alongside closeAll(), for parity?

([{ request }, connectorId, processGroupId]) =>
request.length > 0 && connectorId !== '' && processGroupId !== null
),
mergeMap(([{ request }, connectorId, processGroupId, connections]) => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two small things on this effect:

  • With mergeMap, pressing Delete twice quickly sends the same revisions twice. The second request gets a 409, which shows a banner and reloads the flow. exhaustMap would make this consistent with createCanvasComponent$.
  • If the filter above drops a request, the reducer has already set saving: true and nothing clears it. In practice canEdit means the flow is always loaded by then, so this is defensive only.

expect(result.connections).toEqual([]);
});

it('does not restore a connection leaving a deleted remote process group from an older snapshot', () => {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reducer correctly maps a connection's source to the child process group when sourceGroupId !== processGroupId. These specs cover the remote process group case, but not deleting a child process group whose output ports have outgoing connections. Could you add a case for that?

@rfellows rfellows added the ui Pull requests for work relating to the user interface label Nov 9, 2026

@rfellows rfellows left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @mcgilman 👍

@rfellows
rfellows merged commit 0e1e7f1 into apache:main Nov 10, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ui Pull requests for work relating to the user interface

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants