style(web): move the row-count select into the card header
It was sitting in a strip below the heading with a "Show" label and a "newest first" hint — three lines of chrome for one control. The select now lives at the right end of the card's own header bar (`margin-left:auto` inside the flex h2), compact and case-normal so it reads as a control and does not grow the bar. Label and hint are gone; the header text names the card, the values speak for themselves, and screen readers keep the `aria-label`.
This commit is contained in:
+3
-3
@@ -295,9 +295,9 @@ Gitea at most one call per 10s window; the VM columns are re-read on every
|
|||||||
refresh.
|
refresh.
|
||||||
|
|
||||||
Rows are ordered **newest first** (a queued run, which has no start time yet,
|
Rows are ordered **newest first** (a queued run, which has no start time yet,
|
||||||
sorts above everything; ties break on Gitea's run id). The **Show** selector in
|
sorts above everything; ties break on Gitea's run id). The row-count dropdown at
|
||||||
the card's header picks how many to list — 10 / 25 / 50 / 100, default from
|
the right end of the card's header bar picks how many to list — 10 / 25 / 50 /
|
||||||
`[web].executions_limit` (10). The choice rides on the card's own polling URL
|
100, default from `[web].executions_limit` (10). The choice rides on the card's own polling URL
|
||||||
(`/executions?limit=N`), so it survives every 5s refresh with no client-side
|
(`/executions?limit=N`), so it survives every 5s refresh with no client-side
|
||||||
state; a value set in the config outside those four is offered as an extra
|
state; a value set in the config outside those four is offered as an extra
|
||||||
option rather than dropped.
|
option rather than dropped.
|
||||||
|
|||||||
@@ -281,17 +281,19 @@ dd code, dd .mono { overflow-wrap: anywhere; }
|
|||||||
/* A row of buttons (e.g. Purge / Empty all) that wraps on narrow cards. */
|
/* A row of buttons (e.g. Purge / Empty all) that wraps on narrow cards. */
|
||||||
.btn-row { display: flex; flex-wrap: wrap; gap: 0.5rem; }
|
.btn-row { display: flex; flex-wrap: wrap; gap: 0.5rem; }
|
||||||
|
|
||||||
/* Small control strip under a card's heading (Executions row count): right
|
/* A control living inside a card's header bar (Executions row count), pushed to
|
||||||
* aligned so it reads as a view option, not as part of the data below. */
|
* the bar's right end. Compact and case-normal so it reads as a control rather
|
||||||
.card-toolbar {
|
* than part of the uppercase heading text, and short enough not to grow the
|
||||||
display: flex;
|
* bar's height. */
|
||||||
flex-wrap: wrap;
|
.head-select {
|
||||||
align-items: center;
|
margin-left: auto;
|
||||||
justify-content: flex-end;
|
padding: 0.1rem 0.35rem;
|
||||||
gap: 0.5rem;
|
font-size: 0.8rem;
|
||||||
margin: -0.35rem 0 0.7rem;
|
line-height: 1.2;
|
||||||
|
text-transform: none;
|
||||||
|
letter-spacing: normal;
|
||||||
|
color: var(--text);
|
||||||
}
|
}
|
||||||
.card-toolbar select { padding: 0.2rem 0.4rem; }
|
|
||||||
|
|
||||||
/* Per-template expandable backup list (Templates panel). */
|
/* Per-template expandable backup list (Templates panel). */
|
||||||
.backups-details > summary {
|
.backups-details > summary {
|
||||||
|
|||||||
@@ -11,15 +11,18 @@
|
|||||||
scrolled out of the window (or that no run ever claimed) keeps its row and
|
scrolled out of the window (or that no run ever claimed) keeps its row and
|
||||||
its Remove button.
|
its Remove button.
|
||||||
|
|
||||||
The row-count selector re-fetches the card with ``?limit=N``, and the card it
|
The row-count selector sits in the card's own header bar (right end) and
|
||||||
renders carries that same limit on its own polling URL -- that is what makes
|
re-fetches the card with ``?limit=N``; the card it renders carries that same
|
||||||
the choice survive the 5s refresh without any client-side state.
|
limit on its polling URL, which is what makes the choice survive the 5s
|
||||||
|
refresh without any client-side state. It carries no visible label -- the
|
||||||
|
header text names the card and the values are self-evident -- so screen
|
||||||
|
readers get ``aria-label`` instead.
|
||||||
#}
|
#}
|
||||||
<section class="card card--wide" id="executions-card" hx-get="/executions?limit={{ limit }}" hx-trigger="every 5s, ci:refresh from:body" hx-swap="outerHTML">
|
<section class="card card--wide" id="executions-card" hx-get="/executions?limit={{ limit }}" hx-trigger="every 5s, ci:refresh from:body" hx-swap="outerHTML">
|
||||||
<h2><svg class="icon" aria-hidden="true"><use href="#i-play"></use></svg>Executions</h2>
|
<h2>
|
||||||
<div class="card-toolbar">
|
<svg class="icon" aria-hidden="true"><use href="#i-play"></use></svg>Executions
|
||||||
<label for="executions-limit">Show</label>
|
<select id="executions-limit" name="limit" class="head-select"
|
||||||
<select id="executions-limit" name="limit" aria-label="Number of executions to show"
|
aria-label="Number of executions to show"
|
||||||
hx-get="/executions" hx-target="#executions-card" hx-swap="outerHTML" hx-trigger="change">
|
hx-get="/executions" hx-target="#executions-card" hx-swap="outerHTML" hx-trigger="change">
|
||||||
{% for choice in limit_choices %}
|
{% for choice in limit_choices %}
|
||||||
<option value="{{ choice }}" {{ 'selected' if choice == limit else '' }}>{{ choice }}</option>
|
<option value="{{ choice }}" {{ 'selected' if choice == limit else '' }}>{{ choice }}</option>
|
||||||
@@ -28,8 +31,7 @@
|
|||||||
<option value="{{ limit }}" selected>{{ limit }}</option>
|
<option value="{{ limit }}" selected>{{ limit }}</option>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
</select>
|
</select>
|
||||||
<span class="field-hint">newest first</span>
|
</h2>
|
||||||
</div>
|
|
||||||
{% if not backend_available %}
|
{% if not backend_available %}
|
||||||
<p class="notice notice-warn" role="alert">Backend unavailable (vmrun not found on this host).</p>
|
<p class="notice notice-warn" role="alert">Backend unavailable (vmrun not found on this host).</p>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|||||||
@@ -385,7 +385,10 @@ def test_default_limit_is_ten(tmp_path: Path, monkeypatch: pytest.MonkeyPatch) -
|
|||||||
|
|
||||||
assert limits == [10]
|
assert limits == [10]
|
||||||
assert '<option value="10" selected>10</option>' in resp.text
|
assert '<option value="10" selected>10</option>' in resp.text
|
||||||
assert "newest first" in resp.text
|
# The selector lives inside the card's header bar, not in a strip below it.
|
||||||
|
head = resp.text.split("</h2>", 1)[0]
|
||||||
|
assert "head-select" in head
|
||||||
|
assert "<label" not in resp.text
|
||||||
|
|
||||||
|
|
||||||
def test_selector_offers_the_choices_and_marks_the_current_one(
|
def test_selector_offers_the_choices_and_marks_the_current_one(
|
||||||
|
|||||||
Reference in New Issue
Block a user