mirror of
https://github.com/olehomelchenko/astrolabe.git
synced 2026-08-08 02:02:33 +00:00
Chart builder: drop unparseable expressions mid-edit, polite glyphed inline feedback
This commit is contained in:
@@ -368,6 +368,19 @@ bullet is the contract; cite it, not the source.)_
|
||||
other shows the text visually with no live role. Two live regions would announce the same
|
||||
message twice.
|
||||
|
||||
**Resolved — inline _live_ validation feedback is polite, glyphed, and field-linked.** A
|
||||
validator that re-checks on **every keystroke** (the Chart Builder expression inputs — a
|
||||
calculated field, a filter in expression mode) is **not** an assertive `alert`: that would
|
||||
interrupt on each character (APG _Alert_ "avoid frequent interruptions"; WCAG 2.2.4). It is a
|
||||
**polite `role="status"`** line, and severity reads from a **status glyph** (round error /
|
||||
triangle warning, arch 09 §5.2) **plus** colour — never colour alone (§3; WCAG 1.4.1), exactly
|
||||
like the guidance warnings above it. The owning `<input>` carries `aria-invalid` for the state
|
||||
and `aria-describedby` pointing at the message node so the text is available on focus, not only
|
||||
when it changes (GOV.UK _error-message_ field association). Contrast the editor's **render**
|
||||
error, which is a discrete, post-debounce result and stays the single `alert` of the rule
|
||||
above. _(Consulted via /council → WAI-ARIA APG Alert, GOV.UK error-message, NN/g #9. This
|
||||
bullet is the contract; cite it, not the source.)_
|
||||
|
||||
**Resolved — feature-modal dismissal & initial focus.** A feature modal (Datasets, Chart
|
||||
Builder) is a **passive** `dialog-modal`: dismissed by the close
|
||||
button, Escape, or a backdrop click (a passive modal carries no in-flight transaction, so
|
||||
|
||||
@@ -25,7 +25,34 @@
|
||||
Newest first. The at-a-glance build-order tracker is §4; per-item detail is §3. This log is
|
||||
the quick "where are we" — read it first.
|
||||
|
||||
- **2026-06-11** — **1C + 1D + 1E shipped (the Data section). Up next: Phase 2 (2A value-or-field channels, then 2B field shelf).**
|
||||
- **2026-06-11 (later)** — **Owed debts on the Data section closed. Up next: Phase 2 (2A value-or-field channels, then 2B field shelf).**
|
||||
- **Council pass** on the new error/disclosure copy (the previously-deferred auto-fire
|
||||
surface). Three a11y conformance gaps against `architecture/10` were fixed: the inline
|
||||
expression feedback now carries a **status glyph** (round error / triangle warning), not
|
||||
colour alone (§3, WCAG 1.4.1); the parse error is a **polite `role="status"`**, not a
|
||||
per-keystroke assertive alert (APG Alert / WCAG 2.2.4); and the message is linked to its
|
||||
input via **`aria-describedby`** (GOV.UK error-message). Unknown-field copy clarified to
|
||||
"…— not a column in this dataset." Resolution recorded in `architecture/10` §5.
|
||||
- **Manual/visual pass** run via a headless-Chrome (Playwright) walk-through of the live
|
||||
builder — filter shelf (predicate + `is between`), field↔expression toggle, expression
|
||||
error/unknown-field glyphs (filter _and_ calc inputs), calculated field, data-preview
|
||||
table with type chips, smart-default chart. All surfaces render as intended.
|
||||
- **Bug found + fixed (mid-edit preview resilience).** `filterTransformObject` /
|
||||
`calculateTransformObject` emitted **any non-empty** expression — including a half-typed,
|
||||
unparseable one — so the preview blanked with a raw render error while the user typed.
|
||||
They now **drop a syntactically-invalid expression** like an empty/incomplete entry
|
||||
(guarded by core `validateExpression`), matching `buildTransforms`' own "a config
|
||||
mid-edit still renders" contract; the inline feedback still flags the typo. Pure core,
|
||||
tested (+2 cases). Visually confirmed: an invalid filter/calc now keeps the last-good
|
||||
chart instead of breaking the preview.
|
||||
- **Verified:** `typecheck` + `test` (741 passing) + `eslint` clean.
|
||||
- **Still open (copy judgment, user's call):** the preview's catch-all
|
||||
`"Couldn't render this chart: {raw Vega message}"` puts a diagnostic in the headline
|
||||
(arch 10 says diagnostics go in a disclosure) — correct in the editor, debatable in the
|
||||
builder; and the builder's terse `"Dataset «X» not found."` drops the next-step the
|
||||
contract mandates (near-unreachable in the builder). Both noted, not changed.
|
||||
|
||||
- **2026-06-11** — **1C + 1D + 1E shipped (the Data section).**
|
||||
- A new **Data section** at the top of the builder's left pane — "here are your rows;
|
||||
shape them, then encode them" — emits the spec's top-level `transform` array.
|
||||
- **1C · Filters** — a guarded **field + operator + value** predicate shelf. Operators
|
||||
|
||||
@@ -65,3 +65,15 @@
|
||||
|
||||
- [ ] Library search / sort / empty states, the storage monitor, About & Donate
|
||||
modals, and the busy indicator all look deliberate and behave per spec.
|
||||
|
||||
## Driving these checks headlessly
|
||||
|
||||
The eye-checks above can be scripted as a headless walk-through (Playwright with the
|
||||
already-installed Chromium browser cache) for repeatable screenshots, alongside a live
|
||||
browser.
|
||||
|
||||
- **Select by accessible name / role / placeholder, never by CSS class.** CSS-module class
|
||||
names are content-hashed and unstable; the component tests select the same way.
|
||||
- **Reaching the Chart Builder:** open Datasets from the **header command button** (the
|
||||
pane-toggle-strip `Datasets` button only exists once the workspace has content) → **New
|
||||
Dataset** → paste rows inline → **Build Chart**.
|
||||
|
||||
@@ -35,7 +35,7 @@ The section is ordered **input → shaping** so the distinction reads at a glanc
|
||||
- The **field** dropdown offers the dataset's columns plus any calculated fields.
|
||||
- The **operators** offered depend on the field's type: a measure or temporal field offers `is` / `is not` / `<` / `≤` / `>` / `≥` / `is between` (two bounds); a category offers `is` / `is not` / `is one of` (a comma-separated membership list). A quantitative value compares as a number; other types compare as text (ISO dates sort correctly as text).
|
||||
- A filter can be switched to an **expression** power-mode — a raw Vega predicate expression (e.g. `datum.value > 0`) — for what the guarded shelf can't say. The toggle is reversible.
|
||||
- An **incomplete** filter (no value yet, a blank range bound, an empty expression) is ignored, so the live preview keeps rendering while the user types.
|
||||
- An **incomplete** filter (no value yet, a blank range bound, an empty or syntactically-invalid expression) is ignored, so the live preview keeps rendering while the user types.
|
||||
|
||||
### Calculated fields
|
||||
|
||||
@@ -47,6 +47,7 @@ The section is ordered **input → shaping** so the distinction reads at a glanc
|
||||
|
||||
- Both expression inputs (a filter's expression mode, a calculated field) are validated with **Vega's own expression parser** — the same one the chart uses — so a syntax error is reported **inline** the moment it appears, matching exactly what the chart would accept.
|
||||
- A `datum.<field>` reference that does not match a known column raises a soft **"unknown field"** warning (a typo guard) without blocking — the value is genuinely valid Vega, it just won't resolve.
|
||||
- An expression that does not parse is **left out of the produced spec** (like an incomplete filter or an unnamed calculated field): the inline error is the only feedback, and a half-typed expression never reaches the renderer — the preview keeps showing the last valid chart.
|
||||
|
||||
## Inputs and Controls
|
||||
|
||||
|
||||
Reference in New Issue
Block a user