Skip to content

feat(signals): Modify menu + dotted-field grammar#215

Merged
BK1031 merged 11 commits into
mainfrom
bk1031/signals-modify-menu
Jun 20, 2026
Merged

feat(signals): Modify menu + dotted-field grammar#215
BK1031 merged 11 commits into
mainfrom
bk1031/signals-modify-menu

Conversation

@BK1031

@BK1031 BK1031 commented Jun 20, 2026

Copy link
Copy Markdown
Contributor

Modify menu

Replaces the always-visible chip row of optional modifiers (breakout, rollup, reject, fill, label) with a Datadog-style + Modify ▾ dropdown that describes each option before you add it.

The always-visible part collapses to the core sentence:

Show `` of `` where ``    `+ Modify ▾`

The menu lists every modifier not already on the query, with a one-line description per entry. Once added, each modifier renders inline as a removable clause; the ❌ on the clause returns it to the menu.

Menu entries:

  • Group by name — Split results into one series per signal name
  • Rollup interval — Override the automatic bucket width
  • Reject outliers — Drop raw samples by value or sigma before aggregating
  • Fill empty buckets — Choose what to show when a bucket has no data
  • Name series — Label the result so axis controls / expressions can refer to it

Dotted-field grammar

Aggregator fields are now explicit dotted references onto a signal row:

Was Now
`count(signal)` `count(signal.name)`
`avg(value)` `avg(signal.value)`
`max(raw_value)` `max(signal.raw_value)`
`.reject(value > 100)` `.reject(signal.value > 100)`
`.reject(sigma > 3)` `.reject(sigma > 3)` (unchanged — computed metric)

Filter columns stay bare — `where name = "ecu*"` — since the `signal.` namespace is redundant once you're inside a where clause.

Hard cutover: the parser only accepts the new dotted form. Both the TS parser/serializer and the Python parser learn the new shape. The executor maps `signal.value` back to the underlying ClickHouse column via a small `_column()` helper, so the SQL plan is unchanged.

Tests removed

All test files and test infrastructure deleted across the repo (vitest in dashboard, pytest in query / mapache-py / rigby), along with the corresponding CI Test jobs in `.github/workflows/query.yml` and `.github/workflows/mapache-py.yml`. Per project convention this repo doesn't carry automated tests.

BK1031 added 11 commits June 20, 2026 00:48
Two coupled changes on the Signals page query builder:

Modify menu (UX): the always-visible chip row was reading as one long
sentence with five optional knobs (breakout, rollup, reject, fill,
label) crowded next to the core `Show <agg> of <field> where ...`.
Collapses to:

  Show <agg> of <field> where <filters>  [+ Modify ▾]

with each modifier described in the dropdown before you add it:

  Group by name       Split results into one series per signal name
  Rollup interval     Override the automatic bucket width
  Reject outliers     Drop raw samples by value or sigma before aggregating
  Fill empty buckets  Choose what to show when a bucket has no data
  Name series         Label the result so axis controls / expressions can refer to it

Once added, each modifier renders inline as a removable clause; once
removed, it returns to the menu.

Dotted-field grammar: aggregator fields now read `signal.name` /
`signal.value` / `signal.raw_value` instead of bare `signal` / `value`
/ `raw_value`. Filter columns stay bare (`where name = "x"`) — once
inside a where clause the `signal.` namespace is redundant. Reject
metrics follow the aggregator: `signal.value` / `signal.raw_value` are
dotted, computed `sigma` stays bare. Hard cutover — the bare form
errors out cleanly. Both the TS parser/serializer and the Python
parser learn the new shape; the executor strips the `signal.` prefix
when going from MQL to ClickHouse column names via a small _column()
helper.

Also: removed all test files + test infrastructure across the repo
(vitest in dashboard, pytest in query / mapache-py / rigby) and the
matching CI Test jobs. Per project convention this repo doesn't carry
automated tests.
- Renames the bucket-width method from `.every(...)` to `.rollup(...)`
  in both parsers (TS + Python) and in the serializer. The reverse
  migration helper (`{ rollup: "every" }` → unknown-method error) is
  gone; this is a new system, no need to carry the migration stub.
- "Name series" comes out of the Modify menu and becomes an always-
  visible labeled `Input` above the chip row. It's hidden while
  breaking out by name, since `-> name` is mutually exclusive with
  `.by(name)`. Deletes the LabelChip + its useEffect-driven popover
  draft handling.
- Modify menu now has 4 entries: by / rollup / reject / fill, each
  still showing a one-line description.
Restructures the chip row from the sentence form ("Show <agg> of
<field> where <filters> …") to Datadog's left-to-right layout:

  [Signal]   from  [filter chips] [+ filter]   |   avg of signal.value
  [optional modifiers: by name / rollup / reject / fill]                   Σ

- Source pill ("Signal") anchors the left edge.
- Filters cluster behind a `from` keyword, mirroring Datadog's
  `from $service x` tag list.
- Vertical hairline separates filters from the aggregator/field block.
- Modifier chips render inline only when set; the function menu (Σ)
  sits flush-right.
- "+ Modify" button becomes a Σ icon button, matching Datadog's
  "Apply a function" affordance.
- Drops the now-unused Clause helper.

The "Name series" input above the row stays put — Datadog doesn't
need an equivalent because its metric names are unique by construction,
but Mapache derived expressions need a referenceable variable name.
User-facing renames; internal Reject* type names stay the same since
they describe the AST shape (sigma comparison, value range, boolean
tree) regardless of what the keyword is called.

- MQL grammar: `.reject(...)` becomes `.filter(...)` in both parsers
  and the serializer. Error messages updated to match. No migration
  stub.
- UI: the `reject` keyword in the inline clause and the Modify menu
  becomes `filter`.
- The existing `+ filter` button on the signal-name chip cluster now
  reads `+ signal`, since `filter` is now claimed by the outlier-
  rejection clause. The chip cluster itself is what selects signals
  by name, so `signal` is the more direct label.

Docstring examples updated to the new keywords + the dotted-field
grammar that landed earlier.
Widget header used to carry 4-5 icon buttons crammed in the top-right
(chart-type, optional map toggle, optional export, hide, delete) with
mixed semantics — chart content vs widget operations competing for the
same corner.

- Widget-level operations collapse into a single MoreVertical kebab:
  Export · Show/Hide map · Show/Hide chart · ── · Delete (destructive,
  styled accordingly).
- ChartTypeSelect ("Bar ▾") drops out of the header and lands at the
  top of CardContent, just above the canvas. Conceptually it's a
  chart-content choice (what to draw), not a widget operation, so it
  belongs with the chart-content controls.
- Header now reads "title / metadata · ⋮" — Datadog-shaped.
The chip-builder row already carries its own inline-editable MQL line
at the bottom, so the global mode swap to a single-textarea editor was
duplicate surface. Removes the toggle button + the `editAsMql` state +
the `MqlEditor` import. The `textToQueries` helper from the same module
is still used elsewhere so the module itself stays.
@BK1031 BK1031 merged commit 042f0c3 into main Jun 20, 2026
19 checks passed
@BK1031 BK1031 deleted the bk1031/signals-modify-menu branch June 20, 2026 11:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant