diff --git a/adminSiteClient/constants.ts b/adminSiteClient/constants.ts
index aac38f56c2..2bbc58ea27 100644
--- a/adminSiteClient/constants.ts
+++ b/adminSiteClient/constants.ts
@@ -9,4 +9,5 @@ export const GDOC_DIFF_OMITTABLE_PROPERTIES = [
"linkedCharts",
"linkedDocuments",
"relatedCharts",
+ "linkedChartViews",
]
diff --git a/db/model/Gdoc/GdocBase.ts b/db/model/Gdoc/GdocBase.ts
index 9fc9741293..64e0c4fb00 100644
--- a/db/model/Gdoc/GdocBase.ts
+++ b/db/model/Gdoc/GdocBase.ts
@@ -491,6 +491,13 @@ export class GdocBase implements OwidGdocBaseInterface {
text: insight.title,
})
links.push(insightLink)
+ } else if (insight.narrativeChartName) {
+ const insightLink = createLinkForChartView({
+ name: insight.narrativeChartName,
+ source: this,
+ componentType: block.type,
+ })
+ links.push(insightLink)
}
})
@@ -796,6 +803,9 @@ export class GdocBase implements OwidGdocBaseInterface {
const chartIdsBySlug = await mapSlugsToIds(knex)
const publishedExplorersBySlug =
await db.getPublishedExplorersBySlug(knex)
+ const chartViewNames = await getChartViewsInfo(knex)
+ .then((cv) => cv.map((c) => c.name))
+ .then((chartViewNames) => new Set(chartViewNames))
const linkErrors: OwidGdocErrorMessage[] = []
for (const link of this.links) {
@@ -840,6 +850,16 @@ export class GdocBase implements OwidGdocBaseInterface {
}
break
}
+ case OwidGdocLinkType.ChartView: {
+ if (!chartViewNames.has(link.target)) {
+ linkErrors.push({
+ property: "content",
+ message: `Narrative chart with name ${link.target} does not exist`,
+ type: OwidGdocErrorMessageType.Error,
+ })
+ }
+ break
+ }
}
}
diff --git a/db/model/Gdoc/enrichedToMarkdown.ts b/db/model/Gdoc/enrichedToMarkdown.ts
index 794700f30a..28be14ebc3 100644
--- a/db/model/Gdoc/enrichedToMarkdown.ts
+++ b/db/model/Gdoc/enrichedToMarkdown.ts
@@ -275,7 +275,13 @@ ${b.url}`
{ url: insight.url },
exportComponents
)
- : undefined
+ : insight.narrativeChartName
+ ? markdownComponent(
+ "NarrativeChart",
+ { name: insight.narrativeChartName },
+ exportComponents
+ )
+ : undefined
const content =
enrichedBlocksToMarkdown(
insight.content,
diff --git a/db/model/Gdoc/enrichedToRaw.ts b/db/model/Gdoc/enrichedToRaw.ts
index 08e8e1fa28..f090d2372e 100644
--- a/db/model/Gdoc/enrichedToRaw.ts
+++ b/db/model/Gdoc/enrichedToRaw.ts
@@ -428,6 +428,7 @@ export function enrichedBlockToRawBlock(
title: insight.title,
filename: insight.filename,
url: insight.url,
+ narrativeChartName: insight.narrativeChartName,
content: insight.content?.map((content) =>
enrichedBlockToRawBlock(content)
),
diff --git a/db/model/Gdoc/exampleEnrichedBlocks.ts b/db/model/Gdoc/exampleEnrichedBlocks.ts
index 74b2a0f884..66f3e085ed 100644
--- a/db/model/Gdoc/exampleEnrichedBlocks.ts
+++ b/db/model/Gdoc/exampleEnrichedBlocks.ts
@@ -440,6 +440,33 @@ export const enrichedBlockExamples: Record<
},
],
},
+ {
+ title: "Key insight number 3",
+ type: "key-insight-slide",
+ narrativeChartName: "world-has-become-less-democratic",
+ content: [
+ {
+ type: "text",
+ parseErrors: [],
+ value: [
+ {
+ spanType: "span-simple-text",
+ text: "I am the first paragraph of the third insight.",
+ },
+ ],
+ },
+ {
+ type: "text",
+ parseErrors: [],
+ value: [
+ {
+ spanType: "span-simple-text",
+ text: "I am the second paragraph of the third insight.",
+ },
+ ],
+ },
+ ],
+ },
],
parseErrors: [],
},
diff --git a/db/model/Gdoc/rawToArchie.ts b/db/model/Gdoc/rawToArchie.ts
index b1b344a449..35eb35aa7b 100644
--- a/db/model/Gdoc/rawToArchie.ts
+++ b/db/model/Gdoc/rawToArchie.ts
@@ -562,6 +562,7 @@ function* rawKeyInsightsToArchieMLString(
yield* propertyToArchieMLString("title", insight)
yield* propertyToArchieMLString("filename", insight)
yield* propertyToArchieMLString("url", insight)
+ yield* propertyToArchieMLString("narrativeChartName", insight)
if (insight.content) {
yield "[.+content]"
for (const content of insight.content) {
diff --git a/db/model/Gdoc/rawToEnriched.ts b/db/model/Gdoc/rawToEnriched.ts
index 209fcc5984..047d67ec6d 100644
--- a/db/model/Gdoc/rawToEnriched.ts
+++ b/db/model/Gdoc/rawToEnriched.ts
@@ -1597,16 +1597,25 @@ function parseKeyInsights(raw: RawBlockKeyInsights): EnrichedBlockKeyInsights {
if (!rawInsight.title) {
parseErrors.push({ message: "Key insight is missing a title" })
}
- if (!rawInsight.url && !rawInsight.filename) {
+ if (
+ !rawInsight.url &&
+ !rawInsight.filename &&
+ !rawInsight.narrativeChartName
+ ) {
parseErrors.push({
message:
- "Key insight is missing a url or filename. One of these two fields must be specified.",
+ "Key insight is missing a url, filename or narrativeChartName. One of these two fields must be specified.",
})
}
- if (rawInsight.url && rawInsight.filename) {
+ const hasMoreThanOneResourceField =
+ Number(!!rawInsight.url) +
+ Number(!!rawInsight.filename) +
+ Number(!!rawInsight.narrativeChartName) >
+ 1
+ if (hasMoreThanOneResourceField) {
parseErrors.push({
message:
- "Key insight has both a url and a filename. Only one of these two fields can be specified.",
+ "Key insight has more than just one of the fields url, filename, narrativeChartName. Only one of these fields can be specified.",
})
}
const url = Url.fromURL(extractUrl(rawInsight.url))
@@ -1640,6 +1649,10 @@ function parseKeyInsights(raw: RawBlockKeyInsights): EnrichedBlockKeyInsights {
if (rawInsight.filename) {
enrichedInsight.filename = rawInsight.filename
}
+ if (rawInsight.narrativeChartName) {
+ enrichedInsight.narrativeChartName =
+ rawInsight.narrativeChartName
+ }
enrichedInsights.push(enrichedInsight)
}
}
diff --git a/packages/@ourworldindata/types/src/gdocTypes/ArchieMlComponents.ts b/packages/@ourworldindata/types/src/gdocTypes/ArchieMlComponents.ts
index 3d1130ea3e..50222fee90 100644
--- a/packages/@ourworldindata/types/src/gdocTypes/ArchieMlComponents.ts
+++ b/packages/@ourworldindata/types/src/gdocTypes/ArchieMlComponents.ts
@@ -598,6 +598,7 @@ export type RawBlockKeyInsightsSlide = {
title?: string
filename?: string
url?: string
+ narrativeChartName?: string
content?: OwidRawGdocBlock[]
}
@@ -614,6 +615,7 @@ export type EnrichedBlockKeyInsightsSlide = {
title: string
filename?: string
url?: string
+ narrativeChartName?: string
content: OwidEnrichedGdocBlock[]
}
diff --git a/site/gdocs/components/KeyInsights.tsx b/site/gdocs/components/KeyInsights.tsx
index 0b283c5bc4..ead6e90c38 100644
--- a/site/gdocs/components/KeyInsights.tsx
+++ b/site/gdocs/components/KeyInsights.tsx
@@ -15,6 +15,7 @@ import {
import { ArticleBlocks } from "./ArticleBlocks.js"
import Image from "./Image.js"
import Chart from "./Chart.js"
+import NarrativeChart from "./NarrativeChart.js"
export const KEY_INSIGHTS_CLASS_NAME = "key-insights"
export const KEY_INSIGHTS_INSIGHT_PARAM = "insight"
@@ -293,9 +294,11 @@ export const KeyInsights = ({
function renderAssetForInsight({
filename,
url,
+ narrativeChartName,
}: {
filename?: string
url?: string
+ narrativeChartName?: string
}): React.ReactElement | null {
if (filename) {
return (
@@ -313,6 +316,18 @@ export const KeyInsights = ({
/>
)
}
+ if (narrativeChartName) {
+ return (
+