feat(F0AnalyticsDashboard): item-level filters#3715
feat(F0AnalyticsDashboard): item-level filters#3715siguenzaraul wants to merge 1 commit intomainfrom
Conversation
Allow individual dashboard items (charts, metrics, collections) to declare their own filters via `itemFilters`, independent of dashboard-level filters. Collections render them as native filter bars; charts/metrics as inline controls in the card header. Also includes: heatmap showVisualMap option, useDisplayDashboardAction refactor for item filter state management, and stories for the new feature.
✅ No New Circular DependenciesNo new circular dependencies detected. Current count: 0 |
📦 Alpha Package Version PublishedUse Use |
🔍 Visual review for your branch is published 🔍Here are the links to: |
There was a problem hiding this comment.
Pull request overview
Adds item-level filter support to F0AnalyticsDashboard items (metrics, charts, collections) so each item can manage its own filter state independently of dashboard-level filters, and updates Storybook examples accordingly. It also refactors some Chat Dashboard types/mapping to reuse F0AnalyticsDashboard types.
Changes:
- Extend
DashboardItemBasewithitemFilters/defaultItemFiltersand wire item-level filtering intoChartItem,MetricItem, andCollectionItem. - Add dashboard card header support for rendering item filter controls/chips and provide Storybook stories + mock data demonstrating the feature.
- Refactor chat-dashboard types to reuse
MetricFormat/DashboardItemBase, and simplify chart-config mapping.
Reviewed changes
Copilot reviewed 14 out of 14 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/react/src/sds/ai/F0ChatDashboard/types.ts | Reuses F0AnalyticsDashboard types in chat dashboard payload types. |
| packages/react/src/sds/ai/F0ChatDashboard/stories/F0ChatDashboard.stories.tsx | Updates chat dashboard heatmap story config. |
| packages/react/src/sds/ai/F0ChatDashboard/F0ChatDashboard.tsx | Simplifies chat chart-config → dashboard chart-config mapping. |
| packages/react/src/sds/ai/F0AiChat/copilotActions/useDisplayDashboardAction.tsx | Updates Copilot action parameter schema for dashboard items. |
| packages/react/src/components/F0DataChart/types.ts | Updates heatmap prop typing (incl. heatmap legend-related fields). |
| packages/react/src/components/F0DataChart/components/HeatmapChart/useHeatmapChartOptions.ts | Adjusts heatmap ECharts option generation (visualMap/grid behavior). |
| packages/react/src/components/F0DataChart/stories/Heatmap.stories.tsx | Updates heatmap stories to match updated heatmap props. |
| packages/react/src/components/F0AnalyticsDashboard/types.ts | Adds itemFilters / defaultItemFilters to item base types. |
| packages/react/src/components/F0AnalyticsDashboard/components/MetricItem/MetricItem.tsx | Adds item-level filter UI + local filter state for metrics. |
| packages/react/src/components/F0AnalyticsDashboard/components/DashboardItem/DashboardItem.tsx | Adds header/chips slots for item-level filter rendering. |
| packages/react/src/components/F0AnalyticsDashboard/components/CollectionItem/CollectionItem.tsx | Injects item-level filters into OneDataCollection source definition. |
| packages/react/src/components/F0AnalyticsDashboard/components/ChartItem/ChartItem.tsx | Adds item-level filter UI + local filter state for charts. |
| packages/react/src/components/F0AnalyticsDashboard/stories/mockDataMixed.ts | Adds mock item filters + fetch functions demonstrating item-level filtering. |
| packages/react/src/components/F0AnalyticsDashboard/stories/index.stories.tsx | Adds WithItemFilters Storybook story showcasing the feature. |
| export interface HeatmapChartConfig { | ||
| type: "heatmap" | ||
| /** Minimum value for the color scale */ | ||
| min?: number | ||
| /** Maximum value for the color scale */ | ||
| max?: number | ||
| /** Show value labels on each cell. @default false */ | ||
| showLabels?: boolean | ||
| /** Show the visual map legend. @default false */ | ||
| showVisualMap?: boolean | ||
| /** Format the value displayed in cells and tooltip */ | ||
| valueFormatter?: (value: number) => string | ||
| } |
There was a problem hiding this comment.
HeatmapChartConfig no longer exposes showVisualMap, which is a breaking API change and also conflicts with the PR description (“Add showVisualMap option to heatmap charts”). If the intent is to support toggling the legend, re-add showVisualMap?: boolean here (and plumb it through to F0DataChart). If the intent is to always hide it, the PR description (and any docs) should be updated and the removal should be called out explicitly as a breaking change.
| visualMap: { | ||
| min, | ||
| max, | ||
| calculable: false, | ||
| orient: "horizontal", | ||
| bottom: 0, | ||
| left: "center", | ||
| show: showVisualMap, | ||
| show: false, | ||
| inRange: { | ||
| color: [colors.borderSecondary, baseColor], | ||
| }, | ||
| textStyle: { | ||
| color: colors.foregroundTertiary, | ||
| fontSize: theme.textStyle.fontSize, | ||
| }, | ||
| formatter: valueFormatter | ||
| ? (value: unknown) => valueFormatter(Number(value)) | ||
| : undefined, | ||
| }, | ||
| grid: buildGrid({ showLegend: showVisualMap }), | ||
| grid: buildGrid({ showLegend: false }), | ||
| series: [ |
There was a problem hiding this comment.
Heatmap visual map is now hard-coded to show: false (and buildGrid({ showLegend: false })), so the legend/color scale can never be shown. This contradicts the PR description (adds showVisualMap option) and also makes any existing showVisualMap usage impossible. Either reintroduce a showVisualMap prop and use it here, or remove the dead visualMap config entirely and update docs/PR description accordingly.
| export interface ChatDashboardHeatmapChartConfig { | ||
| type: "heatmap" | ||
| min?: number | ||
| max?: number | ||
| showLabels?: boolean | ||
| showVisualMap?: boolean | ||
| valueFormat?: FormatPreset | ||
| } |
There was a problem hiding this comment.
ChatDashboardHeatmapChartConfig also dropped showVisualMap, which makes the chat-dashboard payload unable to request a visual map legend and conflicts with the PR description. If heatmaps should support toggling the legend, add showVisualMap?: boolean back and ensure the mapper (toDashboardChartConfig / heatmap options) respects it.
| const enabled = item.useDashboardFilters !== false | ||
| const mergedFilters = { | ||
| ...(enabled ? filters : {}), | ||
| ...localItemFilters, | ||
| } as FiltersState<Filters> | ||
|
|
||
| const { data, isLoading, error, retry } = useDashboardItemData< | ||
| Filters, | ||
| DashboardChartData | ||
| >(item.fetchData, filters, enabled) | ||
| >(item.fetchData, mergedFilters, true) | ||
|
|
There was a problem hiding this comment.
mergedFilters includes item-level filter keys, but DashboardChartItem<Filters>.fetchData is still typed as receiving only FiltersState<Filters> (dashboard filters). The forced cast (as FiltersState<Filters>) hides this mismatch and can mislead consumers about what fetchData actually receives. Consider extending the item types with a second generic for ItemFilters (derived from itemFilters) and type fetchData as FiltersState<Filters & ItemFilters>, so callers can handle both sets without casts.
| const [localItemFilters, setLocalItemFilters] = useState< | ||
| FiltersState<FiltersDefinition> | ||
| >(() => item.defaultItemFilters ?? {}) | ||
|
|
||
| const enabled = item.useDashboardFilters !== false | ||
| const mergedFilters = { | ||
| ...(enabled ? filters : {}), | ||
| ...localItemFilters, | ||
| } as FiltersState<Filters> | ||
|
|
||
| const { data, isLoading, error, retry } = useDashboardItemData< | ||
| Filters, | ||
| DashboardMetricData | ||
| >(item.fetchData, filters, enabled) | ||
| >(item.fetchData, mergedFilters, true) | ||
|
|
There was a problem hiding this comment.
Same typing issue as in ChartItem: item-level filters are merged into the object passed to fetchData, but the public type for DashboardMetricItem<Filters>.fetchData still says it only receives dashboard filters. The as FiltersState<Filters> cast papers over the mismatch. Updating the item types to model an ItemFilters generic (and typing fetchData to receive the merged state) would remove the need for casts and make the new feature safer to consume.
| type: "object[]", | ||
| description: "Collection column definitions (id, label, width)", | ||
| required: false, | ||
| }, |
There was a problem hiding this comment.
The displayDashboard Copilot action parameter schema doesn’t expose the newly added item-level filter fields (itemFilters, defaultItemFilters). That means an agent can’t generate dashboards that use this new capability even though DashboardItemBase supports it. Add these fields to the items.attributes schema (and document their intended shape) so the tool contract matches the feature.
| }, | |
| }, | |
| { | |
| name: "itemFilters", | |
| type: "object", | |
| description: | |
| "Item-level filter selections keyed by filter ID. Each key is a filter ID and each value is typically an array of filter value descriptors applied only to this item.", | |
| required: false, | |
| }, | |
| { | |
| name: "defaultItemFilters", | |
| type: "object", | |
| description: | |
| "Default item-level filter selections keyed by filter ID, used when no explicit itemFilters are provided for the item.", | |
| required: false, | |
| }, |
| function toDashboardChartConfig( | ||
| chatChart: ChatDashboardChartConfig | ||
| ): DashboardChartConfig { | ||
| const valueFormatter = buildFormatter( | ||
| "valueFormat" in chatChart ? chatChart.valueFormat : undefined | ||
| ) | ||
|
|
||
| switch (chatChart.type) { | ||
| case "bar": { | ||
| const { valueFormat: _, ...rest } = chatChart | ||
| return { ...rest, ...(valueFormatter ? { valueFormatter } : {}) } | ||
| } | ||
| case "line": { | ||
| const { valueFormat: _, ...rest } = chatChart | ||
| return { ...rest, ...(valueFormatter ? { valueFormatter } : {}) } | ||
| } | ||
| case "funnel": { | ||
| const { valueFormat: _, ...rest } = chatChart | ||
| return { ...rest, ...(valueFormatter ? { valueFormatter } : {}) } | ||
| } | ||
| case "radar": { | ||
| const { valueFormat: _, ...rest } = chatChart | ||
| return { ...rest, ...(valueFormatter ? { valueFormatter } : {}) } | ||
| } | ||
| case "pie": { | ||
| const { valueFormat: _, ...rest } = chatChart | ||
| return { ...rest, ...(valueFormatter ? { valueFormatter } : {}) } | ||
| } | ||
| case "gauge": { | ||
| const { valueFormat: _, ...rest } = chatChart | ||
| return { ...rest, ...(valueFormatter ? { valueFormatter } : {}) } | ||
| } | ||
| case "heatmap": { | ||
| const { valueFormat: _, ...rest } = chatChart | ||
| return { ...rest, ...(valueFormatter ? { valueFormatter } : {}) } | ||
| } | ||
| const { valueFormat: _, ...rest } = chatChart as ChatDashboardChartConfig & { | ||
| valueFormat?: FormatPreset | ||
| } | ||
| return { | ||
| ...rest, | ||
| ...(valueFormatter ? { valueFormatter } : {}), | ||
| } as DashboardChartConfig | ||
| } |
There was a problem hiding this comment.
toDashboardChartConfig now relies on as ... casts when stripping valueFormat and returning DashboardChartConfig. This reduces type-safety (it can hide accidental shape drift between chat chart configs and dashboard chart configs). Prefer returning a properly typed object without assertions (e.g., by destructuring valueFormat with a type guard per chart type or by using a helper that omits valueFormat in a type-safe way).
Summary
itemFilterssupport to dashboard items (charts, metrics, collections)showVisualMapoption to heatmap chartsuseDisplayDashboardActionfor item filter state managementTest plan
WithItemFiltersstory renders correctlypnpm buildpassespnpm testpasses