Skip to content

Commit

Permalink
✨ render DIs in search results
Browse files Browse the repository at this point in the history
  • Loading branch information
ikesau authored and mlbrgl committed Mar 7, 2025
1 parent 8a3e5f0 commit a5aaf51
Show file tree
Hide file tree
Showing 5 changed files with 84 additions and 60 deletions.
62 changes: 26 additions & 36 deletions baker/algolia/utils/pages.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ import { getAlgoliaClient } from "../configureAlgolia.js"
import { htmlToText } from "html-to-text"
import {
PageRecord,
PageType,
SearchIndexName,
WordpressPageType,
} from "../../../site/search/searchTypes.js"
import { getAnalyticsPageviewsByUrlObj } from "../../../db/model/Pageview.js"
import { ArticleBlocks } from "../../../site/gdocs/components/ArticleBlocks.js"
Expand All @@ -40,7 +42,6 @@ import { SearchIndex } from "algoliasearch"
import { match, P } from "ts-pattern"
import { gdocFromJSON } from "../../../db/model/Gdoc/GdocFactory.js"
import { formatUrls } from "../../../site/formatting.js"
import { TypeAndImportance } from "./types.js"
import {
BAKED_BASE_URL,
CLOUDFLARE_IMAGES_URL,
Expand All @@ -59,13 +60,10 @@ function generateCountryRecords(
pageviews: Record<string, RawPageview>
): PageRecord[] {
return countries.map((country) => {
const postTypeAndImportance: TypeAndImportance = {
type: "country",
importance: -1,
}
const record = {
objectID: country.slug,
...postTypeAndImportance,
type: WordpressPageType.Country,
importance: -1,
slug: `country/${country.slug}`,
title: country.name,
content: `All available indicators for ${country.name}.`,
Expand Down Expand Up @@ -108,15 +106,20 @@ async function generateWordpressRecords(
const getPostTypeAndImportance = (
post: FormattedPost,
tags: Pick<DbPlainTag, "name">[]
): TypeAndImportance => {
): {
type: PageType
importance: number
} => {
if (post.slug.startsWith("about/") || post.slug === "about")
return { type: "about", importance: 1 }
if (post.slug.match(/\bfaqs?\b/i)) return { type: "faq", importance: 1 }
if (post.type === "post") return { type: "article", importance: 0 }
return { type: OwidGdocType.AboutPage, importance: 1 }
if (post.slug.match(/\bfaqs?\b/i))
return { type: WordpressPageType.Other, importance: 1 }
if (post.type === "post")
return { type: OwidGdocType.Article, importance: 0 }
if (tags.some((t) => t.name === "Entries"))
return { type: "topic", importance: 3 }
return { type: OwidGdocType.TopicPage, importance: 3 }

return { type: "other", importance: 0 }
return { type: WordpressPageType.Other, importance: 0 }
}

const records: PageRecord[] = []
Expand Down Expand Up @@ -214,33 +217,20 @@ function generateGdocRecords(
pageviews: Record<string, RawPageview>,
cloudflareImagesByFilename: Record<string, DbEnrichedImage>
): PageRecord[] {
const getPostTypeAndImportance = (
const getPostImportance = (
gdoc: OwidGdocPostInterface | OwidGdocDataInsightInterface
): TypeAndImportance => {
): number => {
return match(gdoc.content.type)
.with(OwidGdocType.Article, () => ({
type: "article" as const,
importance: "deprecation-notice" in gdoc.content ? -0.5 : 0,
}))
.with(OwidGdocType.AboutPage, () => ({
type: "about" as const,
importance: 1,
}))
.with(OwidGdocType.Article, () =>
"deprecation-notice" in gdoc.content ? -0.5 : 0
)
.with(OwidGdocType.AboutPage, () => 1)
.with(
P.union(OwidGdocType.TopicPage, OwidGdocType.LinearTopicPage),
() => ({
type: "topic" as const,
importance: 3,
})
() => 3
)
.with(P.union(OwidGdocType.Fragment, undefined), () => ({
type: "other" as const,
importance: 0,
}))
.with(OwidGdocType.DataInsight, () => ({
type: "data-insight" as const,
importance: 0,
}))
.with(P.union(OwidGdocType.Fragment, undefined), () => 0)
.with(OwidGdocType.DataInsight, () => 0)
.exhaustive()
}

Expand All @@ -258,15 +248,15 @@ function generateGdocRecords(
)
)
const chunks = generateChunksFromHtmlText(renderedPostContent)
const postTypeAndImportance = getPostTypeAndImportance(gdoc)
let i = 0

const thumbnailUrl = getThumbnailUrl(gdoc, cloudflareImagesByFilename)

for (const chunk of chunks) {
const record = {
objectID: `${gdoc.id}-c${i}`,
...postTypeAndImportance,
importance: getPostImportance(gdoc),
type: gdoc.content.type as PageType,
slug: gdoc.slug,
title: gdoc.content.title || "",
content: chunk,
Expand Down
8 changes: 1 addition & 7 deletions baker/algolia/utils/types.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
import { DbEnrichedVariable } from "@ourworldindata/types"
import { ChartRecord, PageType } from "../../../site/search/searchTypes.js"

/** Pages */
export interface TypeAndImportance {
type: PageType
importance: number
}
import { ChartRecord } from "../../../site/search/searchTypes.js"

/** Charts */
export interface RawChartRecordRow {
Expand Down
4 changes: 4 additions & 0 deletions site/search/Search.scss
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,10 @@ $reset-button-margin: 16px;
display: flex;
}

.search-results__page-hit-dateline {
@include h5-black-caps;
}

.search-results__page-hit-img-container {
margin-right: 16px;
@include sm-only {
Expand Down
30 changes: 28 additions & 2 deletions site/search/SearchPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
groupBy,
uniqBy,
Region,
OwidGdocType,
} from "@ourworldindata/utils"
import {
InstantSearch,
Expand Down Expand Up @@ -41,6 +42,7 @@ import {
pageTypeDisplayNames,
IExplorerViewHit,
PageRecord,
checkIsWordpressPageType,
} from "./searchTypes.js"
import { EXPLORERS_ROUTE_FOLDER } from "@ourworldindata/explorer"
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome/index.js"
Expand All @@ -58,15 +60,38 @@ import {
getEntityQueryStr,
} from "./SearchUtils.js"
import { ChartHit } from "./ChartHit.js"
import DataInsightDateline from "../gdocs/components/DataInsightDateline.js"
import { getCanonicalUrl } from "@ourworldindata/components"

const siteAnalytics = new SiteAnalytics()

// The rule doesn't support class components in the same file.
// eslint-disable-next-line react-refresh/only-export-components
function PagesHit({ hit }: { hit: IPageHit }) {
const dateline =
hit.type === OwidGdocType.DataInsight && hit.date ? (
<DataInsightDateline
className="search-results__page-hit-dateline"
publishedAt={new Date(hit.date)}
formatOptions={{
year: "numeric",
month: "long",
day: "2-digit",
}}
/>
) : null

const href = checkIsWordpressPageType(hit.type)
? `/${hit.slug}`
: getCanonicalUrl("", {
slug: hit.slug,
content: {
type: hit.type,
},
})
return (
<a
href={`${BAKED_BASE_URL}/${hit.slug}`}
href={href}
data-algolia-index={getIndexName(SearchIndexName.Pages)}
data-algolia-object-id={hit.objectID}
data-algolia-position={hit.__position}
Expand All @@ -83,6 +108,7 @@ function PagesHit({ hit }: { hit: IPageHit }) {
)}
<div className="search-results__page-hit-text-container">
<header className="page-hit__header">
{dateline}
<h4 className="h3-bold search-results__page-hit-title">
{hit.title}
</h4>
Expand All @@ -92,7 +118,7 @@ function PagesHit({ hit }: { hit: IPageHit }) {
</header>
<Snippet
className="body-3-medium search-results__page-hit-snippet"
attribute="excerpt"
attribute="content"
highlightedTagName="strong"
hit={hit}
/>
Expand Down
40 changes: 25 additions & 15 deletions site/search/searchTypes.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,32 @@
import { OwidGdocType } from "@ourworldindata/types"
import { BaseHit, Hit } from "instantsearch.js/es/types/results.js"

export type PageType =
| "about"
| "topic"
| "country"
| "faq"
| "article"
| "other"
| "data-insight"
export enum WordpressPageType {
Other = "other",
Country = "country",
}

export function checkIsWordpressPageType(
type: string
): type is WordpressPageType {
return (
type === WordpressPageType.Country || type === WordpressPageType.Other
)
}

export type PageType = OwidGdocType | WordpressPageType

export const pageTypeDisplayNames: Record<PageType, string> = {
about: "About",
topic: "Topic",
country: "Country",
faq: "FAQ",
article: "Article",
"data-insight": "Data Insight",
other: "Topic", // this is a band-aid to avoid showing "Other" for items that we now largely consider to be "Topics". Caveat: some non-topic pages are still indexed as "other" (e.g. /jobs). See https://owid.slack.com/archives/C04N12KT6GY/p1693580177430049?thread_ts=1693336759.239919&cid=C04N12KT6GY
[OwidGdocType.AboutPage]: "About",
[OwidGdocType.Article]: "Article",
[OwidGdocType.DataInsight]: "Data Insight",
[OwidGdocType.LinearTopicPage]: "Topic",
[OwidGdocType.TopicPage]: "Topic",
[WordpressPageType.Country]: "Country",
[WordpressPageType.Other]: "",
[OwidGdocType.Author]: "", // Should never be indexed
[OwidGdocType.Fragment]: "", // Should never be indexed
[OwidGdocType.Homepage]: "", // Should never be indexed
}

export interface PageRecord {
Expand Down

0 comments on commit a5aaf51

Please sign in to comment.