Skip to content

Presentation controls: per-chart cross-filter scope, named markdown blocks, tab links, axis-title spacing, big-number sizes, mixed scatter - #57

Merged
debabsah merged 9 commits into
mainfrom
feat/presentation-controls-r2
Oct 6, 2026
Merged

debabsah merged 9 commits into
mainfrom
feat/presentation-controls-r2

Conversation

@debabsah

@debabsah debabsah commented Oct 6, 2026 •

Copy link
Copy Markdown
Owner

Seven presentation controls, one commit each, ported onto main:

  • cross_filter_scope per chart: "global" | "tab" | "none" | [chart names] → chart_configuration. apply and restore re-key it to live chart ids; decompile reads it back. adopt no longer lists per-chart scopes as a reset. Waterfall refuses it with big numbers, heatmaps and histograms (no Behavior.InteractiveChart at 4.1.4, 5.0.0 and 6.1.0); box plot takes it.
  • Markdown block id → MARKDOWN-, a target for dashboard CSS, in rows, header and footer rows, and sketch legends.
  • Tab links in markdown: words / tab:Parent/Child.
  • Axis-title spacing: x_axis_title_margin, y_axis_title_margin, y_axis_title_position, which override main's automatic spacing. Unset, bundles build unchanged. Decompile now reads back stored spacing that differs, Superset's "Left" included.
  • Big numbers: header_font_size, subtitle_font_size, and a trendline's trend_date_format. It's not called date_format because the design rules read that field as "the number is a date". readability.kpi-text judges the chart at its own sizes.
  • Mixed chart query kind: "scatter".

Fixes since the first push

  • Decompile: a "tab" scope whose tab it flattened reads as the charts the scope reached, so the spec it writes loads. A scope entry it can't match to a chart, or that isn't shaped as Superset saves it, is named as a loss instead of dropped or crashing. A cleared title margin or position beside its title is named as a loss again.
  • Tab links: a title may hold balanced parentheses. A top tab titled like a sub-tab's Parent/Child path is refused as ambiguous, and decompile leaves a link it can't name uniquely as its URL.
  • restore maps the backup's own chart_configuration to the live chart ids by uuid (chartsInScope too) instead of rebuilding it from the decompiled spec, so charts decompile can't read keep their scopes.
  • plan: a scope naming a chart renamed in an adopted spec compares under the new name.
  • The scope, tab-link and markdown-id checks run after the layout check, so a chart missing from the layout gets the layout error.
  • Standards: a markdown block's id counts in a row's hash.
  • Docs: a tab link opens its tab for a viewer signed in to Superset, whose URL carries native_filters_key, so the click reloads the page. Where Superset can't save filter state, the click only changes the hash and the tab stays; LIMITS.md says to name the tab in the link's words. Seen live on 6.1.0.

Verification

  • Offline suite: 2464 passed, 1 skipped (2465 tests, 80 modules). params_drift --all clean on 4.1.4, 5.0.0 and 6.1.0. Schema file regenerated.
  • A real dashboard that uses all seven, including 79 per-chart scopes: its spec, converted to main's field names, compiles to the same layout and dashboard metadata as before. The remaining parameter differences are main's own: the time binding, no server_page_length, and y_axis_bounds.
  • plan against that live dashboard: one chart changes, its y range moving from echart_options to y_axis_bounds (same range).
  • Live CI (sandbox Superset 4.1.4, 5.0.0 and 6.1.0) passes.

debabsah and others added 9 commits October 6, 2026 10:41
…iled

A mixed chart's query took kind bar, line or area; scatter joins them and compiles
to seriesType / seriesTypeB "scatter" (MixedTimeseries/controlPanel.tsx seriesType
choices; EchartsTimeseriesSeriesType.Scatter in Timeseries/types.ts:44-52 at 6.1.0,
the same enum at 4.1.4 and 5.0.0). Decompile keeps it instead of reporting a loss;
smooth and the step types stay outside the surface and are still named.

Ported from the presentation-controls branch onto main's area kind.
…ndline takes trend_date_format

The sizes the compiler pinned (0.4 / 0.15) become spec fields, limited to the
options the panel offers (BigNumber/sharedControls.ts FONT_SIZE_OPTIONS_LARGE /
_SMALL, identical at 4.1.4, 5.0.0 and 6.1.0) and registered as Superset defaults, so
a written 0.4 builds and plans like an omitted one. The subtitle size still rides
the legacy subheader_font_size key; a trendline's comparison keeps 0.15.

trend_date_format writes a trendline's time_format, unforced: it formats the
trendline's dates (BigNumberWithTrendline/controlPanel.tsx:212, transformProps.ts:
245-249, :275 at 6.1.0); forced, the number itself would print as a date. Not named
date_format: the design rules read date_format as "this big number is a date".

Decompile reads all three back; a size outside the options is a named loss.
readability.kpi-text scales its measured px by the chart's own shares.

Ported from the presentation-controls branch (where the trendline field was
time_format).
…s_title_margin, y_axis_title_position)

main writes each title's margin and position itself (30 px under the axis, 15 px
above it, a horizontal bar's laid out for its swapped axes). An axis chart can now
set its own: the titleControls keys (sections/chartTitle.tsx:41-101 at 6.1.0, the
same names at 4.1.4 and 5.0.0), which win over the tool's spacing; unset, every
bundle builds as before. A mixed chart's secondary title shares the y pair. Each
needs its title, the only place Superset reads it (Timeseries/transformProps.ts:
737-740).

axis_title_defaults is the one place the tool's spacing lives: compile writes it,
decompile reads a stored value that differs from it back as the chart's own
(Superset's "Left" included, so adopt and plan keep a UI chart's layout), and plan
compares a written default equal to an unset one.

Ported from the presentation-controls branch, where the keys were emitted only when
set; here they override main's automatic spacing.
… target for dashboard css

A markdown block's id (a lowercase slug, ^[a-z][a-z0-9-]{0,47}$) replaces its
positional component id with MARKDOWN-<id>. Superset renders the component id as the
block's DOM id (gridComponents/Markdown/Markdown.tsx:418 at 6.1.0;
gridComponents/Markdown.jsx:363 at 4.1.4 and 5.0.0), so dashboard.css can style one
block as #MARKDOWN-<id>.

Named blocks work wherever main puts markdown: rows, header and footer rows, and
sketch legends (Layout.markdown_blocks). Validated: the slug pattern, the sdc- prefix
reserved for unnamed blocks' ids, and uniqueness across the whole layout. Decompile
reads MARKDOWN-<slug> back as the block's id, in rows and in sketches, so plan is
clean after apply and reports a renamed block as a layout change. UI-minted ids
(MARKDOWN-<nanoid>, mixed case and '_', newComponentFactory.ts:74 at 6.1.0) are
never read as names.

Ported from the presentation-controls branch, extended to main's sketch blocks.
…compiled and compared by the tab it opens

In a markdown block, [words](tab:Title) or (tab:Parent/Child) compiles to
/superset/dashboard/<slug>/#<tab component id>. Superset opens the tab named in the
URL hash when the dashboard loads: getLocationHash (dashboard/util/getLocationHash.ts:
20) feeds directPathToChild (dashboard/actions/hydrate.ts:287-294 at 6.1.0,
hydrate.js:222-226 at 4.1.4 / 5.0.0), and each tab set starts on the child on that
path (gridComponents/Tabs/Tabs.tsx:135-140 at 6.1.0, Tabs.jsx:190-193 at 4.1.4 and
:139-142 at 5.0.0). A hash change on the open page is not read, so the link is the
full dashboard URL; filter selections not saved in the URL reset (documented).

A bare title names a top tab, else a sub-tab; Parent/Child names a sub-tab.
Validation lists the valid targets for an unknown title and asks for Parent/Child
when two sub-tabs share a title. Links resolve in every markdown block main has:
rows, header and footer rows, and sketch legends. tab_component_id is now the one
place tab ids are made. Decompile turns links to this dashboard's tabs back into
tab:Title / tab:Parent/Child; plan resolves both sides' links first, so a link to
another tab is a layout change and two spellings of one tab are not.

Ported from the presentation-controls branch, extended to main's sketch blocks.
…med charts; compiled, re-keyed after import, decompiled and diffed

A chart's cross_filter_scope ("global" default | "tab" | "none" | [chart names])
compiles to json_metadata.chart_configuration as 6.1.0 stores it: keyed by chart id,
{id, crossFilters: {scope: {rootPath, excluded}, chartsInScope}}
(superset-frontend/src/dashboard/types.ts:87-106). "tab" roots the scope at the
chart's innermost TAB; a list roots it at ROOT_ID and excludes every other chart; the
chart's own id is excluded, as the scoping modal saves it (ScopingModal.tsx:240-246).
"none" is what the scoping tree saves with nothing ticked (FilterScope/utils.ts:
261-270): no root, which reaches no chart, one added later included
(getChartIdsInFilterScope.ts:75-85).

Ids don't exist at compile time. The bundle carries the layout's placeholder ids,
which the 6.1.0 importer remaps (superset/commands/dashboard/importers/v1/utils.py:
147-190) and 4.1.4 / 5.0.0 leave alone, so apply's scope stage and restore rewrite
chart_configuration from the live layout's ids on every release. Charts are found by
uuid: the spec's own (an adopted dashboard's included), or, on restore, the backup's.

Decompile maps ids back to names through the layout, so plan reports a changed or
clobbered scope as a changed chart (a list compares as a set). With that, main's
adopt no longer lists per-chart scopes as a reset: a scope the spec can't carry is a
decompile loss instead. Validated: needs dashboard.cross_filters; big numbers,
heatmaps, histograms and waterfalls declare no Behavior.InteractiveChart (their
index.ts at 4.1.4, 5.0.0 and 6.1.0) and are refused; "tab" needs the chart in a tab;
a list names other spec charts once each. A written "global" builds as omitted.

Ported from the presentation-controls branch onto main's adopted identities and
waterfall chart type.
…ite count for the presentation controls

A lowercase MARKDOWN-<slug> is a named block's id now, so the tests that fake a
dashboard assembled in Superset's UI use an id shaped like the ones the UI mints
(`${type}-${nanoid()}`, mixed case and '_', newComponentFactory.ts:74 at 6.1.0);
their expectations are unchanged. The restore test's decompile stub carries
chart_uuids, as every DecompileResult does. A live layout's chart node without meta
no longer stops the cross-filter scope stage.

schema/dashboard_spec.schema.json regenerated; offline suite 2457 tests, 80 modules.
…up's scopes

- decompile: a "tab" scope whose tab was flattened reads as the charts it
  reached; entries it can't match or that are malformed are named as losses
  instead of dropped or crashing; a cleared title margin or position beside
  its title is named as a loss again.
- tab links: a title may hold balanced parentheses; a top tab titled like a
  sub-tab's Parent/Child path is refused as ambiguous, and decompile leaves
  a link it can't name uniquely as its URL.
- restore: maps the backup's own chart_configuration to the live chart ids
  by uuid (chartsInScope too) instead of rebuilding it from the decompiled
  spec, so charts decompile can't read keep their scopes.
- plan: a scope naming a chart renamed in an adopted spec compares under
  the new name.
- spec: scope, tab-link and markdown-id checks run after the layout check.
- standards: a markdown block's id counts in a row's hash.
- schema: x_axis_title_margin's description gives a horizontal bar's 64.
@debabsah
debabsah merged commit a44d6c0 into main Oct 6, 2026
7 checks passed
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