Skip to content

Commit 16c14d6

Browse files
authored
Merge pull request #1545 from visualize-admin/feat/dashboard-filters
Dashboard filters
2 parents 8fd3755 + 910bf8a commit 16c14d6

53 files changed

Lines changed: 2469 additions & 1371 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

app/charts/column/chart-column.tsx

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ import {
1616
AxisWidthBand,
1717
AxisWidthBandDomain,
1818
} from "@/charts/shared/axis-width-band";
19-
import { BrushTime } from "@/charts/shared/brush";
19+
import { BrushTime, shouldShowBrush } from "@/charts/shared/brush";
2020
import {
2121
ChartContainer,
2222
ChartControlsContainer,
@@ -26,6 +26,7 @@ import { Tooltip } from "@/charts/shared/interaction/tooltip";
2626
import { LegendColor } from "@/charts/shared/legend-color";
2727
import { ColumnConfig, useChartConfigFilters } from "@/config-types";
2828
import { TimeSlider } from "@/configurator/interactive-filters/time-slider";
29+
import { useDashboardInteractiveFilters } from "@/stores/interactive-filters";
2930

3031
import { ChartProps, VisualizationProps } from "../shared/ChartProps";
3132

@@ -39,6 +40,12 @@ export const ChartColumns = memo((props: ChartProps<ColumnConfig>) => {
3940
const { chartConfig, dimensions } = props;
4041
const { fields, interactiveFiltersConfig } = chartConfig;
4142
const filters = useChartConfigFilters(chartConfig);
43+
const { sharedFilters } = useDashboardInteractiveFilters();
44+
45+
const showTimeBrush = shouldShowBrush(
46+
interactiveFiltersConfig,
47+
sharedFilters
48+
);
4249

4350
return (
4451
<>
@@ -49,7 +56,7 @@ export const ChartColumns = memo((props: ChartProps<ColumnConfig>) => {
4956
<AxisHeightLinear /> <AxisWidthBand />
5057
<ColumnsStacked /> <AxisWidthBandDomain />
5158
<InteractionColumns />
52-
{interactiveFiltersConfig?.timeRange.active && <BrushTime />}
59+
{showTimeBrush && <BrushTime />}
5360
</ChartSvg>
5461
<Tooltip type="multiple" />
5562
</ChartContainer>
@@ -80,7 +87,7 @@ export const ChartColumns = memo((props: ChartProps<ColumnConfig>) => {
8087
<ErrorWhiskersGrouped />
8188
<AxisWidthBandDomain />
8289
<InteractionColumns />
83-
{interactiveFiltersConfig?.timeRange.active && <BrushTime />}
90+
{showTimeBrush && <BrushTime />}
8491
</ChartSvg>
8592
<Tooltip type="multiple" />
8693
</ChartContainer>
@@ -111,7 +118,7 @@ export const ChartColumns = memo((props: ChartProps<ColumnConfig>) => {
111118
<ErrorWhiskers />
112119
<AxisWidthBandDomain />
113120
<InteractionColumns />
114-
{interactiveFiltersConfig?.timeRange.active && <BrushTime />}
121+
{showTimeBrush && <BrushTime />}
115122
</ChartSvg>
116123
<Tooltip type="single" />
117124
</ChartContainer>

app/charts/combo/chart-combo-line-column.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,13 @@ import { AxisHeightLinearDual } from "@/charts/combo/axis-height-linear-dual";
66
import { ComboLineColumn } from "@/charts/combo/combo-line-column";
77
import { ComboLineColumnChart } from "@/charts/combo/combo-line-column-state";
88
import { AxisWidthBand } from "@/charts/shared/axis-width-band";
9-
import { BrushTime } from "@/charts/shared/brush";
9+
import { BrushTime, shouldShowBrush } from "@/charts/shared/brush";
1010
import { ChartContainer, ChartSvg } from "@/charts/shared/containers";
1111
import { HoverDotMultiple } from "@/charts/shared/interaction/hover-dots-multiple";
1212
import { Ruler } from "@/charts/shared/interaction/ruler";
1313
import { Tooltip } from "@/charts/shared/interaction/tooltip";
1414
import { ComboLineColumnConfig } from "@/config-types";
15+
import { useDashboardInteractiveFilters } from "@/stores/interactive-filters";
1516

1617
import { ChartProps, VisualizationProps } from "../shared/ChartProps";
1718

@@ -25,6 +26,7 @@ export const ChartComboLineColumn = memo(
2526
(props: ChartProps<ComboLineColumnConfig>) => {
2627
const { chartConfig } = props;
2728
const { interactiveFiltersConfig } = chartConfig;
29+
const { sharedFilters } = useDashboardInteractiveFilters();
2830

2931
return (
3032
<ComboLineColumnChart {...props}>
@@ -35,7 +37,9 @@ export const ChartComboLineColumn = memo(
3537
<AxisWidthBand />
3638
<ComboLineColumn />
3739
<InteractionColumns />
38-
{interactiveFiltersConfig?.timeRange.active && <BrushTime />}
40+
{shouldShowBrush(interactiveFiltersConfig, sharedFilters) && (
41+
<BrushTime />
42+
)}
3943
</ChartSvg>
4044
<HoverDotMultiple />
4145
<Ruler rotate />

app/charts/combo/chart-combo-line-dual.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,14 @@ import { AxisHeightLinearDual } from "@/charts/combo/axis-height-linear-dual";
55
import { ComboLineDual } from "@/charts/combo/combo-line-dual";
66
import { ComboLineDualChart } from "@/charts/combo/combo-line-dual-state";
77
import { AxisTime, AxisTimeDomain } from "@/charts/shared/axis-width-time";
8-
import { BrushTime } from "@/charts/shared/brush";
8+
import { BrushTime, shouldShowBrush } from "@/charts/shared/brush";
99
import { ChartContainer, ChartSvg } from "@/charts/shared/containers";
1010
import { HoverDotMultiple } from "@/charts/shared/interaction/hover-dots-multiple";
1111
import { Ruler } from "@/charts/shared/interaction/ruler";
1212
import { Tooltip } from "@/charts/shared/interaction/tooltip";
1313
import { InteractionHorizontal } from "@/charts/shared/overlay-horizontal";
1414
import { ComboLineDualConfig } from "@/config-types";
15+
import { useDashboardInteractiveFilters } from "@/stores/interactive-filters";
1516

1617
import { ChartProps, VisualizationProps } from "../shared/ChartProps";
1718

@@ -25,6 +26,7 @@ export const ChartComboLineDual = memo(
2526
(props: ChartProps<ComboLineDualConfig>) => {
2627
const { chartConfig } = props;
2728
const { interactiveFiltersConfig } = chartConfig;
29+
const { sharedFilters } = useDashboardInteractiveFilters();
2830

2931
return (
3032
<ComboLineDualChart {...props}>
@@ -35,7 +37,9 @@ export const ChartComboLineDual = memo(
3537
<AxisTimeDomain />
3638
<ComboLineDual />
3739
<InteractionHorizontal />
38-
{interactiveFiltersConfig?.timeRange.active && <BrushTime />}
40+
{shouldShowBrush(interactiveFiltersConfig, sharedFilters) && (
41+
<BrushTime />
42+
)}
3943
</ChartSvg>
4044
<HoverDotMultiple />
4145
<Ruler />

app/charts/combo/chart-combo-line-single.tsx

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { ComboLineSingle } from "@/charts/combo/combo-line-single";
55
import { ComboLineSingleChart } from "@/charts/combo/combo-line-single-state";
66
import { AxisHeightLinear } from "@/charts/shared/axis-height-linear";
77
import { AxisTime, AxisTimeDomain } from "@/charts/shared/axis-width-time";
8-
import { BrushTime } from "@/charts/shared/brush";
8+
import { BrushTime, shouldShowBrush } from "@/charts/shared/brush";
99
import {
1010
ChartContainer,
1111
ChartControlsContainer,
@@ -17,6 +17,7 @@ import { Tooltip } from "@/charts/shared/interaction/tooltip";
1717
import { LegendColor } from "@/charts/shared/legend-color";
1818
import { InteractionHorizontal } from "@/charts/shared/overlay-horizontal";
1919
import { ComboLineSingleConfig } from "@/config-types";
20+
import { useDashboardInteractiveFilters } from "@/stores/interactive-filters";
2021

2122
import { ChartProps, VisualizationProps } from "../shared/ChartProps";
2223

@@ -30,6 +31,8 @@ export const ChartComboLineSingle = memo(
3031
(props: ChartProps<ComboLineSingleConfig>) => {
3132
const { chartConfig, measures } = props;
3233
const { interactiveFiltersConfig } = chartConfig;
34+
const { sharedFilters } = useDashboardInteractiveFilters();
35+
3336
const getLegendItemDimension = useCallback(
3437
(label: string) => {
3538
return measures.find((measure) => measure.label === label);
@@ -44,7 +47,9 @@ export const ChartComboLineSingle = memo(
4447
<AxisHeightLinear /> <AxisTime /> <AxisTimeDomain />
4548
<ComboLineSingle />
4649
<InteractionHorizontal />
47-
{interactiveFiltersConfig?.timeRange.active && <BrushTime />}
50+
{shouldShowBrush(interactiveFiltersConfig, sharedFilters) && (
51+
<BrushTime />
52+
)}
4853
</ChartSvg>
4954
<HoverDotMultiple />
5055
<Ruler />

app/charts/index.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -338,7 +338,7 @@ export const META: Meta = {
338338

339339
type GetInitialConfigOptions = {
340340
key?: string;
341-
iris: { iri: string; publishIri: string }[];
341+
iris: { iri: string; publishIri: string; joinBy?: string[] }[];
342342
chartType: ChartType;
343343
dimensions: Dimension[];
344344
measures: Measure[];
@@ -364,10 +364,11 @@ export const getInitialConfig = (
364364
// Technically, we should scope filters per cube; but as we only set initial
365365
// filters for area charts, and we can only have multi-cubes for combo charts,
366366
// we can ignore the filters scoping for now.
367-
cubes: iris.map(({ iri, publishIri }) => ({
367+
cubes: iris.map(({ iri, publishIri, joinBy }) => ({
368368
iri,
369369
publishIri,
370370
filters: filters ?? {},
371+
joinBy,
371372
})),
372373
activeField: undefined,
373374
};

app/charts/line/chart-lines.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import { Lines } from "@/charts/line/lines";
55
import { LineChart } from "@/charts/line/lines-state";
66
import { AxisHeightLinear } from "@/charts/shared/axis-height-linear";
77
import { AxisTime, AxisTimeDomain } from "@/charts/shared/axis-width-time";
8-
import { BrushTime } from "@/charts/shared/brush";
8+
import { BrushTime, shouldShowBrush } from "@/charts/shared/brush";
99
import {
1010
ChartContainer,
1111
ChartControlsContainer,
@@ -17,6 +17,7 @@ import { Tooltip } from "@/charts/shared/interaction/tooltip";
1717
import { LegendColor } from "@/charts/shared/legend-color";
1818
import { InteractionHorizontal } from "@/charts/shared/overlay-horizontal";
1919
import { LineConfig } from "@/config-types";
20+
import { useDashboardInteractiveFilters } from "@/stores/interactive-filters";
2021

2122
import { ChartProps, VisualizationProps } from "../shared/ChartProps";
2223

@@ -29,6 +30,7 @@ export const ChartLinesVisualization = (
2930
export const ChartLines = memo((props: ChartProps<LineConfig>) => {
3031
const { chartConfig } = props;
3132
const { fields, interactiveFiltersConfig } = chartConfig;
33+
const { sharedFilters } = useDashboardInteractiveFilters();
3234

3335
return (
3436
<LineChart {...props}>
@@ -37,7 +39,9 @@ export const ChartLines = memo((props: ChartProps<LineConfig>) => {
3739
<AxisHeightLinear /> <AxisTime /> <AxisTimeDomain />
3840
<Lines />
3941
<InteractionHorizontal />
40-
{interactiveFiltersConfig?.timeRange.active && <BrushTime />}
42+
{shouldShowBrush(interactiveFiltersConfig, sharedFilters) && (
43+
<BrushTime />
44+
)}
4145
</ChartSvg>
4246

4347
<Ruler />

app/charts/shared/brush/index.tsx

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,17 @@ import { makeGetClosestDatesFromDateRange } from "@/charts/shared/brush/utils";
1212
import type { ChartWithInteractiveXTimeRangeState } from "@/charts/shared/chart-state";
1313
import { useChartState } from "@/charts/shared/chart-state";
1414
import { useChartTheme } from "@/charts/shared/use-chart-theme";
15+
import {
16+
ColumnConfig,
17+
ComboLineColumnConfig,
18+
ComboLineDualConfig,
19+
ComboLineSingleConfig,
20+
LineConfig,
21+
} from "@/configurator";
1522
import { Observation } from "@/domain/data";
1623
import { useFormatFullDateAuto } from "@/formatters";
1724
import {
25+
SharedFilter,
1826
useChartInteractiveFilters,
1927
useInteractiveFiltersGetState,
2028
} from "@/stores/interactive-filters";
@@ -26,6 +34,28 @@ export const HANDLE_HEIGHT = 14;
2634
export const BRUSH_HEIGHT = 3;
2735
export const HEIGHT = HANDLE_HEIGHT + BRUSH_HEIGHT;
2836

37+
export const shouldShowBrush = (
38+
interactiveFiltersConfig:
39+
| (
40+
| LineConfig
41+
| ComboLineSingleConfig
42+
| ComboLineDualConfig
43+
| ComboLineColumnConfig
44+
| ColumnConfig
45+
)["interactiveFiltersConfig"]
46+
| undefined,
47+
sharedFilters: SharedFilter[] | undefined
48+
) => {
49+
const chartTimeRange = interactiveFiltersConfig?.timeRange;
50+
const chartTimeRangeIri = chartTimeRange?.componentIri;
51+
const sharedFilter = sharedFilters?.find(
52+
(x) => x.type === "timeRange" && x.componentIri === chartTimeRangeIri
53+
);
54+
return (
55+
(chartTimeRange?.active && !sharedFilter) || sharedFilter?.active == false
56+
);
57+
};
58+
2959
export const BrushTime = () => {
3060
const ref = useRef<SVGGElement>(null);
3161
const timeRange = useChartInteractiveFilters((d) => d.timeRange);

app/charts/shared/chart-data-filters.tsx

Lines changed: 11 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import {
3030
canRenderDatePickerField,
3131
DatePickerField,
3232
} from "@/configurator/components/field-date-picker";
33+
import { extractDataPickerOptionsFromDimension } from "@/configurator/components/ui-helpers";
3334
import { FIELD_VALUE_NONE } from "@/configurator/constants";
3435
import {
3536
Dimension,
@@ -363,15 +364,17 @@ const DataFilter = ({
363364
);
364365
};
365366

366-
type DataFilterGenericDimensionProps = {
367+
export type DataFilterGenericDimensionProps = {
367368
dimension: Dimension;
368369
value: string;
369370
onChange: (e: SelectChangeEvent<unknown>) => void;
370371
options?: Array<{ label: string; value: string }>;
371372
disabled: boolean;
372373
};
373374

374-
const DataFilterGenericDimension = (props: DataFilterGenericDimensionProps) => {
375+
export const DataFilterGenericDimension = (
376+
props: DataFilterGenericDimensionProps
377+
) => {
375378
const { dimension, value, onChange, options: propOptions, disabled } = props;
376379
const { label, isKeyDimension } = dimension;
377380
const noneLabel = t({
@@ -488,48 +491,17 @@ const DataFilterTemporalDimension = ({
488491
) => void;
489492
disabled: boolean;
490493
}) => {
491-
const { isKeyDimension, label, values, timeUnit, timeFormat } = dimension;
494+
const { label, timeUnit, timeFormat } = dimension;
492495
const formatLocale = useTimeFormatLocale();
493496
const formatDate = formatLocale.format(timeFormat);
494497
const parseDate = formatLocale.parse(timeFormat);
495498

496-
const noneLabel = t({
497-
id: "controls.dimensionvalue.none",
498-
message: "No Filter",
499-
});
500499
const { minDate, maxDate, options, optionValues } = useMemo(() => {
501-
if (values.length) {
502-
const options = values.map((d) => {
503-
return {
504-
label: `${d.value}`,
505-
value: `${d.value}`,
506-
};
507-
});
508-
509-
return {
510-
minDate: parseDate(values[0].value as string) as Date,
511-
maxDate: parseDate(values[values.length - 1].value as string) as Date,
512-
options: isKeyDimension
513-
? options
514-
: [
515-
{
516-
value: FIELD_VALUE_NONE,
517-
label: noneLabel,
518-
isNoneValue: true,
519-
},
520-
...options,
521-
],
522-
optionValues: options.map((d) => d.value),
523-
};
524-
} else {
525-
return {
526-
minDate: new Date(),
527-
maxDate: new Date(),
528-
options: [],
529-
optionValues: [],
530-
};
531-
}
532-
}, [isKeyDimension, noneLabel, values, parseDate]);
500+
return extractDataPickerOptionsFromDimension({
501+
dimension,
502+
parseDate,
503+
});
504+
}, [dimension, parseDate]);
533505

534506
return canRenderDatePickerField(timeUnit) ? (
535507
<DatePickerField

0 commit comments

Comments
 (0)