From 3a05c684443d43d0167d9a157c27352400de9924 Mon Sep 17 00:00:00 2001 From: Daniel Bachler Date: Wed, 6 Mar 2024 11:10:41 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=9A=A7=20remove=20typeorm=20annotations?= =?UTF-8?q?=20from=20GDocs=20classes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also remove the `GdocXImage` and `GdocXTag` classes and switches them to knex. Also introduces OwidGdocIndexItem which is a more lightweight representation of a Gdoc that is used in the overview page of the admin. --- .vscode/settings.json | 7 +- adminSiteClient/GdocsBreadcrumbsInput.tsx | 2 +- adminSiteClient/GdocsIndexPage.tsx | 36 +- adminSiteClient/GdocsStore.tsx | 21 +- adminSiteClient/PostsIndexPage.tsx | 7 +- adminSiteClient/TagsIndexPage.tsx | 7 +- adminSiteClient/gdocsDeploy.ts | 6 +- adminSiteServer/apiRouter.ts | 363 ++++++---- adminSiteServer/app.tsx | 33 +- adminSiteServer/authentication.tsx | 99 ++- adminSiteServer/mockSiteRouter.tsx | 117 +-- adminSiteServer/routerHelpers.tsx | 34 +- baker/DatapageHelpers.ts | 29 +- baker/GDriveImagesBaker.tsx | 15 +- baker/GrapherBaker.tsx | 25 +- baker/GrapherBakingUtils.ts | 4 +- baker/SiteBaker.tsx | 65 +- baker/algolia/indexChartsToAlgolia.ts | 5 +- baker/algolia/indexToAlgolia.tsx | 8 +- baker/countryProfiles.tsx | 8 +- baker/siteRenderers.tsx | 19 +- baker/sitemap.ts | 2 +- db/db.ts | 30 +- db/migrateWpPostsToArchieMl.ts | 2 + db/model/Chart.ts | 57 +- db/model/ChartRevision.ts | 46 +- db/model/Dataset.ts | 46 +- db/model/Gdoc/GdocAuthor.ts | 39 +- db/model/Gdoc/GdocBase.ts | 334 ++++----- db/model/Gdoc/GdocDataInsight.ts | 47 +- db/model/Gdoc/GdocFactory.ts | 670 ++++++++++++++---- db/model/Gdoc/GdocFaq.ts | 68 -- db/model/Gdoc/GdocHomepage.ts | 23 +- db/model/Gdoc/GdocPost.ts | 106 ++- db/model/Gdoc/gdocUtils.ts | 21 - db/model/GdocXImage.ts | 14 +- db/model/GdocXTag.ts | 14 +- db/model/Image.ts | 124 ++-- db/model/Link.ts | 114 ++- db/model/Post.ts | 170 +++-- db/model/User.ts | 45 +- db/tests/basic.test.ts | 26 +- devTools/markdownTest/markdown.ts | 3 +- .../types/src/dbTypes/Images.ts | 29 +- .../types/src/dbTypes/PostsGdocs.ts | 5 +- .../types/src/domainTypes/Tag.ts | 10 - .../types/src/gdocTypes/Gdoc.ts | 37 +- .../types/src/gdocTypes/Image.ts | 6 +- packages/@ourworldindata/types/src/index.ts | 11 +- site/gdocs/components/Image.tsx | 12 +- site/gdocs/pages/DataInsight.tsx | 6 +- 51 files changed, 1780 insertions(+), 1247 deletions(-) delete mode 100644 db/model/Gdoc/GdocFaq.ts delete mode 100644 packages/@ourworldindata/types/src/domainTypes/Tag.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index 05bdc24a80d..fcfae73aa0d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -20,5 +20,8 @@ "javascript.preferences.importModuleSpecifierEnding": "js", "[sql]": { "editor.defaultFormatter": "inferrinizzard.prettier-sql-vscode" - } -} \ No newline at end of file + }, + "Prettier-SQL.keywordCase": "upper", + "Prettier-SQL.SQLFlavourOverride": "mysql", + "Prettier-SQL.expressionWidth": 80 +} diff --git a/adminSiteClient/GdocsBreadcrumbsInput.tsx b/adminSiteClient/GdocsBreadcrumbsInput.tsx index 1e650b3f1fa..bed28d02554 100644 --- a/adminSiteClient/GdocsBreadcrumbsInput.tsx +++ b/adminSiteClient/GdocsBreadcrumbsInput.tsx @@ -86,7 +86,7 @@ export const GdocsBreadcrumbsInput = ({ breadcrumbs[breadcrumbs.length - 1].href = undefined } else breadcrumbs = undefined - setCurrentGdoc({ ...gdoc, breadcrumbs }) + setCurrentGdoc({ ...gdoc, breadcrumbs: breadcrumbs ?? null }) } const setItemAtIndex = (item: BreadcrumbItem, i: number) => { diff --git a/adminSiteClient/GdocsIndexPage.tsx b/adminSiteClient/GdocsIndexPage.tsx index 4770350830a..76176819997 100644 --- a/adminSiteClient/GdocsIndexPage.tsx +++ b/adminSiteClient/GdocsIndexPage.tsx @@ -16,14 +16,14 @@ import { } from "@fortawesome/free-solid-svg-icons" import { FontAwesomeIcon } from "@fortawesome/react-fontawesome/index.js" import { - Tag, + DbChartTagJoin, OwidGdocType, SearchWord, buildSearchWordsFromSearchString, filterFunctionForSearchWords, spansToUnformattedPlainText, - OwidGdoc, checkIsGdocPost, + OwidGdocIndexItem, } from "@ourworldindata/utils" import { Route, RouteComponentProps } from "react-router-dom" import { Link } from "./Link.js" @@ -139,11 +139,11 @@ export class GdocsIndexPage extends React.Component { } @computed - get tags(): Tag[] { + get tags(): DbChartTagJoin[] { return this.context?.availableTags || [] } - @computed get allGdocsToShow(): OwidGdoc[] { + @computed get allGdocsToShow(): OwidGdocIndexItem[] { const { searchWords, context } = this if (!context) return [] @@ -156,18 +156,18 @@ export class GdocsIndexPage extends React.Component { ? context.gdocs.filter( (gdoc) => // don't filter docs with no type set - !gdoc.content.type || !!this.filters[gdoc.content.type] + !gdoc.type || !!this.filters[gdoc.type] ) : context.gdocs if (searchWords.length > 0) { const filterFn = filterFunctionForSearchWords( searchWords, - (gdoc: OwidGdoc) => { + (gdoc: OwidGdocIndexItem) => { const properties = [ - gdoc.content.title, + gdoc.title, gdoc.slug, - gdoc.content.authors?.join(" "), + gdoc.authors?.join(" "), gdoc.tags?.map(({ name }) => name).join(" "), gdoc.id, ] @@ -232,17 +232,16 @@ export class GdocsIndexPage extends React.Component {
- {gdoc.content.type ? ( + {gdoc.type ? ( - {iconGdocTypeMap[gdoc.content.type]} + {iconGdocTypeMap[gdoc.type]} ) : null} { className="gdoc-index-item__title" title="Preview article" > - {gdoc.content.title || "Untitled"} + {gdoc.title || "Untitled"}

- {gdoc.content.authors?.join(", ")} + {gdoc.authors?.join(", ")}

- {gdoc.content.type && + {gdoc.type && ![ OwidGdocType.Fragment, OwidGdocType.AboutPage, - ].includes(gdoc.content.type) && + ].includes(gdoc.type) && gdoc.tags ? ( { : undefined } href={ - gdoc.content.type !== - OwidGdocType.Fragment + gdoc.type !== OwidGdocType.Fragment ? `${BAKED_BASE_URL}/${gdoc.slug}` : undefined } diff --git a/adminSiteClient/GdocsStore.tsx b/adminSiteClient/GdocsStore.tsx index 2e34c9eefb9..9f90ac04b54 100644 --- a/adminSiteClient/GdocsStore.tsx +++ b/adminSiteClient/GdocsStore.tsx @@ -3,11 +3,14 @@ import { action, observable } from "mobx" import { getOwidGdocFromJSON, OwidGdocJSON, - Tag, + DbChartTagJoin, OwidGdoc, + DbPlainTag, + OwidGdocIndexItem, } from "@ourworldindata/utils" import { AdminAppContext } from "./AdminAppContext.js" import { Admin } from "./Admin.js" +import { extractGdocIndexItem } from "@ourworldindata/types" /** * This was originally a MobX data domain store (see @@ -17,8 +20,8 @@ import { Admin } from "./Admin.js" * Today, this store acts as CRUD proxy for requests to API endpoints. */ export class GdocsStore { - @observable gdocs: OwidGdoc[] = [] - @observable availableTags: Tag[] = [] + @observable gdocs: OwidGdocIndexItem[] = [] + @observable availableTags: DbChartTagJoin[] = [] admin: Admin constructor(admin: Admin) { @@ -32,9 +35,13 @@ export class GdocsStore { @action async update(gdoc: OwidGdoc): Promise { - return this.admin + const item: OwidGdoc = await this.admin .requestJSON(`/api/gdocs/${gdoc.id}`, gdoc, "PUT") .then(getOwidGdocFromJSON) + const indexItem = extractGdocIndexItem(gdoc) + const gdocToUpdateIndex = this.gdocs.findIndex((g) => g.id === gdoc.id) + if (gdocToUpdateIndex >= 0) this.gdocs[gdocToUpdateIndex] = indexItem + return item } @action @@ -61,7 +68,9 @@ export class GdocsStore { @action async fetchGdocs() { - const gdocs = (await this.admin.getJSON("/api/gdocs")) as OwidGdoc[] + const gdocs = (await this.admin.getJSON( + "/api/gdocs" + )) as OwidGdocIndexItem[] this.gdocs = gdocs } @@ -72,7 +81,7 @@ export class GdocsStore { } @action - async updateTags(gdoc: OwidGdoc, tags: Tag[]) { + async updateTags(gdoc: OwidGdocIndexItem, tags: DbPlainTag[]) { const json = await this.admin.requestJSON( `/api/gdocs/${gdoc.id}/setTags`, { tagIds: tags.map((t) => t.id) }, diff --git a/adminSiteClient/PostsIndexPage.tsx b/adminSiteClient/PostsIndexPage.tsx index e15ae4f09cb..21bd2aacb7e 100644 --- a/adminSiteClient/PostsIndexPage.tsx +++ b/adminSiteClient/PostsIndexPage.tsx @@ -3,12 +3,11 @@ import { observer } from "mobx-react" import { observable, computed, action, runInAction } from "mobx" import { - DbChartTagJoin, - Tag, buildSearchWordsFromSearchString, filterFunctionForSearchWords, SearchWord, uniq, + DbChartTagJoin, } from "@ourworldindata/utils" import { AdminLayout } from "./AdminLayout.js" import { SearchField, FieldsRow, Timeago } from "./Forms.js" @@ -52,7 +51,7 @@ enum GdocStatus { interface PostRowProps { post: PostIndexMeta - availableTags: Tag[] + availableTags: DbChartTagJoin[] } @observer @@ -257,7 +256,7 @@ export class PostsIndexPage extends React.Component { @observable posts: PostIndexMeta[] = [] @observable maxVisibleRows = 50 @observable searchInput?: string - @observable availableTags: Tag[] = [] + @observable availableTags: DbChartTagJoin[] = [] @computed get searchWords(): SearchWord[] { const { searchInput } = this diff --git a/adminSiteClient/TagsIndexPage.tsx b/adminSiteClient/TagsIndexPage.tsx index e24a9dc3729..b5f8a0e42a7 100644 --- a/adminSiteClient/TagsIndexPage.tsx +++ b/adminSiteClient/TagsIndexPage.tsx @@ -5,7 +5,7 @@ import * as lodash from "lodash" import { Redirect } from "react-router-dom" import { AdminLayout } from "./AdminLayout.js" import { FieldsRow, Modal, TextField } from "./Forms.js" -import { Tag, DbChartTagJoin } from "@ourworldindata/utils" +import { DbChartTagJoin } from "@ourworldindata/utils" import { TagBadge } from "./TagBadge.js" import { AdminAppContext, AdminAppContextType } from "./AdminAppContext.js" @@ -166,7 +166,10 @@ export class TagsIndexPage extends React.Component {

)} {parent.children.map((tag) => ( - + ))}
)