rfellows opened a new pull request, #11126:
URL: https://github.com/apache/nifi/pull/11126
# NIFI-15816: Add Generic Connector Wizard to NiFi frontend (shared library)
## Description
This change introduces the **generic connector configuration wizard** into
the NiFi frontend. In NiFi, **connectors** represent managed data-pipeline
components whose configuration is often too rich for a single form. The
**Connector Wizard** is a guided, multi-step experience that walks operators
through **property groups** defined by the connector's descriptors, validates
input, supports **connectivity verification**, and finally **applies** the
configuration to the running system.
The wizard supports two UI modes:
- **Generic (auto-generated) UI** -- Steps and fields are driven from
server-provided configuration metadata (property groups, types, dependencies,
allowable values, etc.). The shared library renders the appropriate controls
without connector-specific Angular code.
- **Custom UI** -- A connector can supply an external URL; the host
application embeds that UI in an **iframe**. The parent page and the embedded
UI coordinate through a **typed `postMessage` protocol** so custom UIs can
request navigation, report save/verify lifecycle events, and receive
cluster-related acknowledgments (for example **disconnected-node
acknowledgment** for mutating NiFi requests) without tight coupling to NiFi's
internal state shape.
This PR is intentionally **library-first**: reusable wizard UI, state,
services, and types live under `nifi-frontend/.../libs/shared/` so multiple
feature areas can host the same wizard with different route shells and store
wiring.
## Architecture
### Layering
- **Presentation** -- `ConnectorWizardComponent` orchestrates the shell
(stepper / navigation chrome, summary step, documentation side panel, banners).
Step content is composed from generic building blocks (`WizardComponent`,
property-group cards, `ConnectorPropertyInput`, step actions, verification UX).
- **State** -- **NgRx SignalStore** with a composed
**`withConnectorWizard()`** feature encapsulates wizard lifecycle: loading the
connector, per-step dirty/saved state, verification results, secrets/assets,
dynamic allowable values, summary refresh, and apply. An abstract
**`ConnectorWizardStore`** class is the **Angular DI token**; shared components
inject that token. Hosts provide either **`StandardConnectorWizardStore`**
(`signalStore(withConnectorWizard())`) or a **custom store** that composes
`withConnectorWizard()` with app-specific step rules.
- **API boundary** -- **`ConnectorConfigurationService`** centralizes REST
calls for loading connector entities, saving steps, verification, applying
configuration, uploading assets, and related operations used by the store's
`rxMethod`-style effects.
- **Iframe protocol** -- **`ConnectorMessageClient`** (in the shared
library) is the **child/iframe** API: typed methods emit `postMessage` to
`window.parent` with **origin scoping** (derived from `document.referrer`), and
exposes streams such as **`disconnectedNodeAcknowledgment$()`** with strict
validation of inbound parent messages. **`ConnectorMessageHost`** (NiFi app:
`pages/connectors/service/connector-message-host.service.ts`) is the **parent**
listener: it validates **origin**, optional **iframe `contentWindow` matching**
(anti-spoofing), and message shape via **`isConnectorMessage()`**, then routes
events (e.g. router navigation). The canonical message contracts live in
**`connector-message.types.ts`** (`CONNECTOR_MESSAGE_NAMESPACE`, discriminated
unions, type guards).
- **Forms** -- **`ConnectorPropertyInput`** implements
**`ControlValueAccessor`** so reactive forms can render **STRING**,
**BOOLEAN**, **SECRET**, **ASSET**, and related descriptor-driven types
consistently, including dynamic allowable values and asset upload hooks.
### Component diagram
```mermaid
flowchart TB
subgraph HostApp["NiFi app (host)"]
CC["Connector configure route / shell"]
CMH["ConnectorMessageHost\n(parent postMessage listener)"]
CC --> CMH
end
subgraph SharedLib["libs/shared"]
CW["ConnectorWizardComponent"]
CS["ConnectorConfigurationStepComponent"]
SUM["ConnectorConfigurationSummaryStepComponent"]
CPI["ConnectorPropertyInput"]
WZ["WizardComponent"]
CMC["ConnectorMessageClient\n(iframe child API)"]
Store["ConnectorWizardStore (DI
token)\nStandardConnectorWizardStore\n+ withConnectorWizard()"]
API["ConnectorConfigurationService"]
Types["Types & validation utils\n(connector config, messages)"]
CW --> CS
CW --> SUM
CS --> WZ
CS --> CPI
CW --> Store
CS --> Store
SUM --> Store
Store --> API
CMC --> Types
CMH --> Types
end
CC --> CW
CMC -.->|"postMessage\n(origin-checked)"| CMH
```
## Iframe support and security
Embedded custom UIs use **`ConnectorMessageClient`** to emit structured
events (navigation, step saved/errors, verify started/success/error, config
applied/errors, UI ready). The parent uses
**`ConnectorMessageHost.startListening()`** with an explicit **expected
origin** (from the connector's `configurationUrl`) and optional **iframe
element** resolution so **`event.source`** must match the real iframe window
when available. Inbound messages are accepted only if they pass **namespace +
type** validation (`isConnectorMessage` / `isParentToConnectorMessage`).
Child-side **`disconnectedNodeAcknowledgment$()`** similarly requires matching
**origin**, **`event.source === window.parent`**, and validated payload shape
-- a **fail-closed** posture for cross-window messaging.
## Key design decisions
- **`NifiSpinnerDirective`** (and spinner companion) moved into
**`libs/shared`** so shared wizard code does not duplicate NiFi's native
loading affordance.
## User flow (configure -> verify -> apply)
```mermaid
sequenceDiagram
actor User
participant Host as Host page<br/>(Connector configure)
participant Wiz as ConnectorWizard<br/>(shared)
participant Store as ConnectorWizardStore<br/>(withConnectorWizard)
participant API as ConnectorConfigurationService
participant IF as Custom UI<br/>(optional iframe)
User->>Host: Open connector configuration
Host->>Wiz: Host provides store + renders wizard
Wiz->>Store: initializeWithConnector / loadConnector
Store->>API: Fetch connector + step metadata
API-->>Store: Connector + step configs
Store-->>Wiz: Visible steps, working configuration
alt Generic step
User->>Wiz: Edit properties (CVA inputs)
Wiz->>Store: updateUnsavedStepValues / markStepDirty
else Custom step (iframe)
IF->>Host: postMessage (step events) via ConnectorMessageClient
Host->>Store: Route events / state updates
end
User->>Wiz: Save step / advance
Store->>API: saveStep (per step)
API-->>Store: Persisted step configuration
User->>Wiz: Verify (step or all)
Store->>API: verify endpoints
API-->>Store: Verification results / errors
Wiz-->>User: Inline errors, banners, verification dialog progress
User->>Wiz: Apply configuration
Store->>API: applyConfiguration
API-->>Store: Success or error
Wiz-->>User: Snackbar + completion / summary refresh
```
## What's changed (high level)
### `libs/shared`
- New **connector wizard** module: shell components, **SignalStore** +
**`withConnectorWizard`**, **step dependency utilities**, **wizard context
banner**, **documentation panel** (markdown), **custom step directive**,
**summary** and **configuration** steps, **step actions**,
**`ConnectorPropertyInput`**, shared **wizard** primitives,
**`ConnectorConfigurationService`**, **`ConnectorMessageClient`**,
**`UploadService`**, **`ActiveStepService`**, **value-reference** helpers,
**connector validation** utilities, and expanded **type** surface for connector
configuration and messages.
- **`NifiSpinnerDirective`** relocated from the app into shared (re-exports
updated).
- **Barrels** (`components`, `directives`, `services`, `types`, `index`)
updated to export the new public API.
### `apps/nifi`
- **Connectors** area: **iframe host wiring** (`ConnectorMessageHost`,
`connector-configure` integration), **`postMessage` to iframe** for
disconnected-node acknowledgment after **connector-ui-ready**, and related
component updates.
- Broad set of **import rewires** across existing dialogs/forms where
spinner directives now come from **`@nifi/shared`** instead of a previous local
path.
## Testing
- **Vitest** suites ported and adapted to NiFi's frontend test setup.
- Coverage is heavily weighted toward the **SignalStore**
(`connector-wizard.store.spec.ts`), **configuration step** (large component
spec), and **summary step** (extensive table/validation scenarios), plus
utilities, **wizard** shell, **step actions**, **documentation panel**,
**context banner**, **custom step directive**, and **iframe host** behavior.
--
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]