mcgilman opened a new pull request, #11238:
URL: https://github.com/apache/nifi/pull/11238

   … canvas graph controls.
   
   # Summary
   
   [NIFI-15823](https://issues.apache.org/jira/browse/NIFI-15823)
   
   Adds a Provenance preview card to the connector canvas graph-controls side 
panel, sitting directly below the existing Connector info card. When a 
provenance-eligible component is selected on the canvas, the card lists the 
latest provenance events for that component and offers the standard per-event 
actions (view details, view/download input/output content, replay). The preview 
is implemented as a new reusable presentation component under 
`apps/nifi/src/app/ui/common/` so it can be hosted by any page that already 
mounts the reusable `<reusable-canvas>`, and is backed by a new feature-scoped 
NgRx slice that lives with the connector canvas.
   
   ### What changed
   
   **New reusable component 
(`apps/nifi/src/app/ui/common/provenance-preview/`)**
   
   - `ProvenancePreview` — a `mat-expansion-panel` shell containing a compact 
table of recent provenance events. Owns its own collapsed state and persists it 
under `graph-control-visibility[<storageKey>]` via the shared `Storage` 
service. The `storageKey` input is configurable so independent instances on 
different pages do not collide (the connector canvas passes 
`connector-provenance-control`). Cluster-aware: when multiple nodes are 
reporting events the panel exposes a node-filter dropdown sourced from 
`connectedToCluster` + the events themselves. Surfaces a per-row action menu 
(View Details / View Input / View Output / Download Input / Download Output / 
Replay) with each item conditionally enabled based on `contentViewerAvailable`, 
`inputContentAvailable`, `outputContentAvailable`, and `replayAvailable`. Pure 
presentation -- all intent flows out as `output()` events (`refresh`, 
`collapsedChange`, `viewDetails`, `viewContent`, `downloadContent`, 
`replayEvent`) so the host page own
 s the side effects (the "emit, don't dispatch" rule).
   
   **New NgRx state slice 
(`pages/connectors/state/connector-provenance-preview/`)**
   
   - `connectorProvenancePreviewFeatureKey` registered alongside 
`connectorCanvas` in `ConnectorCanvasModule`. State shape is `{ events, error, 
status }` with a `'pending' | 'loading' | 'success' | 'error'` status machine.
   - Actions and effects for `loadLatestEventsForComponent`, 
`openProvenanceEventDialog`, `downloadContent`, `viewContent`, `replayEvent`, 
`showOkDialog`, and `resetState`. Effects reuse the existing 
`ProvenanceService`, `ProvenanceEventDialog`, `OkDialog`, and `ErrorHelper`; 
replay failures surface through the standard `ErrorActions.addBannerError` 
channel with `ErrorContextKey.CONNECTOR_CANVAS`. Module-scoped (`forFeature`) 
so the slice activates with the connector canvas and tears down when leaving.
   - Adds `getLatestEventsForComponent(componentId)` to the shared 
`ProvenanceService`, calling the existing `/provenance-events/latest/{id}` REST 
endpoint.
   
   **Wiring into the connector canvas 
(`pages/connectors/ui/connector-canvas/`)**
   
   - `connector-graph-controls` now hosts `<provenance-preview 
storageKey="connector-provenance-control" …>` below the Connector info card, 
guarded by `@if (canAccessProvenance())` so it is not rendered for users 
without `provenancePermissions.canRead`. All inputs/outputs are forwarded 
through the parent shell unchanged.
   - `connector-canvas.component.ts` wires the slice into the page:
     - Selects `provenanceEvents` / `provenanceStatus` / `provenanceError`, 
plus `connectedToCluster` (from `selectClusterSummary`) and 
`contentViewerAvailable` (from `selectAbout`).
     - Subscribes to a `combineLatest` of route params, input ports, and output 
ports and reduces them through `computeEligibleProvenanceId(...)` to a single 
eligible component id. Eligible types: `Processor`, `Connection`, 
`RemoteProcessGroup`; `InputPort` / `OutputPort` are only eligible when 
`allowRemoteAccess === true`. Everything else (Funnel, Label, ProcessGroup, 
multi-select, no selection) clears the preview via `resetState`.
     - Adds a deferred-load gate. The page tracks `graphControlsOpen` 
(existing) and a `provenanceCollapsed` mirror (updated only via the child's 
`(collapsedChange)` output). Eligibility changes only dispatch 
`loadLatestEventsForComponent` when both flags allow it; otherwise the 
component id is parked in `lastDeferredComponentId` and flushed when the user 
either opens the side panel (`toggleGraphControls`) or expands the card 
(`onProvenanceCollapsedChange(false)`). This avoids issuing the network call -- 
and showing skeleton rows -- for users who keep the card collapsed.
     - Re-emits the child's other outputs as page-level NgRx dispatches: 
`viewDetails -> openProvenanceEventDialog`, `downloadContent -> 
downloadContent`, `viewContent -> viewContent`, `replayEvent -> replayEvent`, 
`refresh -> loadLatestEventsForComponent` for the current eligible id. 
`ngOnDestroy` dispatches `resetState` alongside the existing canvas / entity 
resets.
   
   **Architectural note for reviewers**
   
   The card follows the same separation-of-concerns pattern as the sibling 
cards added in this series (`CanvasNavigationControl`, `ConnectorInfoControl`): 
the child owns its own collapsed state and persists it via the shared 
`graph-control-visibility` bag keyed by its `storageKey` input, and only emits 
intent. The page hosts a small in-memory mirror of that flag for one reason -- 
it gates an eager network call. That mirror starts collapsed-by-default and is 
updated solely through the child's `(collapsedChange)` output, so persistence 
stays single-owner in the child.
   
   The new NgRx slice deliberately lives under `pages/connectors/state/` rather 
than the global provenance module: it is short-lived (registered with 
`forFeature`, reset on every selection change and on destroy), and its 
dialog/replay handlers are connector-canvas specific (they route errors to 
`ErrorContextKey.CONNECTOR_CANVAS`). Reusing the existing `ProvenanceService` 
keeps the REST surface unchanged.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to