Skip to content

Commit c1cbe80

Browse files
authored
Merge branch 'main' into chore/move-dashboard-and-lens-overlays
2 parents c4ce91e + 535e2c1 commit c1cbe80

2,746 files changed

Lines changed: 101227 additions & 48852 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.agents/skills/accessibility/references/components/index.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ Open the guide that matches the component(s) you are writing or refactoring. Rea
1212
| `interactive_components.md` | Names for interactive controls | `EuiBetaBadge`, `EuiButtonIcon`, `EuiComboBox`, `EuiSelect`, `EuiSuperSelect`, `EuiPagination`, `EuiTreeView`, `EuiBreadcrumbs` |
1313
| `overlays.md` | Modals, flyouts, popovers | `EuiModal`, `EuiFlyout`, `EuiFlyoutResizable`, `EuiConfirmModal`, `EuiPopover` |
1414
| `radio_groups.md` | Radio groups (`name` grouping) | `EuiRadio`, `EuiRadioGroup` |
15-
| `tooltip_icon.md` | Tooltip on icon button (no duplicate SR text) | `EuiToolTip`, `EuiButtonIcon` |
15+
| `tooltip_content.md` | No interactive elements in tooltip `content` / `title` | `EuiToolTip`, `EuiIconTip` |
16+
| `tooltip_icon.md` | Tooltip on icon button (wrap + no duplicate SR text, no native `title`) | `EuiToolTip`, `EuiButtonIcon` |
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
# EUI tooltip content: no interactive elements
2+
3+
**Applies to:** `EuiToolTip`, `EuiIconTip` — the `content` and `title` props
4+
5+
Tooltip `content` and `title` render inside a portal with `role="tooltip"`. The overlay only appears while the trigger is hovered or focused and is dismissed on blur, so any focusable element placed inside it is unreachable by keyboard and assistive-technology users. Use **`EuiPopover`** when the content needs to be interactive.
6+
7+
**Related guides:** **`overlays.md`** (`EuiPopover` for interactive content) · **`tooltip_icon.md`** (wrapping `EuiButtonIcon` with `EuiToolTip`) · **`icons_and_tooltips.md`** (`EuiIconTip` vs `EuiToolTip` + `EuiIcon`).
8+
9+
## Canonical usage
10+
11+
- `EuiToolTip` / `EuiIconTip` `content` and `title` may contain:
12+
- **Plain strings** (preferred — easy to localize and read).
13+
- **Non-interactive JSX** — text nodes, `<span>`, `<p>`, `EuiText`, `EuiIcon`, and the display-only badges/cards (`EuiBadge`, `EuiBetaBadge`, `EuiCard`) used **without** `onClick` / `href`.
14+
- They must **not** contain anything focusable:
15+
- Native `<a>`, `<button>`, `<input>`, `<select>`, `<textarea>`.
16+
- Interactive EUI components — `EuiLink`, `EuiButton`, `EuiButtonEmpty`, `EuiButtonIcon`, `EuiFieldText`, `EuiFieldNumber`, `EuiFieldSearch`, `EuiFieldPassword`, `EuiTextArea`, `EuiSelect`, `EuiSuperSelect`, `EuiComboBox`, `EuiSelectable`, `EuiSwitch`, `EuiCheckbox`, `EuiRadio`, `EuiRange`, `EuiDualRange`, `EuiColorPicker`, `EuiDatePicker`, `EuiSuperDatePicker`, `EuiFilterButton`, `EuiPagination`, `EuiTab`, `EuiTreeView`, `EuiContextMenuItem`, `EuiKeyPadMenuItem`, `EuiListGroupItem`, `EuiBreadcrumbs`, `EuiBasicTable`, `EuiInMemoryTable`, `EuiCheckableCard`, …
17+
- The rule searches recursively — interactive elements nested inside fragments, conditional renders (`cond && …`, `cond ? … : …`), or wrapper elements are reported too.
18+
- When users need to interact with the content (click a link, fill a field), switch the wrapper to **`EuiPopover`** triggered by an explicit click — never by hover.
19+
20+
### Manual-review cases (rule is silent)
21+
22+
- **Variable content**`content={tooltipContent}` / `title={titleNode}` is intentionally skipped because it cannot be statically analyzed. Trace the variable and verify it never holds focusable JSX.
23+
- **Conditionally-interactive components**`EuiBadge`, `EuiBetaBadge`, `EuiCard` are excluded from the rule because they render as a plain element without `onClick` / `href`. As soon as you add `onClick` or `href`, they become focusable and the same restriction applies — move the interaction out of the tooltip.
24+
25+
## Examples
26+
27+
```tsx
28+
<EuiToolTip content="Just text">
29+
<EuiButton>Hover me</EuiButton>
30+
</EuiToolTip>
31+
32+
<EuiToolTip content={<EuiText><p>Description</p></EuiText>}>
33+
<EuiButton>Hover me</EuiButton>
34+
</EuiToolTip>
35+
36+
<EuiIconTip content="Informational text" type="info" />
37+
38+
// Display-only badge is fine
39+
<EuiToolTip content={<EuiBadge>v2.0</EuiBadge>}>
40+
<EuiButton>Hover me</EuiButton>
41+
</EuiToolTip>
42+
```
43+
44+
## Common mistakes
45+
46+
```tsx
47+
// WRONG — link inside tooltip is not keyboard-reachable
48+
<EuiToolTip content={<EuiLink href="/docs">Learn more</EuiLink>}>
49+
<EuiButton>Hover me</EuiButton>
50+
</EuiToolTip>
51+
52+
// RIGHT — switch to EuiPopover so the link participates in the focus order
53+
const [isOpen, setIsOpen] = useState(false);
54+
const togglePopover = () => setIsOpen((open) => !open);
55+
const closePopover = () => setIsOpen(false);
56+
57+
<EuiPopover
58+
button={<EuiButton onClick={togglePopover}>More info</EuiButton>}
59+
isOpen={isOpen}
60+
closePopover={closePopover}
61+
>
62+
<EuiLink href="/docs">Learn more</EuiLink>
63+
</EuiPopover>
64+
65+
// WRONG — button inside `EuiIconTip` content
66+
<EuiIconTip content={<EuiButton>Click</EuiButton>} type="info" />
67+
68+
// RIGHT — keep the icon tip purely informational
69+
<EuiIconTip content="Informational text" type="info" />
70+
71+
// WRONG — interactive element inside `title` is also reported
72+
<EuiToolTip title={<EuiLink href="#">Learn more</EuiLink>} content="Info">
73+
<EuiButton>Hover</EuiButton>
74+
</EuiToolTip>
75+
76+
// WRONG — interactive child wrapped in a fragment is reported recursively
77+
<EuiToolTip content={<><span>Text</span><EuiLink href="#">Link</EuiLink></>}>
78+
<EuiButton>Hover</EuiButton>
79+
</EuiToolTip>
80+
81+
// WRONG — interactive child behind `cond && …` is reported
82+
<EuiToolTip content={<span>{cond && <EuiLink href="#">Link</EuiLink>}</span>}>
83+
<EuiButton>Hover</EuiButton>
84+
</EuiToolTip>
85+
86+
// WRONG — interactive child inside a ternary is reported
87+
<EuiToolTip content={cond ? <EuiLink href="#">Link</EuiLink> : null}>
88+
<EuiButton>Hover</EuiButton>
89+
</EuiToolTip>
90+
91+
// WRONG — conditionally-interactive badge with onClick becomes focusable
92+
<EuiToolTip content={<EuiBadge onClick={onClick}>Open</EuiBadge>}>
93+
<EuiButton>Hover</EuiButton>
94+
</EuiToolTip>
95+
```

.agents/skills/accessibility/references/components/tooltip_icon.md

Lines changed: 31 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -2,49 +2,58 @@
22

33
**Applies to:** `EuiToolTip`, `EuiButtonIcon`
44

5-
When **`EuiToolTip`** wraps **`EuiButtonIcon`** and the tooltip **`content`** matches the button's **`aria-label`**, assistive technology can announce the same text twice. Use **`disableScreenReaderOutput`** so the tooltip stays available to sighted users while screen readers hear the name once.
5+
Every **`EuiButtonIcon`** needs two things:
66

7-
**Related guides:** **`focus_and_keyboard.md`** (tooltip anchors / `tabIndex`) · **`icons_and_tooltips.md`** (`EuiIconTip` vs `EuiToolTip` + `EuiIcon`).
7+
1. **A visible tooltip for sighted users** — wrap the button with **`EuiToolTip`**. Do **not** use the native **`title`** prop on `EuiButtonIcon`; browser tooltips are unstyled, have no delay control, and are not reliably announced by screen readers across browser / AT combinations.
8+
2. **An accessible name for assistive technology** — keep **`aria-label`** on the button.
89

9-
## Canonical usage
10+
When the tooltip **`content`** and the button's **`aria-label`** match (same string, same variable, or same `i18n` call), also set **`disableScreenReaderOutput`** on `EuiToolTip` so screen readers announce the name once instead of twice.
1011

11-
- **`content`** equals **`aria-label`** (same string or same variable / same `i18n` call) → set **`disableScreenReaderOutput`** on **`EuiToolTip`**.
12-
- **`content`** differs from **`aria-label`** → no extra prop; both will be announced as intended.
13-
- Child is not **`EuiButtonIcon`** → this pattern doesn't apply; check the related guides above.
12+
**Related guides:** **`focus_and_keyboard.md`** (tooltip anchors / `tabIndex`) · **`icons_and_tooltips.md`** (`EuiIconTip` vs `EuiToolTip` + `EuiIcon`) · **`tooltip_content.md`** (no interactive elements inside tooltip `content` / `title`).
1413

15-
Prefer a single **`i18n.translate`** call (same id + `defaultMessage`) for both **`content`** and **`aria-label`** so the strings can't drift apart.
14+
## Canonical usage
1615

17-
For `{...tooltipProps}` spreads, merge **`disableScreenReaderOutput`** at the callsite or in the spread source.
16+
1. Wrap every `EuiButtonIcon` with `EuiToolTip`. Remove any `title` prop from the button.
17+
2. Pass the same localized string to `EuiToolTip` `content` and the button's `aria-label`. Prefer a single **`i18n.translate`** call (same id + `defaultMessage`) referenced from both places so the strings cannot drift apart.
18+
3. When `content` and `aria-label` match → add **`disableScreenReaderOutput`** on `EuiToolTip`.
19+
4. When `content` and `aria-label` intentionally differ (the tooltip elaborates beyond the name) → do **not** add `disableScreenReaderOutput`; both will be announced as intended.
1820

1921
## Examples
2022

2123
```tsx
22-
<EuiToolTip
23-
content={i18n.translate('filter.add', { defaultMessage: 'Add filter' })}
24-
disableScreenReaderOutput
25-
>
24+
const editLabel = i18n.translate('myFeature.editItem', {
25+
defaultMessage: 'Edit item',
26+
});
27+
28+
<EuiToolTip content={editLabel} disableScreenReaderOutput>
2629
<EuiButtonIcon
27-
iconType="plusInCircle"
28-
aria-label={i18n.translate('filter.add', { defaultMessage: 'Add filter' })}
29-
onClick={onAdd}
30+
iconType="pencil"
31+
aria-label={editLabel}
32+
onClick={onEdit}
3033
/>
3134
</EuiToolTip>
3235
```
3336

3437
## Common mistakes
3538

3639
```tsx
37-
// WRONG — screen reader announces "Add filter" twice
38-
<EuiToolTip content={label}>
39-
<EuiButtonIcon iconType="plusInCircle" aria-label={label} onClick={onAdd} />
40+
// WRONG — no visible tooltip for sighted users
41+
<EuiButtonIcon iconType="trash" aria-label="Delete" onClick={onDelete} />
42+
43+
// WRONG — native `title` is not reliably announced by screen readers and has no consistent visual styling
44+
<EuiButtonIcon title="Delete" aria-label="Delete" iconType="trash" onClick={onDelete} />
45+
46+
// WRONG — tooltip and `aria-label` without `disableScreenReaderOutput` will lead to SR announcement duplication
47+
<EuiToolTip content="Delete">
48+
<EuiButtonIcon iconType="trash" aria-label="Delete" onClick={onDelete} />
4049
</EuiToolTip>
4150

42-
// RIGHT
43-
<EuiToolTip content={label} disableScreenReaderOutput>
44-
<EuiButtonIcon iconType="plusInCircle" aria-label={label} onClick={onAdd} />
51+
// RIGHT — wrap, keep `aria-label`, and add `disableScreenReaderOutput` when `content` matches
52+
<EuiToolTip content="Delete" disableScreenReaderOutput>
53+
<EuiButtonIcon iconType="trash" aria-label="Delete" onClick={onDelete} />
4554
</EuiToolTip>
4655

47-
// WRONG — different ids, strings may drift apart
56+
// WRONG — different i18n ids may drift apart
4857
content={i18n.translate('a.tooltip', { defaultMessage: 'Add' })}
4958
aria-label={i18n.translate('a.button', { defaultMessage: 'Add' })}
5059

.agents/skills/accessibility/references/eslint.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,4 +15,6 @@ Secondary path: when starting from a rule id, jump to the canonical **component
1515
| `@elastic/eui/require-aria-label-for-modals` | [`components/overlays.md`](components/overlays.md) | `{...props}` hides wiring; no visible title without UX change — escalate. |
1616
| `@elastic/eui/require-table-caption` | [`components/data_tables.md`](components/data_tables.md) | `tableCaption` only via `{...tableProps}` — fix at source; no duplicate conflicting captions. |
1717
| `@elastic/eui/sr-output-disabled-tooltip` | [`components/tooltip_icon.md`](components/tooltip_icon.md) | `EuiToolTip` props from spread; child not `EuiButtonIcon`. |
18+
| `@elastic/eui/tooltip-button-icon-wrap` | [`components/tooltip_icon.md`](components/tooltip_icon.md) | `{...props}` without an explicit `title` is silently skipped — verify the spread does not omit a tooltip. No `aria-label` on the button → autofix can't run; supply both `aria-label` and `EuiToolTip` `content`. |
1819
| `@elastic/eui/tooltip-focusable-anchor` | [`components/focus_and_keyboard.md`](components/focus_and_keyboard.md) | `{...anchorProps}` or unknown custom anchor. |
20+
| `@elastic/eui/tooltip-no-interactive-content` | [`components/tooltip_content.md`](components/tooltip_content.md) | Variable content (`content={var}` / `title={var}`) is silently skipped — trace and verify. `EuiBadge` / `EuiBetaBadge` / `EuiCard` with `onClick` / `href` become focusable and need migration to `EuiPopover`. |

.agents/skills/evals-write-spec/SKILL.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ evaluate.describe('Suite name', { tag: tags.serverless.observability.complete },
2424

2525
evaluate('test name', async ({ executorClient, connector }) => {
2626
await executorClient.runExperiment(
27-
{ dataset, task },
27+
{ datasets: [dataset], task },
2828
evaluators
2929
);
3030
});
@@ -202,7 +202,7 @@ export function createEvaluateDataset({
202202
return async ({ dataset }) => {
203203
await executorClient.runExperiment(
204204
{
205-
dataset,
205+
datasets: [dataset],
206206
task: async ({ input }) => {
207207
const response = await chatClient.converse({ messages: [{ message: input.question }] });
208208
return { messages: response.messages, steps: response.steps };

.agents/skills/evals-write-spec/references/evaluator-patterns.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ type MyTaskOutput = TaskOutput & {
2020
};
2121

2222
await executorClient.runExperiment(
23-
{ dataset, task },
23+
{ datasets: [dataset], task },
2424
selectEvaluators<MyExample, MyTaskOutput>([
2525
{
2626
name: 'NonEmptyDocuments',
@@ -246,7 +246,7 @@ A common pattern passes both CODE and LLM evaluators to `runExperiment`:
246246

247247
```ts
248248
await executorClient.runExperiment(
249-
{ dataset, task },
249+
{ datasets: [dataset], task },
250250
[
251251
createCriteriaEvaluator({ evaluators }),
252252
createToolCallsEvaluator({ evaluators }),

.agents/skills/flaky-test-investigator/SKILL.md

Lines changed: 2 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -42,8 +42,6 @@ For every failure, try to retrieve:
4242
- **Server logs** (`kibana.log`, `elasticsearch.log` when present). Cross-reference the failure timestamp with any errors in the logs — a server-side 500 or unexpected warning is strong evidence the failure is a product bug, not a test bug.
4343
- **Full session trace** when the framework supports it (Scout / Playwright). Lets you scrub through every step, locator query, network call, and DOM snapshot.
4444

45-
How to actually find and download each artifact type is framework-specific — see "Retrieve failure artifacts" below.
46-
4745
Things to specifically check in the artifacts before forming a root-cause hypothesis:
4846

4947
- **Did the expected element render at all?** If yes and the selector missed it → flaky selector (Tier 2 fix territory). If no → real rendering / race / data issue (Tier 1 territory).
@@ -53,27 +51,9 @@ Things to specifically check in the artifacts before forming a root-cause hypoth
5351

5452
If artifacts are not available (expired, not uploaded, no `read_artifacts` token), say so in the report rather than fabricating a hypothesis. "Screenshot would have resolved this; not available" is a valid open question.
5553

56-
### Retrieve failure artifacts
57-
58-
The standard recipe is **list → filter by path → download by ID**, always scoped to the failed job's UUID. Two Buildkite gotchas to know about first:
59-
60-
- **Failed-attempt jobs are hidden by default.** `/builds/<n>` returns only the latest attempt; append `?include_retried_jobs=true` to find the original failing job (the one cited in `failed-test` comments). `retried` and `retried_in_job_id` link the two.
61-
- **Per-job artifacts use a different endpoint than build-wide artifacts.** If a build retried to green, failure artifacts only live on the failed job's listing (`bk artifacts list <build> -p <pipeline> --job-uuid <jobId>`). Don't conclude "no screenshot uploaded" until you've checked there.
62-
63-
**Scout** (`@kbn/scout-reporting`, not standard Playwright output — `playwright-report/`, `trace.zip`, and video are NOT published):
64-
65-
- `.scout/reports/scout-playwright-test-failures-<runId>/test-failures-summary.json` — maps test name → HTML report. Start here.
66-
- `.scout/reports/scout-playwright-test-failures-<runId>/<testId>.html` — self-contained: error, stdout, embedded screenshot. Usually sufficient on its own.
67-
- `.scout/reports/scout-playwright-test-failures-<runId>/scout-failures-<runId>.ndjson` — one record per failure (`id` = `<testId>`, `owner`, `location`, `error.*`) for programmatic use.
68-
- `**/.scout/test-artifacts/<test-slug>/test-failed-<N>.png` — plain Playwright screenshot; the PNG doesn't carry `<testId>`, so correlate via spec path.
69-
70-
**FTR** (a single content `<hash>` links every artifact for one failure):
71-
72-
- `target/test_failures/<jobId>_<hash>.{json,log,html}``.json` is source of truth; full Kibana/ES stdout lives in `system-out` (there is no separate `kibana.log`). Pull this first.
73-
- `<test-root>/screenshots/failure/*-<hash>.png` and `<test-root>/failure_debug/html/*-<hash>.html` — UI tests only; fetch only when the failure is UI-side.
74-
- `.es/*.log` — transport/cluster-shaped failures.
54+
### List failure artifacts
7555

76-
`target/test_failures/` is shared with Scout; filter by `.jobName` (e.g. `FTR Configs #90` vs `Scout Lane #12`) to keep only FTR. On Cloud FTR pipelines the layout differs: one self-contained HTML per failure at `<config-path-with-underscores>-<unix-timestamp>/html/<contentHash>.html` — no `target/test_failures/`, screenshot, or DOM artifacts.
56+
`bk artifacts list <build> -p <pipeline> --job-uuid <jobId> --json` returns a JSON listing of every artifact uploaded for the failing job. Pass `--job-uuid <jobId>` for the failed attempt (without it, `bk` only returns the latest attempt and hides retried failures). If a build retried to green, failure artifacts only live on the failed job's listing; don't conclude "no screenshot" until you've scoped to the right job UUID.
7757

7858
### Understand the scope
7959

0 commit comments

Comments
 (0)