diff --git a/adminSiteServer/multiDim.ts b/adminSiteServer/multiDim.ts index 0241b88c571..d018dcbaa55 100644 --- a/adminSiteServer/multiDim.ts +++ b/adminSiteServer/multiDim.ts @@ -11,13 +11,16 @@ import { DbPlainMultiDimXChartConfig, DbRawChartConfig, GrapherInterface, + IndicatorConfig, IndicatorEntryBeforePreProcessing, + IndicatorsBeforePreProcessing, MultiDimDataPageConfigEnriched, MultiDimDataPageConfigPreProcessed, MultiDimDataPageConfigRaw, MultiDimDataPagesTableName, MultiDimDimensionChoices, MultiDimXChartConfigsTableName, + View, } from "@ourworldindata/types" import { mergeGrapherConfigs, @@ -51,19 +54,39 @@ function dimensionsToViewId(dimensions: MultiDimDimensionChoices) { .toLowerCase() } +function catalogPathFromIndicatorEntry( + entry: IndicatorEntryBeforePreProcessing +): string | undefined { + if (typeof entry === "string") return entry + if (typeof entry === "object" && "catalogPath" in entry) { + return entry.catalogPath + } + return undefined +} + +function getAllCatalogPaths(views: View[]) { + const paths = [] + for (const view of views) { + const { y, x, size, color } = view.indicators + if (y) { + if (Array.isArray(y)) { + paths.push(...y.map(catalogPathFromIndicatorEntry)) + } else { + paths.push(catalogPathFromIndicatorEntry(y)) + } + } + for (const entry of [x, size, color]) { + if (entry) paths.push(catalogPathFromIndicatorEntry(entry)) + } + } + return paths.filter((path) => path !== undefined) +} + async function resolveMultiDimDataPageCatalogPathsToIndicatorIds( knex: db.KnexReadonlyTransaction, rawConfig: MultiDimDataPageConfigRaw ): Promise { - const allCatalogPaths = rawConfig.views - .flatMap((view) => - Object.values(view.indicators).flatMap((indicatorOrIndicators) => - Array.isArray(indicatorOrIndicators) - ? indicatorOrIndicators - : [indicatorOrIndicators] - ) - ) - .filter((indicator) => typeof indicator === "string") + const allCatalogPaths = getAllCatalogPaths(rawConfig.views) const catalogPathToIndicatorIdMap = await getVariableIdsByCatalogPath( allCatalogPaths, @@ -84,12 +107,29 @@ async function resolveMultiDimDataPageCatalogPathsToIndicatorIds( ) } - function resolveSingleField(indicator?: IndicatorEntryBeforePreProcessing) { - if (typeof indicator === "string") { - const indicatorId = catalogPathToIndicatorIdMap.get(indicator) - return indicatorId ?? undefined + function resolveSingleField( + indicator?: IndicatorEntryBeforePreProcessing + ): IndicatorConfig | undefined { + switch (typeof indicator) { + case "number": + return { id: indicator } + case "string": { + const id = catalogPathToIndicatorIdMap.get(indicator) + return id ? { id } : undefined + } + case "object": { + if ("id" in indicator) return indicator + if ("catalogPath" in indicator) { + const id = catalogPathToIndicatorIdMap.get( + indicator.catalogPath + ) + return id ? { ...indicator, id } : undefined + } + return undefined + } + default: + return undefined } - return indicator } function resolveSingleOrArrayField( @@ -202,7 +242,7 @@ export async function createMultiDimConfig( ) const variableConfigs = await getMergedGrapherConfigsForVariables( knex, - uniq(config.views.map((view) => view.indicators.y[0])) + uniq(config.views.map((view) => view.indicators.y[0].id)) ) const existingViewIdsToChartConfigIds = await getViewIdToChartConfigIdMap( knex, @@ -215,7 +255,7 @@ export async function createMultiDimConfig( const enrichedViews = await Promise.all( config.views.map(async (view) => { - const variableId = view.indicators.y[0] + const variableId = view.indicators.y[0].id // Main config for each view. const mainGrapherConfig: GrapherInterface = { $schema: defaultGrapherConfig.$schema, @@ -283,7 +323,7 @@ export async function createMultiDimConfig( await upsertMultiDimXChartConfigs(knex, { multiDimId, viewId: dimensionsToViewId(view.dimensions), - variableId: view.indicators.y[0], + variableId: view.indicators.y[0].id, chartConfigId: view.fullConfigId, }) } diff --git a/baker/MultiDimBaker.tsx b/baker/MultiDimBaker.tsx index db04ecdb3c7..3461aa62c94 100644 --- a/baker/MultiDimBaker.tsx +++ b/baker/MultiDimBaker.tsx @@ -37,7 +37,7 @@ import { const getRelevantVariableIds = (config: MultiDimDataPageConfigPreProcessed) => { // A "relevant" variable id is the first y indicator of each view const allIndicatorIds = config.views - .map((view) => view.indicators.y?.[0]) + .map((view) => view.indicators.y?.[0]?.id) .filter((id) => id !== undefined) return new Set(allIndicatorIds) diff --git a/packages/@ourworldindata/types/src/index.ts b/packages/@ourworldindata/types/src/index.ts index a8a3f80db50..54abc363ad4 100644 --- a/packages/@ourworldindata/types/src/index.ts +++ b/packages/@ourworldindata/types/src/index.ts @@ -728,8 +728,10 @@ export { } from "./domainTypes/Author.js" export type { + IndicatorConfig, IndicatorEntryBeforePreProcessing, IndicatorsAfterPreProcessing, + IndicatorsBeforePreProcessing, MultiDimDataPageConfigEnriched, MultiDimDataPageConfigPreProcessed, MultiDimDataPageConfigRaw, diff --git a/packages/@ourworldindata/types/src/siteTypes/MultiDimDataPage.ts b/packages/@ourworldindata/types/src/siteTypes/MultiDimDataPage.ts index ddfd3a3a1b8..cd00af8bbf2 100644 --- a/packages/@ourworldindata/types/src/siteTypes/MultiDimDataPage.ts +++ b/packages/@ourworldindata/types/src/siteTypes/MultiDimDataPage.ts @@ -6,9 +6,23 @@ import { OwidVariableWithSource, } from "../OwidVariable.js" -// Indicator ID, catalog path, or maybe an array of those -export type IndicatorEntryBeforePreProcessing = string | number -export type IndicatorEntryAfterPreProcessing = number // catalog paths have been resolved to indicator IDs +export type IndicatorConfig = Pick +type IndicatorConfigByPath = Pick & { + catalogPath: string +} + +type IndicatorConfigBeforePreProcessing = + | IndicatorConfig + | IndicatorConfigByPath + +// Indicator ID, catalog path or a an object +export type IndicatorEntryBeforePreProcessing = + | string + | number + | IndicatorConfigBeforePreProcessing + +// Catalog paths have been resolved to indicator IDs +export type IndicatorEntryAfterPreProcessing = IndicatorConfig type Metadata = Omit diff --git a/packages/@ourworldindata/utils/src/MultiDimDataPageConfig.test.ts b/packages/@ourworldindata/utils/src/MultiDimDataPageConfig.test.ts index a6fa83b2d0a..4122a6625ae 100644 --- a/packages/@ourworldindata/utils/src/MultiDimDataPageConfig.test.ts +++ b/packages/@ourworldindata/utils/src/MultiDimDataPageConfig.test.ts @@ -51,7 +51,7 @@ const CONFIG: MultiDimDataPageConfigEnriched = { interval: "yearly", }, indicators: { - y: [111, 222], + y: [{ id: 111 }, { id: 222 }], }, fullConfigId: uuidv7(), }, @@ -61,7 +61,7 @@ const CONFIG: MultiDimDataPageConfigEnriched = { interval: "yearly", }, indicators: { - y: [819727], + y: [{ id: 819727 }], }, fullConfigId: uuidv7(), }, diff --git a/packages/@ourworldindata/utils/src/MultiDimDataPageConfig.ts b/packages/@ourworldindata/utils/src/MultiDimDataPageConfig.ts index db93b04fe95..352d1abc3a7 100644 --- a/packages/@ourworldindata/utils/src/MultiDimDataPageConfig.ts +++ b/packages/@ourworldindata/utils/src/MultiDimDataPageConfig.ts @@ -156,27 +156,41 @@ export class MultiDimDataPageConfig { } static viewToDimensionsConfig( - view: View | undefined + view?: View ): OwidChartDimensionInterface[] { - if (!view?.indicators) return [] - - return Object.entries(view.indicators) - .flatMap(([property, variableIdOrIds]) => { - if (Array.isArray(variableIdOrIds)) { - return variableIdOrIds.map((variableId) => ({ - property: property as DimensionProperty, - variableId, - })) - } else { - return [ - { - property: property as DimensionProperty, - variableId: variableIdOrIds, - }, - ] - } + const dimensions: OwidChartDimensionInterface[] = [] + if (!view?.indicators) return dimensions + if (view.indicators.y) { + dimensions.push( + ...view.indicators.y.map(({ id, display }) => ({ + property: DimensionProperty.y, + variableId: id, + display, + })) + ) + } + if (view.indicators.x) { + dimensions.push({ + property: DimensionProperty.x, + variableId: view.indicators.x.id, + display: view.indicators.x.display, + }) + } + if (view.indicators.size) { + dimensions.push({ + property: DimensionProperty.size, + variableId: view.indicators.size.id, + display: view.indicators.size.display, }) - .filter((dim) => dim.variableId !== undefined) + } + if (view.indicators.color) { + dimensions.push({ + property: DimensionProperty.color, + variableId: view.indicators.color.id, + display: view.indicators.color.display, + }) + } + return dimensions } } diff --git a/site/multiDim/MultiDimDataPageContent.tsx b/site/multiDim/MultiDimDataPageContent.tsx index 6edf6798f7c..b79d26e9451 100644 --- a/site/multiDim/MultiDimDataPageContent.tsx +++ b/site/multiDim/MultiDimDataPageContent.tsx @@ -150,10 +150,7 @@ const useVarDatapageData = ( setGrapherConfigIsReady(false) setGrapherConfig(null) setVarDatapageData(null) - const yIndicatorOrIndicators = currentView?.indicators?.["y"] - const variableId = Array.isArray(yIndicatorOrIndicators) - ? yIndicatorOrIndicators[0] - : yIndicatorOrIndicators + const variableId = currentView?.indicators?.["y"]?.[0]?.id if (!variableId) return const datapageDataPromise = cachedGetVariableMetadata(variableId).then( @@ -297,7 +294,7 @@ export const MultiDimDataPageContent = ({ const variables = currentView?.indicators?.["y"] const editUrl = variables?.length === 1 - ? `variables/${variables[0]}/config` + ? `variables/${variables[0].id}/config` : undefined return { ...varGrapherConfig,