Skip to content

[Alerting V2] [UI] Query Sandbox layout — in-editor toolbar, resizable editor/results split, full-height flyout #280866

Description

@baileycash-elastic

Outcome

The ES|QL Query Sandbox uses the in-editor toolbar layout from design: Search and the time controls sit inside the bordered editor panel above the Monaco area, the editor and results are split by an EuiResizableContainer, and the whole sandbox fills the flyout height instead of floating above the footer.

This is layout/styling only. It is split out from the AlertingDateRangePicker extraction (elastic/rna-program#527), which ships separately.

Open decision (blocking)

Where does the split-query control live? Today it is passed into the sandbox via the headerActions prop and renders as a "Split base and alert" button at the end of the in-editor toolbar. The design mock shows a settings gear outside the editor instead.

  • Option A — keep it in the in-editor toolbar (current behavior, no change)
  • Option B — move it into a settings menu/popover anchored outside the editor panel, which likely retires or repurposes the headerActions slot

This is the next iteration of split query. Everything else below is independent of this choice.

Needs UX sign-off

Switching from the expanding editor to EuiResizableContainer changes how scrolling works:

  • Before — the editor grew (native resize grip, 200px default up to 600px max) and the whole sandbox scrolled as one surface inside the flyout body.
  • Now — the flyout body itself does not scroll (.euiFlyoutBody__overflow is overflow: hidden so the layout can fill the flyout). The editor pane and the results pane each scroll independently, and the divider redistributes space between them.

Believed acceptable since both regions stay reachable, but it should be an explicit design call rather than an implementation side effect.

Decisions made

In-editor toolbar

Controls move from a row above the editor to inside the bordered editor panel, directly above Monaco. Order, left to right:

  1. Search (primary action, leftmost)
  2. Time field select
  3. Date range picker (AlertingDateRangePicker, width="auto")
  4. headerActions slot (currently split query — see open decision)

The toolbar row is pinned with flex-grow: 0 / flex-shrink: 0 so dragging the resize handle only changes the Monaco viewport, never the control row. The row uses wrap, so on narrow flyouts controls wrap to a second line and the row grows by content — intentional, and distinct from resize behavior.

CPS picker and the split-query tab bar stay outside the editor panel, above it.

Resizable container

Replace the native CSS resize: vertical shell (a raw div with resize / min-height / max-height) with a vertical EuiResizableContainer:

  • Top panel — bordered editor panel, initialSize={40}, minSize = MIN_EDITOR_HEIGHT
  • EuiResizableButton between the panels
  • Bottom panel — results (validation errors, result count, empty/loading/error states, chart, data grid), initialSize={60}, minSize="20%", scrolls internally

The browser-native resize grip in the editor's bottom-right corner is removed (deleted, not hidden) in favor of the EUI drag handle.

Full-height sandbox

The container was initially a fixed 560px, which left the sandbox floating above the flyout footer. It now fills the flyout, following the pattern already used by the yaml editor in compose_discover_flyout.tsx:

  • EuiFlyoutBody gets euiFullHeight() plus .euiFlyoutBody__overflow / .euiFlyoutBody__overflowContent overrides so it becomes a flex column with min-height: 0
  • Sandbox root is a flex column filling that body
  • Help text, CPS picker, and tabs form a fixed-size header block
  • EuiResizableContainer takes the remaining height

Padding

  • Editor panel — paddingSize="s" to paddingSize="m", per UX request for a wider inset around the toolbar (especially top and left). Asymmetric padding would need theme-token CSS rather than the paddingSize prop.
  • Results panel — paddingSize="none" to paddingSize="s" so validation callouts, the chart, and the grid are not flush against the pane edges.

Split-query behavior (verified)

The base/alert/recovery split relies on an auto-scroll that had to survive the new layout. In compose_discover_tabs.tsx, switching to the alert or recovery tab calls blockEditorRef.current.scrollIntoView({ behavior: 'smooth', block: 'nearest' }) so the editable block scrolls past the locked base query.

Manually confirmed working in a POC. This holds because the immediate scroll parent (the editor body div) keeps overflow: auto through the rework, and the onAlertEditorMount / onRecoveryEditorMount completion handlers are untouched. The related concern that SPLIT_EDITOR_CONTAINER_STYLES (height: 100%) might fail to resolve against a now flex-derived parent — collapsing the block wrapper to MIN_EDITOR_HEIGHT — did not materialize.

Worth re-checking if the layout changes again: the flyout body is no longer a fallback scroller, so the editor pane is the only scroll surface for this interaction.

Minor, unrelated to scroll: EuiResizableButton takes focus on click, so grabbing the divider blurs Monaco. kbn-resizable-layout carries an explicit workaround for the same behavior if it proves annoying.

Acceptance Criteria

  • Search, time field, and date range picker render inside the bordered editor panel, above Monaco, in that order
  • Toolbar row height is unaffected by dragging the resize divider
  • Editor and results are split by EuiResizableContainer; the native CSS resize grip is gone
  • Sandbox fills the flyout height with no gap above the footer
  • Editor panel uses paddingSize="m"; results panel uses paddingSize="s"
  • Base/alert/recovery auto-scroll and ES|QL completions still work in split mode
  • Split-query control placement resolved (see open decision)
  • UX sign-off on the independent-pane scrolling tradeoff

Implementation notes

Touched files, all in @kbn/alerting-v2-rule-form:

Cleanup to fold in before the PR:

  • Layout is currently expressed as inline React.CSSProperties objects. Repo convention is Emotion (@emotion/react) with EUI theme tokens; convert these and replace hardcoded values with tokens where one exists.
  • CpsPicker returns an EuiFlexItem but is now rendered directly inside a plain div, so it is an orphan flex item outside any EuiFlexGroup. Either wrap it or change what the component returns.
  • Existing 23 sandbox tests pass, but only a label was updated. Add assertions for querySandboxResizableContainer, querySandboxEditorPanel, and querySandboxResultsPanel.
  • Confirm the default 40/60 pane split feels right with a short query; a two-line query currently leaves visible empty space under the code because Monaco fills the whole editor pane.

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    Feature:AlertingV2Team:ResponseOpsPlatform ResponseOps team (formerly the Cases and Alerting teams) t//Team:actionable-obsFormerly "obs-ux-management", responsible for SLO, o11y alerting, significant events, & synthetics.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions