Skip to content

Commit

Permalink
Merge pull request #3072 from owid/linked-document-type
Browse files Browse the repository at this point in the history
🔨 use a minimal representation of gdocs to link to
  • Loading branch information
ikesau authored Jan 18, 2024
2 parents c82077d + dbc9dcd commit 6233cc1
Show file tree
Hide file tree
Showing 14 changed files with 88 additions and 43 deletions.
11 changes: 7 additions & 4 deletions baker/SiteBaker.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,9 @@ import {
OwidGdocErrorMessageType,
ImageMetadata,
OwidGdoc,
OwidGdocPostInterface,
OwidGdocType,
DATA_INSIGHTS_INDEX_PAGE_SIZE,
OwidGdocMinimalPostInterface,
} from "@ourworldindata/utils"

import { execWrapper } from "../db/execWrapper.js"
Expand Down Expand Up @@ -83,9 +83,10 @@ import {
} from "../settings/clientSettings.js"
import pMap from "p-map"
import { GdocDataInsight } from "../db/model/Gdoc/GdocDataInsight.js"
import { fullGdocToMinimalGdoc } from "../db/model/Gdoc/gdocUtils.js"

type PrefetchedAttachments = {
linkedDocuments: Record<string, OwidGdocPostInterface>
linkedDocuments: Record<string, OwidGdocMinimalPostInterface>
imageMetadata: Record<string, ImageMetadata>
linkedCharts: {
graphers: Record<string, LinkedChart>
Expand Down Expand Up @@ -290,7 +291,9 @@ export class SiteBaker {
picks?: [string[], string[], string[], string[]]
): Promise<PrefetchedAttachments> {
if (!this._prefetchedAttachmentsCache) {
const publishedGdocs = await GdocPost.getPublishedGdocs()
const publishedGdocs = await GdocPost.getPublishedGdocs().then(
(fullGdocs) => fullGdocs.map(fullGdocToMinimalGdoc)
)
const publishedGdocsDictionary = keyBy(publishedGdocs, "id")

const imageMetadataDictionary: Record<string, Image> =
Expand Down Expand Up @@ -350,7 +353,7 @@ export class SiteBaker {
// Gdoc.linkedImageFilenames normally gets featuredImages, but it relies on linkedDocuments already being populated,
// which is isn't when we're prefetching attachments. So we have to do it manually here.
const featuredImages = Object.values(linkedDocuments)
.map((gdoc) => gdoc.content["featured-image"])
.map((gdoc) => gdoc["featured-image"])
.filter((filename): filename is string => !!filename)

return {
Expand Down
25 changes: 14 additions & 11 deletions db/model/Gdoc/GdocBase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,7 @@ import {
OwidGdocPublicationContext,
BreadcrumbItem,
MinimalDataInsightInterface,
getFeaturedImageFilename,
OwidGdoc,
OwidGdocMinimalPostInterface,
} from "@ourworldindata/utils"
import { BAKED_GRAPHER_URL } from "../../../settings/serverSettings.js"
import { google } from "googleapis"
Expand All @@ -50,6 +49,7 @@ import { EXPLORERS_ROUTE_FOLDER } from "../../../explorer/ExplorerConstants.js"
import { match, P } from "ts-pattern"
import {
extractUrl,
fullGdocToMinimalGdoc,
getAllLinksFromResearchAndWritingBlock,
spansToSimpleString,
} from "./gdocUtils.js"
Expand Down Expand Up @@ -98,7 +98,7 @@ export class GdocBase extends BaseEntity implements OwidGdocBaseInterface {
errors: OwidGdocErrorMessage[] = []
imageMetadata: Record<string, ImageMetadata> = {}
linkedCharts: Record<string, LinkedChart> = {}
linkedDocuments: Record<string, OwidGdocBaseInterface> = {}
linkedDocuments: Record<string, OwidGdocMinimalPostInterface> = {}
latestDataInsights: MinimalDataInsightInterface[] = []

_getSubclassEnrichedBlocks: (gdoc: typeof this) => OwidEnrichedGdocBlock[] =
Expand Down Expand Up @@ -262,7 +262,7 @@ export class GdocBase extends BaseEntity implements OwidGdocBaseInterface {
// but we try (and then filter nulls) because we need featured images if we're using prominent links
// even if this method is being called on a GdocFaq (for example)
const featuredImages = Object.values(this.linkedDocuments)
.map((d) => getFeaturedImageFilename(d as OwidGdoc))
.map((d) => d["featured-image"])
.filter((filename?: string): filename is string => !!filename)

return [...this.filenames, ...featuredImages]
Expand Down Expand Up @@ -582,14 +582,17 @@ export class GdocBase extends BaseEntity implements OwidGdocBaseInterface {
}

async loadLinkedDocuments(): Promise<void> {
const linkedDocuments = await Promise.all(
this.linkedDocumentIds.map(async (target) => {
const linkedDocument = await GdocBase.findOneBy({
id: target,
const linkedDocuments: OwidGdocMinimalPostInterface[] =
await Promise.all(
this.linkedDocumentIds.map(async (target) => {
const linkedDocument = await GdocBase.findOneBy({
id: target,
})
return linkedDocument
})
return linkedDocument
})
).then(excludeNull)
)
.then(excludeNull)
.then((fullGdocs) => fullGdocs.map(fullGdocToMinimalGdoc))

this.linkedDocuments = keyBy(linkedDocuments, "id")
}
Expand Down
4 changes: 2 additions & 2 deletions db/model/Gdoc/GdocDataInsight.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import {
OwidGdocErrorMessageType,
OwidGdocDataInsightContent,
OwidGdocDataInsightInterface,
OwidGdocPostInterface,
MinimalDataInsightInterface,
OwidGdocType,
DATA_INSIGHTS_INDEX_PAGE_SIZE,
OwidGdocMinimalPostInterface,
} from "@ourworldindata/utils"
import { GdocBase } from "./GdocBase.js"
import { getConnection } from "../../../db/db.js"
Expand All @@ -27,7 +27,7 @@ export class GdocDataInsight
}
}

linkedDocuments: Record<string, OwidGdocPostInterface> = {}
linkedDocuments: Record<string, OwidGdocMinimalPostInterface> = {}
latestDataInsights: MinimalDataInsightInterface[] = []
// TODO: support query parameters in grapher urls so we can track country selections
_urlProperties: string[] = ["grapher-url"]
Expand Down
3 changes: 2 additions & 1 deletion db/model/Gdoc/GdocPost.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
OwidEnrichedGdocBlock,
RawBlockText,
RelatedChart,
OwidGdocMinimalPostInterface,
} from "@ourworldindata/utils"
import { GDOCS_DETAILS_ON_DEMAND_ID } from "../../../settings/serverSettings.js"
import {
Expand All @@ -35,7 +36,7 @@ export class GdocPost extends GdocBase implements OwidGdocPostInterface {
}
}

linkedDocuments: Record<string, OwidGdocPostInterface> = {}
linkedDocuments: Record<string, OwidGdocMinimalPostInterface> = {}
relatedCharts: RelatedChart[] = []
_filenameProperties = ["cover-image", "featured-image"]

Expand Down
21 changes: 21 additions & 0 deletions db/model/Gdoc/gdocUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@ import {
Span,
excludeNullish,
EnrichedBlockResearchAndWritingLink,
OwidGdocMinimalPostInterface,
OwidGdocType,
formatDate,
OwidGdocBaseInterface,
} from "@ourworldindata/utils"
import { match, P } from "ts-pattern"
import cheerio from "cheerio"
Expand Down Expand Up @@ -151,3 +155,20 @@ export function parseAuthors(authors?: string): string[] {
.split(",")
.map((author: string) => author.trim())
}

export function fullGdocToMinimalGdoc(
gdoc: OwidGdocBaseInterface
): OwidGdocMinimalPostInterface {
return {
id: gdoc.id,
title: gdoc.content.title || "",
slug: gdoc.slug,
authors: gdoc.content.authors,
publishedAt: gdoc.publishedAt ? formatDate(gdoc.publishedAt) : "",
published: gdoc.published,
subtitle: gdoc.content.subtitle || "",
excerpt: gdoc.content.excerpt || "",
type: gdoc.content.type || OwidGdocType.Article,
"featured-image": gdoc.content["featured-image"],
}
}
18 changes: 15 additions & 3 deletions packages/@ourworldindata/types/src/gdocTypes/Gdoc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export interface OwidGdocBaseInterface {
revisionId: string | null
publicationContext: OwidGdocPublicationContext
breadcrumbs?: BreadcrumbItem[] | null
linkedDocuments?: Record<string, OwidGdocBaseInterface>
linkedDocuments?: Record<string, OwidGdocMinimalPostInterface>
linkedCharts?: Record<string, LinkedChart>
imageMetadata?: Record<string, ImageMetadata>
relatedCharts?: RelatedChart[]
Expand All @@ -54,7 +54,20 @@ export interface OwidGdocBaseInterface {

export interface OwidGdocPostInterface extends OwidGdocBaseInterface {
content: OwidGdocPostContent
linkedDocuments?: Record<string, OwidGdocPostInterface>
}

// Used for linkedDocuments attachments, instead of attaching the entire gdoc model
export interface OwidGdocMinimalPostInterface {
id: string
title: string // used in prominent links, topic-page-intro related topics, etc
slug: string
authors: string[] // used in research & writing block
publishedAt: string // used in research & writing block
published: boolean // used in preview to validate whether or not the post will display
subtitle: string // used in prominent links & research & writing block
excerpt: string // used in prominent links
type: OwidGdocType // used in useLinkedDocument to prepend /data-insights/ to the slug
"featured-image"?: string // used in prominent links and research & writing block
}

export interface OwidGdocDataInsightContent {
Expand All @@ -70,7 +83,6 @@ export const DATA_INSIGHTS_INDEX_PAGE_SIZE = 20

export interface OwidGdocDataInsightInterface extends OwidGdocBaseInterface {
content: OwidGdocDataInsightContent
linkedDocuments?: Record<string, OwidGdocPostInterface>
latestDataInsights?: MinimalDataInsightInterface[]
tags?: Tag[]
}
Expand Down
1 change: 1 addition & 0 deletions packages/@ourworldindata/types/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ export {
type OwidGdocBaseInterface,
type OwidGdocPostContent,
type OwidGdocPostInterface,
type OwidGdocMinimalPostInterface,
type OwidGdocDataInsightContent,
type OwidGdocDataInsightInterface,
type MinimalDataInsightInterface,
Expand Down
7 changes: 5 additions & 2 deletions site/DataInsightsIndexPageContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import ReactDOM from "react-dom"
import {
ImageMetadata,
LinkedChart,
OwidGdocPostInterface,
OwidGdocMinimalPostInterface,
merge,
} from "@ourworldindata/utils"
import { DataInsightBody, indexToIdMap } from "./gdocs/pages/DataInsight.js"
Expand Down Expand Up @@ -93,7 +93,10 @@ export const DataInsightsIndexPageContent = (
{
imageMetadata: {} as Record<string, ImageMetadata>,
linkedCharts: {} as Record<string, LinkedChart>,
linkedDocuments: {} as Record<string, OwidGdocPostInterface>,
linkedDocuments: {} as Record<
string,
OwidGdocMinimalPostInterface
>,
}
)
return (
Expand Down
4 changes: 2 additions & 2 deletions site/gdocs/OwidGdoc.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ import React, { createContext } from "react"
import ReactDOM from "react-dom"
import {
LinkedChart,
OwidGdocPostInterface,
getOwidGdocFromJSON,
ImageMetadata,
RelatedChart,
get,
OwidGdocType,
OwidGdoc as OwidGdocInterface,
MinimalDataInsightInterface,
OwidGdocMinimalPostInterface,
} from "@ourworldindata/utils"
import { DebugProvider } from "./DebugContext.js"
import { match, P } from "ts-pattern"
Expand All @@ -19,7 +19,7 @@ import { Fragment } from "./pages/Fragment.js"

export const AttachmentsContext = createContext<{
linkedCharts: Record<string, LinkedChart>
linkedDocuments: Record<string, OwidGdocPostInterface>
linkedDocuments: Record<string, OwidGdocMinimalPostInterface>
imageMetadata: Record<string, ImageMetadata>
relatedCharts: RelatedChart[]
latestDataInsights?: MinimalDataInsightInterface[]
Expand Down
6 changes: 3 additions & 3 deletions site/gdocs/components/ProminentLink.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ export const ProminentLink = (props: {
let thumbnail: string | undefined = props.thumbnail
if (linkType === "gdoc") {
href = `/${linkedDocument?.slug}`
title = title ?? linkedDocument?.content.title
description = description ?? linkedDocument?.content.excerpt
thumbnail = thumbnail ?? linkedDocument?.content["featured-image"]
title = title ?? linkedDocument?.title
description = description ?? linkedDocument?.excerpt
thumbnail = thumbnail ?? linkedDocument?.["featured-image"]
} else if (linkType === "grapher" || linkType === "explorer") {
href = `${linkedChart?.resolvedUrl}`
title = title ?? linkedChart?.title
Expand Down
8 changes: 3 additions & 5 deletions site/gdocs/components/Recirc.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,12 @@ function RecircItem({ url }: { url: string }) {
return (
<aside className="recirc-article-container">
<h3 className="h3-bold">
<a href={`/${linkedDocument.slug}`}>
{linkedDocument.content.title}
</a>
<a href={`/${linkedDocument.slug}`}>{linkedDocument.title}</a>
</h3>
{linkedDocument.content.authors ? (
{linkedDocument.authors ? (
<div className="body-3-medium-italic">
{formatAuthors({
authors: linkedDocument.content.authors,
authors: linkedDocument.authors,
})}
</div>
) : null}
Expand Down
8 changes: 4 additions & 4 deletions site/gdocs/components/ResearchAndWriting.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@ function ResearchAndWritingLinkContainer(

if (linkedDocument) {
url = `/${linkedDocument.slug}`
title = linkedDocument.content.title || title
authors = linkedDocument.content.authors || authors
subtitle = linkedDocument.content.excerpt || subtitle
filename = linkedDocument.content["featured-image"] || filename
title = linkedDocument.title || title
authors = linkedDocument.authors || authors
subtitle = linkedDocument.excerpt || subtitle
filename = linkedDocument["featured-image"] || filename
}

const heading = React.createElement(
Expand Down
2 changes: 1 addition & 1 deletion site/gdocs/components/TopicPageIntro.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ function TopicPageRelatedTopic({
if (errorMessage && isPreviewing) {
return <li>{errorMessage}</li>
}
const topicText = linkedDocument?.content.title || text
const topicText = linkedDocument?.title || text
const topicUrl = linkedDocument?.slug ? `/${linkedDocument?.slug}` : url
return (
<li>
Expand Down
13 changes: 8 additions & 5 deletions site/gdocs/utils.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,13 @@ import { getLinkType, getUrlTarget } from "@ourworldindata/components"
import {
Span,
SpanLink,
OwidGdocPostInterface,
ImageMetadata,
LinkedChart,
Url,
OwidGdocPostContent,
formatAuthors,
OwidGdocMinimalPostInterface,
OwidGdocType,
} from "@ourworldindata/utils"
import { match } from "ts-pattern"
import { AttachmentsContext } from "./OwidGdoc.js"
Expand Down Expand Up @@ -45,10 +46,10 @@ export const breadcrumbColorForCoverColor = (

export const useLinkedDocument = (
url: string
): { linkedDocument?: OwidGdocPostInterface; errorMessage?: string } => {
): { linkedDocument?: OwidGdocMinimalPostInterface; errorMessage?: string } => {
const { linkedDocuments } = useContext(AttachmentsContext)
let errorMessage: string | undefined = undefined
let linkedDocument: OwidGdocPostInterface | undefined = undefined
let linkedDocument: OwidGdocMinimalPostInterface | undefined = undefined
const linkType = getLinkType(url)
if (linkType !== "gdoc") {
return { linkedDocument }
Expand All @@ -59,7 +60,7 @@ export const useLinkedDocument = (
const hash = urlObj.hash
const urlTarget = getUrlTarget(url)
linkedDocument = linkedDocuments?.[urlTarget] as
| OwidGdocPostInterface
| OwidGdocMinimalPostInterface
| undefined

if (!linkedDocument) {
Expand All @@ -68,10 +69,12 @@ export const useLinkedDocument = (
} else if (!linkedDocument.published) {
errorMessage = `Article with slug "${linkedDocument.slug}" isn't published.`
}
const subdirectory =
linkedDocument.type === OwidGdocType.DataInsight ? "data-insights/" : ""
return {
linkedDocument: {
...linkedDocument,
slug: `${linkedDocument.slug}${queryString}${hash}`,
slug: `${subdirectory}${linkedDocument.slug}${queryString}${hash}`,
},
errorMessage,
}
Expand Down

0 comments on commit 6233cc1

Please sign in to comment.