diff --git a/app/configurator/components/chart-configurator.tsx b/app/configurator/components/chart-configurator.tsx index 3d2d90be1f..511c53f13a 100644 --- a/app/configurator/components/chart-configurator.tsx +++ b/app/configurator/components/chart-configurator.tsx @@ -65,10 +65,14 @@ import { PossibleFiltersDocument, PossibleFiltersQuery, PossibleFiltersQueryVariables, - useDataCubeMetadataWithComponentValuesAndHierarchiesQuery, + useComponentsWithHierarchiesQuery, + useDataCubeMetadataQuery, useDimensionHierarchyQuery, } from "@/graphql/query-hooks"; -import { DataCubeMetadata } from "@/graphql/types"; +import { + DataCubeMetadata, + DataCubeMetadataWithHierarchies, +} from "@/graphql/types"; import { Icon } from "@/icons"; import { useLocale } from "@/locales/use-locale"; import useEvent from "@/utils/use-event"; @@ -306,31 +310,48 @@ const useFilterReorder = ({ unmappedFilters, ]); - const [{ data, fetching: dataFetching }, executeQuery] = - useDataCubeMetadataWithComponentValuesAndHierarchiesQuery({ + const [{ data: metadata, fetching: metadataFetching }, executeMetadataQuery] = + useDataCubeMetadataQuery({ variables: variables, }); + const [ + { data: components, fetching: componentsFetching }, + exectueComponentsQuery, + ] = useComponentsWithHierarchiesQuery({ + variables: variables, + }); useEffect(() => { - executeQuery({ + executeMetadataQuery({ + variables, + }); + exectueComponentsQuery({ variables, }); - }, [variables, executeQuery]); + }, [variables, executeMetadataQuery, exectueComponentsQuery]); const dimensions = useMemo(() => { - const dimensions = data?.dataCubeByIri?.dimensions; + const dimensions = components?.dataCubeByIri?.dimensions; type T = Exclude; - if (!data?.dataCubeByIri?.dimensions) { + + if (!components?.dataCubeByIri?.dimensions) { return [] as T; } + return dimensions as T; - }, [data?.dataCubeByIri?.dimensions]); + }, [components?.dataCubeByIri?.dimensions]); - const metaData = data?.dataCubeByIri; + const data = + metadata && components + ? ({ + ...metadata.dataCubeByIri, + ...components.dataCubeByIri, + } as DataCubeMetadataWithHierarchies) + : null; // Handlers const handleMove = useEvent((dimensionIri: string, delta: number) => { - if (!metaData) { + if (!data) { return; } @@ -345,7 +366,7 @@ const useFilterReorder = ({ type: "CHART_CONFIG_REPLACED", value: { chartConfig, - dataSetMetadata: metaData, + dataSetMetadata: data, }, }); }); @@ -388,7 +409,8 @@ const useFilterReorder = ({ const { fetching: possibleFiltersFetching } = useEnsurePossibleFilters({ state, }); - const fetching = possibleFiltersFetching || dataFetching; + const fetching = + possibleFiltersFetching || metadataFetching || componentsFetching; const { filterDimensions, addableDimensions } = useMemo(() => { const keysOrder = Object.fromEntries( @@ -564,7 +586,7 @@ export const ChartConfigurator = ({ const classes = useStyles({ fetching }); - if (!data?.dataCubeByIri) { + if (!data) { return ( <> @@ -593,10 +615,7 @@ export const ChartConfigurator = ({ role="tablist" aria-labelledby="controls-design" > - + {filterDimensions.length === 0 && diff --git a/app/configurator/components/chart-controls/drag-and-drop-tab.tsx b/app/configurator/components/chart-controls/drag-and-drop-tab.tsx index 84522893cd..e81316ca82 100644 --- a/app/configurator/components/chart-controls/drag-and-drop-tab.tsx +++ b/app/configurator/components/chart-controls/drag-and-drop-tab.tsx @@ -14,7 +14,7 @@ import { getIconName } from "@/configurator/components/ui-helpers"; import { useActiveFieldField } from "@/configurator/config-form"; import { TableColumn } from "@/configurator/config-types"; import { DimensionMetadataFragment } from "@/graphql/query-hooks"; -import { DataCubeMetadata } from "@/graphql/types"; +import { DataCubeMetadataWithHierarchies } from "@/graphql/types"; import { Icon } from "@/icons"; const useStyles = makeStyles((theme: Theme) => ({ @@ -36,7 +36,7 @@ type Props = { id: string; title: ReactNode; items: TableColumn[]; - metaData: DataCubeMetadata; + metaData: DataCubeMetadataWithHierarchies; isDropDisabled?: boolean; emptyComponent?: React.ReactNode; }; diff --git a/app/configurator/components/chart-options-selector.tsx b/app/configurator/components/chart-options-selector.tsx index ddf6f5ee40..3cc96f4bf3 100644 --- a/app/configurator/components/chart-options-selector.tsx +++ b/app/configurator/components/chart-options-selector.tsx @@ -67,10 +67,11 @@ import { } from "@/domain/data"; import { DimensionMetadataFragment, - useDataCubeMetadataWithComponentValuesAndHierarchiesQuery, + useComponentsWithHierarchiesQuery, + useDataCubeMetadataQuery, useDataCubeObservationsQuery, } from "@/graphql/query-hooks"; -import { DataCubeMetadata } from "@/graphql/types"; +import { DataCubeMetadataWithHierarchies } from "@/graphql/types"; import { useLocale } from "@/locales/use-locale"; import { ColorRampField } from "./chart-controls/color-ramp"; @@ -92,16 +93,22 @@ export const ChartOptionsSelector = ({ }, }); - // Unfiltered dimensions & measures values. - const [{ data: metadataData }] = - useDataCubeMetadataWithComponentValuesAndHierarchiesQuery({ - variables: { - iri: dataSet, - sourceType: dataSource.type, - sourceUrl: dataSource.url, - locale, - }, - }); + const [{ data: metadataData }] = useDataCubeMetadataQuery({ + variables: { + iri: dataSet, + sourceType: dataSource.type, + sourceUrl: dataSource.url, + locale, + }, + }); + const [{ data: componentsData }] = useComponentsWithHierarchiesQuery({ + variables: { + iri: dataSet, + sourceType: dataSource.type, + sourceUrl: dataSource.url, + locale, + }, + }); const imputationNeeded = useImputationNeeded({ chartConfig, @@ -109,20 +116,21 @@ export const ChartOptionsSelector = ({ }); const metaData = useMemo(() => { - if (metadataData?.dataCubeByIri) { + if (metadataData?.dataCubeByIri && componentsData?.dataCubeByIri) { return { ...metadataData.dataCubeByIri, + measures: componentsData.dataCubeByIri.measures, dimensions: isTableConfig(chartConfig) - ? metadataData.dataCubeByIri.dimensions + ? componentsData.dataCubeByIri.dimensions : [ // There are no fields that make use of numeric dimensions at the moment. - ...metadataData.dataCubeByIri.dimensions.filter( + ...componentsData.dataCubeByIri.dimensions.filter( (d) => !d.isNumerical ), ], }; } - }, [chartConfig, metadataData?.dataCubeByIri]); + }, [chartConfig, metadataData?.dataCubeByIri, componentsData?.dataCubeByIri]); if (metaData) { return ( @@ -162,7 +170,7 @@ const ActiveFieldSwitch = ({ imputationNeeded, }: { state: ConfiguratorStateConfiguringChart; - metaData: DataCubeMetadata; + metaData: DataCubeMetadataWithHierarchies; imputationNeeded: boolean; }) => { const { activeField } = state; @@ -182,8 +190,8 @@ const ActiveFieldSwitch = ({ activeField ); - const allDimensions = [...metaData.dimensions, ...metaData.measures]; - const component = allDimensions.find( + const allComponents = [...metaData.dimensions, ...metaData.measures]; + const component = allComponents.find( (d) => d.iri === activeFieldComponentIri ); @@ -193,8 +201,9 @@ const ActiveFieldSwitch = ({ state={state} field={activeField} // FIXME: or encoding.field? chartType={state.chartConfig.chartType} - metaData={metaData} component={component} + dimensions={metaData.dimensions} + measures={metaData.measures} imputationNeeded={imputationNeeded} /> ); @@ -206,7 +215,8 @@ const EncodingOptionsPanel = ({ field, chartType, component, - metaData, + dimensions, + measures, imputationNeeded, }: { encoding: EncodingSpec; @@ -214,10 +224,10 @@ const EncodingOptionsPanel = ({ field: string; chartType: ChartType; component: DimensionMetadataFragment | undefined; - metaData: DataCubeMetadata; + dimensions: DimensionMetadataFragment[]; + measures: DimensionMetadataFragment[]; imputationNeeded: boolean; }) => { - const { measures, dimensions } = metaData; const panelRef = useRef(null); const getFieldLabelHint = { @@ -265,7 +275,7 @@ const EncodingOptionsPanel = ({ otherFieldsIris, ]); - const allDimensions = useMemo(() => { + const allComponents = useMemo(() => { return [...measures, ...dimensions]; }, [measures, dimensions]); @@ -274,16 +284,16 @@ const EncodingOptionsPanel = ({ (fields as any)?.[encoding.field] as GenericField | undefined )?.componentIri; - return allDimensions.find((d) => d.iri === encodingIri); - }, [allDimensions, fields, encoding.field]); + return allComponents.find((d) => d.iri === encodingIri); + }, [allComponents, fields, encoding.field]); const hasStandardError = useMemo(() => { - return allDimensions.find((d) => + return allComponents.find((d) => d.related?.some( (r) => r.type === "StandardError" && r.iri === component?.iri ) ); - }, [allDimensions, component]); + }, [allComponents, component]); // TODO: Add proper types here. const optionsByField = useMemo( @@ -358,7 +368,8 @@ const EncodingOptionsPanel = ({ )} @@ -367,11 +378,13 @@ const EncodingOptionsPanel = ({ optionsByField["color"].type === "component" && component && ( ); @@ -438,19 +452,21 @@ const ChartFieldMultiFilter = ({ component, encoding, field, - metaData, + dimensions, + measures, }: { state: ConfiguratorStateConfiguringChart; component: DimensionMetadataFragment | undefined; encoding: EncodingSpec; field: string; - metaData: DataCubeMetadata; + dimensions: DimensionMetadataFragment[]; + measures: DimensionMetadataFragment[]; }) => { const colorComponentIri = get( state.chartConfig, `fields.${field}.color.componentIri` ); - const colorComponent = [...metaData.dimensions, ...metaData.measures].find( + const colorComponent = [...dimensions, ...measures].find( (d) => d.iri === colorComponentIri ); const colorType = get(state.chartConfig, `fields.${field}.color.type`) as @@ -474,14 +490,14 @@ const ChartFieldMultiFilter = ({ ) : ( component && ( { const measuresOptions = useMemo(() => { return getDimensionsByDimensionType({ dimensionTypes: componentTypes, - dimensions: dataSetMetadata.dimensions, - measures: dataSetMetadata.measures, + dimensions, + measures, }).map(({ iri, label }) => ({ value: iri, label })); - }, [dataSetMetadata.dimensions, dataSetMetadata.measures, componentTypes]); + }, [dimensions, measures, componentTypes]); return ( @@ -715,19 +733,23 @@ const ChartFieldSize = ({ }; const ChartFieldColorComponent = ({ + state, chartConfig, field, component, componentTypes, - dataSetMetadata, + dimensions, + measures, optional, enableUseAbbreviations, }: { + state: ConfiguratorStateConfiguringChart; chartConfig: ChartConfig; field: EncodingFieldType; component: DimensionMetadataFragment; componentTypes: ComponentType[]; - dataSetMetadata: DataCubeMetadata; + dimensions: DimensionMetadataFragment[]; + measures: DimensionMetadataFragment[]; optional: boolean; enableUseAbbreviations: boolean; }) => { @@ -735,10 +757,10 @@ const ChartFieldColorComponent = ({ const measuresOptions = useMemo(() => { return getDimensionsByDimensionType({ dimensionTypes: componentTypes, - dimensions: dataSetMetadata.dimensions, - measures: dataSetMetadata.measures, + dimensions, + measures, }).map(({ iri, label }) => ({ value: iri, label })); - }, [dataSetMetadata.dimensions, dataSetMetadata.measures, componentTypes]); + }, [dimensions, measures, componentTypes]); const nbColorOptions = useMemo(() => { return Array.from( { length: Math.min(7, Math.max(0, nbOptions - 2)) }, @@ -752,10 +774,9 @@ const ChartFieldColorComponent = ({ "color", "componentIri", ]) as string | undefined; - const colorComponent = [ - ...dataSetMetadata.dimensions, - ...dataSetMetadata.measures, - ].find((d) => d.iri === colorComponentIri); + const colorComponent = [...dimensions, ...measures].find( + (d) => d.iri === colorComponentIri + ); const colorType = get(chartConfig, [ "fields", field, @@ -827,7 +848,7 @@ const ChartFieldColorComponent = ({ colorComponentIri && component.iri !== colorComponentIri ? ( { - const query = client.readQuery< - DataCubeMetadataWithComponentValuesAndHierarchiesQuery, - DataCubeMetadataWithComponentValuesAndHierarchiesQueryVariables - >(DataCubeMetadataWithComponentValuesAndHierarchiesDocument, { + const metadataQuery = client.readQuery< + DataCubeMetadataQuery, + DataCubeMetadataQueryVariables + >(DataCubeMetadataDocument, { + iri: draft.dataSet, + locale, + sourceType: draft.dataSource.type, + sourceUrl: draft.dataSource.url, + }); + const componentsQuery = client.readQuery< + ComponentsQuery, + ComponentsQueryVariables + >(ComponentsDocument, { iri: draft.dataSet, locale, sourceType: draft.dataSource.type, sourceUrl: draft.dataSource.url, }); - return query?.data?.dataCubeByIri; + return metadataQuery?.data?.dataCubeByIri && + componentsQuery?.data?.dataCubeByIri + ? { + ...metadataQuery.data.dataCubeByIri, + ...componentsQuery.data.dataCubeByIri, + } + : null; }; export const getFilterValue = ( diff --git a/app/configurator/table/table-chart-configurator.tsx b/app/configurator/table/table-chart-configurator.tsx index ec066b62ad..201f2fbc2c 100644 --- a/app/configurator/table/table-chart-configurator.tsx +++ b/app/configurator/table/table-chart-configurator.tsx @@ -1,7 +1,7 @@ import { Trans } from "@lingui/macro"; import { Theme, Typography } from "@mui/material"; import { makeStyles } from "@mui/styles"; -import { useCallback, useState } from "react"; +import { useCallback, useMemo, useState } from "react"; import { DragDropContext, OnDragEndResponder, @@ -21,7 +21,10 @@ import { useOrderedTableColumns } from "@/configurator/components/ui-helpers"; import { TableFields } from "@/configurator/config-types"; import { useConfiguratorState } from "@/configurator/configurator-state"; import { moveFields } from "@/configurator/table/table-config-state"; -import { useDataCubeMetadataWithComponentValuesAndHierarchiesQuery } from "@/graphql/query-hooks"; +import { + useComponentsWithHierarchiesQuery, + useDataCubeMetadataQuery, +} from "@/graphql/query-hooks"; import { useLocale } from "@/locales/use-locale"; import { ChartTypeSelector } from "../components/chart-type-selector"; @@ -55,7 +58,15 @@ export const ChartConfiguratorTable = ({ state: ConfiguratorStateConfiguringChart; }) => { const locale = useLocale(); - const [{ data }] = useDataCubeMetadataWithComponentValuesAndHierarchiesQuery({ + const [{ data: metadata }] = useDataCubeMetadataQuery({ + variables: { + iri: state.dataSet, + sourceType: state.dataSource.type, + sourceUrl: state.dataSource.url, + locale, + }, + }); + const [{ data: components }] = useComponentsWithHierarchiesQuery({ variables: { iri: state.dataSet, sourceType: state.dataSource.type, @@ -64,7 +75,14 @@ export const ChartConfiguratorTable = ({ }, }); - const metaData = data?.dataCubeByIri; + const metaData = useMemo(() => { + return metadata?.dataCubeByIri && components?.dataCubeByIri + ? { + ...metadata.dataCubeByIri, + ...components.dataCubeByIri, + } + : null; + }, [metadata?.dataCubeByIri, components?.dataCubeByIri]); const [, dispatch] = useConfiguratorState(); @@ -107,7 +125,7 @@ export const ChartConfiguratorTable = ({ const fields = state.chartConfig.fields as TableFields; const fieldsArray = useOrderedTableColumns(fields); - if (data?.dataCubeByIri) { + if (metaData) { const groupFields = [...fieldsArray.filter((f) => f.isGroup)]; const columnFields = [...fieldsArray.filter((f) => !f.isGroup)]; @@ -154,18 +172,18 @@ export const ChartConfiguratorTable = ({ Groups} - metaData={data.dataCubeByIri} + metaData={metaData} items={groupFields} isDropDisabled={isGroupsDropDisabled} emptyComponent={} - > + /> Columns} - metaData={data.dataCubeByIri} + metaData={metaData} items={columnFields} - > + /> ); diff --git a/app/graphql/queries/data-cubes.graphql b/app/graphql/queries/data-cubes.graphql index e0904da308..793eac99fc 100644 --- a/app/graphql/queries/data-cubes.graphql +++ b/app/graphql/queries/data-cubes.graphql @@ -183,41 +183,6 @@ query DataCubeMetadata( } } -query DataCubeMetadataWithComponentValuesAndHierarchies( - $iri: String! - $sourceType: String! - $sourceUrl: String! - $locale: String! - $latest: Boolean - $filters: Filters -) { - dataCubeByIri( - iri: $iri - sourceType: $sourceType - sourceUrl: $sourceUrl - locale: $locale - latest: $latest - ) { - iri - title - publisher - publicationStatus - expires - identifier - workExamples - creator { - iri - } - landingPage - dimensions(sourceType: $sourceType, sourceUrl: $sourceUrl) { - ...dimensionMetadataWithHierarchies - } - measures(sourceType: $sourceType, sourceUrl: $sourceUrl) { - ...dimensionMetadataWithHierarchies - } - } -} - query Components( $iri: String! $sourceType: String! diff --git a/app/graphql/query-hooks.ts b/app/graphql/query-hooks.ts index 6cc8a9fafa..2de29a2017 100644 --- a/app/graphql/query-hooks.ts +++ b/app/graphql/query-hooks.ts @@ -755,45 +755,6 @@ export type DataCubeMetadataQueryVariables = Exact<{ export type DataCubeMetadataQuery = { __typename: 'Query', dataCubeByIri?: Maybe<{ __typename: 'DataCube', iri: string, identifier?: Maybe, title: string, description?: Maybe, publisher?: Maybe, version?: Maybe, workExamples?: Maybe>>, contactName?: Maybe, contactEmail?: Maybe, landingPage?: Maybe, expires?: Maybe, datePublished?: Maybe, dateModified?: Maybe, publicationStatus: DataCubePublicationStatus, themes: Array<{ __typename: 'DataCubeTheme', iri: string, label?: Maybe }>, creator?: Maybe<{ __typename: 'DataCubeOrganization', iri: string, label?: Maybe }> }> }; -export type DataCubeMetadataWithComponentValuesAndHierarchiesQueryVariables = Exact<{ - iri: Scalars['String']; - sourceType: Scalars['String']; - sourceUrl: Scalars['String']; - locale: Scalars['String']; - latest?: Maybe; - filters?: Maybe; -}>; - - -export type DataCubeMetadataWithComponentValuesAndHierarchiesQuery = { __typename: 'Query', dataCubeByIri?: Maybe<{ __typename: 'DataCube', iri: string, title: string, publisher?: Maybe, publicationStatus: DataCubePublicationStatus, expires?: Maybe, identifier?: Maybe, workExamples?: Maybe>>, landingPage?: Maybe, creator?: Maybe<{ __typename: 'DataCubeOrganization', iri: string }>, dimensions: Array<( - { __typename: 'GeoCoordinatesDimension' } - & DimensionMetadataWithHierarchies_GeoCoordinatesDimension_Fragment - ) | ( - { __typename: 'GeoShapesDimension' } - & DimensionMetadataWithHierarchies_GeoShapesDimension_Fragment - ) | ( - { __typename: 'NominalDimension' } - & DimensionMetadataWithHierarchies_NominalDimension_Fragment - ) | ( - { __typename: 'NumericalMeasure' } - & DimensionMetadataWithHierarchies_NumericalMeasure_Fragment - ) | ( - { __typename: 'OrdinalDimension' } - & DimensionMetadataWithHierarchies_OrdinalDimension_Fragment - ) | ( - { __typename: 'OrdinalMeasure' } - & DimensionMetadataWithHierarchies_OrdinalMeasure_Fragment - ) | ( - { __typename: 'TemporalDimension' } - & DimensionMetadataWithHierarchies_TemporalDimension_Fragment - )>, measures: Array<( - { __typename: 'NumericalMeasure' } - & DimensionMetadataWithHierarchies_NumericalMeasure_Fragment - ) | ( - { __typename: 'OrdinalMeasure' } - & DimensionMetadataWithHierarchies_OrdinalMeasure_Fragment - )> }> }; - export type ComponentsQueryVariables = Exact<{ iri: Scalars['String']; sourceType: Scalars['String']; @@ -1265,39 +1226,6 @@ export const DataCubeMetadataDocument = gql` export function useDataCubeMetadataQuery(options: Omit, 'query'> = {}) { return Urql.useQuery({ query: DataCubeMetadataDocument, ...options }); }; -export const DataCubeMetadataWithComponentValuesAndHierarchiesDocument = gql` - query DataCubeMetadataWithComponentValuesAndHierarchies($iri: String!, $sourceType: String!, $sourceUrl: String!, $locale: String!, $latest: Boolean, $filters: Filters) { - dataCubeByIri( - iri: $iri - sourceType: $sourceType - sourceUrl: $sourceUrl - locale: $locale - latest: $latest - ) { - iri - title - publisher - publicationStatus - expires - identifier - workExamples - creator { - iri - } - landingPage - dimensions(sourceType: $sourceType, sourceUrl: $sourceUrl) { - ...dimensionMetadataWithHierarchies - } - measures(sourceType: $sourceType, sourceUrl: $sourceUrl) { - ...dimensionMetadataWithHierarchies - } - } -} - ${DimensionMetadataWithHierarchiesFragmentDoc}`; - -export function useDataCubeMetadataWithComponentValuesAndHierarchiesQuery(options: Omit, 'query'> = {}) { - return Urql.useQuery({ query: DataCubeMetadataWithComponentValuesAndHierarchiesDocument, ...options }); -}; export const ComponentsDocument = gql` query Components($iri: String!, $sourceType: String!, $sourceUrl: String!, $locale: String!, $latest: Boolean, $filters: Filters) { dataCubeByIri(