feat: per-chart settings, serial axes, and URL sync#127
Merged
Conversation
…ttings to named types Remove AxisLabels struct and field from Dataset. Add named types Axis, Sort, ChartSettings, and DatasetSettings to support per-chart overrides and axes labeling in a structured, extensible way. Drop the GroupAxisLabels() call from prepareDatasetFromResults (will be replaced by GroupAxes() in a follow-up task).
- Restore axis label population in prepareDatasetFromResults using
parser.GroupAxisLabels(); converts flat map to []Axis in canonical
key order (name/x/y/z) — temporary until GroupAxes() lands in Task 3
- Document Sort.Order valid values ("asc" or "desc")
- Document ChartSettings.Sort pointer semantics (nil = inherit global)
- Add Axis type for ordered axis dimensions with label overrides - Add ChartSettings type for per-chart type overrides (swap, sort, scale, showLabels, autoRotate) - Update Settings to include axes and chartSettings fields - Mark DataSet.axisLabels as @deprecated; keep AxisLabels type for legacy JSON reading
- Fix 1: Change chartSettings from Record<ChartType, ChartSettings> to Partial<Record<ChartType, ChartSettings>> since ChartType has 4 values (bar|line|pie|heatmap) and the intent is a sparse override map - Fix 2: Update autoRotate comment to clarify it overrides the store-level autoRotate when set per-chart - Fix 3: Remove redundant inline comment on axes field (already documented in Axis type block comment above)
…shared.Axis Add GroupAxes() to parse_pattern.go supporting both pattern mode (ordered dims with positional --group labels) and regex mode (named captures mapped to canonical key order name/x/y/z, labels always empty). Replace the temporary inline block in prepareDatasetFromResults with a direct call to parser.GroupAxes(). Remove GroupAxisLabels() and its tests; add TestGroupAxes.
…oupAxes label misalignment - ValidateGroupPattern now tracks seen expanded dimension names and returns an error on duplicates (e.g. "x/y/x" → "duplicate dimension 'xAxis' in pattern") - GroupAxes pattern-mode loop uses a separate groupIdx counter instead of the raw slice index i, so empty parts (e.g. "x//y") no longer shift group labels to the wrong dimension - Add TestValidateGroupPattern case for duplicate dimension - Add TestGroupAxes case for empty-part index alignment
…ge notAllowed maps - Parse labels=<val> and rotate=<val> using strconv.ParseBool instead of silently ignoring the value and always setting true - Return an error when the settings portion after ':' is empty (e.g. "bar:") - Merge scaleNotAllowed and rotateNotAllowed into a single notAllowedForLimitedCharts map - Fix hardcoded "rotate" literal in bare-flag error to use the key variable - Replace duplicate "unknown chart type" test case with distinct cases: empty-rest error and labels=false setting ShowLabels to &false
Adds MigrateDataset to shared/migrate.go which performs a second-pass unmarshal of the old top-level axisLabels field and populates Settings.Axes in canonical order when it is empty. Call sites in convertToDataset (root.go) and parseInputFile (merge.go) are updated so both the html and merge commands transparently upgrade old JSON files.
Re-marshaling a Dataset after Unmarshal loses the legacy axisLabels field (no longer in the struct). Instead, decode the array as []json.RawMessage so each element's raw bytes are preserved for the MigrateDataset second pass.
…taset Slice and map fields are reference types; shallow copy via dst:=src shares backing storage. Deep-copy Sort pointers inside ChartSettings too.
Migration is already handled by parseInputFile. Apply ParseChartSpecs to each loaded dataset (using its own axes for swap validation) before marshaling to HTML. Per-chart settings in loaded JSON are preserved when --chart is not given.
useSettingsStore:
- chartSettings: Partial<Record<ChartType, ChartSettings>> in reactive state
- resolved(key) returns per-chart override or global default
- setForActiveChart(update) writes per-chart overrides for active chart type
- initializeFromDataSet seeds chartSettings from dataset.settings.chartSettings
- selectedSwapIndexMap keyed "${benchmarkId}:${chartType}" for per-chart swap
useDataPoint:
- arrangementMap keyed "${datasetId}:${chartType}" (was plain datasetId)
- setArrangement now takes (datasetId, chartType, target) — chart-type-aware
- activeArrangement reads identity from axes[] key order if present, else presentKeys(data)
- chartType.value used in composite arrangement key so chart-type switch re-applies its swap
AxisSwapper:
- passes chartType.value to get/setSelectedSwapIndex and setArrangement
- getInitialSwapIndex uses axes[] for identity when available
- Pipeline sort/showLabels/scale now come from resolved() (per-chart override or global default) so each chart type uses its own effective settings - activeLabels prefers settings.axes[] (new schema) over legacy axisLabels field, with fallback for old JSON files that haven't been migrated
- isAxisChart now excludes heatmap (scale not valid for pie or heatmap) - ChartSettings sort/showLabels read resolved(), write setForActiveChart() - ScaleSelector and AutoRotateToggle read resolved(), write setForActiveChart() - ChartCard sort/showLabels/scale/autoRotate from resolved() so chart rendering uses per-chart effective values rather than global store fields
…e, swap) Rewrites useUrlRouter to persist and restore per-chart-type settings via URL params (<type>.so/.l/.sc/.rt/.sw), with back-compat for legacy bare s/l/sc params. AxisSwapper now initialises from activeArrangement so URL-restored swaps are reflected immediately.
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
Group cpu/os/arch/pkg under a single Meta struct on both Dataset and
HistoryEntry, slimming HistoryEntry to {tag, timestamp, meta}. Keeps the
core schema generic for arbitrary tabular data, not just benchmarks.
Meta field on Dataset is now *Meta (pointer, omitempty) so datasets with no machine metadata emit no "meta" key in JSON. Cascades into deepCloneDataset, buildHistory, and the TS DataSet type (meta?: Meta). Also tightens lefthook ui-gen-check to skip the gen.go requirement when the UI bundle is genuinely unchanged (e.g. type-only edits).
axisLabels was never released so no files need migrating. cpu/os/arch/pkg were released as flat fields on Dataset and HistoryEntry before 61f6745 grouped them under Meta — migrate those instead. History entries migrated per-entry, skipping any that already carry a Meta value.
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.
Summary
axisLabelswith orderedaxes[](Axis{Key,Label}) and addChartSettings(swap/sort/scale/showLabels/autoRotate) per chart type inDatasetSettings--chartflag: Repeatable per-chart overrides —--chart bar:swap=yx,sort=asc --chart pie:labels— validated against active charts and axis permutationsGroupAxes()preserves--group-pattern/--group-regexdimension order;GroupAxisLabels()removedMigrateDatasettwo-pass unmarshal recovers legacyaxisLabelsfrom old JSON files (including per-element array branch via[]json.RawMessage)deepCloneDatasetdeep-copiesAxesslice andChartSettingsmap (including*Sortpointers)resolved(key)returns per-chart override or global default;setForActiveChartwrites for active type;selectedSwapIndexMapkeyed"${benchmarkId}:${chartType}"arrangementMapkeyed"${datasetId}:${chartType}"— switching chart types applies that type's stored arrangement; identity derived fromaxes[]key ordersort/showLabels/scale/autoRotatecome fromresolved()so each chart type uses its own effective valuesresolved/setForActiveChart;isAxisChartnow excludes heatmap (scale not valid)<type>.so/.l/.sc/.rt/.swparams per chart type; legacy bares/l/scstill parsed for back-compat; swap restore deferred until data loads--chartflag documented incommands/root.mdxwith key table and examples