From c3986a501b0a27638ddd48a3376a65c03931d1df Mon Sep 17 00:00:00 2001 From: Daniel Bachler Date: Wed, 25 Dec 2024 13:42:56 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=94=A8=20crude=20extraction=20of=20fetchi?= =?UTF-8?q?ng=20functionality?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../@ourworldindata/explorer/src/Explorer.tsx | 10 +- .../grapher/src/core/FetchingGrapher.tsx | 156 ++++++++++++++++++ .../grapher/src/core/Grapher.tsx | 141 +--------------- .../grapher/src/core/LegacyToOwidTable.ts | 3 +- 4 files changed, 167 insertions(+), 143 deletions(-) create mode 100644 packages/@ourworldindata/grapher/src/core/FetchingGrapher.tsx diff --git a/packages/@ourworldindata/explorer/src/Explorer.tsx b/packages/@ourworldindata/explorer/src/Explorer.tsx index da070a9e21a..ef601e77e1e 100644 --- a/packages/@ourworldindata/explorer/src/Explorer.tsx +++ b/packages/@ourworldindata/explorer/src/Explorer.tsx @@ -575,7 +575,7 @@ export class Explorer grapher.setAuthoredVersion(config) grapher.reset() grapher.updateFromObject(config) - grapher.downloadData() + // grapher.downloadData() } @action.bound async updateGrapherFromExplorerUsingVariableIds() { @@ -742,11 +742,11 @@ export class Explorer if (dimensions.length === 0) { // If dimensions are empty, explicitly set the table to an empty table // so we don't end up confusingly showing stale data from a previous chart - grapher.receiveOwidData(new Map()) + // grapher.receiveOwidData(new Map()) } else { - await grapher.downloadLegacyDataFromOwidVariableIds( - inputTableTransformer - ) + // await grapher.downloadLegacyDataFromOwidVariableIds( + // inputTableTransformer + // ) } } diff --git a/packages/@ourworldindata/grapher/src/core/FetchingGrapher.tsx b/packages/@ourworldindata/grapher/src/core/FetchingGrapher.tsx new file mode 100644 index 00000000000..fa6f1b79a3d --- /dev/null +++ b/packages/@ourworldindata/grapher/src/core/FetchingGrapher.tsx @@ -0,0 +1,156 @@ +import { + GrapherInterface, + MultipleOwidVariableDataDimensionsMap, + OwidVariableDataMetadataDimensions, +} from "@ourworldindata/types" +import React from "react" +import { Grapher } from "./Grapher.js" +import { loadVariableDataAndMetadata } from "./loadVariable.js" +import { legacyToOwidTableAndDimensions } from "./LegacyToOwidTable.js" +import { OwidTable } from "@ourworldindata/core-table" + +export interface FetchingGrapherProps { + config?: GrapherInterface + configUrl?: string + queryString?: string + dataApiUrl: string +} +export async function FetchingGrapher( + props: FetchingGrapherProps +): Promise { + // if config is not provided, fetch it from configUrl + + const [config, setConfig] = React.useState( + undefined + ) + + const [inputTable, setInputTable] = React.useState( + undefined + ) + + React.useEffect(() => { + async function fetchConfigAndLoadData(): Promise { + if (!config && props.configUrl) { + const fetchedConfig = await fetch(props.configUrl).then((res) => + res.json() + ) + setConfig(fetchedConfig) + } + if (!config) return + const dimensions = config.dimensions || [] + if (dimensions.length === 0) return + const variables = dimensions.map((d) => d.variableId) + const variablesDataMap = await loadVariablesDataSite( + variables, + props.dataApiUrl + ) + const inputTable = legacyToOwidTableAndDimensions( + variablesDataMap, + dimensions + ) + setInputTable(inputTable) + } + void fetchConfigAndLoadData() + }, [props.configUrl, config, props.dataApiUrl]) + + if (!config) return null + if (!inputTable) return null + return +} + +// async function loadVariablesDataAdmin( +// variableFetchBaseUrl: string | undefined, +// variableIds: number[] +// ): Promise { +// const dataFetchPath = (variableId: number): string => +// variableFetchBaseUrl +// ? `${variableFetchBaseUrl}/v1/variableById/data/${variableId}` +// : `/api/data/variables/data/${variableId}.json` +// const metadataFetchPath = (variableId: number): string => +// variableFetchBaseUrl +// ? `${variableFetchBaseUrl}/v1/variableById/metadata/${variableId}` +// : `/api/data/variables/metadata/${variableId}.json` + +// const loadVariableDataPromises = variableIds.map(async (variableId) => { +// const dataPromise = window.admin.getJSON( +// dataFetchPath(variableId) +// ) as Promise +// const metadataPromise = window.admin.getJSON( +// metadataFetchPath(variableId) +// ) as Promise +// const [data, metadata] = await Promise.all([ +// dataPromise, +// metadataPromise, +// ]) +// return { data, metadata: { ...metadata, id: variableId } } +// }) +// const variablesData: OwidVariableDataMetadataDimensions[] = +// await Promise.all(loadVariableDataPromises) +// const variablesDataMap = new Map( +// variablesData.map((data) => [data.metadata.id, data]) +// ) +// return variablesDataMap +// } + +async function loadVariablesDataSite( + variableIds: number[], + dataApiUrl: string +): Promise { + const loadVariableDataPromises = variableIds.map((variableId) => + loadVariableDataAndMetadata(variableId, dataApiUrl) + ) + const variablesData: OwidVariableDataMetadataDimensions[] = + await Promise.all(loadVariableDataPromises) + const variablesDataMap = new Map( + variablesData.map((data) => [data.metadata.id, data]) + ) + return variablesDataMap +} + +// function downloadData(): void { +// if (this.manuallyProvideData) { +// } else if (this.owidDataset) { +// this._receiveOwidDataAndApplySelection(this.owidDataset) +// } else void this.downloadLegacyDataFromOwidVariableIds() +// } + +// async function downloadLegacyDataFromOwidVariableIds( +// inputTableTransformer?: ChartTableTransformer +// ): Promise { +// if (this.variableIds.length === 0) +// // No data to download +// return + +// try { +// let variablesDataMap: MultipleOwidVariableDataDimensionsMap + +// const startMark = performance.now() +// if (this.useAdminAPI) { +// // TODO grapher model: switch this to downloading multiple data and metadata files +// variablesDataMap = await loadVariablesDataAdmin( +// this.dataApiUrlForAdmin, +// this.variableIds +// ) +// } else { +// variablesDataMap = await loadVariablesDataSite( +// this.variableIds, +// this.dataApiUrl +// ) +// } +// this.createPerformanceMeasurement("downloadVariablesData", startMark) + +// this._receiveOwidDataAndApplySelection( +// variablesDataMap, +// inputTableTransformer +// ) +// } catch (err) { +// // eslint-disable-next-line no-console +// console.log(`Error fetching '${err}'`) +// console.error(err) +// Bugsnag?.notify(`Error fetching variables: ${err}`, (event) => { +// event.addMetadata("context", { +// variableIds: this.variableIds, +// }) +// }) +// } +// } diff --git a/packages/@ourworldindata/grapher/src/core/Grapher.tsx b/packages/@ourworldindata/grapher/src/core/Grapher.tsx index 5a4248b58a1..44cfa5f2d53 100644 --- a/packages/@ourworldindata/grapher/src/core/Grapher.tsx +++ b/packages/@ourworldindata/grapher/src/core/Grapher.tsx @@ -240,55 +240,6 @@ declare global { } } -async function loadVariablesDataAdmin( - variableFetchBaseUrl: string | undefined, - variableIds: number[] -): Promise { - const dataFetchPath = (variableId: number): string => - variableFetchBaseUrl - ? `${variableFetchBaseUrl}/v1/variableById/data/${variableId}` - : `/api/data/variables/data/${variableId}.json` - const metadataFetchPath = (variableId: number): string => - variableFetchBaseUrl - ? `${variableFetchBaseUrl}/v1/variableById/metadata/${variableId}` - : `/api/data/variables/metadata/${variableId}.json` - - const loadVariableDataPromises = variableIds.map(async (variableId) => { - const dataPromise = window.admin.getJSON( - dataFetchPath(variableId) - ) as Promise - const metadataPromise = window.admin.getJSON( - metadataFetchPath(variableId) - ) as Promise - const [data, metadata] = await Promise.all([ - dataPromise, - metadataPromise, - ]) - return { data, metadata: { ...metadata, id: variableId } } - }) - const variablesData: OwidVariableDataMetadataDimensions[] = - await Promise.all(loadVariableDataPromises) - const variablesDataMap = new Map( - variablesData.map((data) => [data.metadata.id, data]) - ) - return variablesDataMap -} - -async function loadVariablesDataSite( - variableIds: number[], - dataApiUrl: string -): Promise { - const loadVariableDataPromises = variableIds.map((variableId) => - loadVariableDataAndMetadata(variableId, dataApiUrl) - ) - const variablesData: OwidVariableDataMetadataDimensions[] = - await Promise.all(loadVariableDataPromises) - const variablesDataMap = new Map( - variablesData.map((data) => [data.metadata.id, data]) - ) - return variablesDataMap -} - const DEFAULT_MS_PER_TICK = 100 // Exactly the same as GrapherInterface, but contains options that developers want but authors won't be touching. @@ -560,8 +511,6 @@ export class Grapher this.updateFromObject(props) } - if (!props.table) this.downloadData() - this.populateFromQueryParams( legacyToCurrentGrapherQueryParams(props.queryStr ?? "") ) @@ -607,13 +556,6 @@ export class Grapher return obj } - @action.bound downloadData(): void { - if (this.manuallyProvideData) { - } else if (this.owidDataset) { - this._receiveOwidDataAndApplySelection(this.owidDataset) - } else void this.downloadLegacyDataFromOwidVariableIds() - } - @action.bound updateFromObject(obj?: GrapherProgrammaticInterface): void { if (!obj) return @@ -1088,63 +1030,9 @@ export class Grapher // In old browsers, the above may throw an error - just ignore it } } - - @action.bound - async downloadLegacyDataFromOwidVariableIds( - inputTableTransformer?: ChartTableTransformer - ): Promise { - if (this.variableIds.length === 0) - // No data to download - return - - try { - let variablesDataMap: MultipleOwidVariableDataDimensionsMap - - const startMark = performance.now() - if (this.useAdminAPI) { - // TODO grapher model: switch this to downloading multiple data and metadata files - variablesDataMap = await loadVariablesDataAdmin( - this.dataApiUrlForAdmin, - this.variableIds - ) - } else { - variablesDataMap = await loadVariablesDataSite( - this.variableIds, - this.dataApiUrl - ) - } - this.createPerformanceMeasurement( - "downloadVariablesData", - startMark - ) - - this._receiveOwidDataAndApplySelection( - variablesDataMap, - inputTableTransformer - ) - } catch (err) { - // eslint-disable-next-line no-console - console.log(`Error fetching '${err}'`) - console.error(err) - Bugsnag?.notify(`Error fetching variables: ${err}`, (event) => { - event.addMetadata("context", { - variableIds: this.variableIds, - }) - }) - } - } - - @action.bound receiveOwidData( - json: MultipleOwidVariableDataDimensionsMap - ): void { - // TODO grapher model: switch this to downloading multiple data and metadata files - this._receiveOwidDataAndApplySelection(json) - } - @action.bound private _setInputTable( json: MultipleOwidVariableDataDimensionsMap, - legacyConfig: Partial, - inputTableTransformer?: ChartTableTransformer + legacyConfig: Partial ): void { // TODO grapher model: switch this to downloading multiple data and metadata files @@ -1167,9 +1055,7 @@ export class Grapher startMark ) - if (inputTableTransformer) - this.inputTable = inputTableTransformer(tableWithColors) - else this.inputTable = tableWithColors + this.inputTable = tableWithColors // We need to reset the dimensions because some of them may have changed slugs in the legacy // transformation (can happen when columns use targetTime) @@ -1184,30 +1070,17 @@ export class Grapher } else this.applyOriginalSelectionAsAuthored() } - @action rebuildInputOwidTable( - inputTableTransformer?: ChartTableTransformer - ): void { + @action rebuildInputOwidTable(): void { // TODO grapher model: switch this to downloading multiple data and metadata files if (!this.legacyVariableDataJson) return this._setInputTable( this.legacyVariableDataJson, - this.legacyConfigAsAuthored, - inputTableTransformer + this.legacyConfigAsAuthored ) } @observable private legacyVariableDataJson?: MultipleOwidVariableDataDimensionsMap - - @action.bound private _receiveOwidDataAndApplySelection( - json: MultipleOwidVariableDataDimensionsMap, - inputTableTransformer?: ChartTableTransformer - ): void { - this.legacyVariableDataJson = json - - this.rebuildInputOwidTable(inputTableTransformer) - } - @action.bound appendNewEntitySelectionOptions(): void { const { selection } = this const currentEntities = selection.availableEntityNameSet @@ -1431,12 +1304,6 @@ export class Grapher // todo: can we remove this? // I believe these states can only occur during editing. @action.bound private ensureValidConfigWhenEditing(): void { - this.disposers.push( - reaction( - () => this.variableIds, - () => this.downloadLegacyDataFromOwidVariableIds() - ) - ) const disposers = [ autorun(() => { if (!this.availableTabs.includes(this.activeTab)) diff --git a/packages/@ourworldindata/grapher/src/core/LegacyToOwidTable.ts b/packages/@ourworldindata/grapher/src/core/LegacyToOwidTable.ts index 79b4fa25e8f..bc43da41123 100644 --- a/packages/@ourworldindata/grapher/src/core/LegacyToOwidTable.ts +++ b/packages/@ourworldindata/grapher/src/core/LegacyToOwidTable.ts @@ -86,7 +86,8 @@ export const legacyToOwidTableAndDimensions = ( const valueColumnColor = dimension.display?.color // Ensure the column slug is unique by copying it from the dimensions // (there can be two columns of the same variable with different targetTimes) - valueColumnDef.slug = dimension.slug + if (dimension.slug) valueColumnDef.slug = dimension.slug + else throw new Error("Dimension slug was undefined") // Because database columns can contain mixed types, we want to avoid // parsing for Grapher data until we fix that. valueColumnDef.skipParsing = true