Skip to content

Commit

Permalink
Merge branch 'master' into deprecated-articles
Browse files Browse the repository at this point in the history
  • Loading branch information
rakyi committed Sep 5, 2024
2 parents 5188a41 + 0a61d87 commit 0e544ca
Show file tree
Hide file tree
Showing 98 changed files with 6,102 additions and 1,991 deletions.
54 changes: 54 additions & 0 deletions .github/workflows/check-default-grapher-config.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
name: Check default grapher config
on:
push:
branches:
- "**"
- "!master"
paths:
- "packages/@ourworldindata/grapher/src/schema/**"

jobs:
commit-default-config:
runs-on: ubuntu-latest

steps:
- name: Clone repository
uses: actions/checkout@v4
with:
ref: ${{ github.head_ref }}

- uses: ./.github/actions/setup-node-yarn-deps
- uses: ./.github/actions/build-tsc

- uses: hustcer/setup-nu@v3
with:
version: "0.80" # Don't use 0.80 here, as it was a float number and will be convert to 0.8, you can use v0.80/0.80.0 or '0.80'

# Turn all yaml files in the schema directory into json (should only be one)
- name: Convert yaml schema to json
run: |
(ls packages/@ourworldindata/grapher/src/schema/*.yaml
| each {|yaml|
open $yaml.name
| to json
| save -f ($yaml.name
| path parse
| upsert extension "json"
| path join) })
shell: nu {0}

# Construct default config objects for all grapher schemas in the schema directory (should only be one)
- name: Generate default grapher config
run: |
(ls packages/@ourworldindata/grapher/src/schema/grapher-schema.*.json
| each {|json|
node itsJustJavascript/devTools/schema/generate-default-object-from-schema.js $json.name --save-ts packages/@ourworldindata/grapher/src/schema/defaultGrapherConfig.ts })
shell: nu {0}

- name: Run prettier
run: yarn fixPrettierAll

- uses: stefanzweifel/git-auto-commit-action@v5
with:
commit_message: "🤖 update default grapher config"
file_pattern: "packages/@ourworldindata/grapher/src/schema/defaultGrapherConfig.ts"
148 changes: 148 additions & 0 deletions adminSiteClient/AbstractChartEditor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
import {
isEqual,
omit,
GrapherInterface,
diffGrapherConfigs,
mergeGrapherConfigs,
} from "@ourworldindata/utils"
import { action, computed, observable, when } from "mobx"
import { EditorFeatures } from "./EditorFeatures.js"
import { Admin } from "./Admin.js"
import { defaultGrapherConfig, Grapher } from "@ourworldindata/grapher"

export type EditorTab =
| "basic"
| "data"
| "text"
| "customize"
| "map"
| "scatter"
| "marimekko"
| "revisions"
| "refs"
| "export"
| "inheritance"
| "debug"

export interface AbstractChartEditorManager {
admin: Admin
patchConfig: GrapherInterface
parentConfig?: GrapherInterface
isInheritanceEnabled?: boolean
}

export abstract class AbstractChartEditor<
Manager extends AbstractChartEditorManager = AbstractChartEditorManager,
> {
manager: Manager

@observable.ref grapher = new Grapher()
@observable.ref currentRequest: Promise<any> | undefined // Whether the current chart state is saved or not
@observable.ref tab: EditorTab = "basic"
@observable.ref errorMessage?: { title: string; content: string }
@observable.ref previewMode: "mobile" | "desktop"
@observable.ref showStaticPreview = false
@observable.ref savedPatchConfig: GrapherInterface = {}

// parent config derived from the current chart config
@observable.ref parentConfig: GrapherInterface | undefined = undefined
// if inheritance is enabled, the parent config is applied to grapher
@observable.ref isInheritanceEnabled: boolean | undefined = undefined

constructor(props: { manager: Manager }) {
this.manager = props.manager
this.previewMode =
localStorage.getItem("editorPreviewMode") === "mobile"
? "mobile"
: "desktop"

when(
() => this.manager.parentConfig !== undefined,
() => (this.parentConfig = this.manager.parentConfig)
)

when(
() => this.manager.isInheritanceEnabled !== undefined,
() =>
(this.isInheritanceEnabled = this.manager.isInheritanceEnabled)
)

when(
() => this.grapher.hasData && this.grapher.isReady,
() => (this.savedPatchConfig = this.patchConfig)
)
}

/** original grapher config used to init the grapher instance */
@computed get originalGrapherConfig(): GrapherInterface {
const { patchConfig, parentConfig, isInheritanceEnabled } = this.manager
if (!isInheritanceEnabled) return patchConfig
return mergeGrapherConfigs(parentConfig ?? {}, patchConfig)
}

/** live-updating full config */
@computed get fullConfig(): GrapherInterface {
return mergeGrapherConfigs(defaultGrapherConfig, this.grapher.object)
}

/** parent config currently applied to grapher */
@computed get activeParentConfig(): GrapherInterface | undefined {
return this.isInheritanceEnabled ? this.parentConfig : undefined
}

@computed get activeParentConfigWithDefaults():
| GrapherInterface
| undefined {
if (!this.activeParentConfig) return undefined
return mergeGrapherConfigs(
defaultGrapherConfig,
this.activeParentConfig
)
}

/** patch config of the chart that is written to the db on save */
@computed get patchConfig(): GrapherInterface {
return diffGrapherConfigs(
this.fullConfig,
this.activeParentConfigWithDefaults ?? defaultGrapherConfig
)
}

@computed get isModified(): boolean {
return !isEqual(
omit(this.patchConfig, "version"),
omit(this.savedPatchConfig, "version")
)
}

@computed get features(): EditorFeatures {
return new EditorFeatures(this)
}

@action.bound updateLiveGrapher(config: GrapherInterface): void {
this.grapher.reset()
this.grapher.updateFromObject(config)
this.grapher.updateAuthoredVersion(config)
}

// only works for top-level properties
isPropertyInherited(property: keyof GrapherInterface): boolean {
if (!this.isInheritanceEnabled || !this.activeParentConfigWithDefaults)
return false
return (
!Object.hasOwn(this.patchConfig, property) &&
Object.hasOwn(this.activeParentConfigWithDefaults, property)
)
}

// only works for top-level properties
couldPropertyBeInherited(property: keyof GrapherInterface): boolean {
if (!this.isInheritanceEnabled || !this.activeParentConfig) return false
return Object.hasOwn(this.activeParentConfig, property)
}

abstract get isNewGrapher(): boolean
abstract get availableTabs(): EditorTab[]

abstract saveGrapher(props?: { onError?: () => void }): Promise<void>
}
12 changes: 12 additions & 0 deletions adminSiteClient/AdminApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import { BulkGrapherConfigEditorPage } from "./BulkGrapherConfigEditor.js"
import { GdocsIndexPage, GdocsMatchProps } from "./GdocsIndexPage.js"
import { GdocsPreviewPage } from "./GdocsPreviewPage.js"
import { GdocsStoreProvider } from "./GdocsStore.js"
import { IndicatorChartEditorPage } from "./IndicatorChartEditorPage.js"

@observer
class AdminErrorMessage extends React.Component<{ admin: Admin }> {
Expand Down Expand Up @@ -200,6 +201,17 @@ export class AdminApp extends React.Component<{
path="/users"
component={UsersIndexPage}
/>
<Route
exact
path="/variables/:variableId/config"
render={({ match }) => (
<IndicatorChartEditorPage
variableId={parseInt(
match.params.variableId
)}
/>
)}
/>
<Route
exact
path="/variables/:variableId"
Expand Down
Loading

0 comments on commit 0e544ca

Please sign in to comment.