@@ -40,7 +40,6 @@ import {
4040import { useTimeFormatLocale } from "@/formatters" ;
4141import { useDataCubesComponentsQuery } from "@/graphql/hooks" ;
4242import {
43- DataCubeObservationFilter ,
4443 PossibleFiltersDocument ,
4544 PossibleFiltersQuery ,
4645 PossibleFiltersQueryVariables ,
@@ -52,6 +51,7 @@ import {
5251 useChartInteractiveFilters ,
5352 useInteractiveFiltersGetState ,
5453} from "@/stores/interactive-filters" ;
54+ import { assert } from "@/utils/assert" ;
5555import { hierarchyToOptions } from "@/utils/hierarchy" ;
5656import useEvent from "@/utils/use-event" ;
5757
@@ -62,64 +62,72 @@ type PreparedFilter = {
6262 mappedFilters : Filters ;
6363} ;
6464
65- type ChartDataFiltersProps = {
65+ export const useChartDataFiltersState = ( {
66+ dataSource,
67+ chartConfig,
68+ } : {
6669 dataSource : DataSource ;
6770 chartConfig : ChartConfig ;
68- } ;
69-
70- export const ChartDataFilters = ( props : ChartDataFiltersProps ) => {
71- const { dataSource, chartConfig } = props ;
71+ } ) => {
72+ const componentIris =
73+ chartConfig . interactiveFiltersConfig ?. dataFilters . componentIris ;
74+ assert ( componentIris , "Data filters are not enabled for this chart." ) ;
75+ const [ open , setOpen ] = useState ( false ) ;
76+ useEffect ( ( ) => {
77+ if ( componentIris . length === 0 ) {
78+ setOpen ( false ) ;
79+ }
80+ } , [ componentIris . length ] ) ;
7281 const { loading } = useLoadingState ( ) ;
73- const dataFilters = useChartInteractiveFilters ( ( d ) => d . dataFilters ) ;
74- const componentIris = chartConfig . interactiveFiltersConfig ?. dataFilters
75- . componentIris as string [ ] ;
7682 const queryFilters = useQueryFilters ( {
7783 chartConfig,
7884 allowNoneValues : true ,
7985 componentIris,
8086 } ) ;
81- const [ filtersVisible , setFiltersVisible ] = useState ( false ) ;
82-
83- useEffect ( ( ) => {
84- if ( componentIris . length === 0 ) {
85- setFiltersVisible ( false ) ;
86- }
87- } , [ componentIris . length ] ) ;
88-
89- const preparedFilters : PreparedFilter [ ] | undefined = useMemo ( ( ) => {
87+ const preparedFilters = useMemo ( ( ) => {
9088 return chartConfig . cubes . map ( ( cube ) => {
91- const cubeQueryFilters = queryFilters . find (
92- ( d ) => d . iri === cube . iri
93- ) as DataCubeObservationFilter ;
89+ const cubeQueryFilters = queryFilters . find ( ( d ) => d . iri === cube . iri ) ;
90+ assert ( cubeQueryFilters , "Cube query filters not found." ) ;
9491 const filtersByMappingStatus = getFiltersByMappingStatus ( chartConfig , {
9592 cubeIri : cube . iri ,
9693 } ) ;
9794 const { unmappedFilters, mappedFilters } = filtersByMappingStatus ;
9895 const unmappedKeys = Object . keys ( unmappedFilters ) ;
99- const unmappedFiltersArray = Object . entries (
96+ const unmappedEntries = Object . entries (
10097 cubeQueryFilters . filters as Filters
10198 ) . filter ( ( [ k ] ) => unmappedKeys . includes ( k ) ) ;
102- const interactiveFiltersArray = unmappedFiltersArray . filter ( ( [ k ] ) =>
99+ const interactiveFiltersList = unmappedEntries . filter ( ( [ k ] ) =>
103100 componentIris . includes ( k )
104101 ) ;
105-
106102 return {
107103 cubeIri : cube . iri ,
108- interactiveFilters : Object . fromEntries ( interactiveFiltersArray ) ,
109- unmappedFilters : Object . fromEntries (
110- unmappedFiltersArray
111- ) as SingleFilters ,
104+ interactiveFilters : Object . fromEntries ( interactiveFiltersList ) ,
105+ unmappedFilters : Object . fromEntries ( unmappedEntries ) as SingleFilters ,
112106 mappedFilters,
113107 } ;
114108 } ) ;
115109 } , [ chartConfig , componentIris , queryFilters ] ) ;
116-
117110 const { error } = useEnsurePossibleInteractiveFilters ( {
118111 dataSource,
119112 chartConfig,
120113 preparedFilters,
121114 } ) ;
115+ return {
116+ open,
117+ setOpen,
118+ dataSource,
119+ chartConfig,
120+ loading,
121+ error,
122+ preparedFilters,
123+ componentIris,
124+ } ;
125+ } ;
122126
127+ export const ChartDataFiltersToggle = (
128+ props : ReturnType < typeof useChartDataFiltersState >
129+ ) => {
130+ const { open, setOpen, loading, error, componentIris } = props ;
123131 return error ? (
124132 < Typography variant = "body2" color = "error" >
125133 < Trans id = "controls.section.data.filters.possible-filters-error" >
@@ -128,10 +136,9 @@ export const ChartDataFilters = (props: ChartDataFiltersProps) => {
128136 </ Trans >
129137 </ Typography >
130138 ) : (
131- < Flex sx = { { flexDirection : "column" , mt : 4 } } >
139+ < Flex sx = { { flexDirection : "column" , width : "100%" } } >
132140 < Flex
133141 sx = { {
134- justifyContent : "flex-end" ,
135142 alignItems : "flex-start" ,
136143 gap : 3 ,
137144 minHeight : 20 ,
@@ -140,91 +147,107 @@ export const ChartDataFilters = (props: ChartDataFiltersProps) => {
140147 { componentIris . length > 0 && (
141148 < Button
142149 variant = "text"
150+ color = "primary"
151+ size = "small"
143152 endIcon = {
144153 < Icon
145154 name = "add"
146155 size = { 16 }
147156 style = { {
148- transform : filtersVisible ? "rotate(45deg)" : "rotate(0deg)" ,
157+ transform : open ? "rotate(45deg)" : "rotate(0deg)" ,
149158 transition : "transform 0.2s ease-in-out" ,
150159 } }
151160 />
152161 }
153162 sx = { {
154163 display : "flex" ,
155- fontSize : [ "0.75rem" , "0.75rem" , "0.75rem" ] ,
156164 alignItems : "center" ,
157165 minWidth : "fit-content" ,
158166 minHeight : 0 ,
167+ ml : - 2 ,
159168 px : 2 ,
160169 py : 1 ,
161170 } }
162- onClick = { ( ) => setFiltersVisible ( ! filtersVisible ) }
171+ onClick = { ( ) => setOpen ( ! open ) }
163172 >
164173 { loading && (
165174 < span style = { { marginTop : "0.1rem" , marginRight : "0.5rem" } } >
166175 < LoadingIndicator />
167176 </ span >
168177 ) }
169- { filtersVisible ? (
170- < Trans id = "interactive.data.filters.hide" > Hide Filters</ Trans >
171- ) : (
172- < Trans id = "interactive.data.filters.show" > Show Filters</ Trans >
173- ) }
178+ < Typography variant = "body2" >
179+ { open ? (
180+ < Trans id = "interactive.data.filters.hide" > Hide Filters</ Trans >
181+ ) : (
182+ < Trans id = "interactive.data.filters.show" > Show Filters</ Trans >
183+ ) }
184+ </ Typography >
174185 </ Button >
175186 ) }
176187 </ Flex >
177-
178- { componentIris . length > 0 && (
179- < Box
180- data-testid = "published-chart-interactive-filters"
181- sx = { {
182- display : filtersVisible ? "grid" : "none" ,
183- columnGap : 3 ,
184- rowGap : 2 ,
185- gridTemplateColumns : "repeat(auto-fit, minmax(240px, 1fr))" ,
186- } }
187- >
188- { preparedFilters ?. map ( ( { cubeIri, interactiveFilters } ) =>
189- Object . keys ( interactiveFilters ) . map ( ( dimensionIri ) => (
190- < DataFilter
191- key = { dimensionIri }
192- cubeIri = { cubeIri }
193- dimensionIri = { dimensionIri }
194- dataSource = { dataSource }
195- chartConfig = { chartConfig }
196- dataFilters = { dataFilters }
197- interactiveFilters = { interactiveFilters }
198- disabled = { loading }
199- />
200- ) )
201- ) }
202- </ Box >
203- ) }
204188 </ Flex >
205189 ) ;
206190} ;
207191
208- type DataFilterProps = {
192+ export const ChartDataFiltersList = (
193+ props : ReturnType < typeof useChartDataFiltersState >
194+ ) => {
195+ const {
196+ open,
197+ dataSource,
198+ chartConfig,
199+ loading,
200+ preparedFilters,
201+ componentIris,
202+ } = props ;
203+ const dataFilters = useChartInteractiveFilters ( ( d ) => d . dataFilters ) ;
204+ return componentIris . length > 0 ? (
205+ < Box
206+ data-testid = "published-chart-interactive-filters"
207+ sx = { {
208+ display : open ? "grid" : "none" ,
209+ columnGap : 3 ,
210+ rowGap : 2 ,
211+ gridTemplateColumns : "repeat(auto-fit, minmax(240px, 1fr))" ,
212+ } }
213+ >
214+ { preparedFilters . map ( ( { cubeIri, interactiveFilters } ) => {
215+ return Object . keys ( interactiveFilters ) . map ( ( dimensionIri ) => {
216+ return (
217+ < DataFilter
218+ key = { dimensionIri }
219+ cubeIri = { cubeIri }
220+ dimensionIri = { dimensionIri }
221+ dataSource = { dataSource }
222+ chartConfig = { chartConfig }
223+ dataFilters = { dataFilters }
224+ interactiveFilters = { interactiveFilters }
225+ disabled = { loading }
226+ />
227+ ) ;
228+ } ) ;
229+ } ) }
230+ </ Box >
231+ ) : null ;
232+ } ;
233+
234+ const DataFilter = ( {
235+ cubeIri,
236+ dimensionIri,
237+ dataSource,
238+ chartConfig,
239+ dataFilters,
240+ interactiveFilters,
241+ disabled,
242+ } : {
209243 cubeIri : string ;
210244 dimensionIri : string ;
211245 dataSource : DataSource ;
212246 chartConfig : ChartConfig ;
213247 dataFilters : DataFilters ;
214248 interactiveFilters : Filters ;
215249 disabled : boolean ;
216- } ;
217-
218- const DataFilter = ( props : DataFilterProps ) => {
219- const {
220- cubeIri,
221- dimensionIri,
222- dataSource,
223- chartConfig,
224- dataFilters,
225- interactiveFilters,
226- disabled,
227- } = props ;
250+ } ) => {
228251 const locale = useLocale ( ) ;
229252 const filters = useChartConfigFilters ( chartConfig ) ;
230253 const chartLoadingState = useLoadingState ( ) ;
0 commit comments