Skip to content

[Alerting v2] Add HorizontalMinimalStepper component#268739

Merged
yiannisnikolopoulos merged 9 commits into
elastic:mainfrom
jasonrhodes:rna/pr-a-compose-discover-foundation
May 12, 2026
Merged

[Alerting v2] Add HorizontalMinimalStepper component#268739
yiannisnikolopoulos merged 9 commits into
elastic:mainfrom
jasonrhodes:rna/pr-a-compose-discover-foundation

Conversation

@jasonrhodes
Copy link
Copy Markdown
Member

@jasonrhodes jasonrhodes commented May 11, 2026

Summary

Adds HorizontalMinimalStepper, a compact stepped-progress indicator for flyout headers.

The existing EuiStepsHorizontal renders numbered circles with labels below each step — it's designed for full-page wizards and is too tall and visually heavy for a flyout header. This component fits in a single 8px-tall row alongside other controls.

This is the first in a series of PRs building the v2 rule authoring experience (stepped Edit Form flyout + Discover Sandbox). This component is purely presentational with no dependencies on the rest of that work.


What it looks like

horizontal-stepper.mp4
● ● — ○  Recovery Condition              2 / 4  [⊞] [</>]
  • Past steps — small filled blue circle (8 × 8px)
  • Current step — wider blue pill (24 × 8px), animates from dot on step change
  • Future steps — small grey circle (8 × 8px)
  • Bold current step title immediately after the indicators
  • Muted N / N step counter at the far right
  • Icon-only controls (e.g. Form/YAML toggle) sit alongside via standard EuiFlexGroup — the component has no slot API

Animation

CSS-only spring transition on step change. React keeps the same keyed <div> across renders, so updating width and border-radius styles triggers the CSS transition automatically without any JS.

width 220ms cubic-bezier(0.34, 1.56, 0.64, 1)
border-radius 220ms cubic-bezier(0.34, 1.56, 0.64, 1)

cubic-bezier(0.34, 1.56, 0.64, 1) is a spring curve — slight overshoot then settle. The transition is wrapped in ${euiCanAnimate} in the Emotion styles file, so prefers-reduced-motion: reduce is handled automatically by the browser with no JS check required.


API

Status-driven, mirrors EuiStepsHorizontal:

<HorizontalMinimalStepper
  steps={[
    { title: 'Alert Condition',    status: 'complete'   },
    { title: 'Recovery Condition', status: 'current'    },
    { title: 'Details',            status: 'incomplete' },
    { title: 'Notifications',      status: 'incomplete' },
  ]}
/>

Placing controls alongside the stepper is the caller's responsibility:

<EuiFlexGroup alignItems="center" gutterSize="s">
  <EuiFlexItem grow>
    <HorizontalMinimalStepper steps={steps} />
  </EuiFlexItem>
  <EuiFlexItem grow={false}>
    <EuiButtonGroup options={TOGGLE_OPTIONS} isIconOnly ... />
  </EuiFlexItem>
</EuiFlexGroup>

Viewing in Storybook

Stories are at Alerting V2 / Compose Discover / HorizontalMinimalStepper.

Run Storybook locally

cd ~/__projects__/kibana-dev/pr-a-foundation
yarn storybook alerting-v2-rule-form

Storybook starts on http://localhost:9001. Navigate to:

Alerting V2 → Compose Discover → HorizontalMinimalStepper

Stories included

Story What it shows
Interactive Click Next/Back to see the dot→pill animation live
All States All four step positions rendered simultaneously for comparison
With Icon Toggle Stepper alongside a Form/YAML EuiButtonGroup isIconOnly — the expected real-world usage
Three Steps Variant when Recovery Condition step is absent (tracking disabled)
Reduced Motion Documents the no-animation state for prefers-reduced-motion: reduce

Accessibility

  • role="group" + aria-label on the container announces step context to screen readers
  • Indicator dots are aria-hidden (decorative — conveyed by the label)
  • aria-current="step" on the current step title
  • aria-label on the N/N counter for screen reader parity

Notes for reviewers

  • This component is local to alerting-v2-rule-form/flyout/compose_discover/ for now. If adopted elsewhere it should be promoted (and may warrant an EUI contribution).
  • Styles use Emotion css + ${euiCanAnimate}, matching the pattern used by EuiAccordion, EuiProgress, EuiLoadingSpinner, and other animated EUI components.
  • No click handlers per step — navigation is via Back/Next buttons in the flyout footer, keeping this component purely presentational.

A compact stepped-progress indicator for use in flyout headers, designed
to match the rule authoring UX spec (see design screenshots in PR).

The existing EuiStepsHorizontal renders numbered circles with labels under
each step — too tall and visually heavy for the constrained flyout header
context. This component takes a single row with:

  ● ● — ○  Current step title              2 / 4  [icon]

Indicators:
- Past steps:    small filled circle (8 × 8px), EUI primary blue
- Current step:  wider pill (24 × 8px), EUI primary blue
- Future steps:  small filled circle (8 × 8px), EUI lightShade grey

Animation: CSS-only spring transition (cubic-bezier(0.34, 1.56, 0.64, 1))
on width + border-radius as step changes. React keeps the same keyed <div>
across renders so style updates trigger the transition automatically.
Respects prefers-reduced-motion.

API mirrors EuiStepsHorizontal (status-driven, not index-driven):
  steps: Array<{ title: string; status: 'current' | 'complete' | 'incomplete' }>
  animated?: boolean  (default true)

Layout note: placing controls (e.g. a Form/YAML icon toggle) alongside the
stepper is intentionally the caller's responsibility via EuiFlexGroup —
the component has no rightSlot API to keep it composable.

Storybook: Alerting V2 / Compose Discover / HorizontalMinimalStepper

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@github-actions github-actions Bot added the author:actionable-obs PRs authored by the actionable obs team label May 11, 2026
@jasonrhodes jasonrhodes added release_note:skip Skip the PR/issue when compiling release notes backport:skip This PR does not require backporting v9.5.0 labels May 11, 2026
jasonrhodes and others added 2 commits May 11, 2026 14:49
Replaces inline styles with Emotion css`` + euiCanAnimate from @elastic/eui,
matching the pattern used by EuiAccordion, EuiProgress, EuiLoadingSpinner,
and every other animated EUI component.

- horizontal_minimal_stepper.styles.ts: indicator styles per status variant,
  spring transition wrapped in ${euiCanAnimate} so prefers-reduced-motion is
  handled automatically by the browser via CSS @media query — no JS check needed
- horizontal_minimal_stepper.tsx: uses css prop, drops animated prop (the CSS
  media query is the only mechanism needed), uses useEuiTheme via styles hook
- stories: AnimationDisabled → ReducedMotion with chromatic prefersReducedMotion
  parameter; removes animated={false} usage

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@jasonrhodes jasonrhodes marked this pull request as ready for review May 11, 2026 19:17
@jasonrhodes jasonrhodes requested a review from a team as a code owner May 11, 2026 19:17
@jasonrhodes
Copy link
Copy Markdown
Member Author

@elasticmachine merge upstream

Copy link
Copy Markdown
Contributor

@baileycash-elastic baileycash-elastic left a comment

Choose a reason for hiding this comment

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

straightforward. ux looks good, animation is subtle but nice. 🚢

- Add @emotion/react/types/css-prop to tsconfig types so the css prop
  typechecks on raw HTML elements (pattern from kbn-classic-stream-flyout)
- Remove animated prop from stories (animation is CSS-only, no prop needed)
- Extract useState hooks in story render functions into named components
  (InteractiveStory, ThreeStepsStory) to satisfy react-hooks/rules-of-hooks
- Escape quotes in JSX text; reformat for prettier compliance

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
The CI project-references build (tsc -b tsconfig.refs.json) does not pick
up the @emotion/react/types/css-prop augmentation from package tsconfig,
so the css prop on plain HTML elements fails type check there.

Use @emotion/react's ClassNames render-prop instead: it converts
SerializedStyles to real CSS class names applied via className, which
is always valid on HTML elements and keeps the euiCanAnimate transitions
working exactly as before.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
@kibanamachine
Copy link
Copy Markdown
Contributor

💛 Build succeeded, but was flaky

Failed CI Steps

Test Failures

  • [job] [logs] Scout Lane #7 - stateful-classic / default / local-stateful-classic - APM integration not installed but setup completed - Admin user
  • [job] [logs] Scout Lane #7 - stateful-classic / default / local-stateful-classic - Observability Landing Page (discover.isEsqlDefault enabled) - redirects to onboarding when no logs data exists

Metrics [docs]

✅ unchanged

History

Copy link
Copy Markdown
Contributor

@joana-cps joana-cps left a comment

Choose a reason for hiding this comment

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

👏 Looks good to me!
Thanks for putting this together so quickly!

@yiannisnikolopoulos yiannisnikolopoulos merged commit 28edb54 into elastic:main May 12, 2026
33 checks passed
jasonrhodes added a commit that referenced this pull request May 12, 2026
…m state (#268774)

## Summary

Closes #268771

Adds `ComposeDiscoverFlyout`, the stepped Edit Form flyout for v2 rule
authoring. This is PR B in a series; PR A (#268739) adds
`HorizontalMinimalStepper` as a foundation.

**What's in this PR:**
- `ComposeDiscoverFlyout` component with a 3-step form: **Alert
Condition → Details & Artifacts → Notifications**
- Complete RHF migration: all submitted values (`name`, `tags`,
`schedule`, `lookback`, `timeField`, `grouping`, `query`, delays) live
in `useForm<FormValues>()`; reducer owns only UI state (`step`,
`childOpen`, `yamlMode`, `queryCommitted`, etc.)
- **Create mode** — wired to `useCreateRule` mutation; entry point is
the new **"Create in flyout"** button on the rules list (alongside
**"Create rule"** which still navigates to the full-page form)
- **Edit mode** — wired to `useUpdateRule`; entry point is the edit icon
on any rule row (replaces `QuickEditRuleFlyout`)
- **Discover Sandbox** — child flyout with a single ES|QL editor, Lens
histogram, and data grid; opens via "Open query editor" / "Edit query"
in the Alert Condition step
- **YAML preview** — toggle in header shows read-only CodeEditor with
rule YAML; editing round-trip is deferred
- Reuses `RuleDetailsFieldGroup` and `RuleExecutionFieldGroup` from PR
#268164

**What's NOT in this PR (deferred):**
- No Recovery Condition step (PR E)
- No tracking toggle or split-query support
- Notifications step is a placeholder callout
- Runbook URL / Dashboard link are disabled stubs
- Sandbox UI unpolished (redesign in PR C)
- YAML round-trip editing deferred

### State architecture

```
useForm<FormValues>()   ← submitted values: name, tags, schedule, query, timeField, grouping, delays
useReducer(uiReducer)   ← UI only: step, childOpen, fullQuery, yamlMode, queryCommitted, sandboxDateStart/End
```

One bridge: when the user clicks **Apply changes** in the Sandbox, a
`useEffect` syncs `uiState.fullQuery → setValue('evaluation.query.base',
...)`. Everything else writes directly to RHF via `useFormContext()`.

---

## Test plan

### Prerequisites

Start Elasticsearch:
```bash
cd ~/__projects__/kibana-dev/pr-b-rhf-form
node scripts/es snapshot --license=trial
```

Start Kibana (Node 24 required):
```bash
export NVM_DIR="$HOME/.nvm" && source "$NVM_DIR/nvm.sh" && nvm use 24
KBN_USE_RSPACK=true yarn start \
  --server.port=5603 \
  --server.basePath=/ifh \
  --server.rewriteBasePath=true
```

`config/kibana.dev.yml`:
```yaml
xpack.alerting_v2.enabled: true
dev.basePathProxyTarget: 5604
mockIdpPlugin.enabled: false
```

Navigate to: `http://localhost:5603/ifh/app/management/alertingV2/rules`

---

### Create flow

- [ ] Click **Create in flyout** (next to the primary "Create rule"
button) — flyout opens in create mode; Discover Sandbox opens alongside
it automatically
- [ ] Verify 3 steps in the header stepper: Alert Condition, Details &
Artifacts, Notifications
- [ ] In the Sandbox: type a query (e.g. `FROM logs-* | STATS count =
COUNT(*) BY host.name | WHERE count > 0`), click **Search** — verify
histogram and results grid appear
- [ ] Click **Apply changes** — Sandbox closes; Alert Condition step
shows the committed query summary
- [ ] Change the **Time field** dropdown — verify it reflects in the
form
- [ ] Adjust **schedule** and **lookback** via the schedule fields
- [ ] Click **Next** → **Details & Artifacts**: fill in rule name and
tags via the standard field group
- [ ] Click **Next** → **Notifications**: verify placeholder callout
appears (not wired yet — expected)
- [ ] Click **Create rule** — verify rule appears in the list with
correct name, tags, and schedule
- [ ] Verify the primary **Create rule** button (filled, left of "Create
in flyout") still navigates to the full-page form

### Edit flow

- [ ] Click the edit (pencil) icon on an existing rule — flyout opens in
edit mode, pre-populated with that rule's values
- [ ] Modify the rule name in Details & Artifacts
- [ ] Click **Save rule** — verify the rule updates and the change
appears in the list

### YAML preview

- [ ] Toggle YAML mode in the flyout header — stepper collapses;
CodeEditor shows read-only rule YAML
- [ ] Fill in form fields, toggle YAML mode — verify YAML reflects the
current values

### Edge cases

- [ ] Open the Sandbox, edit the query, close without clicking **Apply
changes** — verify the Alert Condition step still shows the previously
committed query
- [ ] Verify **Next** is disabled while the Sandbox is open

---------

Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Bailey Cash <bailey.cash@elastic.co>
patrykkopycinski pushed a commit to patrykkopycinski/kibana that referenced this pull request May 13, 2026
## Summary

Adds `HorizontalMinimalStepper`, a compact stepped-progress indicator
for flyout headers.

The existing `EuiStepsHorizontal` renders numbered circles with labels
below each step — it's designed for full-page wizards and is too tall
and visually heavy for a flyout header. This component fits in a single
8px-tall row alongside other controls.

This is the first in a series of PRs building the v2 rule authoring
experience (stepped Edit Form flyout + Discover Sandbox). This component
is purely presentational with no dependencies on the rest of that work.

---

## What it looks like


https://github.com/user-attachments/assets/ff9cc91e-7ce5-442b-90a6-9570d5bd4c72

```
● ● — ○  Recovery Condition              2 / 4  [⊞] [</>]
```

- **Past steps** — small filled blue circle (8 × 8px)
- **Current step** — wider blue pill (24 × 8px), animates from dot on
step change
- **Future steps** — small grey circle (8 × 8px)
- Bold current step title immediately after the indicators
- Muted `N / N` step counter at the far right
- Icon-only controls (e.g. Form/YAML toggle) sit alongside via standard
`EuiFlexGroup` — the component has no slot API

---

## Animation

CSS-only spring transition on step change. React keeps the same keyed
`<div>` across renders, so updating `width` and `border-radius` styles
triggers the CSS transition automatically without any JS.

```ts
width 220ms cubic-bezier(0.34, 1.56, 0.64, 1)
border-radius 220ms cubic-bezier(0.34, 1.56, 0.64, 1)
```

`cubic-bezier(0.34, 1.56, 0.64, 1)` is a spring curve — slight overshoot
then settle. The transition is wrapped in `${euiCanAnimate}` in the
Emotion styles file, so `prefers-reduced-motion: reduce` is handled
automatically by the browser with no JS check required.

---

## API

Status-driven, mirrors `EuiStepsHorizontal`:

```tsx
<HorizontalMinimalStepper
  steps={[
    { title: 'Alert Condition',    status: 'complete'   },
    { title: 'Recovery Condition', status: 'current'    },
    { title: 'Details',            status: 'incomplete' },
    { title: 'Notifications',      status: 'incomplete' },
  ]}
/>
```

Placing controls alongside the stepper is the caller's responsibility:

```tsx
<EuiFlexGroup alignItems="center" gutterSize="s">
  <EuiFlexItem grow>
    <HorizontalMinimalStepper steps={steps} />
  </EuiFlexItem>
  <EuiFlexItem grow={false}>
    <EuiButtonGroup options={TOGGLE_OPTIONS} isIconOnly ... />
  </EuiFlexItem>
</EuiFlexGroup>
```

---

## Viewing in Storybook

Stories are at **Alerting V2 / Compose Discover /
HorizontalMinimalStepper**.

### Run Storybook locally

```bash
cd ~/__projects__/kibana-dev/pr-a-foundation
yarn storybook alerting-v2-rule-form
```

Storybook starts on `http://localhost:9001`. Navigate to:

```
Alerting V2 → Compose Discover → HorizontalMinimalStepper
```

### Stories included

| Story | What it shows |
|---|---|
| **Interactive** | Click Next/Back to see the dot→pill animation live |
| **All States** | All four step positions rendered simultaneously for
comparison |
| **With Icon Toggle** | Stepper alongside a Form/YAML `EuiButtonGroup
isIconOnly` — the expected real-world usage |
| **Three Steps** | Variant when Recovery Condition step is absent
(tracking disabled) |
| **Reduced Motion** | Documents the no-animation state for
`prefers-reduced-motion: reduce` |

---

## Accessibility

- `role="group"` + `aria-label` on the container announces step context
to screen readers
- Indicator dots are `aria-hidden` (decorative — conveyed by the label)
- `aria-current="step"` on the current step title
- `aria-label` on the N/N counter for screen reader parity

---

## Notes for reviewers

- This component is local to
`alerting-v2-rule-form/flyout/compose_discover/` for now. If adopted
elsewhere it should be promoted (and may warrant an EUI contribution).
- Styles use Emotion `css` + `${euiCanAnimate}`, matching the pattern
used by `EuiAccordion`, `EuiProgress`, `EuiLoadingSpinner`, and other
animated EUI components.
- No click handlers per step — navigation is via Back/Next buttons in
the flyout footer, keeping this component purely presentational.

---------

Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
patrykkopycinski pushed a commit to patrykkopycinski/kibana that referenced this pull request May 13, 2026
…m state (elastic#268774)

## Summary

Closes elastic#268771

Adds `ComposeDiscoverFlyout`, the stepped Edit Form flyout for v2 rule
authoring. This is PR B in a series; PR A (elastic#268739) adds
`HorizontalMinimalStepper` as a foundation.

**What's in this PR:**
- `ComposeDiscoverFlyout` component with a 3-step form: **Alert
Condition → Details & Artifacts → Notifications**
- Complete RHF migration: all submitted values (`name`, `tags`,
`schedule`, `lookback`, `timeField`, `grouping`, `query`, delays) live
in `useForm<FormValues>()`; reducer owns only UI state (`step`,
`childOpen`, `yamlMode`, `queryCommitted`, etc.)
- **Create mode** — wired to `useCreateRule` mutation; entry point is
the new **"Create in flyout"** button on the rules list (alongside
**"Create rule"** which still navigates to the full-page form)
- **Edit mode** — wired to `useUpdateRule`; entry point is the edit icon
on any rule row (replaces `QuickEditRuleFlyout`)
- **Discover Sandbox** — child flyout with a single ES|QL editor, Lens
histogram, and data grid; opens via "Open query editor" / "Edit query"
in the Alert Condition step
- **YAML preview** — toggle in header shows read-only CodeEditor with
rule YAML; editing round-trip is deferred
- Reuses `RuleDetailsFieldGroup` and `RuleExecutionFieldGroup` from PR
elastic#268164

**What's NOT in this PR (deferred):**
- No Recovery Condition step (PR E)
- No tracking toggle or split-query support
- Notifications step is a placeholder callout
- Runbook URL / Dashboard link are disabled stubs
- Sandbox UI unpolished (redesign in PR C)
- YAML round-trip editing deferred

### State architecture

```
useForm<FormValues>()   ← submitted values: name, tags, schedule, query, timeField, grouping, delays
useReducer(uiReducer)   ← UI only: step, childOpen, fullQuery, yamlMode, queryCommitted, sandboxDateStart/End
```

One bridge: when the user clicks **Apply changes** in the Sandbox, a
`useEffect` syncs `uiState.fullQuery → setValue('evaluation.query.base',
...)`. Everything else writes directly to RHF via `useFormContext()`.

---

## Test plan

### Prerequisites

Start Elasticsearch:
```bash
cd ~/__projects__/kibana-dev/pr-b-rhf-form
node scripts/es snapshot --license=trial
```

Start Kibana (Node 24 required):
```bash
export NVM_DIR="$HOME/.nvm" && source "$NVM_DIR/nvm.sh" && nvm use 24
KBN_USE_RSPACK=true yarn start \
  --server.port=5603 \
  --server.basePath=/ifh \
  --server.rewriteBasePath=true
```

`config/kibana.dev.yml`:
```yaml
xpack.alerting_v2.enabled: true
dev.basePathProxyTarget: 5604
mockIdpPlugin.enabled: false
```

Navigate to: `http://localhost:5603/ifh/app/management/alertingV2/rules`

---

### Create flow

- [ ] Click **Create in flyout** (next to the primary "Create rule"
button) — flyout opens in create mode; Discover Sandbox opens alongside
it automatically
- [ ] Verify 3 steps in the header stepper: Alert Condition, Details &
Artifacts, Notifications
- [ ] In the Sandbox: type a query (e.g. `FROM logs-* | STATS count =
COUNT(*) BY host.name | WHERE count > 0`), click **Search** — verify
histogram and results grid appear
- [ ] Click **Apply changes** — Sandbox closes; Alert Condition step
shows the committed query summary
- [ ] Change the **Time field** dropdown — verify it reflects in the
form
- [ ] Adjust **schedule** and **lookback** via the schedule fields
- [ ] Click **Next** → **Details & Artifacts**: fill in rule name and
tags via the standard field group
- [ ] Click **Next** → **Notifications**: verify placeholder callout
appears (not wired yet — expected)
- [ ] Click **Create rule** — verify rule appears in the list with
correct name, tags, and schedule
- [ ] Verify the primary **Create rule** button (filled, left of "Create
in flyout") still navigates to the full-page form

### Edit flow

- [ ] Click the edit (pencil) icon on an existing rule — flyout opens in
edit mode, pre-populated with that rule's values
- [ ] Modify the rule name in Details & Artifacts
- [ ] Click **Save rule** — verify the rule updates and the change
appears in the list

### YAML preview

- [ ] Toggle YAML mode in the flyout header — stepper collapses;
CodeEditor shows read-only rule YAML
- [ ] Fill in form fields, toggle YAML mode — verify YAML reflects the
current values

### Edge cases

- [ ] Open the Sandbox, edit the query, close without clicking **Apply
changes** — verify the Alert Condition step still shows the previously
committed query
- [ ] Verify **Next** is disabled while the Sandbox is open

---------

Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Bailey Cash <bailey.cash@elastic.co>
DennisKo pushed a commit to DennisKo/kibana that referenced this pull request May 13, 2026
…m state (elastic#268774)

## Summary

Closes elastic#268771

Adds `ComposeDiscoverFlyout`, the stepped Edit Form flyout for v2 rule
authoring. This is PR B in a series; PR A (elastic#268739) adds
`HorizontalMinimalStepper` as a foundation.

**What's in this PR:**
- `ComposeDiscoverFlyout` component with a 3-step form: **Alert
Condition → Details & Artifacts → Notifications**
- Complete RHF migration: all submitted values (`name`, `tags`,
`schedule`, `lookback`, `timeField`, `grouping`, `query`, delays) live
in `useForm<FormValues>()`; reducer owns only UI state (`step`,
`childOpen`, `yamlMode`, `queryCommitted`, etc.)
- **Create mode** — wired to `useCreateRule` mutation; entry point is
the new **"Create in flyout"** button on the rules list (alongside
**"Create rule"** which still navigates to the full-page form)
- **Edit mode** — wired to `useUpdateRule`; entry point is the edit icon
on any rule row (replaces `QuickEditRuleFlyout`)
- **Discover Sandbox** — child flyout with a single ES|QL editor, Lens
histogram, and data grid; opens via "Open query editor" / "Edit query"
in the Alert Condition step
- **YAML preview** — toggle in header shows read-only CodeEditor with
rule YAML; editing round-trip is deferred
- Reuses `RuleDetailsFieldGroup` and `RuleExecutionFieldGroup` from PR
elastic#268164

**What's NOT in this PR (deferred):**
- No Recovery Condition step (PR E)
- No tracking toggle or split-query support
- Notifications step is a placeholder callout
- Runbook URL / Dashboard link are disabled stubs
- Sandbox UI unpolished (redesign in PR C)
- YAML round-trip editing deferred

### State architecture

```
useForm<FormValues>()   ← submitted values: name, tags, schedule, query, timeField, grouping, delays
useReducer(uiReducer)   ← UI only: step, childOpen, fullQuery, yamlMode, queryCommitted, sandboxDateStart/End
```

One bridge: when the user clicks **Apply changes** in the Sandbox, a
`useEffect` syncs `uiState.fullQuery → setValue('evaluation.query.base',
...)`. Everything else writes directly to RHF via `useFormContext()`.

---

## Test plan

### Prerequisites

Start Elasticsearch:
```bash
cd ~/__projects__/kibana-dev/pr-b-rhf-form
node scripts/es snapshot --license=trial
```

Start Kibana (Node 24 required):
```bash
export NVM_DIR="$HOME/.nvm" && source "$NVM_DIR/nvm.sh" && nvm use 24
KBN_USE_RSPACK=true yarn start \
  --server.port=5603 \
  --server.basePath=/ifh \
  --server.rewriteBasePath=true
```

`config/kibana.dev.yml`:
```yaml
xpack.alerting_v2.enabled: true
dev.basePathProxyTarget: 5604
mockIdpPlugin.enabled: false
```

Navigate to: `http://localhost:5603/ifh/app/management/alertingV2/rules`

---

### Create flow

- [ ] Click **Create in flyout** (next to the primary "Create rule"
button) — flyout opens in create mode; Discover Sandbox opens alongside
it automatically
- [ ] Verify 3 steps in the header stepper: Alert Condition, Details &
Artifacts, Notifications
- [ ] In the Sandbox: type a query (e.g. `FROM logs-* | STATS count =
COUNT(*) BY host.name | WHERE count > 0`), click **Search** — verify
histogram and results grid appear
- [ ] Click **Apply changes** — Sandbox closes; Alert Condition step
shows the committed query summary
- [ ] Change the **Time field** dropdown — verify it reflects in the
form
- [ ] Adjust **schedule** and **lookback** via the schedule fields
- [ ] Click **Next** → **Details & Artifacts**: fill in rule name and
tags via the standard field group
- [ ] Click **Next** → **Notifications**: verify placeholder callout
appears (not wired yet — expected)
- [ ] Click **Create rule** — verify rule appears in the list with
correct name, tags, and schedule
- [ ] Verify the primary **Create rule** button (filled, left of "Create
in flyout") still navigates to the full-page form

### Edit flow

- [ ] Click the edit (pencil) icon on an existing rule — flyout opens in
edit mode, pre-populated with that rule's values
- [ ] Modify the rule name in Details & Artifacts
- [ ] Click **Save rule** — verify the rule updates and the change
appears in the list

### YAML preview

- [ ] Toggle YAML mode in the flyout header — stepper collapses;
CodeEditor shows read-only rule YAML
- [ ] Fill in form fields, toggle YAML mode — verify YAML reflects the
current values

### Edge cases

- [ ] Open the Sandbox, edit the query, close without clicking **Apply
changes** — verify the Alert Condition step still shows the previously
committed query
- [ ] Verify **Next** is disabled while the Sandbox is open

---------

Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Bailey Cash <bailey.cash@elastic.co>
kelvtanv pushed a commit to kelvtanv/kibana that referenced this pull request May 14, 2026
…m state (elastic#268774)

## Summary

Closes elastic#268771

Adds `ComposeDiscoverFlyout`, the stepped Edit Form flyout for v2 rule
authoring. This is PR B in a series; PR A (elastic#268739) adds
`HorizontalMinimalStepper` as a foundation.

**What's in this PR:**
- `ComposeDiscoverFlyout` component with a 3-step form: **Alert
Condition → Details & Artifacts → Notifications**
- Complete RHF migration: all submitted values (`name`, `tags`,
`schedule`, `lookback`, `timeField`, `grouping`, `query`, delays) live
in `useForm<FormValues>()`; reducer owns only UI state (`step`,
`childOpen`, `yamlMode`, `queryCommitted`, etc.)
- **Create mode** — wired to `useCreateRule` mutation; entry point is
the new **"Create in flyout"** button on the rules list (alongside
**"Create rule"** which still navigates to the full-page form)
- **Edit mode** — wired to `useUpdateRule`; entry point is the edit icon
on any rule row (replaces `QuickEditRuleFlyout`)
- **Discover Sandbox** — child flyout with a single ES|QL editor, Lens
histogram, and data grid; opens via "Open query editor" / "Edit query"
in the Alert Condition step
- **YAML preview** — toggle in header shows read-only CodeEditor with
rule YAML; editing round-trip is deferred
- Reuses `RuleDetailsFieldGroup` and `RuleExecutionFieldGroup` from PR
elastic#268164

**What's NOT in this PR (deferred):**
- No Recovery Condition step (PR E)
- No tracking toggle or split-query support
- Notifications step is a placeholder callout
- Runbook URL / Dashboard link are disabled stubs
- Sandbox UI unpolished (redesign in PR C)
- YAML round-trip editing deferred

### State architecture

```
useForm<FormValues>()   ← submitted values: name, tags, schedule, query, timeField, grouping, delays
useReducer(uiReducer)   ← UI only: step, childOpen, fullQuery, yamlMode, queryCommitted, sandboxDateStart/End
```

One bridge: when the user clicks **Apply changes** in the Sandbox, a
`useEffect` syncs `uiState.fullQuery → setValue('evaluation.query.base',
...)`. Everything else writes directly to RHF via `useFormContext()`.

---

## Test plan

### Prerequisites

Start Elasticsearch:
```bash
cd ~/__projects__/kibana-dev/pr-b-rhf-form
node scripts/es snapshot --license=trial
```

Start Kibana (Node 24 required):
```bash
export NVM_DIR="$HOME/.nvm" && source "$NVM_DIR/nvm.sh" && nvm use 24
KBN_USE_RSPACK=true yarn start \
  --server.port=5603 \
  --server.basePath=/ifh \
  --server.rewriteBasePath=true
```

`config/kibana.dev.yml`:
```yaml
xpack.alerting_v2.enabled: true
dev.basePathProxyTarget: 5604
mockIdpPlugin.enabled: false
```

Navigate to: `http://localhost:5603/ifh/app/management/alertingV2/rules`

---

### Create flow

- [ ] Click **Create in flyout** (next to the primary "Create rule"
button) — flyout opens in create mode; Discover Sandbox opens alongside
it automatically
- [ ] Verify 3 steps in the header stepper: Alert Condition, Details &
Artifacts, Notifications
- [ ] In the Sandbox: type a query (e.g. `FROM logs-* | STATS count =
COUNT(*) BY host.name | WHERE count > 0`), click **Search** — verify
histogram and results grid appear
- [ ] Click **Apply changes** — Sandbox closes; Alert Condition step
shows the committed query summary
- [ ] Change the **Time field** dropdown — verify it reflects in the
form
- [ ] Adjust **schedule** and **lookback** via the schedule fields
- [ ] Click **Next** → **Details & Artifacts**: fill in rule name and
tags via the standard field group
- [ ] Click **Next** → **Notifications**: verify placeholder callout
appears (not wired yet — expected)
- [ ] Click **Create rule** — verify rule appears in the list with
correct name, tags, and schedule
- [ ] Verify the primary **Create rule** button (filled, left of "Create
in flyout") still navigates to the full-page form

### Edit flow

- [ ] Click the edit (pencil) icon on an existing rule — flyout opens in
edit mode, pre-populated with that rule's values
- [ ] Modify the rule name in Details & Artifacts
- [ ] Click **Save rule** — verify the rule updates and the change
appears in the list

### YAML preview

- [ ] Toggle YAML mode in the flyout header — stepper collapses;
CodeEditor shows read-only rule YAML
- [ ] Fill in form fields, toggle YAML mode — verify YAML reflects the
current values

### Edge cases

- [ ] Open the Sandbox, edit the query, close without clicking **Apply
changes** — verify the Alert Condition step still shows the previously
committed query
- [ ] Verify **Next** is disabled while the Sandbox is open

---------

Co-authored-by: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Co-authored-by: kibanamachine <42973632+kibanamachine@users.noreply.github.com>
Co-authored-by: Bailey Cash <bailey.cash@elastic.co>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author:actionable-obs PRs authored by the actionable obs team backport:skip This PR does not require backporting release_note:skip Skip the PR/issue when compiling release notes v9.5.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Alerting v2] HorizontalMinimalStepper — compact step indicator component

6 participants