Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🚧 temporary christmas feature branch #4376

Draft
wants to merge 30 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
f45a4e9
chore: use node 22
marcelgerber Dec 22, 2024
fa3bde8
chore: update node version in dockerfiles & tests
marcelgerber Dec 22, 2024
e954517
chore: update node version to 22.13
marcelgerber Jan 8, 2025
afcddde
feat: pre-fetch chart views metadata in gdocs
marcelgerber Dec 11, 2024
c1067df
feat: NarrativeChart component
marcelgerber Dec 11, 2024
8f3e381
refactor: properly attach gdocs attachments
marcelgerber Dec 12, 2024
7b90855
enhance: ability to filter `chartViewMetadata`
marcelgerber Dec 12, 2024
8e45ff4
refactor: add narrative-chart to `extractGdocComponentInfo`
marcelgerber Dec 16, 2024
7b61123
refactor: chartViewMetadata -> narrativeViewInfo
marcelgerber Dec 17, 2024
eab3dac
enhance: narrative views are reflected as links in gdocs
marcelgerber Dec 17, 2024
8b1fa6e
refactor: filter down `narrativeViewsInfo`
marcelgerber Dec 17, 2024
3a7ceca
refactor: change `linkType` enum
marcelgerber Dec 17, 2024
02717ec
fix: fix error when publishing NarrativeChart with error
marcelgerber Dec 18, 2024
95b23b8
enhance: add narrative chart support to MultiEmbedder
marcelgerber Dec 18, 2024
cab124f
enhance: basic config to hide some grapher elements
marcelgerber Dec 18, 2024
cf94fed
fix: correctly generate narrative view query params
marcelgerber Dec 18, 2024
cc77847
refactor: use consistent names -- chart views & narrative charts
marcelgerber Dec 19, 2024
073fa23
feat: correctly generate query params for chart view
marcelgerber Dec 19, 2024
0823bfe
style: remove unused import
marcelgerber Dec 19, 2024
2ef0506
enhance: enable narrative charts on staging server
marcelgerber Dec 19, 2024
e272937
enhance: show static preview of chart view
marcelgerber Dec 19, 2024
4c6ed34
enhance: make "explore the data" button blue
marcelgerber Dec 19, 2024
a7d896e
feat: use nice modal for entering narrative chart name, gracefully ha…
marcelgerber Jan 9, 2025
b943f29
style: fix eslint warnings
marcelgerber Jan 9, 2025
d69d129
enhance(admin): don't show slug for narrative charts
marcelgerber Jan 9, 2025
436c2a9
🛠️ first round of apiRouter refactor
danyx23 Dec 18, 2024
51f6dfa
🔨 refactor request handler lambdas to named functions
danyx23 Dec 20, 2024
9fd9512
🔨 finish refactoring of api routes
danyx23 Dec 20, 2024
50fb028
🐝 fix unused imports
danyx23 Dec 20, 2024
ff2359c
🚧 Temporary optimistic merge of several features branches during the …
danyx23 Jan 9, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .devcontainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
ARG VARIANT=18
ARG VARIANT=22
FROM mcr.microsoft.com/vscode/devcontainers/javascript-node:dev-${VARIANT}

COPY .tmux.conf /home/node/.tmux.conf
Expand Down
2 changes: 1 addition & 1 deletion .nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
18.16.0
22.13.0
2 changes: 1 addition & 1 deletion adminSiteClient/AdminSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ export const AdminSidebar = (): React.ReactElement => (
{chartViewsFeatureEnabled && (
<li>
<Link to="/chartViews">
<FontAwesomeIcon icon={faPanorama} /> Narrative views
<FontAwesomeIcon icon={faPanorama} /> Narrative charts
</Link>
</li>
)}
Expand Down
26 changes: 9 additions & 17 deletions adminSiteClient/ChartEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import {
getParentVariableIdFromChartConfig,
mergeGrapherConfigs,
isEmpty,
slugify,
omit,
CHART_VIEW_PROPS_TO_OMIT,
} from "@ourworldindata/utils"
Expand Down Expand Up @@ -200,23 +199,13 @@ export class ChartEditor extends AbstractChartEditor<ChartEditorManager> {
)
}

async saveAsNarrativeView(): Promise<void> {
async saveAsChartView(
name: string
): Promise<{ success: boolean; errorMsg?: string }> {
const { patchConfig, grapher } = this

const chartJson = omit(patchConfig, CHART_VIEW_PROPS_TO_OMIT)

const suggestedName = grapher.title ? slugify(grapher.title) : undefined

const name = prompt(
"Please enter a programmatic name for the narrative view. Note that this name cannot be changed later.",
suggestedName
)

if (name === null) return

// Need to open intermediary tab before AJAX to avoid popup blockers
const w = window.open("/", "_blank") as Window

const body = {
name,
parentChartId: grapher.id,
Expand All @@ -228,11 +217,14 @@ export class ChartEditor extends AbstractChartEditor<ChartEditorManager> {
body,
"POST"
)

if (json.success)
w.location.assign(
if (json.success) {
window.open(
this.manager.admin.url(`chartViews/${json.chartViewId}/edit`)
)
return { success: true }
} else {
return { success: false, errorMsg: json.errorMsg }
}
}

publishGrapher(): void {
Expand Down
5 changes: 3 additions & 2 deletions adminSiteClient/ChartViewEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
References,
type EditorTab,
} from "./AbstractChartEditor.js"
import { ENV } from "../settings/clientSettings.js"
import { BAKED_BASE_URL, ENV } from "../settings/clientSettings.js"
import {
CHART_VIEW_PROPS_TO_OMIT,
CHART_VIEW_PROPS_TO_PERSIST,
Expand All @@ -16,7 +16,8 @@ import { diffGrapherConfigs, omit, pick } from "@ourworldindata/utils"
// Don't yet show chart views in the admin interface
// This is low-stakes - if it shows up anyhow (e.g. on staging servers), it's not a big deal.
// TODO: Remove this flag once we're launching this feature
export const chartViewsFeatureEnabled = ENV === "development"
export const chartViewsFeatureEnabled =
ENV === "development" || BAKED_BASE_URL.includes("narrative-")

export interface Chart {
id: number
Expand Down
6 changes: 3 additions & 3 deletions adminSiteClient/ChartViewIndexPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { AdminAppContext } from "./AdminAppContext.js"
import { Timeago } from "./Forms.js"
import { ColumnsType } from "antd/es/table/InternalTable.js"
import { ApiChartViewOverview } from "../adminShared/AdminTypes.js"
import { BAKED_GRAPHER_URL } from "../settings/clientSettings.js"
import { GRAPHER_DYNAMIC_THUMBNAIL_URL } from "../settings/clientSettings.js"
import { Link } from "./Link.js"
import {
buildSearchWordsFromSearchString,
Expand All @@ -28,7 +28,7 @@ function createColumns(
width: 200,
render: (chartConfigId) => (
<img
src={`${BAKED_GRAPHER_URL}/by-uuid/${chartConfigId}.svg`}
src={`${GRAPHER_DYNAMIC_THUMBNAIL_URL}/by-uuid/${chartConfigId}.svg`}
style={{ maxWidth: 200, maxHeight: 200 }}
/>
),
Expand Down Expand Up @@ -135,7 +135,7 @@ export function ChartViewIndexPage() {
}, [admin])

return (
<AdminLayout title="Narrative views">
<AdminLayout title="Narrative charts">
<main className="ChartViewIndexPage">
<Flex justify="space-between">
<Input
Expand Down
2 changes: 1 addition & 1 deletion adminSiteClient/EditorReferencesTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ export const ReferencesSection = (props: {

const chartViews = !!props.references?.chartViews?.length && (
<>
<p>Narrative views based on this chart</p>
<p>Narrative charts based on this chart</p>
<ul className="list-group">
{props.references.chartViews.map((chartView) => (
<li key={chartView.id} className="list-group-item">
Expand Down
33 changes: 20 additions & 13 deletions adminSiteClient/EditorTextTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
} from "./Forms.js"
import { AbstractChartEditor } from "./AbstractChartEditor.js"
import { ErrorMessages } from "./ChartEditorTypes.js"
import { isChartViewEditorInstance } from "./ChartViewEditor.js"

@observer
export class EditorTextTab<
Expand Down Expand Up @@ -74,6 +75,10 @@ export class EditorTextTab<
return this.props.errorMessages
}

@computed get showChartSlug() {
return !isChartViewEditorInstance(this.props.editor)
}

@computed get showAnyAnnotationFieldInTitleToggle() {
const { features } = this.props.editor
return (
Expand Down Expand Up @@ -139,19 +144,21 @@ export class EditorTextTab<
/>
)}
{this.showAnyAnnotationFieldInTitleToggle && <hr />}
<AutoTextField
label="/grapher"
value={grapher.displaySlug}
onValue={this.onSlug}
isAuto={grapher.slug === undefined}
onToggleAuto={() =>
(grapher.slug =
grapher.slug === undefined
? grapher.displaySlug
: undefined)
}
helpText="Human-friendly URL for this chart"
/>
{this.showChartSlug && (
<AutoTextField
label="/grapher"
value={grapher.displaySlug}
onValue={this.onSlug}
isAuto={grapher.slug === undefined}
onToggleAuto={() =>
(grapher.slug =
grapher.slug === undefined
? grapher.displaySlug
: undefined)
}
helpText="Human-friendly URL for this chart"
/>
)}
<BindAutoStringExt
label="Subtitle"
readFn={(grapher) => grapher.currentSubtitle}
Expand Down
64 changes: 64 additions & 0 deletions adminSiteClient/NarrativeChartNameModal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { useEffect, useMemo, useRef, useState } from "react"
import { Form, Input, InputRef, Modal, Spin } from "antd"

export const NarrativeChartNameModal = (props: {
initialName: string
open: "open" | "open-loading" | "closed"
errorMsg?: string
onSubmit: (name: string) => void
onCancel?: () => void
}) => {
const [name, setName] = useState<string>(props.initialName)
const inputField = useRef<InputRef>(null)
const isLoading = useMemo(() => props.open === "open-loading", [props.open])
const isOpen = useMemo(() => props.open !== "closed", [props.open])

useEffect(() => setName(props.initialName), [props.initialName])

useEffect(() => {
if (isOpen) {
inputField.current?.focus({ cursor: "all" })
}
}, [isOpen])

return (
<Modal
title="Save as narrative chart"
open={isOpen}
onOk={() => props.onSubmit(name)}
onCancel={props.onCancel}
onClose={props.onCancel}
okButtonProps={{ disabled: !name || isLoading }}
cancelButtonProps={{ disabled: isLoading }}
>
<div>
<p>
This will create a new narrative chart that is linked to
this chart. Any currently pending changes will be applied to
the narrative chart.
</p>
<p>
Please enter a programmatic name for the narrative chart.{" "}
<i>Note that this name cannot be changed later.</i>
</p>
<Form.Item label="Name">
<Input
ref={inputField}
onChange={(e) => setName(e.target.value)}
value={name}
disabled={isLoading}
/>
</Form.Item>
{isLoading && <Spin />}
{props.errorMsg && (
<div
className="alert alert-danger"
style={{ whiteSpace: "pre-wrap" }}
>
{props.errorMsg}
</div>
)}
</div>
</Modal>
)
}
65 changes: 50 additions & 15 deletions adminSiteClient/SaveButtons.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Component } from "react"
import { ChartEditor, isChartEditorInstance } from "./ChartEditor.js"
import { action, computed } from "mobx"
import { action, computed, observable } from "mobx"
import { observer } from "mobx-react"
import { excludeUndefined, omit } from "@ourworldindata/utils"
import { excludeUndefined, omit, slugify } from "@ourworldindata/utils"
import {
IndicatorChartEditor,
isIndicatorChartEditorInstance,
Expand All @@ -17,6 +17,7 @@ import {
chartViewsFeatureEnabled,
isChartViewEditorInstance,
} from "./ChartViewEditor.js"
import { NarrativeChartNameModal } from "./NarrativeChartNameModal.js"

@observer
export class SaveButtons<Editor extends AbstractChartEditor> extends Component<{
Expand Down Expand Up @@ -61,10 +62,6 @@ class SaveButtonsForChart extends Component<{
void this.props.editor.saveAsNewGrapher()
}

@action.bound onSaveAsNarrativeView() {
void this.props.editor.saveAsNarrativeView()
}

@action.bound onPublishToggle() {
if (this.props.editor.grapher.isPublished)
this.props.editor.unpublishGrapher()
Expand All @@ -79,6 +76,29 @@ class SaveButtonsForChart extends Component<{
])
}

@computed get initialNarrativeChartName(): string {
return slugify(this.props.editor.grapher.title ?? "")
}

@observable narrativeChartNameModalOpen:
| "open"
| "open-loading"
| "closed" = "closed"
@observable narrativeChartNameModalError: string | undefined = undefined

@action.bound async onSubmitNarrativeChartButton(name: string) {
const { editor } = this.props

this.narrativeChartNameModalOpen = "open-loading"
const res = await editor.saveAsChartView(name)
if (res.success) {
this.narrativeChartNameModalOpen = "closed"
} else {
this.narrativeChartNameModalOpen = "open"
this.narrativeChartNameModalError = res.errorMsg
}
}

render() {
const { editingErrors } = this
const { editor } = this.props
Expand Down Expand Up @@ -117,15 +137,30 @@ class SaveButtonsForChart extends Component<{
</button>
</div>
{chartViewsFeatureEnabled && (
<div className="mt-2">
<button
className="btn btn-primary"
onClick={this.onSaveAsNarrativeView}
disabled={isSavingDisabled}
>
Save as narrative view
</button>
</div>
<>
<div className="mt-2">
<button
className="btn btn-primary"
onClick={() => {
this.narrativeChartNameModalOpen = "open"
this.narrativeChartNameModalError =
undefined
}}
disabled={isSavingDisabled}
>
Save as narrative chart
</button>
</div>
<NarrativeChartNameModal
open={this.narrativeChartNameModalOpen}
initialName={this.initialNarrativeChartName}
errorMsg={this.narrativeChartNameModalError}
onSubmit={this.onSubmitNarrativeChartButton}
onCancel={() =>
(this.narrativeChartNameModalOpen = "closed")
}
/>
</>
)}
{editingErrors.map((error, i) => (
<div key={i} className="alert alert-danger mt-2">
Expand Down
Loading
Loading