# Create Pipeline Wizard (`pipelinewizard-01`) - SignalOS page block

> Five-step modal wizard for creating a pipeline: configure name, description, and model orchestration (Details), answer domain context questions (Context), review and confirm derived sub use cases (Use Case), select data source connections (Connectors), then review and submit (Review). Fully controlled props API with per-step loading states.

- **Version:** 0.4.1
- **Kind:** block (group: reusable-components) · **Category:** pages
- **Install:** `npx shadcn@4.1.2 add @signalos/pipelinewizard-01`
- **Registry dependencies (pulled automatically):** @signalos/tokens, @signalos/utils, @signalos/badge, @signalos/button, @signalos/dialog, @signalos/label, @signalos/select, @signalos/textarea, @signalos/form-dialog, @signalos/text-field, @signalos/icon-button, @signalos/view-controler
- **npm dependencies:** lucide-react@^1.7.0, react-markdown@^9.0.0
- **Files installed:** `src/components/blocks/pipelinewizard-01/CreatePipelineWizard.tsx`, `src/components/blocks/pipelinewizard-01/CreatePipelineWizard.types.ts`, `src/components/blocks/pipelinewizard-01/CreatePipelineWizard.constants.ts`, `src/components/blocks/pipelinewizard-01/CreatePipelineWizard.utils.ts`, `src/components/blocks/pipelinewizard-01/components/ModelSelect.tsx`, `src/components/blocks/pipelinewizard-01/components/ReviewRow.tsx`, `src/components/blocks/pipelinewizard-01/components/WizardStepIndicator.tsx`, `src/components/blocks/pipelinewizard-01/components/WizardStepBody.tsx`, `src/components/blocks/pipelinewizard-01/components/SubUseCasesStep.tsx`, `src/components/blocks/pipelinewizard-01/components/DocumentPreviewDialog.tsx`, `src/components/blocks/pipelinewizard-01/components/WizardStepConnectors.tsx`, `src/components/blocks/pipelinewizard-01/components/WizardStepContext.tsx`, `src/components/blocks/pipelinewizard-01/components/WizardStepDetails.tsx`, `src/components/blocks/pipelinewizard-01/components/WizardStepReview.tsx`

## Access

This is a private registry: pulling source requires a `SIGNALOS_REGISTRY_TOKEN`
(GitHub fine-grained PAT with read access to the signal-widgets repo) and an
`@signalos` entry in components.json `"registries"`. Previews and this document are public.

## Usage

```tsx
// after: npx shadcn@4.1.2 add @signalos/pipelinewizard-01
// mount the pulled page in a route, e.g. src/app/reusable-components/page.tsx
import CreatePipelineWizard from "@/components/blocks/pipelinewizard-01/CreatePipelineWizard"

export default function Page() {
  return <CreatePipelineWizard />
}
```

## Props

### `ConnectionLike`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `id` | `string` | yes | - |  |
| `name` | `string` | yes | - |  |
| `connector_name` | `string \| undefined` | no | - | Connector type label, e.g. "salesforce". |
| `status` | `string \| undefined` | no | - | Connection status label, e.g. "active". |

### `OrchestrationModelLike`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `canonical` | `string` | yes | - |  |
| `display` | `string` | yes | - |  |
| `family_display` | `string \| undefined` | no | - | Provider / family grouping label shown as a select section header. |
| `lifecycle_warning` | `boolean \| undefined` | no | - | When set, the model is flagged as retiring in the picker. |

### `ContextQuestion`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `question_key` | `string` | yes | - |  |
| `question_text` | `string` | yes | - |  |
| `context` | `string \| undefined` | no | - |  |

### `CreatePipelinePayload`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `name` | `string` | yes | - |  |
| `description` | `string \| undefined` | no | - |  |
| `platform_connection_ids` | `string[]` | yes | - | Selected connection ids. |
| `onboarding_context` | `string \| undefined` | no | - | Collected onboarding context, already formatted as a string. |
| `model` | `string \| undefined` | no | - |  |
| `supporting_model` | `string \| undefined` | no | - |  |
| `embedding_model` | `string \| undefined` | no | - |  |

### `CreatePipelineWizardProps`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `open` | `boolean` | yes | - |  |
| `onOpenChange` | `(open: boolean) => void` | yes | - |  |
| `step` | `number \| undefined` | no | - | The currently active step index (0–3). When provided, the wizard is fully controlled: the parent owns step transitions and should react to `onStepChange` to kick off per-step data fetches. |
| `onStepChange` | `((step: number) => void) \| undefined` | no | - | Called when the wizard wants to move to a different step index. |
| `name` | `string \| undefined` | no | - |  |
| `onNameChange` | `((value: string) => void) \| undefined` | no | - |  |
| `description` | `string \| undefined` | no | - |  |
| `onDescriptionChange` | `((value: string) => void) \| undefined` | no | - |  |
| `selectedConnectionIds` | `string[] \| undefined` | no | - |  |
| `onSelectedConnectionIdsChange` | `((ids: string[]) => void) \| undefined` | no | - |  |
| `fieldErrors` | `Record<string, string> \| undefined` | no | - |  |
| `onFieldErrorsChange` | `((errors: Record<string, string>) => void) \| undefined` | no | - |  |
| `reasoningModel` | `string \| undefined` | no | - |  |
| `onReasoningModelChange` | `((canonical: string) => void) \| undefined` | no | - |  |
| `supportingModel` | `string \| undefined` | no | - |  |
| `onSupportingModelChange` | `((canonical: string) => void) \| undefined` | no | - |  |
| `embeddingModel` | `string \| undefined` | no | - |  |
| `onEmbeddingModelChange` | `((canonical: string) => void) \| undefined` | no | - |  |
| `connections` | `ConnectionLike[] \| undefined` | no | - |  |
| `llmModels` | `OrchestrationModelLike[] \| undefined` | no | - |  |
| `embeddingModels` | `OrchestrationModelLike[] \| undefined` | no | - |  |
| `isLoadingModels` | `boolean \| undefined` | no | - | True while models are being fetched (Step 1). |
| `isLoadingQuestions` | `boolean \| undefined` | no | - | True while onboarding questions are being fetched (Step 2). |
| `isLoadingConnectors` | `boolean \| undefined` | no | - | True while connectors are being fetched (Step 3). |
| `isSubmitting` | `boolean \| undefined` | no | - | True while the create mutation is in-flight. |
| `contextQuestions` | `ContextQuestion[] \| undefined` | no | - |  |
| `contextAnswers` | `Record<string, string> \| undefined` | no | - | Current answer map, keyed by `question_key`. |
| `onContextAnswerChange` | `((key: string, value: string) => void) \| undefined` | no | - |  |
| `onOpen` | `(() => void) \| undefined` | no | - | Called when the wizard is first opened so the parent can kick off fetches. |
| `onSubmit` | `((payload: CreatePipelinePayload) => void) \| undefined` | no | - | Called with the collected form data when the user clicks "Create pipeline". |
| `onCreateCustomModel` | `(() => void) \| undefined` | no | - | Called when the user clicks "Create model" inside the model picker. |
| `data-testid` | `string \| undefined` | no | - | Test identifier rendered as `data-testid` on the dialog content. |
| `contextMode` | `ContextMode \| undefined` | no | - |  |
| `onContextModeChange` | `((mode: ContextMode) => void) \| undefined` | no | - |  |
| `supportingDocuments` | `File[] \| undefined` | no | - | Supporting documents staged on the Context step, in "document" mode. |
| `onSupportingDocumentsChange` | `((files: File[]) => void) \| undefined` | no | - | Called with the full next list whenever staged supporting documents change. |
| `resolvedUseCase` | `string \| undefined` | no | - | The use case as resolved by the backend from an uploaded document. |
| `resolvedOrgDomain` | `string \| undefined` | no | - | The organization domain as the backend resolved it, alongside `resolvedUseCase`. |
| `subUseCaseProposals` | `SubUseCaseProposal[] \| undefined` | no | - | Proposed / confirmed / rejected sub use cases derived from the context. |
| `onSubUseCaseProposalsChange` | `((proposals: SubUseCaseProposal[]) => void) \| undefined` | no | - | Called whenever the proposal list changes (confirm, reject, edit, add, undo). |
| `isLoadingSubUseCases` | `boolean \| undefined` | no | - | True while the initial derivation call is in flight. |
| `subUseCasesFailed` | `boolean \| undefined` | no | - | True when the derivation call itself failed; not the same as an empty proposal list. |
| `onRederiveSubUseCases` | `(() => void) \| undefined` | no | - | Called when the user asks to re-derive sub use cases from the current wording. |
| `isRederivingSubUseCases` | `boolean \| undefined` | no | - | True while a re-derive call is in flight. |
| `subUseCaseEditTargetId` | `string \| null \| undefined` | no | - | The proposal id currently being edited, or null when the dialog is closed. |
| `onSubUseCaseEditTargetIdChange` | `((id: string \| null) => void) \| undefined` | no | - | Called to open/close the edit dialog (opening also seeds the draft). |
| `subUseCaseEditDraftTitle` | `string \| undefined` | no | - | Draft title field value for the edit dialog. |
| `onSubUseCaseEditDraftTitleChange` | `((title: string) => void) \| undefined` | no | - | Called when the edit dialog's title field changes. |
| `subUseCaseEditDraftStatement` | `string \| undefined` | no | - | Draft statement field value for the edit dialog. |
| `onSubUseCaseEditDraftStatementChange` | `((statement: string) => void) \| undefined` | no | - | Called when the edit dialog's statement field changes. |
| `subUseCaseEditError` | `string \| null \| undefined` | no | - | Validation error shown in the edit dialog, if any. |
| `onSubmitSubUseCaseEdit` | `(() => void) \| undefined` | no | - | Called when the user submits the edit dialog. |
| `subUseCaseRejectTargetId` | `string \| null \| undefined` | no | - | The proposal id currently being rejected, or null when the dialog is closed. |
| `onSubUseCaseRejectTargetIdChange` | `((id: string \| null) => void) \| undefined` | no | - | Called to open/close the reject dialog. |
| `subUseCaseRejectNote` | `string \| undefined` | no | - | Reject-reason note field value. |
| `onSubUseCaseRejectNoteChange` | `((note: string) => void) \| undefined` | no | - | Called when the reject dialog's note field changes. |
| `onSubmitSubUseCaseReject` | `(() => void) \| undefined` | no | - | Called when the user submits the reject dialog. |
| `subUseCaseAddOpen` | `boolean \| undefined` | no | - | Whether the add dialog is open. |
| `onSubUseCaseAddOpenChange` | `((open: boolean) => void) \| undefined` | no | - | Called to open/close the add dialog. |
| `subUseCaseAddDraftTitle` | `string \| undefined` | no | - | Draft title field value for the add dialog. |
| `onSubUseCaseAddDraftTitleChange` | `((title: string) => void) \| undefined` | no | - | Called when the add dialog's title field changes. |
| `subUseCaseAddDraftStatement` | `string \| undefined` | no | - | Draft statement field value for the add dialog. |
| `onSubUseCaseAddDraftStatementChange` | `((statement: string) => void) \| undefined` | no | - | Called when the add dialog's statement field changes. |
| `subUseCaseAddError` | `string \| null \| undefined` | no | - | Validation error shown in the add dialog, if any. |
| `onSubmitSubUseCaseAdd` | `(() => void) \| undefined` | no | - | Called when the user submits the add dialog. |

### `SubUseCaseStatus`

```ts
export type SubUseCaseStatus = "proposed" | "confirmed" | "rejected"
```

### `SubUseCaseProposal`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `id` | `string` | yes | - | Stable identity within this session — index-based ids (UC1.1, UC1.2, …) are assigned for display. |
| `title` | `string` | yes | - |  |
| `statement` | `string` | yes | - |  |
| `status` | `SubUseCaseStatus` | yes | - |  |
| `derivation_basis` | `string[] \| undefined` | no | - |  |
| `hand_added` | `boolean \| undefined` | no | - |  |
| `review_note` | `string \| undefined` | no | - | Recorded when rejected — why this proposal was declined. |

### `ContextMode`

```ts
export type ContextMode = "questions" | "document"
```

### `SubUseCaseDraft`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `title` | `string` | yes | - |  |
| `statement` | `string` | yes | - |  |

### `SubUseCaseEditDialogState`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `targetId` | `string \| null` | yes | - | The proposal id being edited, or null when the dialog is closed. |
| `draft` | `SubUseCaseDraft` | yes | - |  |
| `onDraftChange` | `(draft: SubUseCaseDraft) => void` | yes | - |  |
| `error` | `string \| null` | yes | - |  |
| `onSubmit` | `() => void` | yes | - |  |
| `onCancel` | `() => void` | yes | - |  |

### `SubUseCaseRejectDialogState`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `targetId` | `string \| null` | yes | - | The proposal id being rejected, or null when the dialog is closed. |
| `note` | `string` | yes | - |  |
| `onNoteChange` | `(note: string) => void` | yes | - |  |
| `onSubmit` | `() => void` | yes | - |  |
| `onCancel` | `() => void` | yes | - |  |

### `SubUseCaseAddDialogState`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `open` | `boolean` | yes | - |  |
| `draft` | `SubUseCaseDraft` | yes | - |  |
| `onDraftChange` | `(draft: SubUseCaseDraft) => void` | yes | - |  |
| `error` | `string \| null` | yes | - |  |
| `onSubmit` | `() => void` | yes | - |  |
| `onCancel` | `() => void` | yes | - |  |

### `SubUseCasesStepProps`

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `proposals` | `SubUseCaseProposal[]` | yes | - |  |
| `isLoading` | `boolean \| undefined` | no | - | True while the initial derivation call is in flight. |
| `hasFailed` | `boolean \| undefined` | no | - | True when the derivation call itself failed; not the same as an empty proposal list. |
| `onRederive` | `(() => void) \| undefined` | no | - | Re-run derivation from the current use case / org domain wording. |
| `isRederiving` | `boolean \| undefined` | no | - | True while a re-derive call is in flight. |
| `onConfirm` | `(id: string) => void` | yes | - | Marks a proposal confirmed. |
| `onUndo` | `(id: string) => void` | yes | - | Reverts a decided proposal back to "proposed". |
| `onOpenEdit` | `(id: string) => void` | yes | - | Opens the edit dialog for a proposal. |
| `onOpenReject` | `(id: string) => void` | yes | - | Opens the reject dialog for a proposal. |
| `onOpenAdd` | `() => void` | yes | - | Opens the add dialog. |
| `onConfirmAll` | `() => void` | yes | - | Confirms every undecided proposal, leaving rejected ones alone. |
| `editDialog` | `SubUseCaseEditDialogState` | yes | - |  |
| `rejectDialog` | `SubUseCaseRejectDialogState` | yes | - |  |
| `addDialog` | `SubUseCaseAddDialogState` | yes | - |  |

## Changelog

## 0.4.1

- Lift all sub use case actions and dialog state (confirm, undo, edit, reject, add) out of `SubUseCasesStep` and into `CreatePipelineWizard`, making `SubUseCasesStep` props-in/events-out: it now takes `onConfirm`/`onUndo`/`onOpenEdit`/`onOpenReject`/`onOpenAdd`/`onConfirmAll` plus fully controlled `editDialog`/`rejectDialog`/`addDialog` state instead of owning `useState` internally.
- Add `SubUseCaseDraft`, `SubUseCaseEditDialogState`, `SubUseCaseRejectDialogState`, and `SubUseCaseAddDialogState` type definitions; `WizardStepBody` and `CreatePipelineWizardProps`'s wiring pass these through unchanged.

## 0.3.1

- Declare `react-markdown` in `dependencies` and add `@signalos/icon-button`/`@signalos/view-controler` to `registryDependencies`, previously undeclared imports used by `DocumentPreviewDialog.tsx` and `WizardStepContext.tsx`.

## 0.3.0

- Fix compile errors: `CreatePipelineWizard` referenced an undeclared `supportingDocuments` local and a nonexistent `setSupportingDocuments` setter instead of the controlled `supportingDocuments`/`onSupportingDocumentsChange` props; `WizardStepBody` rendered `SubUseCasesStep` off six identifiers it never received as props.
- Thread `subUseCaseProposals`, `onSubUseCaseProposalsChange`, `isLoadingSubUseCases`, `subUseCasesFailed`, `onRederiveSubUseCases`, and `isRederivingSubUseCases` through `WizardStepBody` so the "Use Case" step renders.
- Add `@signalos/badge`, `@signalos/dialog`, and `@signalos/label` to `registryDependencies`, and ship the previously-unlisted `SubUseCasesStep.tsx` in `files[]`.

## 0.2.0

- Extract `WizardStepBody` and `WizardStepIndicator` into dedicated component files; export `ModelSelect` and `ReviewRow` from the `components/` folder.
- Add `WizardStep` and `WizardStepIndicatorProps` type definitions; ship new component files in registry manifest.

## 0.1.6

- Fix cross-item imports to use canonical @/components paths; add missing signalos.category to manifests.

# pipelinewizard01
## 0.1.5
- format the code
## 0.1.4

- Post-initial content update.

## 0.1.0

- Initial release: four-step pipeline creation wizard (Details → Context → Connectors → Review)
  composed from FormDialog, TextField, Textarea, and Select primitives. Fully controlled props API
  with per-step loading states, context questions, model orchestration pickers, and connector
  multi-selection. Step state can be lifted to the parent via `step` / `onStepChange` to trigger
  per-step data fetches.
