diff --git a/adminSiteServer/apiRouter.ts b/adminSiteServer/apiRouter.ts index 862e50b817..9992f5369f 100644 --- a/adminSiteServer/apiRouter.ts +++ b/adminSiteServer/apiRouter.ts @@ -115,6 +115,7 @@ import { CHART_VIEW_PROPS_TO_PERSIST, CHART_VIEW_PROPS_TO_OMIT, DbEnrichedImage, + JsonString, } from "@ourworldindata/types" import { uuidv7 } from "uuidv7" import { @@ -122,6 +123,7 @@ import { getVariableDataRoute, getVariableMetadataRoute, defaultGrapherConfig, + grapherConfigToQueryParams, } from "@ourworldindata/grapher" import { getDatasetById, setTagsForDataset } from "../db/model/Dataset.js" import { getUserById, insertUser, updateUser } from "../db/model/User.js" @@ -3567,7 +3569,7 @@ postRouteWithRWTransaction(apiRouter, "/tagGraph", async (req, res, trx) => { res.send({ success: true }) }) -const createPatchConfigAndFullConfigForChartView = async ( +const createPatchConfigAndQueryParamsForChartView = async ( knex: db.KnexReadonlyTransaction, parentChartId: number, config: GrapherInterface @@ -3592,8 +3594,10 @@ const createPatchConfigAndFullConfigForChartView = async ( ...pick(fullConfigIncludingDefaults, CHART_VIEW_PROPS_TO_PERSIST), } + const queryParams = grapherConfigToQueryParams(config) + const fullConfig = mergeGrapherConfigs(parentChartConfig, patchConfigToSave) - return { patchConfig: patchConfigToSave, fullConfig } + return { patchConfig: patchConfigToSave, fullConfig, queryParams } } getRouteWithROTransaction(apiRouter, "/chartViews", async (req, res, trx) => { @@ -3654,10 +3658,11 @@ getRouteWithROTransaction( > & { lastEditedByUser: string chartConfigId: string - configFull: string - configPatch: string + configFull: JsonString + configPatch: JsonString parentChartId: number - parentConfigFull: string + parentConfigFull: JsonString + queryParamsForParentChart: JsonString } const row = await db.knexRawFirst( @@ -3672,7 +3677,8 @@ getRouteWithROTransaction( cc.full as configFull, cc.patch as configPatch, cv.parentChartId, - pcc.full as parentConfigFull + pcc.full as parentConfigFull, + cv.queryParamsForParentChart FROM chart_views cv JOIN chart_configs cc ON cv.chartConfigId = cc.id JOIN charts pc ON cv.parentChartId = pc.id @@ -3692,6 +3698,9 @@ getRouteWithROTransaction( configFull: parseChartConfig(row.configFull), configPatch: parseChartConfig(row.configPatch), parentConfigFull: parseChartConfig(row.parentConfigFull), + queryParamsForParentChart: JSON.parse( + row.queryParamsForParentChart + ), } return chartView @@ -3708,8 +3717,8 @@ postRouteWithRWTransaction(apiRouter, "/chartViews", async (req, res, trx) => { throw new JsonError("Invalid request", 400) } - const { patchConfig, fullConfig } = - await createPatchConfigAndFullConfigForChartView( + const { patchConfig, fullConfig, queryParams } = + await createPatchConfigAndQueryParamsForChartView( trx, parentChartId, rawConfig @@ -3728,6 +3737,7 @@ postRouteWithRWTransaction(apiRouter, "/chartViews", async (req, res, trx) => { parentChartId, lastEditedByUserId: res.locals.user.id, chartConfigId: chartConfigId, + queryParamsForParentChart: JSON.stringify(queryParams), } const result = await trx.table(ChartViewsTableName).insert(insertRow) const [resultId] = result @@ -3757,8 +3767,8 @@ putRouteWithRWTransaction( throw new JsonError(`No chart view found for id ${id}`, 404) } - const { patchConfig, fullConfig } = - await createPatchConfigAndFullConfigForChartView( + const { patchConfig, fullConfig, queryParams } = + await createPatchConfigAndQueryParamsForChartView( trx, existingRow.parentChartId, rawConfig @@ -3772,10 +3782,14 @@ putRouteWithRWTransaction( ) // update chart_views - await trx.table(ChartViewsTableName).where({ id }).update({ - updatedAt: new Date(), - lastEditedByUserId: res.locals.user.id, - }) + await trx + .table(ChartViewsTableName) + .where({ id }) + .update({ + updatedAt: new Date(), + lastEditedByUserId: res.locals.user.id, + queryParamsForParentChart: JSON.stringify(queryParams), + }) return { success: true } } diff --git a/db/migration/1733151294656-ChartViewsAddQueryParam.ts b/db/migration/1733151294656-ChartViewsAddQueryParam.ts new file mode 100644 index 0000000000..30efc1e9d2 --- /dev/null +++ b/db/migration/1733151294656-ChartViewsAddQueryParam.ts @@ -0,0 +1,17 @@ +import { MigrationInterface, QueryRunner } from "typeorm" + +export class ChartViewsAddQueryParam1733151294656 + implements MigrationInterface +{ + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`-- sql + ALTER TABLE chart_views ADD COLUMN queryParamsForParentChart JSON NULL AFTER parentChartId; + `) + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`-- sql + ALTER TABLE chart_views DROP COLUMN queryParamsForParentChart; + `) + } +} diff --git a/packages/@ourworldindata/grapher/src/dataTable/DataTable.tsx b/packages/@ourworldindata/grapher/src/dataTable/DataTable.tsx index 8455cdc536..3e1af11460 100644 --- a/packages/@ourworldindata/grapher/src/dataTable/DataTable.tsx +++ b/packages/@ourworldindata/grapher/src/dataTable/DataTable.tsx @@ -577,6 +577,8 @@ export class DataTable extends React.Component<{ @computed private get tableCaption(): React.ReactElement | null { if (this.hasDimensionHeaders) return null + if (this.displayDimensions.length === 0) return null + const singleDimension = this.displayDimensions[0] const titleFragments = (singleDimension.display.columnName .attributionShort || diff --git a/packages/@ourworldindata/grapher/src/index.ts b/packages/@ourworldindata/grapher/src/index.ts index 0e4edc0f45..b9b100cdf1 100644 --- a/packages/@ourworldindata/grapher/src/index.ts +++ b/packages/@ourworldindata/grapher/src/index.ts @@ -78,6 +78,7 @@ export { getSelectedEntityNamesParam, generateSelectedEntityNamesParam, } from "./core/EntityUrlBuilder" +export { grapherConfigToQueryParams } from "./core/GrapherUrl.js" export { type SlideShowManager, SlideShowController, diff --git a/packages/@ourworldindata/grapher/src/stackedCharts/AbstractStackedChart.tsx b/packages/@ourworldindata/grapher/src/stackedCharts/AbstractStackedChart.tsx index 9004f81350..2a5110442d 100644 --- a/packages/@ourworldindata/grapher/src/stackedCharts/AbstractStackedChart.tsx +++ b/packages/@ourworldindata/grapher/src/stackedCharts/AbstractStackedChart.tsx @@ -286,6 +286,8 @@ export class AbstractStackedChart @computed private get entitiesAsSeries(): readonly StackedRawSeries[] { + if (!this.yColumns.length) return [] + const { isProjection, owidRowsByEntityName } = this.yColumns[0] return this.selectionArray.selectedEntityNames .map((seriesName) => { diff --git a/packages/@ourworldindata/types/src/dbTypes/ChartViews.ts b/packages/@ourworldindata/types/src/dbTypes/ChartViews.ts index e08437d5fb..5a5ad5d92b 100644 --- a/packages/@ourworldindata/types/src/dbTypes/ChartViews.ts +++ b/packages/@ourworldindata/types/src/dbTypes/ChartViews.ts @@ -1,3 +1,4 @@ +import { JsonString } from "../domainTypes/Various.js" import { GrapherInterface } from "../grapherTypes/GrapherTypes.js" export const ChartViewsTableName = "chart_views" @@ -6,6 +7,7 @@ export interface DbInsertChartView { name: string chartConfigId: string parentChartId: number + queryParamsForParentChart?: JsonString | null createdAt?: Date | null updatedAt?: Date | null lastEditedByUserId: number