From 49cfdbfc4f14426045681d6d020b42439048c99f Mon Sep 17 00:00:00 2001 From: Gleb Sologub Date: Tue, 1 Sep 2026 00:53:13 +0200 Subject: [PATCH] docs(dashboards): document the Field switcher control (#11710) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * docs(dashboards): document the Field switcher control Adds the fourth dashboard control type to the Controls page: what it does, how it differs from a filter (which narrows rows) and a time granularity switcher (which rebuckets them), and how to configure Field Type, the replaced member, and the alternatives viewers may switch to. Covers the settings that are not self-evident from the UI: - the default option, and what happens when the member serving as it is removed from the alternatives; - per-option default granularity for time dimensions, why it exists, and how a viewer's own granularity pick outranks it while an untouched granularity control does not; - the user attribute default, and why a value outside the alternatives is ignored rather than forced; - that the swap keeps the replaced member's output name, so column formatting, sorting, pivots and conditional formatting survive a switch; - what the "could not be applied" notice means — the switch is applied only if both the SQL and the query description take it — and how that differs from a chart the control simply doesn't scope, which shows no notice. States the two current limitations plainly rather than leaving them to be discovered: a field switcher cannot be a parent control's child, and a viewer's choice is not carried in the shared URL, so a recipient opens on the control's own default. Both are noted as limitations, not design. Also updates the surfaces that enumerate the control types — the page intro, the widgets index, the Add Controls menu list, the Visibility and Interaction with charts sections, and the URL parameter table — and records on the Dashboard Agent page that the agent does not drive field switchers, which its "only controls that exist on the dashboard" wording would otherwise imply. * docs(dashboards): keep #default-option pointing at the Parent section The new "Default option" heading sits ABOVE the Parent one, so slugification gave it `#default-option` and pushed the pre-existing heading to `#default-option-1`. That silently re-pointed the Parent section's own reference at the Field switcher, and would have retargeted every inbound link to `.../controls#default-option` — which `docs-mintlify/CLAUDE.md` asks stay stable (claude). The new heading takes an explicit `{#field-switcher-default-option}`, the two references that mean it follow, and the Parent reference is left alone. My "27 anchors, 0 missing" check could not have caught this: it collected slugs into a set, so a duplicate collapsed into one entry and both targets still existed — only the mapping changed. Rewritten to flag a slug produced by more than one heading, and to diff every anchor against origin/master so a pre-existing one that moved is an error. Both now report clean. Also from the same review: - "Interaction with charts" still scoped controls by *dimension*, which describes only half a field switcher — one set to Measure scopes on a measure. Carried the intro's "member" down, and said which control targets which. - Dropped the `*(none yet)*` row from the parameter table: it contradicted the table's own lead-in, and Parent — the other parameterless control — is already handled in the prose bullets, where the field switcher's case is covered too. * docs(dashboards): the Controls mapping sidebar takes measures, so say member The **Controls mapping** subsection was written entirely in terms of dimensions, while the section above it now says field switchers are in scope and that you can "remap it onto a different member" — so the two disagreed about what the sidebar accepts (claude). The review flagged this as a genuine ambiguity it could not settle from this repo, with two possible fixes. Checked the implementation, and it is the first one: a measure-kind Field switcher's picker lists the view's MEASURES, not its dimensions — deliberately, because "the dimension list would stage a mapping the swap pipeline could never resolve" (`ReportFilterMappingSidebar.tsx`). So the subsection gets the same "member" treatment line 299 got, and the time-granularity restriction that was a trailing sentence becomes a table covering every control: filters offer dimensions, time granularity switchers time-typed dimensions, and a field switcher whichever kind it replaces. Two consequences of that rewrite, handled here rather than left behind: - `[ref-time-grain]` lost its only use and is removed; reference definitions are file-scoped, so it was dead weight. - "Mappings are also configurable by AI agents" predates this control and would now read as covering it. Agents author FILTER / TIME_GRAIN only, so the sentence now names those and says field switcher mappings are yours. Also adds **Field switcher** to the product taxonomy in `docs-mintlify/CLAUDE.md`, which governs the vocabulary this page uses and still listed three control types. * docs(dashboards): the third "parent control targets no…" said dimension Line 13 and line 297 make the same claim and both now say "member"; this one still said "dimension" (claude). Since the page switched to "member" precisely because a field switcher can target a measure, the odd one out reads as if it were drawing a distinction it isn't. Swept the rest of the page for the same slip. Three other "dimension" mentions remain and all three are correct as they stand, so they are deliberately left: the time granularity switcher "targets a single time dimension" (it does), a parent's reset row saying "no filtering on that dimension" (a filter child, which is dimension-scoped), and the URL paragraph's "no matching control for that dimension" (only f_ and tg_ have parameters, both dimension-scoped). --- docs-mintlify/CLAUDE.md | 1 + .../dashboards/dashboard-agent.mdx | 5 + .../dashboards/widgets/controls.mdx | 104 +++++++++++++++--- .../dashboards/widgets/index.mdx | 4 +- 4 files changed, 95 insertions(+), 19 deletions(-) diff --git a/docs-mintlify/CLAUDE.md b/docs-mintlify/CLAUDE.md index f06f9ab5f9b18..c2443056d1014 100644 --- a/docs-mintlify/CLAUDE.md +++ b/docs-mintlify/CLAUDE.md @@ -124,6 +124,7 @@ Make sure to use correct terms. On billing, pricing, and support pages, use **on - Controls - Filter - Time granularity + - Field switcher - Parent - AI summary - Layout diff --git a/docs-mintlify/docs/explore-analyze/dashboards/dashboard-agent.mdx b/docs-mintlify/docs/explore-analyze/dashboards/dashboard-agent.mdx index 063676c078149..f3805226f3b5f 100644 --- a/docs-mintlify/docs/explore-analyze/dashboards/dashboard-agent.mdx +++ b/docs-mintlify/docs/explore-analyze/dashboards/dashboard-agent.mdx @@ -151,6 +151,10 @@ If you need any of those, use the [Workbook Agent][ref-workbook-agent] instead. applies to your session only — it is never saved to the dashboard. If you ask it to change something with no control on the dashboard, it explains the current state instead of applying a change. +- **Field switchers aren't driven by the agent.** The agent can read and change + [filters and time granularities][ref-controls]; a + [field switcher][ref-field-switcher] is not among the controls it operates, so + ask it about the data instead and change the field yourself in the control. - **No authoring on published dashboards.** The published Dashboard Agent cannot create reports or build dashboards, edit the saved dashboard, or change the data model. Those live in the [Workbook Agent][ref-workbook-agent]. @@ -161,5 +165,6 @@ If you need any of those, use the [Workbook Agent][ref-workbook-agent] instead. [ref-workbooks]: /docs/explore-analyze/workbooks [ref-workbook-agent]: /docs/explore-analyze/workbooks/workbook-agent [ref-controls]: /docs/explore-analyze/dashboards/widgets/controls +[ref-field-switcher]: /docs/explore-analyze/dashboards/widgets/controls#field-switcher [ref-control-visibility]: /docs/explore-analyze/dashboards/widgets/controls#visibility [ref-embedding]: /embedding/iframe/dashboards diff --git a/docs-mintlify/docs/explore-analyze/dashboards/widgets/controls.mdx b/docs-mintlify/docs/explore-analyze/dashboards/widgets/controls.mdx index 82efef0a63912..ed8b68add7a4d 100644 --- a/docs-mintlify/docs/explore-analyze/dashboards/widgets/controls.mdx +++ b/docs-mintlify/docs/explore-analyze/dashboards/widgets/controls.mdx @@ -1,15 +1,16 @@ --- title: Controls -description: Filter, time granularity switcher, and parent widgets that let dashboard viewers change what's shown on the dashboard. +description: Filter, time granularity switcher, field switcher, and parent widgets that let dashboard viewers change what's shown on the dashboard. --- -Controls are widgets that let dashboard viewers change what's shown without leaving the dashboard. The dashboard builder offers three control types: +Controls are widgets that let dashboard viewers change what's shown without leaving the dashboard. The dashboard builder offers four control types: - [Filter](#filter) — Narrow the data shown on the dashboard - [Time granularity switcher](#time-granularity-switcher) — Change the granularity of time-based dimensions +- [Field switcher](#field-switcher) — Swap which dimension or measure the charts are built on - [Parent](#parent) — Re-point several other controls at once from a single dropdown -Filters and time granularity switchers each target a dimension from your semantic model, and apply the selected value to every [chart][ref-charts] on the dashboard whose query references that dimension. A parent control works one level up: it targets no dimension of its own and drives *other controls* instead. +The first three each target a member from your semantic model, and apply the viewer's choice to every [chart][ref-charts] on the dashboard whose query references that member. Filters and time granularity switchers change *how a member is queried* — which rows come back, which buckets they fall into. A field switcher goes further and changes *which member is queried at all*. A parent control works one level up: it targets no member of its own and drives *other controls* instead. ## Filter @@ -95,11 +96,73 @@ Custom granularities defined in the [data model][ref-granularities] aren't offer You can configure a default granularity that's applied when the dashboard loads. If no default is set, charts use the granularity that was saved on the underlying report — viewers can still switch granularities, but the dashboard opens with each chart at its original granularity. +## Field switcher + +A field switcher lets viewers change *which* dimension or measure the charts are built on — swapping a revenue chart's breakdown from **Status** to **City**, or its measure from **Order count** to **Total revenue** — without leaving the dashboard or opening the report. + +Where a [filter](#filter) narrows the rows and a [time granularity switcher](#time-granularity-switcher) rebuckets them, a field switcher replaces the member itself in the chart's query. One dashboard can then answer several questions that would otherwise need a chart each. + +In the [dashboard builder][ref-workbooks], open the **Add Controls** menu in the toolbar and choose **Field Switcher**, then click **Configure Field Switcher** to set it up. + +### Choosing what it switches + +A field switcher works on one member kind at a time — set **Field Type** to either **Dimension** or **Measure**. The rest of the settings follow from that choice: + +| Setting | What it does | +|---|---| +| **Field Type** | Whether this control swaps a dimension or a measure. Switching the type resets the settings below it, since the two draw from different pools. | +| **Dimension to Replace** / **Measure to Replace** | The member the charts are currently built on — the one this control stands in for. | +| **Alternatives** | The members viewers may switch to. The replaced member is always offered as well, so a viewer can get back to the original view. | + +Alternatives come from the control's own semantic view, and must be the same kind as the replaced member — a dimension switcher offers dimensions, a measure switcher offers measures. + +### Default option {#field-switcher-default-option} + +The member a viewer starts on is set the same way a filter's static default is: by picking it in the control while you're in the dashboard builder. The selection is saved on the widget and applied to every viewer when the dashboard loads. If you never pick one, the dashboard opens on the replaced member. + +Removing a member from **Alternatives** after it was serving as the default clears the default, so viewers can't start on a member the control no longer offers. + +### Default granularity per option + +When a dimension switcher offers **time** dimensions, each of them can carry its own granularity, set under **Default granularity per option**. + +This exists because a swap otherwise inherits whatever granularity the chart already had. A viewer moving from **Created at** to a **Completed at** that only makes sense monthly would get the replaced dimension's daily buckets, and the author would have no way to say otherwise. + +Each time option is either pinned to a granularity or left at **Inherit from the chart**, which is the default and the behavior of every control configured before this setting existed. Non-time options don't have the setting, and a measure switcher has no granularities to speak of. + +If the dashboard also has a [time granularity switcher](#time-granularity-switcher) pointed at the swapped-in dimension, the viewer's own pick wins over the per-option granularity — a granularity a viewer actively chose outranks one the author set as a starting point. A granularity control nobody has touched does not. + +### User attribute default {#field-switcher-user-attribute-default} + +Like [filters](#user-attribute-default) and [parent controls](#parent-user-attribute-default), a field switcher can start each viewer on their own member. Turn on **User attribute default** in the control's settings and pick a [user attribute][ref-user-attributes]; when the dashboard loads, Cube reads that attribute for the current viewer and opens the control on the member it names. + +This is how one dashboard opens on the breakdown each audience cares about — a **Breakdown** switcher opening on `region` for one team and `channel` for another, from a single published dashboard. + +The attribute seeds the *selection*, exactly as the [default option](#field-switcher-default-option) does, and loses to a pick the viewer has already made. A value that isn't among the **Alternatives** is ignored rather than forced: the attribute is set per user and the options are set per dashboard, so the two can drift apart without anyone editing either, and the safe reading of an unusable value is "no opinion" — the control falls back to the default option. + +### What the swap preserves + +The swapped-in member is queried under the replaced member's output name, so everything the chart configured against that column keeps working across a switch — column formatting, sorting, pivots, and conditional formatting rules all survive, rather than resetting each time the viewer picks a different member. + +### When a chart can't take the switch {#when-a-chart-cant-take-the-switch} + +Cube applies the switch in two places: to the SQL that runs, and to the query description the chart formats its results with. It applies the switch only if **both** take it — otherwise the chart would be labelled and formatted as one member while showing another's numbers, which nothing on screen would reveal. + +When only one half can take it, the chart keeps rendering the member it was built on and shows a notice reading **"The Field switcher could not be applied to this chart"**. The usual reason is a query Cube can't read back as semantic members — a hand-written one, or one built with a `JOIN` or `UNION`. The rest of the dashboard still switches. + +A chart whose query doesn't use the replaced member at all is a different case: it is simply out of the control's scope, exactly as it would be for a filter, and shows no notice. + +A chart with a [period comparison][ref-charts] is a narrower case: the comparison can't follow a member switch, so the chart applies the switch and drops the comparison, saying so in its own notice rather than silently showing a comparison that no longer matches the data. + + +A field switcher can't be a [parent control's](#parent) child, and a viewer's choice in one isn't carried in the [shared URL](#sharing-the-current-selection). Both are current limitations rather than deliberate design. + + ## Parent A parent control is a dropdown of options you define. Picking one re-points a whole row of other controls at once — so a viewer makes a single choice instead of adjusting three or four filters by hand. -Unlike the other two control types, a parent control targets no dimension and never touches a chart query directly. It applies values to the controls it *drives* — its **children** — and those children then apply themselves to charts exactly as if the viewer had operated each one. Filters and time granularity switchers can both be children; a parent control cannot be a child of another parent control. +Unlike the other control types, a parent control targets no member and never touches a chart query directly. It applies values to the controls it *drives* — its **children** — and those children then apply themselves to charts exactly as if the viewer had operated each one. Filters and time granularity switchers can both be children; a [field switcher](#field-switcher) cannot yet, and a parent control cannot be a child of another parent control. For example, an **Analysis** parent with the options `Retail`, `Wholesale` and `Promo` can set a **Channel** filter, a **Minimum order value** filter, and a **Date range** filter to a different combination for each option. Viewers see one dropdown; you can [hide](#visibility) the children if the individual values aren't worth showing. @@ -135,7 +198,7 @@ A control can be driven by only one parent control at a time. Mapping a child th ### Mapping status on child controls -Once a dashboard has at least one parent control, every filter and time granularity switcher on it shows a small indicator reporting how it's driven: +Once a dashboard has at least one parent control, every filter and time granularity switcher on it shows a small indicator reporting how it's driven. [Field switchers](#field-switcher) don't, since a parent can't drive one: | Status | Meaning | |---|---| @@ -212,13 +275,14 @@ What does and doesn't travel in the link: - **Only what the viewer chose.** Values that came from the control's own configuration — a static default, a [default granularity](#default-granularity) — are not written into the URL. Every viewer already gets those from the dashboard itself, and leaving them out means a link stays correct after the dashboard's defaults change. - **Never a personalized default.** A value resolved from a [user attribute](#user-attribute-default) stays out of the link — whether it seeded a filter directly or reached one through a [parent control](#parent) opening on the viewer's own option. Sharing a dashboard never pins your attribute value onto the recipient; they see it through their own attributes. - **Filters and granularities together.** Picking both puts both in the link, including when a [parent control](#parent) sets several children at once. A parent control isn't serialized itself — the link carries the values its children ended up with, so the recipient sees the same data while the parent dropdown opens on whatever default it resolves for them, which may not be the option the sharer picked. +- **Not the field switcher, yet.** A [field switcher](#field-switcher) has no parameter of its own, so a viewer's member choice doesn't travel in the link. The recipient opens on the control's [default option](#field-switcher-default-option), or on their own [user attribute](#field-switcher-user-attribute-default) where one is set — and on the charts the sharer was looking at, built on a different member than the sharer saw. - **Written out on published dashboards only.** Reading these parameters works anywhere, including [embedded][ref-embed-url-filters] dashboards; it's the writing that is published-only. In the dashboard builder the URL is left to the editing session, so changing a control there doesn't rewrite it. When a dashboard opens with these parameters, they are applied on top of whatever defaults the controls carry. A parameter is ignored when nothing on the dashboard can honor it — there is no matching control for that dimension, or the requested granularity isn't in the switcher's [allowed granularities](#allowed-granularities). ## Visibility -Each control has a **Visibility** setting that determines how it appears on the published dashboard. The setting applies to all three control types. +Each control has a **Visibility** setting that determines how it appears on the published dashboard. The setting applies to all four control types. | Visibility | Behavior on the published dashboard | |---|---| @@ -230,13 +294,13 @@ Set the visibility from the **Visibility** dropdown when editing the control. ** ## Interaction with charts -This section applies to filters and time granularity switchers. A [parent control](#parent) has no dimension and never applies to a chart itself, so it doesn't appear in any chart's [Controls mapping](#controls-mapping) — it acts only through the children it drives, and it's those children that show up here. +This section applies to filters, time granularity switchers and field switchers. A [parent control](#parent) has no member of its own and never applies to a chart itself, so it doesn't appear in any chart's [Controls mapping](#controls-mapping) — it acts only through the children it drives, and it's those children that show up here. -When a control is added to a dashboard, it's automatically wired up to every [chart][ref-charts] whose query already uses the same dimension. Charts that don't reference that dimension are left alone, so a dashboard can mix scoped and unscoped views by default. You can override this default per chart from its [Controls mapping](#controls-mapping) — disable the control for that chart, or remap it onto a different dimension. +When a control is added to a dashboard, it's automatically wired up to every [chart][ref-charts] whose query already uses the same member. Charts that don't reference that member are left alone, so a dashboard can mix scoped and unscoped views by default. Filters and time granularity switchers always target a dimension; a [field switcher](#field-switcher) targets a dimension or a measure depending on its **Field Type**, and scopes on whichever it is set to. You can override this default per chart from its [Controls mapping](#controls-mapping) — disable the control for that chart, or remap it onto a different member. ### Incompatible controls -If controls of a certain type are incompatible with a particular chart's query, the chart skips all controls of that type and renders the data without them. Filters and time granularity switchers are skipped independently — if filters fail but a time granularity switcher works, the chart shows the granularity-adjusted data without filtering, and vice versa. +If controls of a certain type are incompatible with a particular chart's query, the chart skips all controls of that type and renders the data without them. Each type is skipped independently — if filters fail but a time granularity switcher works, the chart shows the granularity-adjusted data without filtering, and vice versa. A [field switcher](#field-switcher) that can't be applied says so [on the chart itself](#when-a-chart-cant-take-the-switch) rather than through the icons below. The chart displays a warning icon to indicate the problem: @@ -249,26 +313,32 @@ Hover over the icon for details. Click it to open the chart's [Controls mapping] ### Controls mapping -Each chart decides which controls apply to it through its **Controls mapping**. The mapping is resolved automatically in most cases and only needs manual attention when a control targets a dimension the chart doesn't have. +Each chart decides which controls apply to it through its **Controls mapping**. The mapping is resolved automatically in most cases and only needs manual attention when a control targets a member the chart doesn't have. Open **Controls mapping** from a chart's settings menu to inspect or override the mapping for that chart. For each control on the dashboard you can: - **Toggle the control on or off** for the chart, even when a mapping exists -- **Pick a different dimension** from the chart's semantic view to remap the control to +- **Pick a different member** from the chart's semantic view to remap the control to Three states show up in the mapping sidebar: | Status | What it means | |---|---| -| **Mapped automatically** | The control's dimension exists on the chart's semantic view, so it's wired up without configuration. | -| **Manually mapped** | You (or an AI agent) picked a specific dimension for this chart. **Reset** restores the automatic mapping. | -| **Can't map automatically** | The control targets a dimension that doesn't exist on the chart's semantic view. The chart is unaffected by the control until you map it manually. | +| **Mapped automatically** | The control's member exists on the chart's semantic view, so it's wired up without configuration. | +| **Manually mapped** | You (or an AI agent) picked a specific member for this chart. **Reset** restores the automatic mapping. | +| **Can't map automatically** | The control targets a member that doesn't exist on the chart's semantic view. The chart is unaffected by the control until you map it manually. | -For [time granularity switchers][ref-time-grain], the dimension picker is restricted to time-typed dimensions on the chart's semantic view, since other dimension types can't be resolved by the time granularity pipeline. +Each control's picker offers only the members it can actually be resolved against, so a mapping you can stage is a mapping that will work: + +| Control | What the picker offers | +|---|---| +| [Filter](#filter) | Dimensions on the chart's semantic view. | +| [Time granularity switcher](#time-granularity-switcher) | Time-typed dimensions only — other types can't be resolved by the time granularity pipeline. | +| [Field switcher](#field-switcher) set to **Dimension** | Dimensions. | +| [Field switcher](#field-switcher) set to **Measure** | Measures, since the control replaces a measure. | -Mappings are also configurable by AI agents when they build or edit a dashboard, so an agent can wire controls across charts that use different semantic views without you needing to revisit each chart manually. +Filter and time granularity mappings are also configurable by AI agents when they build or edit a dashboard, so an agent can wire those controls across charts that use different semantic views without you needing to revisit each chart manually. Field switchers are outside what agents author, so their mappings are yours to set. -[ref-time-grain]: #time-granularity-switcher [ref-embed-url-filters]: /embedding/iframe/dashboards#pre-set-dashboard-filters-via-url [ref-workbooks]: /docs/explore-analyze/workbooks diff --git a/docs-mintlify/docs/explore-analyze/dashboards/widgets/index.mdx b/docs-mintlify/docs/explore-analyze/dashboards/widgets/index.mdx index ca5fd69109586..c4145c9eb3ff2 100644 --- a/docs-mintlify/docs/explore-analyze/dashboards/widgets/index.mdx +++ b/docs-mintlify/docs/explore-analyze/dashboards/widgets/index.mdx @@ -11,13 +11,13 @@ The dashboard builder supports the following widget types: - [Charts](/docs/explore-analyze/dashboards/widgets/charts) — Visualize reports from your workbook - [Text](/docs/explore-analyze/dashboards/widgets/text) — Add titles, descriptions, and rich formatting in Markdown -- [Controls](/docs/explore-analyze/dashboards/widgets/controls) — Let viewers filter the data, switch the time granularity, or drive several controls at once +- [Controls](/docs/explore-analyze/dashboards/widgets/controls) — Let viewers filter the data, switch the time granularity, swap which field the charts are built on, or drive several controls at once - [AI summary](/docs/explore-analyze/dashboards/widgets/ai-summary) — Generate narrative summaries of dashboard data on demand - [Spacer & Divider](/docs/explore-analyze/dashboards/widgets/layout) — Non-data layout elements for whitespace and section breaks ## Adding widgets -Add widgets from the toolbar at the top of the dashboard builder: pick reports from the **Charts** picker to add charts, use the **Add Widgets** menu for text, AI summaries, and layout elements, or the **Add Controls** menu for **Filter**, **Time Granularity** and **Parent** controls. +Add widgets from the toolbar at the top of the dashboard builder: pick reports from the **Charts** picker to add charts, use the **Add Widgets** menu for text, AI summaries, and layout elements, or the **Add Controls** menu for **Filter**, **Time Granularity**, **Field Switcher** and **Parent** controls. Each item — a toolbar button, or an option inside the **Add Widgets** / **Add Controls** menus — can be added in two ways: