feat(web): add weighted MAAD dashboard view - #120
Merged
Merged
Conversation
/api/netflow/dimension-stats returns the stored d0, d1 and d2 per source, bucket and address side for one measure, IP version and direction over a half-open window, with the usual coverage timelines. /api/netflow/maad-status reports whether the product ran MAAD, detected from its maad_q_grid rows.
… bytes The dashboard gets a MAAD measure control whose value lives in the measure search param. A new MAAD Dimensions card charts D0/D1/D2 for the selected measure. The spectrum card explains that weighted measures have no spectrum, and both MAAD cards say when a dataset was built without MAAD. Drilldowns carry the measure to the file page, whose measure control now reads and writes it.
The Controls card now reads as one toolbar. Reset View sits in the header, granularity keeps its five options on one line, and a labelled MAAD group holds the measure and the address family. Both MAAD cards share that family, so it appears once instead of in each card. Segmented controls lay out horizontally, including direction and the file page's MAAD controls. MAAD Dimensions charts one side and one dimension at a time, with one line per source. Sources take fixed slots from a validated categorical palette with light and dark steps, the y-axis fits the data, and the tooltip shows three decimals. The spectrum card picks its source and side with segmented controls. Card headers name the active measure and family. Unavailable MAAD cards show a compact placeholder, and their reserved height shrinks to match. Linear time axes in these cards put ticks on bucket starts, so day boundaries get labels as they do in Traffic Overview. The default ticks stay when fewer than two buckets fall inside the plotted range.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Note
🤖 Claude Opus 5.5 on behalf of Oliver
Explain Like I'm Lost
MAAD (multifractal address-structure analysis) is computed per bucket for three measures: plain addresses, and packet- and byte-weighted addresses. The pipeline already stores all three, but the dashboard only charted the address measure. This PR lets the dashboard switch between them and charts the stored D0/D1/D2 dimensions over time.
Why
Before this PR, you could only see weighted MAAD on a single file's detail page, so you couldn't watch how packet or byte weighting changes the address structure over a range. The MAAD controls were also spread across individual cards.
Implementation
Stacked on #106.
What changes
Addresses | Packets | Bytes) and the IP address family (IPv4 (/8–/24) | IPv6 (/23–/64)). Both are stored in the URL, as?measure=addresses|packets|bytesand the existing?ipVersion=4|6. Defaults (addresses,4) are left out of generated links. The family applies to both MAAD cards, so this is the only place it appears. Reset View sets both back to their defaults. Datasets built without MAAD don't show the group.Source | DestinationandD0 | D1 | D2, and draws one line per selected source. The default is Source D1, because D1 responds to the weighting and D0 barely does. Each source keeps a fixed colour from a colourblind-checked palette, with separate light and dark shades. The y-axis fits the data with 10% padding. The tooltip shows three decimals. Day boundaries get x-axis labels, as in Traffic Overview. Click and range drilldown work like the other line charts.spectrum-statsrequest.MAAD Dimensions Bytes · IPv4 (/8–/24). That keeps the context visible when a card sits far below Controls.--no-maad, so nomaad_q_gridrows): both MAAD cards collapse to a short "MAAD was not computed for this dataset…" placeholder and send no MAAD requests./netflow/files/<slug>?…&ipVersion=6&measure=bytes. On the file page, the family and measure controls read and write those URL params, and an invalid value returns 400. The Next File link carries dataset, direction, ipVersion and measure.GET /api/netflow/dimension-statstakes the same params asstructure-stats:routers,granularity,startDateandendDate(a half-open[start, end)window),direction,ipVersionandmeasure. It returns per-router coverage timelines with{saD0, saD1, saD2, daD0, daD1, daD2}, wherenullmeans too few addresses.GET /api/netflow/maad-statusreturns{ computed }.v6because a card was added, so any saved custom order resets once.How to review
Setup: a database built with MAAD. Either a real one or the Playwright fixture works (
bun run test:e2eseedsfixture-routerwith one 5-minute bucket for all three measures)./datasets/<id>?startDate=…&endDate=…&groupBy=hour. Controls should show two tidy rows (dates, granularity and sources first, then MAAD), with no wrapped or stacked segmented controls.measure=…, the dimensions request carriesmeasure=, and the card header updates. The spectrum card shows the "only computed for the Addresses measure" placeholder.ipVersion=6, and both MAAD cards refetch withipVersion=6.measure=bytes,ipVersion=6andgroupBy=5min, click a point on any chart. The file page opens with Bytes and IPv6 selected. Click Next File: both stay selected.?measure=flows: it falls back to Addresses./netflow/files/<slug>?measure=flowsreturns 400.--no-maad. Controls has no MAAD group, and both MAAD cards show the short "MAAD was not computed" placeholder.Decisions and edge cases
maad_q_grid, which the pipeline writes only when MAAD runs. In a D1 deployment where one database is shared across datasets, this flag is database-wide, not per dataset.measurein the dashboard URL falls back to Addresses, which matches how the other search params behave. The APIs and the file page reject it with 400.NULL(too few addresses) show as gaps, not zeros.tau/tau_sdblobs, so they pass the blob validation added in feat: store MAAD results as compact f32 rows #119.Verification
bun run format,bun run lint,bun run typecheck,bun run test:web(181 tests),bun run test:dbandbun run test:e2e(14 tests) all pass.api-maad-dimensions, dataset page load, schema, file navigation and file page tests.dashboard-maad-measure.spec.tscovers switching the measure, a single shared family control that refetches both cards, choosing a side and dimension, rejecting an invalid param, and drilling down to a file.maad-ip-version.spec.tsnow drives the shared family control, and checks that the file page's measure and family both survive Next File.UI Changes
Screenshots are pending upload. They'll be added here: a before image of the first iteration (before the redesign), and after images for Addresses, Bytes, a dataset without MAAD, dark mode and a 1024px width.
Made by Claude Opus 5.5 in Claude Code (T3 Code).