From 413819b4ba35c9c663cc68cfeac9f1d30084193f Mon Sep 17 00:00:00 2001 From: Bartosz Prusinowski Date: Fri, 28 Oct 2022 14:56:56 +0200 Subject: [PATCH 01/15] feat: Add IF timeSlider to types & fixtures --- app/charts/chart-config-ui-options.ts | 3 +- app/charts/index.ts | 4 ++ app/charts/shared/chart-helpers.spec.tsx | 6 +++ app/charts/shared/use-interactive-filters.tsx | 2 + .../use-sync-interactive-filters.spec.tsx | 3 ++ app/configurator/config-types.ts | 9 ++++ .../interactive-filters-config-options.tsx | 12 ++--- .../interactive-filters-config-state.tsx | 45 ++++++++----------- .../interactive-filters-configurator.tsx | 9 ++-- app/docs/annotations.docs.tsx | 9 ++++ app/docs/columns.docs.tsx | 3 ++ app/docs/fixtures.ts | 3 ++ app/docs/lines.docs.tsx | 13 +++++- app/docs/scatterplot.docs.tsx | 13 +++++- app/homepage/examples.tsx | 6 +++ .../dev/chartConfig-column-covid19.json | 3 ++ app/test/__fixtures/config/prod/line-1.json | 2 +- app/utils/chart-config/versioning.ts | 45 ++++++++++++++++++- 18 files changed, 146 insertions(+), 44 deletions(-) diff --git a/app/charts/chart-config-ui-options.ts b/app/charts/chart-config-ui-options.ts index 46c29e2d92..18e905b85f 100644 --- a/app/charts/chart-config-ui-options.ts +++ b/app/charts/chart-config-ui-options.ts @@ -48,7 +48,8 @@ export interface EncodingSpec { options?: EncodingOption[]; } -// dataFilters is enabled by default. +// dataFilters is enabled by default +// timeSlider is enabled dynamically based on availability of temporal dimensions type InteractiveFilterType = "legend" | "timeRange"; export interface ChartSpec { diff --git a/app/charts/index.ts b/app/charts/index.ts index e3e2d67526..46966d613e 100644 --- a/app/charts/index.ts +++ b/app/charts/index.ts @@ -96,6 +96,7 @@ export const findPreferredDimension = ( }; const INITIAL_INTERACTIVE_FILTERS_CONFIG: InteractiveFiltersConfig = { + // FIXME: we shouldn't keep empty props legend: { active: false, componentIri: "", @@ -109,6 +110,9 @@ const INITIAL_INTERACTIVE_FILTERS_CONFIG: InteractiveFiltersConfig = { to: "", }, }, + timeSlider: { + componentIri: "", + }, dataFilters: { active: false, componentIris: [], diff --git a/app/charts/shared/chart-helpers.spec.tsx b/app/charts/shared/chart-helpers.spec.tsx index 3e64f07cbb..e15c8c3619 100644 --- a/app/charts/shared/chart-helpers.spec.tsx +++ b/app/charts/shared/chart-helpers.spec.tsx @@ -34,6 +34,9 @@ const commonInteractiveFiltersConfig = { to: "2020-01-01", }, }, + timeSlider: { + componentIri: "", + }, dataFilters: { componentIris: [col("3"), col("4")], active: false, @@ -47,6 +50,9 @@ const commonInteractiveFiltersState: InteractiveFiltersState = { from: new Date(2021, 0, 1), to: new Date(2021, 11, 31), }, + timeSlider: { + value: undefined, + }, dataFilters: { [col("3")]: { type: "single", diff --git a/app/charts/shared/use-interactive-filters.tsx b/app/charts/shared/use-interactive-filters.tsx index 691abbeba1..68ab4b1767 100644 --- a/app/charts/shared/use-interactive-filters.tsx +++ b/app/charts/shared/use-interactive-filters.tsx @@ -6,6 +6,7 @@ import { FilterValueSingle } from "@/configurator"; export type InteractiveFiltersState = { categories: { [x: string]: boolean }; timeRange: { from: Date | undefined; to: Date | undefined }; + timeSlider: { value: Date | undefined }; dataFilters: { [x: string]: FilterValueSingle }; }; @@ -43,6 +44,7 @@ type InteractiveFiltersStateAction = const INTERACTIVE_FILTERS_INITIAL_STATE: InteractiveFiltersState = { categories: {}, timeRange: { from: undefined, to: undefined }, + timeSlider: { value: undefined }, dataFilters: {}, }; diff --git a/app/charts/shared/use-sync-interactive-filters.spec.tsx b/app/charts/shared/use-sync-interactive-filters.spec.tsx index 6c325027f1..f624cb3ca7 100644 --- a/app/charts/shared/use-sync-interactive-filters.spec.tsx +++ b/app/charts/shared/use-sync-interactive-filters.spec.tsx @@ -23,6 +23,9 @@ const chartConfig = { "http://environment.ld.admin.ch/foen/px/0703010000_103/dimension/1", ], }, + timeSlider: { + componentIri: "", + }, timeRange: { active: false, componentIri: "https://fake-iri/dimension/2", diff --git a/app/configurator/config-types.ts b/app/configurator/config-types.ts index a316d2c868..50d64d9e2a 100644 --- a/app/configurator/config-types.ts +++ b/app/configurator/config-types.ts @@ -102,6 +102,14 @@ export type InteractiveFiltersTimeRange = t.TypeOf< typeof InteractiveFiltersTimeRange >; +const InteractiveFiltersTimeSlider = t.type({ + // FIXME: add range + componentIri: t.string, +}); +export type InteractiveFiltersTimeSlider = t.TypeOf< + typeof InteractiveFiltersTimeSlider +>; + const InteractiveFiltersDataConfig = t.type({ active: t.boolean, componentIris: t.array(t.string), @@ -114,6 +122,7 @@ const InteractiveFiltersConfig = t.union([ t.type({ legend: InteractiveFiltersLegend, timeRange: InteractiveFiltersTimeRange, + timeSlider: InteractiveFiltersTimeSlider, dataFilters: InteractiveFiltersDataConfig, }), t.undefined, diff --git a/app/configurator/interactive-filters/interactive-filters-config-options.tsx b/app/configurator/interactive-filters/interactive-filters-config-options.tsx index 2c8ed235be..59452a89ee 100644 --- a/app/configurator/interactive-filters/interactive-filters-config-options.tsx +++ b/app/configurator/interactive-filters/interactive-filters-config-options.tsx @@ -21,10 +21,9 @@ import { EditorBrush } from "@/configurator/interactive-filters/editor-time-brus import { toggleInteractiveFilterDataDimension, useInteractiveDataFiltersToggle, - useInteractiveFiltersToggle, + useInteractiveLegendFiltersToggle, useInteractiveTimeRangeFiltersToggle, } from "@/configurator/interactive-filters/interactive-filters-config-state"; -import { InteractiveFilterType } from "@/configurator/interactive-filters/interactive-filters-configurator"; import { isTemporalDimension } from "@/domain/data"; import { useFormatFullDateAuto } from "@/formatters"; import { @@ -71,12 +70,11 @@ export const InteractiveFiltersOptions = ({ {component?.label} - @@ -341,18 +339,16 @@ const InteractiveDataFilterOptionsCheckbox = ({ }; // Generic toggle -const InteractiveFiltersToggle = ({ +const InteractiveLegendFiltersToggle = ({ label, - path, defaultChecked, disabled = false, }: { label: string; - path: InteractiveFilterType; defaultChecked?: boolean; disabled?: boolean; }) => { - const fieldProps = useInteractiveFiltersToggle({ path }); + const fieldProps = useInteractiveLegendFiltersToggle(); return ( { +export const useInteractiveLegendFiltersToggle = () => { const [state, dispatch] = useConfiguratorState(isDescribing); - const onChange = useCallback<(e: ChangeEvent) => void>( - (e) => { - const newIFConfig = produce( - state.chartConfig.interactiveFiltersConfig, - (draft) => { - if (draft?.[path]) { - draft[path].active = e.currentTarget.checked; - } - - return draft; + const onChange = useEvent((e: ChangeEvent) => { + const newConfig = produce( + state.chartConfig.interactiveFiltersConfig, + (draft) => { + if (draft?.legend) { + draft.legend.active = e.currentTarget.checked; } - ); - dispatch({ - type: "INTERACTIVE_FILTER_CHANGED", - value: newIFConfig, - }); - }, - [dispatch, path, state] - ); + return draft; + } + ); + + dispatch({ + type: "INTERACTIVE_FILTER_CHANGED", + value: newConfig, + }); + }); const stateValue = get( state, - `chartConfig.interactiveFiltersConfig.${path}.active` + "chartConfig.interactiveFiltersConfig.legend.active" ); const checked = stateValue ? stateValue : false; return { - name: path, + name: "legend", checked, onChange, }; diff --git a/app/configurator/interactive-filters/interactive-filters-configurator.tsx b/app/configurator/interactive-filters/interactive-filters-configurator.tsx index d1a4776292..915bc47a6e 100644 --- a/app/configurator/interactive-filters/interactive-filters-configurator.tsx +++ b/app/configurator/interactive-filters/interactive-filters-configurator.tsx @@ -20,7 +20,11 @@ import { isTemporalDimension } from "@/domain/data"; import { useDataCubeMetadataWithComponentValuesQuery } from "@/graphql/query-hooks"; import { useLocale } from "@/locales/use-locale"; -export type InteractiveFilterType = "legend" | "timeRange" | "dataFilters"; +export type InteractiveFilterType = + | "legend" + | "timeRange" + | "timeSlider" + | "dataFilters"; export const InteractiveFiltersConfigurator = ({ state: { @@ -128,8 +132,7 @@ const InteractiveFilterTabField = ({ const checked = state.activeField === value; const active = get( state, - `chartConfig.interactiveFiltersConfig["${value}"].active`, - "" + `chartConfig.interactiveFiltersConfig["${value}"].active` ); return ( diff --git a/app/docs/annotations.docs.tsx b/app/docs/annotations.docs.tsx index e70f3b0e2e..0e1081188a 100644 --- a/app/docs/annotations.docs.tsx +++ b/app/docs/annotations.docs.tsx @@ -44,6 +44,9 @@ ${( componentIri: "", presets: { type: "range", from: "", to: "" }, }, + timeSlider: { + componentIri: "", + }, dataFilters: { active: false, componentIris: [] }, }} aspectRatio={0.4} @@ -184,6 +187,9 @@ ${( componentIri: "", presets: { type: "range", from: "", to: "" }, }, + timeSlider: { + componentIri: "", + }, dataFilters: { active: false, componentIris: [] }, }} aspectRatio={0.4} @@ -223,6 +229,9 @@ ${( componentIri: "", presets: { type: "range", from: "", to: "" }, }, + timeSlider: { + componentIri: "", + }, dataFilters: { active: false, componentIris: [] }, }} aspectRatio={0.4} diff --git a/app/docs/columns.docs.tsx b/app/docs/columns.docs.tsx index 43e964e1c4..ea3a1c484c 100644 --- a/app/docs/columns.docs.tsx +++ b/app/docs/columns.docs.tsx @@ -41,6 +41,9 @@ ${( active: false, componentIri: "http://fake-iri", }, + timeSlider: { + componentIri: "", + }, }} fields={columnFields} measures={columnMeasures} diff --git a/app/docs/fixtures.ts b/app/docs/fixtures.ts index a7f23e409e..ccee44d801 100644 --- a/app/docs/fixtures.ts +++ b/app/docs/fixtures.ts @@ -42,6 +42,9 @@ export const states: ConfiguratorState[] = [ filters: {}, interactiveFiltersConfig: { legend: { active: false, componentIri: "" }, + timeSlider: { + componentIri: "", + }, timeRange: { active: false, componentIri: "", diff --git a/app/docs/lines.docs.tsx b/app/docs/lines.docs.tsx index d2b93de73b..6682ee8481 100644 --- a/app/docs/lines.docs.tsx +++ b/app/docs/lines.docs.tsx @@ -25,13 +25,22 @@ ${( dimensions={dimensions} measures={measures} interactiveFiltersConfig={{ - legend: { active: true, componentIri: "" }, + legend: { + active: true, + componentIri: "", + }, timeRange: { active: true, componentIri: "", presets: { type: "range", from: "", to: "" }, }, - dataFilters: { active: false, componentIris: [] }, + timeSlider: { + componentIri: "", + }, + dataFilters: { + active: false, + componentIris: [], + }, }} aspectRatio={0.4} > diff --git a/app/docs/scatterplot.docs.tsx b/app/docs/scatterplot.docs.tsx index edddd7ea80..efff2dd84e 100644 --- a/app/docs/scatterplot.docs.tsx +++ b/app/docs/scatterplot.docs.tsx @@ -31,13 +31,22 @@ ${( dimensions={scatterplotDimensions} measures={scatterplotMeasures} interactiveFiltersConfig={{ - legend: { active: true, componentIri: "" }, + legend: { + active: true, + componentIri: "", + }, timeRange: { active: false, componentIri: "", presets: { type: "range", from: "", to: "" }, }, - dataFilters: { active: false, componentIris: [] }, + timeSlider: { + componentIri: "", + }, + dataFilters: { + active: false, + componentIris: [], + }, }} aspectRatio={1} > diff --git a/app/homepage/examples.tsx b/app/homepage/examples.tsx index dcfae30f7e..3a936a41d2 100644 --- a/app/homepage/examples.tsx +++ b/app/homepage/examples.tsx @@ -112,6 +112,9 @@ export const Examples = ({ }, componentIri: "", }, + timeSlider: { + componentIri: "", + }, legend: { active: false, componentIri: "", @@ -194,6 +197,9 @@ export const Examples = ({ }, componentIri: "", }, + timeSlider: { + componentIri: "", + }, legend: { active: true, componentIri: "", diff --git a/app/test/__fixtures/config/dev/chartConfig-column-covid19.json b/app/test/__fixtures/config/dev/chartConfig-column-covid19.json index a40d4a74ac..d03c57cd2a 100644 --- a/app/test/__fixtures/config/dev/chartConfig-column-covid19.json +++ b/app/test/__fixtures/config/dev/chartConfig-column-covid19.json @@ -25,6 +25,9 @@ "to": "" } }, + "timeSlider": { + "componentIri": "" + }, "dataFilters": { "active": false, "componentIris": [] diff --git a/app/test/__fixtures/config/prod/line-1.json b/app/test/__fixtures/config/prod/line-1.json index 3d1ddf0ad2..3626ee28c9 100644 --- a/app/test/__fixtures/config/prod/line-1.json +++ b/app/test/__fixtures/config/prod/line-1.json @@ -11,7 +11,7 @@ "url": "https://lindas.admin.ch/query" }, "chartConfig": { - "version": "1.2.1", + "version": "1.3.0", "fields": { "x": { "componentIri": "http://environment.ld.admin.ch/foen/px/0703010000_105/dimension/0" diff --git a/app/utils/chart-config/versioning.ts b/app/utils/chart-config/versioning.ts index 44f26be35d..9f0230ab88 100644 --- a/app/utils/chart-config/versioning.ts +++ b/app/utils/chart-config/versioning.ts @@ -1,6 +1,6 @@ import produce from "immer"; -export const CHART_CONFIG_VERSION = "1.2.1"; +export const CHART_CONFIG_VERSION = "1.3.0"; type Migration = { description: string; @@ -430,6 +430,49 @@ const migrations: Migration[] = [ }); } + return newConfig; + }, + }, + { + description: `ALL + interactiveFiltersConfig { + + timeSlider + }`, + from: "1.2.1", + to: "1.3.0", + up: (config: any) => { + let newConfig = { ...config, version: "1.3.0" }; + + const { interactiveFiltersConfig } = newConfig; + + if (interactiveFiltersConfig) { + newConfig = produce(newConfig, (draft: any) => { + draft.interactiveFiltersConfig = { + ...draft.interactiveFiltersConfig, + timeSlider: { + componentIri: "", + }, + }; + }); + } + + return newConfig; + }, + down: (config: any) => { + let newConfig = { ...config, version: "1.2.1" }; + + const { interactiveFiltersConfig } = newConfig; + + if (interactiveFiltersConfig) { + newConfig = produce(newConfig, (draft: any) => { + draft.interactiveFiltersConfig = { + legend: draft.interactiveFiltersConfig.legend, + time: draft.interactiveFiltersConfig.time, + dataFilters: draft.interactiveFiltersConfig.dataFilters, + }; + }); + } + return newConfig; }, }, From e3c5d09bc4ce049240c9f4ebab1918eb916fecf3 Mon Sep 17 00:00:00 2001 From: Bartosz Prusinowski Date: Fri, 28 Oct 2022 16:21:06 +0200 Subject: [PATCH 02/15] refactor: Improve annotations selector --- .../components/chart-annotations-selector.tsx | 62 +++++++++++-------- 1 file changed, 37 insertions(+), 25 deletions(-) diff --git a/app/configurator/components/chart-annotations-selector.tsx b/app/configurator/components/chart-annotations-selector.tsx index 39488d0ad1..a375435cfb 100644 --- a/app/configurator/components/chart-annotations-selector.tsx +++ b/app/configurator/components/chart-annotations-selector.tsx @@ -1,5 +1,5 @@ import { Box } from "@mui/material"; -import { useEffect, useRef } from "react"; +import { useEffect, useMemo, useRef } from "react"; import { ConfiguratorStateDescribingChart } from "@/configurator"; import { @@ -12,6 +12,7 @@ import { MetaInputField } from "@/configurator/components/field"; import { getFieldLabel } from "@/configurator/components/field-i18n"; import { getIconName } from "@/configurator/components/ui-helpers"; import { InteractiveFiltersOptions } from "@/configurator/interactive-filters/interactive-filters-config-options"; +import { InteractiveFilterType } from "@/configurator/interactive-filters/interactive-filters-configurator"; import { locales } from "@/locales/locales"; import { useLocale } from "@/locales/use-locale"; @@ -20,54 +21,65 @@ export const ChartAnnotationsSelector = ({ }: { state: ConfiguratorStateDescribingChart; }) => { + const { activeField, meta } = state; const panelRef = useRef(null); useEffect(() => { if (panelRef && panelRef.current) { panelRef.current.focus(); } - }, [state.activeField]); + }, [activeField]); const locale = useLocale(); - const af = state.activeField === "title" ? "title" : "description"; + const isInteractiveFilterField = useMemo(() => { + switch (activeField as InteractiveFilterType) { + case "dataFilters": + case "legend": + case "timeRange": + case "timeSlider": + return true; + + default: + return false; + } + }, [activeField]); // Reorder locales so the input field for // the current locale is on top const orderedLocales = [locale, ...locales.filter((l) => l !== locale)]; - if (state.activeField) { + if (activeField) { return ( - {state.activeField === "timeRange" || - state.activeField === "legend" || - state.activeField === "dataFilters" ? ( + {isInteractiveFilterField ? ( ) : ( - - {state.activeField && getFieldLabel(state.activeField)} + + {getFieldLabel(activeField)} - {state.activeField && - orderedLocales.map((locale) => ( - - - - ))} + {orderedLocales.map((d) => ( + + + + ))} )} From 0be24f4b5ed8cbfa3b8eac0fc72bcfa167a9be60 Mon Sep 17 00:00:00 2001 From: Bartosz Prusinowski Date: Tue, 1 Nov 2022 09:57:15 +0100 Subject: [PATCH 03/15] feat: Add initial IF timeSlider --- app/charts/shared/chart-helpers.tsx | 4 +- app/configurator/components/ui-helpers.ts | 2 + .../interactive-filters/helpers.ts | 36 ++++++ .../interactive-filters-config-options.tsx | 114 +++++++++++++++++- .../interactive-filters-config-state.tsx | 38 ++++++ .../interactive-filters-configurator.tsx | 56 ++++++--- 6 files changed, 225 insertions(+), 25 deletions(-) create mode 100644 app/configurator/interactive-filters/helpers.ts diff --git a/app/charts/shared/chart-helpers.tsx b/app/charts/shared/chart-helpers.tsx index c04d58437a..f463a6d6e3 100644 --- a/app/charts/shared/chart-helpers.tsx +++ b/app/charts/shared/chart-helpers.tsx @@ -32,14 +32,14 @@ export type QueryFilters = Filters | FilterValueSingle; // - removes none values since they should not be sent as part of the GraphQL query export const prepareQueryFilters = ( { chartType, filters, interactiveFiltersConfig }: ChartConfig, - IFState: InteractiveFiltersState + state: InteractiveFiltersState ): Filters => { let res: QueryFilters; const dataFiltersActive = interactiveFiltersConfig?.dataFilters.active; if (chartType !== "table") { const queryFilters = dataFiltersActive - ? { ...filters, ...IFState.dataFilters } + ? { ...filters, ...state.dataFilters } : filters; res = queryFilters; } else { diff --git a/app/configurator/components/ui-helpers.ts b/app/configurator/components/ui-helpers.ts index be3947c65e..399961377c 100644 --- a/app/configurator/components/ui-helpers.ts +++ b/app/configurator/components/ui-helpers.ts @@ -188,6 +188,8 @@ export const getIconName = (name: string): IconName => { return "tableColumnTimeHidden"; case "time": return "time"; + case "play": + return "play"; default: return "table"; diff --git a/app/configurator/interactive-filters/helpers.ts b/app/configurator/interactive-filters/helpers.ts new file mode 100644 index 0000000000..9cf67d10f1 --- /dev/null +++ b/app/configurator/interactive-filters/helpers.ts @@ -0,0 +1,36 @@ +import { getFieldComponentIri } from "@/charts"; +import { isTemporalDimension } from "@/domain/data"; +import { + DimensionMetadataFragment, + TemporalDimension, +} from "@/graphql/query-hooks"; + +import { ChartConfig } from "../config-types"; + +export const getTimeSliderFilterDimensions = ({ + chartConfig, + dataCubeByIri, +}: { + chartConfig: ChartConfig; + dataCubeByIri: { + dimensions: DimensionMetadataFragment[]; + measures: DimensionMetadataFragment[]; + }; +}): TemporalDimension[] => { + if (dataCubeByIri) { + const allComponents = [ + ...dataCubeByIri.dimensions, + ...dataCubeByIri.measures, + ]; + const xComponentIri = getFieldComponentIri(chartConfig.fields, "x"); + const xComponent = allComponents.find((d) => d.iri === xComponentIri); + + return allComponents.filter( + (d) => + isTemporalDimension(d) && + (isTemporalDimension(xComponent) ? d.iri !== xComponent.iri : true) + ) as TemporalDimension[]; + } + + return []; +}; diff --git a/app/configurator/interactive-filters/interactive-filters-config-options.tsx b/app/configurator/interactive-filters/interactive-filters-config-options.tsx index 59452a89ee..1cf048137c 100644 --- a/app/configurator/interactive-filters/interactive-filters-config-options.tsx +++ b/app/configurator/interactive-filters/interactive-filters-config-options.tsx @@ -1,10 +1,17 @@ import { t, Trans } from "@lingui/macro"; import { Box } from "@mui/material"; import { extent } from "d3"; -import React, { ChangeEvent, useCallback, useEffect, useRef } from "react"; +import get from "lodash/get"; +import React, { + ChangeEvent, + useCallback, + useEffect, + useMemo, + useRef, +} from "react"; import { getFieldComponentIri, getFieldComponentIris } from "@/charts"; -import { Checkbox } from "@/components/form"; +import { Checkbox, Select } from "@/components/form"; import { Loading } from "@/components/hint"; import { ControlSection, @@ -23,22 +30,30 @@ import { useInteractiveDataFiltersToggle, useInteractiveLegendFiltersToggle, useInteractiveTimeRangeFiltersToggle, + useInteractiveTimeSliderFiltersSelect, } from "@/configurator/interactive-filters/interactive-filters-config-state"; +import { InteractiveFilterType } from "@/configurator/interactive-filters/interactive-filters-configurator"; import { isTemporalDimension } from "@/domain/data"; import { useFormatFullDateAuto } from "@/formatters"; import { DimensionMetadataFragment, + TemporalDimension, TimeUnit, useDataCubeMetadataWithComponentValuesQuery, } from "@/graphql/query-hooks"; import { useLocale } from "@/locales/use-locale"; +import { FIELD_VALUE_NONE } from "../constants"; + +import { getTimeSliderFilterDimensions } from "./helpers"; + export const InteractiveFiltersOptions = ({ state, }: { state: ConfiguratorStateDescribingChart; }) => { - const { activeField, chartConfig, dataSet, dataSource } = state; + const { chartConfig, dataSet, dataSource } = state; + const activeField = state.activeField as InteractiveFilterType; const locale = useLocale(); const [{ data }] = useDataCubeMetadataWithComponentValuesQuery({ @@ -93,6 +108,19 @@ export const InteractiveFiltersOptions = ({ ); + } else if (activeField === "timeSlider") { + return ( + + + + Time slider + + + + + + + ); } else if (activeField === "dataFilters") { return ( @@ -112,7 +140,7 @@ export const InteractiveFiltersOptions = ({ return null; }; -const InteractiveTimeFilterToggle = ({ +const InteractiveTimeRangeFilterToggle = ({ label, defaultChecked, disabled = false, @@ -176,7 +204,7 @@ const InteractiveTimeRangeFilterOptions = ({ <> {timeExtent && timeExtent[0] && timeExtent[1] ? ( <> - { + const locale = useLocale(); + const [{ data }] = useDataCubeMetadataWithComponentValuesQuery({ + variables: { + iri: dataSet, + sourceType: dataSource.type, + sourceUrl: dataSource.url, + locale, + }, + }); + + const value = + get(chartConfig, "interactiveFiltersConfig.timeSlider.componentIri") || + FIELD_VALUE_NONE; + + if (data?.dataCubeByIri) { + const timeSliderDimensions = getTimeSliderFilterDimensions({ + chartConfig, + dataCubeByIri: data.dataCubeByIri, + }); + + return ( + + ); + } else { + return ; + } +}; + +const InteractiveTimeSliderFilterOptionsSelect = ({ + dimensions, + value, +}: { + dimensions: TemporalDimension[]; + value: string; +}) => { + const fieldProps = useInteractiveTimeSliderFiltersSelect(); + const options = useMemo(() => { + return [ + { + label: t({ + id: "controls.none", + message: "None", + }), + value: FIELD_VALUE_NONE, + isNoneValue: true, + }, + ...dimensions.map((d) => ({ + label: d.label, + value: d.iri, + })), + ]; + }, [dimensions]); + + return ( +