# Test Run Stream

> A test run that streams. Run and Stop, each step appearing and updating in place as the server reports it, a live elapsed time and summary, and what the run saved, with its raw data behind a toggle.

Source: https://docs.nasaqui.com/components/test-run-stream

## Install

```bash
npx shadcn@latest add https://docs.nasaqui.com/r/test-run-stream.json
```

Try a source, pipeline or workflow once and watch it work. Each step shows up as soon as the server reports it,
spins while it runs, and settles to passed, failed or skipped with its duration, a count of what it produced and a
detail line. A live line under the header keeps time and counts. **Stop** aborts the run. Below the steps, what the
run saved (records, pages, messages) with a link, a few facts, a preview and the raw data as JSON.

Use `StepEditor`'s Test run tab when results come back all at once; use this when they stream.

## When to use

- "Test" on a data source, connector or plugin that fetches and saves things.
- A dry run of a workflow or pipeline where each step takes a while.

## When not to use

- A list of past runs: use `RunHistory`.
- Raw log lines: use `LogViewer`.

## Import

```tsx
import { TestRunStream } from "@fadymondy/nasaq";
```

## Quick start

With server-sent events:

```tsx
<TestRunStream
  controls={<Input ltr type="number" min={1} value={max} onChange={(e) => setMax(e.currentTarget.value)} className="w-20" />}
  run={(on, signal) => {
    const es = new EventSource(`/api/sources/${slug}/test-run?max=${max}`);
    signal.addEventListener("abort", () => es.close());
    es.addEventListener("step", (e) => on.step(JSON.parse(e.data)));
    es.addEventListener("saved", (e) => on.result(JSON.parse(e.data)));
    es.addEventListener("complete", () => { es.close(); on.done(); });
    es.addEventListener("error", () => { es.close(); on.fail("The connection closed."); });
  }}
/>
```

Or return a promise: resolving finishes the run, rejecting fails it.

## Anatomy

- `data-slot="test-run-stream"` (`data-state`: `idle`, `running`, `done`, `stopped`, `error`): a `section` named by
  its heading.
- Header: title, description, your `controls`, **Run test** / **Stop**, and **Clear** after a run.
- `test-run-summary`: a live status line ("Finished in 2.4 s · 4 passed · 1 skipped").
- An error message when the run fails.
- Steps: an `ol` of `test-run-step` rows (`data-status`).
- Saved: a list of `test-run-result` items with **Show raw data**.
- Before the first run, an empty state.

## API

| Prop | Type | Notes |
| --- | --- | --- |
| `run` | `(handlers, signal) => void \| Promise` | Starts a run. Report with `handlers`; stop when `signal` aborts. |
| `controls` | `ReactNode` | Options before the Run button. |
| `disabled` | `boolean` | Blocks starting a run. |
| `title`, `description` | `ReactNode` | `null` hides them. |
| `headingAs` | `ElementType` | Default `h3`. |
| `onStateChange` | `(state) => void` | |
| `labels` | `Partial<TestRunStreamLabels>` | `status` and `summary` merge with the built-in ones. |

`TestRunHandlers`: `step(step)` adds a step or updates the one with the same `id` (or `name`); `result(result)`;
`done()`; `fail(message)`. Calls after the run ended or was stopped are ignored, so a late event never mixes into the
next run.

`TestRunStep`: `{ id?, name, status, detail?, durationMs?, count?, error? }`. `status` is `running`, `ok`, `error` or
`skipped`; `success` and `failed` are understood, anything else counts as running.

`TestRunResult`: `{ id, title?, url?, meta?: string[], body?, raw? }`.

### Helpers

From `test-run-stream-logic.ts`, pure: `testRunStepStatus`, `upsertTestRunStep`, `settleTestRunSteps` (running →
skipped when a run ends), `testRunCounts`, `formatTestRunDuration` ("850 ms", "2.4 s", "1 m 05 s"). Types
`TestRunStep`, `TestRunStepStatus`, `TestRunResult`, `TestRunState`, `TestRunCounts`.

## Accessibility

- The summary line is a polite live region, so progress and the outcome are announced without reading every step.
- Each step says its state in words next to the icon; the icons are hidden from assistive tech.
- A failed run is an `alert`. Result links say they open in a new tab. **Show raw data** has `aria-expanded`.
- Stop takes the Run button's place, so focus stays put when a run starts or ends.

## RTL & i18n

English and Arabic strings are built in. Numbers follow the locale; durations, hashes and raw data stay left to
right; names and previews follow their own direction.

## Styling & tokens

`bg-card`, `border-border`, `rounded-card`. Step states use `Status` tones; a failed run uses `bg-nq-danger-soft`.

## Do / Don't

- Do send a step's start and its end with the same `id`, so the row updates instead of repeating.
- Do close your stream when `signal` aborts.
- Don't save anything for real in a test run; say so in the description.

## Related

`step-editor`, `run-history`, `log-viewer`, `code-block`, `status`.

## Lab

Workflow › Test Run Stream: Default, Failing, Arabic.

## Code

### React

```tsx
<TestRunStream
  controls={<Input ltr type="number" min={1} value={max} onChange={(e) => setMax(e.currentTarget.value)} className="w-20" />}
  run={(on, signal) => {
    const es = new EventSource(`/api/sources/${slug}/test-run?max=${max}`);
    signal.addEventListener("abort", () => es.close());
    es.addEventListener("step", (e) => on.step(JSON.parse(e.data)));
    es.addEventListener("saved", (e) => on.result(JSON.parse(e.data)));
    es.addEventListener("complete", () => { es.close(); on.done(); });
    es.addEventListener("error", () => { es.close(); on.fail("The connection closed."); });
  }}
/>
```

### shadcn

```tsx
<TestRunStream
  controls={<Input ltr type="number" min={1} value={max} onChange={(e) => setMax(e.currentTarget.value)} className="w-20" />}
  run={(on, signal) => {
    const es = new EventSource(`/api/sources/${slug}/test-run?max=${max}`);
    signal.addEventListener("abort", () => es.close());
    es.addEventListener("step", (e) => on.step(JSON.parse(e.data)));
    es.addEventListener("saved", (e) => on.result(JSON.parse(e.data)));
    es.addEventListener("complete", () => { es.close(); on.done(); });
    es.addEventListener("error", () => { es.close(); on.fail("The connection closed."); });
  }}
/>
```

### Vue

```vue
<script setup lang="ts">
import { NqInput, NqTestRunStream, type TestRunHandlers } from "@fadymondy/nasaq/vue";
import { ref } from "vue";

const slug = "news-feed";
const max = ref("5");

function run(on: TestRunHandlers, signal: AbortSignal) {
  const es = new EventSource(`/api/sources/${slug}/test-run?max=${max.value}`);
  signal.addEventListener("abort", () => es.close());
  es.addEventListener("step", (e) => on.step(JSON.parse((e as MessageEvent).data)));
  es.addEventListener("saved", (e) => on.result(JSON.parse((e as MessageEvent).data)));
  es.addEventListener("complete", () => {
    es.close();
    on.done();
  });
  es.addEventListener("error", () => {
    es.close();
    on.fail("The connection closed.");
  });
}
</script>

<template>
  <NqTestRunStream :run="run">
    <template #controls>
      <NqInput v-model="max" ltr type="number" min="1" class="w-20" />
    </template>
  </NqTestRunStream>
</template>
```

### Blade

```blade
<div class="max-w-3xl" x-data="{ max: 5 }">
    <x-nq::test-run-stream
        x-on:test-run-start="
            const on = $event.detail;
            const es = new EventSource(`/api/sources/blog/test-run?max=${max}`);
            on.signal.addEventListener(`abort`, () => es.close());
            es.addEventListener(`step`, (e) => on.step(JSON.parse(e.data)));
            es.addEventListener(`saved`, (e) => on.result(JSON.parse(e.data)));
            es.addEventListener(`complete`, () => { es.close(); on.done(); });
            es.addEventListener(`error`, () => { es.close(); on.fail(`The connection closed.`); });
        "
    >
        <x-slot:controls>
            <x-nq::field.input type="number" min="1" x-model="max" dir="ltr" class="w-20" aria-label="{{ \Nasaq\Nasaq::t('Maximum items', 'الحد الأقصى للعناصر') }}" />
        </x-slot:controls>
    </x-nq::test-run-stream>
</div>
```

### HTML + Alpine

```html
<div class="max-w-3xl" x-data="{ max: 5 }">
    <section data-slot="test-run-stream" x-data="nqTestRunStream(JSON.parse('{\u0022blocked\u0022:false,\u0022labels\u0022:{\u0022title\u0022:\u0022Test run\u0022,\u0022description\u0022:\u0022Runs once without publishing anything, and shows each step as it happens.\u0022,\u0022run\u0022:\u0022Run test\u0022,\u0022runAgain\u0022:\u0022Run again\u0022,\u0022stop\u0022:\u0022Stop\u0022,\u0022clear\u0022:\u0022Clear\u0022,\u0022idleTitle\u0022:\u0022No test run yet\u0022,\u0022idleBody\u0022:\u0022Run a test to watch each step as it happens.\u0022,\u0022steps\u0022:\u0022Steps\u0022,\u0022results\u0022:\u0022Saved\u0022,\u0022running\u0022:\u0022Running\u0022,\u0022stepsCount\u0022:\u0022{n} steps\u0022,\u0022finished\u0022:\u0022Finished in {time}\u0022,\u0022stopped\u0022:\u0022Stopped after {time}\u0022,\u0022failed\u0022:\u0022Failed after {time}\u0022,\u0022waiting\u0022:\u0022Waiting for the first step\\u2026\u0022,\u0022status\u0022:{\u0022running\u0022:\u0022Running\u0022,\u0022ok\u0022:\u0022Passed\u0022,\u0022error\u0022:\u0022Failed\u0022,\u0022skipped\u0022:\u0022Skipped\u0022},\u0022summary\u0022:{\u0022ok\u0022:\u0022{n} passed\u0022,\u0022error\u0022:\u0022{n} failed\u0022,\u0022skipped\u0022:\u0022{n} skipped\u0022},\u0022items\u0022:\u0022{n} items\u0022,\u0022untitled\u0022:\u0022Untitled\u0022,\u0022opensNewTab\u0022:\u0022(opens in a new tab)\u0022,\u0022showRaw\u0022:\u0022Show raw data\u0022,\u0022hideRaw\u0022:\u0022Hide raw data\u0022,\u0022raw\u0022:\u0022Raw data\u0022,\u0022noResults\u0022:\u0022Nothing was saved.\u0022}}'))" x-id="['nq-test-run']"
    x-bind:data-state="state"  x-bind:aria-labelledby="uid(`title`)"     x-on:test-run-start="const on = $event.detail;
            const es = new EventSource(`/api/sources/blog/test-run?max=${max}`);
            on.signal.addEventListener(`abort`, () =&gt; es.close());
            es.addEventListener(`step`, (e) =&gt; on.step(JSON.parse(e.data)));
            es.addEventListener(`saved`, (e) =&gt; on.result(JSON.parse(e.data)));
            es.addEventListener(`complete`, () =&gt; { es.close(); on.done(); });
            es.addEventListener(`error`, () =&gt; { es.close(); on.fail(`The connection closed.`); });" class="flex flex-col rounded-card border border-border bg-card">
    <header class="flex flex-wrap items-start gap-3 border-b border-border px-5 py-4">
                    <div class="flex min-w-48 flex-1 flex-col gap-1">
                                    <h3 x-bind:id="uid(`title`)" class="text-h4 text-foreground">Test run</h3>
                                                    <p class="text-body-sm text-muted-foreground">Runs once without publishing anything, and shows each step as it happens.</p>
                            </div>
                <div class="flex flex-wrap items-center gap-2">
            <input data-slot="input" type="number"
                    min="1" x-model="max" dir="ltr" aria-label="Maximum items" class="min-w-0 rounded-control border border-input bg-card px-3 text-body text-foreground min-h-[var(--nq-touch-min,0px)] transition-colors duration-150 ease-nq outline-none placeholder:text-muted-foreground focus-visible:border-nq-focus focus-visible:outline-1 focus-visible:outline-nq-focus data-invalid:border-nq-danger aria-invalid:border-nq-danger disabled:cursor-not-allowed disabled:opacity-50 pointer-coarse:text-[16px] h-control w-20">
            <button data-slot="button"
     type="button"                         data-action="stop" x-show="isRunning()" x-on:click="stop()" style="display: none" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 border-border bg-card text-foreground hover:bg-nq-hover h-control px-[var(--nq-control-pad)]">
        <svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <rect width="18" height="18" x="3" y="3" rx="2"/>
</svg>                Stop</button>
            <button data-slot="button"
     type="button"                         x-show="showClear()" x-on:click="clear()" style="display: none" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 text-foreground hover:bg-nq-hover h-control px-[var(--nq-control-pad)]">
        <svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M3 12a9 9 0 1 0 9-9 9.75 9.75 0 0 0-6.74 2.74L3 8"/>
  <path d="M3 3v5h5"/>
</svg>                Clear</button>
            <button data-slot="button"
     type="button"                         data-action="run" x-show="! isRunning()" x-bind:disabled="blocked" x-on:click="start()" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 bg-primary text-primary-foreground hover:bg-[color-mix(in_oklab,var(--nq-action)_88%,var(--nq-fg))] h-control px-[var(--nq-control-pad)]">
        <svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M5 5a2 2 0 0 1 3.008-1.728l11.997 6.998a2 2 0 0 1 .003 3.458l-12 7A2 2 0 0 1 5 19z"/>
</svg>                <span x-text="runLabel()">Run test</span></button>
        </div>
    </header>
    <div class="flex flex-col gap-4 px-5 py-4">
        <p role="status" data-slot="test-run-summary" x-text="line()" x-bind:class="isIdle() ? `sr-only` : `text-muted-foreground`" class="text-body-sm tabular-nums sr-only"></p>
        <p role="alert" dir="auto" x-show="error" x-text="error" style="display: none" class="rounded-control bg-nq-danger-soft px-3 py-2 text-body-sm text-nq-danger-text"></p>
        <div x-show="isIdle()">
            <div data-slot="empty-state" class="flex flex-col items-center justify-center gap-3 border border-dashed border-border px-6 py-12 text-center rounded-card">
            <span data-slot="state-icon" class="inline-flex size-10 items-center justify-center rounded-control border border-border bg-card [&amp;_svg]:size-5 text-muted-foreground">
            <svg aria-hidden="true" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M14 2v6a2 2 0 0 0 .245.96l5.51 10.08A2 2 0 0 1 18 22H6a2 2 0 0 1-1.755-2.96l5.51-10.08A2 2 0 0 0 10 8V2"/>
  <path d="M6.453 15h11.094"/>
  <path d="M8.5 2h7"/>
</svg>        </span>
        <div class="flex max-w-sm flex-col gap-1">
        <p class="text-label text-foreground">No test run yet</p>
                    <p class="text-body-sm text-muted-foreground">Run a test to watch each step as it happens.</p>
            </div>
    </div>
        </div>
        <div x-show="! isIdle()" style="display: none" class="flex flex-col gap-4">
            <div class="flex flex-col gap-2">
                <h4 x-bind:id="uid(`steps`)" class="text-caption text-muted-foreground">Steps</h4>
                <ol x-show="steps.length" x-bind:aria-labelledby="uid(`steps`)" style="display: none" class="divide-y divide-border rounded-control border border-border">
                    <template x-for="(step, i) in steps" x-bind:key="stepKey(step)">
                        <li data-slot="test-run-step" x-bind:data-status="stepStatus(step)" class="flex items-start gap-3 px-3 py-2.5">
                            <span aria-hidden="true" class="mt-0.5 flex size-5 shrink-0 items-center justify-center">
                                <svg data-slot="spinner" aria-hidden="true" x-show="stepIs(step, `running`)" class="size-4 animate-spin motion-reduce:animate-none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M21 12a9 9 0 1 1-6.219-8.56"/>
</svg>                                <span data-slot="status" data-tone="success" x-show="stepIs(step, `ok`)" style="display: none" class="inline-flex min-w-0 items-center gap-1.5 text-body-sm text-foreground">
            <svg aria-hidden="true" class="size-3.5 shrink-0 text-nq-success-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <path d="m9 12 2 2 4-4"/>
</svg>        <span class="truncate" ></span>
</span>
                                <span data-slot="status" data-tone="danger" x-show="stepIs(step, `error`)" style="display: none" class="inline-flex min-w-0 items-center gap-1.5 text-body-sm text-foreground">
            <svg aria-hidden="true" class="size-3.5 shrink-0 text-nq-danger-text" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
  <path d="m15 9-6 6"/>
  <path d="m9 9 6 6"/>
</svg>        <span class="truncate" ></span>
</span>
                                <span data-slot="status" data-tone="neutral" x-show="stepIs(step, `skipped`)" style="display: none" class="inline-flex min-w-0 items-center gap-1.5 text-body-sm text-foreground">
            <svg aria-hidden="true" class="size-3.5 shrink-0 text-muted-foreground" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <circle cx="12" cy="12" r="10"/>
</svg>        <span class="truncate" ></span>
</span>
                            </span>
                            <div class="flex min-w-0 flex-1 flex-col gap-0.5">
                                <div class="flex flex-wrap items-center gap-x-2 gap-y-1">
                                    <span class="text-caption text-muted-foreground tabular-nums" x-text="stepNumber(i)"></span>
                                    <span dir="auto" class="text-label text-foreground" x-text="step.name"></span>
                                    <span data-slot="badge"  style="display: none"     x-show="hasCount(step)" x-text="itemsText(step)" class="inline-flex h-5 shrink-0 items-center gap-1 whitespace-nowrap rounded-[4px] border px-1.5 text-caption font-medium [&_svg]:size-3 border-border bg-secondary text-foreground"></span>
                                </div>
                                <p dir="auto" x-show="step.detail" x-text="step.detail" style="display: none" class="text-caption text-muted-foreground"></p>
                                <p dir="auto" x-show="step.error" x-text="step.error" style="display: none" class="text-caption text-nq-danger-text"></p>
                            </div>
                            <span class="flex shrink-0 flex-col items-end gap-0.5">
                                <span x-text="labels.status[stepStatus(step)]" x-bind:class="stepStatusClass(step)" class="text-caption"></span>
                                <bdi dir="ltr" x-show="hasDuration(step)" x-text="duration(step)" style="display: none" class="text-caption text-muted-foreground tabular-nums"></bdi>
                            </span>
                        </li>
                    </template>
                </ol>
                <p x-show="waiting()" style="display: none" class="flex items-center gap-2 rounded-control border border-dashed border-border px-3 py-2.5 text-body-sm text-muted-foreground">
                    <svg data-slot="spinner" aria-hidden="true" class="size-4 animate-spin motion-reduce:animate-none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M21 12a9 9 0 1 1-6.219-8.56"/>
</svg>                    Waiting for the first step…
                </p>
            </div>
            <div x-show="showResults()" style="display: none" class="flex flex-col gap-2">
                <h4 x-bind:id="uid(`results`)" class="flex items-center gap-2 text-caption text-muted-foreground">
                    Saved
                    <span data-slot="badge"     x-text="resultCount()" class="inline-flex h-5 shrink-0 items-center gap-1 whitespace-nowrap rounded-[4px] border px-1.5 text-caption font-medium [&_svg]:size-3 border-border bg-secondary text-foreground">0</span>
                </h4>
                <ul x-show="results.length" x-bind:aria-labelledby="uid(`results`)" style="display: none" class="divide-y divide-border rounded-control border border-border">
                    <template x-for="r in results" x-bind:key="r.id">
                        <li data-slot="test-run-result" x-bind:data-result="r.id" class="flex flex-col gap-1.5 p-3">
                            <div class="flex min-w-0 items-start gap-2">
                                <template x-if="r.url">
                                    <a x-bind:href="r.url" target="_blank" rel="noopener noreferrer" dir="auto" class="min-w-0 flex-1 truncate text-label text-foreground underline decoration-nq-line underline-offset-4 hover:decoration-current">
                                        <span x-text="resultTitle(r)"></span>
                                        <svg aria-hidden="true" class="ms-1 inline size-3.5 align-[-2px] text-muted-foreground" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M15 3h6v6"/>
  <path d="M10 14 21 3"/>
  <path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6"/>
</svg>                                        <span class="sr-only">(opens in a new tab)</span>
                                    </a>
                                </template>
                                <template x-if="! r.url">
                                    <span dir="auto" class="min-w-0 flex-1 truncate text-label text-foreground" x-text="resultTitle(r)"></span>
                                </template>
                            </div>
                            <div x-show="hasMeta(r)" style="display: none" class="flex flex-wrap gap-x-3 gap-y-1 text-caption text-muted-foreground">
                                <template x-for="(m, mi) in (r.meta || [])" x-bind:key="mi"><bdi x-text="m"></bdi></template>
                            </div>
                            <p dir="auto" x-show="r.body" x-text="r.body" style="display: none" class="line-clamp-3 text-body-sm text-muted-foreground"></p>
                            <div x-show="hasRaw(r)" style="display: none" class="flex flex-col gap-2">
                                <button data-slot="button"
     type="button"                         x-bind:aria-expanded="isRaw(r.id) ? `true` : `false`" x-bind:aria-controls="rawId(r.id)" x-on:click="toggleRaw(r.id)" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 text-foreground underline decoration-nq-line underline-offset-4 hover:decoration-current h-auto px-0 w-fit">
        <span x-text="rawLabel(r.id)">Show raw data</span></button>
                                <template x-if="isRaw(r.id)">
                                    <div x-bind:id="rawId(r.id)">
                                        <figure data-slot="code-block" data-language="json" dir="ltr" x-data="nqCodeBlock(JSON.parse('{\u0022code\u0022:\u0022\u0022,\u0022language\u0022:\u0022json\u0022,\u0022marked\u0022:[],\u0022lineNumbers\u0022:false}'))" x-bind:data-highlighted="highlighted ? '' : null" x-effect="setCode(rawJson(r))"
    class="group/code relative m-0 overflow-hidden rounded-surface border border-border bg-nq-surface-soft text-start [--shiki-foreground:var(--nq-fg)] [--shiki-background:transparent] [--shiki-token-comment:var(--nq-fg-muted)] [--shiki-token-keyword:var(--nq-accent-text)] [--shiki-token-string:var(--nq-success-text)] [--shiki-token-string-expression:var(--nq-success-text)] [--shiki-token-constant:var(--nq-warning-text)] [--shiki-token-function:var(--nq-info-text)] [--shiki-token-parameter:var(--nq-fg-body)] [--shiki-token-punctuation:var(--nq-fg-muted)] [--shiki-token-link:var(--nq-info-text)]">
            <figcaption data-slot="code-block-header" class="flex h-row items-center justify-between gap-2 border-b border-border ps-3 pe-1.5 font-mono text-caption text-muted-foreground">
            <span class="truncate">Raw data</span>
                            <span class="contents" x-data="nqCopyButton(() => (code), 1500)">
    <button data-slot="copy-button"
     type="button"                         aria-label="Copy code" x-on:click="copy()" x-bind:data-copied="state === &#039;copied&#039; ? &#039;&#039; : null" class="inline-flex shrink-0 select-none items-center justify-center gap-2 whitespace-nowrap rounded-control border border-transparent font-sans text-label transition-colors duration-150 ease-nq min-h-[var(--nq-touch-min,0px)] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-nq-focus disabled:pointer-events-none disabled:opacity-50 data-disabled:pointer-events-none data-disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0 text-foreground hover:bg-nq-hover size-control-sm p-0 data-copied:text-nq-success-text">
        <svg aria-hidden="true" x-show="state !== 'copied'" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <rect width="14" height="14" x="8" y="8" rx="2" ry="2"/>
  <path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/>
</svg>        <svg aria-hidden="true" x-show="state === 'copied'" style="display: none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
  <path d="M20 6 9 17l-5-5"/>
</svg></button>
    <span data-slot="copy-button-status" role="status" aria-live="polite" class="sr-only"
        data-copied-label="Code copied to clipboard" data-failed-label="Could not copy"
        x-text="state === 'copied' ? $el.dataset.copiedLabel : state === 'failed' ? $el.dataset.failedLabel : ''"></span>
</span>
                    </figcaption>
        <pre data-slot="code-block-pre" role="region" tabindex="0" aria-label="Raw data"
        class="m-0 overflow-auto bg-transparent py-3 font-mono text-code text-[var(--shiki-foreground)] outline-none focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-nq-focus max-h-64"><code class="block w-max min-w-full"><span data-line="1"  class="flex min-h-[1lh] border-s-2 border-transparent pe-4 whitespace-pre ps-3"><span data-code-line></span></span></code></pre>
</figure>
                                    </div>
                                </template>
                            </div>
                        </li>
                    </template>
                </ul>
                <p x-show="! results.length" class="text-body-sm text-muted-foreground" style="display: none">Nothing was saved.</p>
            </div>
        </div>
    </div>
</section>
</div>
```
