fix(ui): correct Automations row semantics (#127252)

Amp-Thread-ID: https://ampcode.com/threads/T-01a021f4-b547-7788-a916-d4a94cbd3e3b

Co-authored-by: Amp <amp@ampcode.com>
This commit is contained in:
Peter Steinberger
2026-08-21 09:05:52 -07:00
committed by GitHub
parent 8531da1993
commit 7085604a26
4 changed files with 32 additions and 20 deletions
+5 -1
View File
@@ -63,7 +63,11 @@ suite.define(() => {
expect(response?.status()).toBe(200);
const row = page.locator(`[data-test-id="cron-row-${job.id}"]`);
await row.waitFor({ state: "visible", timeout: 10_000 });
await row.locator(".cron-table__name-text").click();
expect(await page.locator(".cron-table__head").getAttribute("role")).toBeNull();
expect(await row.getAttribute("role")).toBeNull();
const openTask = row.getByRole("button", { name: /Nightly digest/ });
await openTask.focus();
await page.keyboard.press("Enter");
const detail = page.locator('.cron-page[data-panel-mode="job"]');
await detail.waitFor({ state: "visible" });
+18 -2
View File
@@ -116,7 +116,22 @@ describe("cron view list pane", () => {
expect(onJobsFiltersReset).toHaveBeenCalledTimes(1);
});
it("renders table rows with schedule and status cells and selects on click", () => {
it("does not expose table rows without complete table semantics", () => {
const container = renderView({ jobs: [createJob("job-1")] });
for (const row of container.querySelectorAll('[role="row"]')) {
expect(row.closest('[role="table"], [role="grid"], [role="treegrid"]')).not.toBeNull();
expect(
Array.from(row.children).every((child) =>
child.matches(
'[role="cell"], [role="gridcell"], [role="columnheader"], [role="rowheader"]',
),
),
).toBe(true);
}
});
it("renders table rows with independent native buttons for opening tasks", () => {
const onSelectJob = vi.fn();
const job = createJob("job-1", {
trigger: { script: "json({ fire: true })" },
@@ -134,6 +149,7 @@ describe("cron view list pane", () => {
const rows = Array.from(container.querySelectorAll(".cron-table__row"));
expect(rows).toHaveLength(3);
expect(rows[0]?.getAttribute("role")).toBeNull();
expect(rows[0]?.textContent).toContain("Cron 0 9 * * *");
expect(rows[1]?.classList.contains("cron-table__row--paused")).toBe(true);
expect(rows[1]?.textContent).toContain("Paused");
@@ -150,7 +166,7 @@ describe("cron view list pane", () => {
"Trigger configured",
);
(rows[1] as HTMLElement).click();
getElement(rows[1] as Element, ".cron-table__name", HTMLButtonElement).click();
expect(onSelectJob).toHaveBeenCalledWith(paused);
});
+4 -16
View File
@@ -728,7 +728,7 @@ function renderJobsFilterPopover(props: CronProps, active: boolean) {
function renderJobsTable(props: CronProps, hasAnyJobsFilters: boolean) {
return html`
<div class="cron-table ${props.canManage ? "" : "cron-table--read-only"}">
<div class="cron-table__head" role="row">
<div class="cron-table__head">
<span>${t("cron.jobs.name")}</span>
<span>${t("cron.jobs.schedule")}</span>
<span>${t("cron.jobs.nextRun")}</span>
@@ -775,18 +775,10 @@ function renderJobRow(job: CronJob, props: CronProps) {
return html`
<div
class="cron-table__row ${job.enabled ? "" : "cron-table__row--paused"}"
role="button"
tabindex="0"
data-test-id=${`cron-row-${job.id}`}
@click=${() => props.onSelectJob(job)}
@keydown=${(e: KeyboardEvent) => {
if (e.key === "Enter" || e.key === " ") {
e.preventDefault();
props.onSelectJob(job);
}
}}
>
<span class="cron-table__name">
<button type="button" class="cron-table__name">
${renderJobStateIndicator(job)}
<span class="cron-table__name-copy">
<span class="cron-table__name-line">
@@ -814,17 +806,13 @@ function renderJobRow(job: CronJob, props: CronProps) {
`
: nothing}
</span>
</span>
</button>
${renderJobCell("cron-table__schedule", t("cron.jobs.schedule"), formatCronSchedule(job))}
${renderJobCell("cron-table__next", t("cron.jobs.nextRun"), nextRun)}
${renderJobCell("cron-table__last", t("cron.jobs.lastRun"), renderLastRunCell(job))}
${props.canManage
? html`
<span
class="cron-table__actions"
@click=${(e: Event) => e.stopPropagation()}
@keydown=${(e: Event) => e.stopPropagation()}
>
<span class="cron-table__actions" @click=${(e: Event) => e.stopPropagation()}>
<button
type="button"
class="btn btn--sm btn--ghost cron-row-run"
+5 -1
View File
@@ -324,7 +324,7 @@
}
.cron-table__row:hover,
.cron-table__row:focus-visible {
.cron-table__row:focus-within {
background: var(--bg-hover);
}
@@ -338,9 +338,13 @@
align-items: flex-start;
gap: 10px;
min-width: 0;
padding: 0;
border: 0;
color: var(--text-strong);
background: transparent;
font-size: 13px;
font-weight: 600;
text-align: left;
}
.cron-table__state {