Skip to content

Commit

Permalink
feat(admin): ability to diff chart revisions
Browse files Browse the repository at this point in the history
  • Loading branch information
marcelgerber committed Apr 8, 2024
1 parent a49f0e0 commit dc69d8e
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 19 deletions.
3 changes: 2 additions & 1 deletion adminSiteClient/ChartEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
PostReference,
ChartRedirect,
DimensionProperty,
Json,
} from "@ourworldindata/utils"
import { computed, observable, runInAction, when } from "mobx"
import { BAKED_GRAPHER_URL } from "../settings/clientSettings.js"
Expand All @@ -39,7 +40,7 @@ export interface Dataset {
export interface Log {
userId: number
userName: string
config: string
config: Json
createdAt: string
}

Expand Down
80 changes: 64 additions & 16 deletions adminSiteClient/EditorHistoryTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,24 +2,21 @@ import React from "react"
import { observer } from "mobx-react"
import { ChartEditor, Log } from "./ChartEditor.js"
import { Section, Timeago } from "./Forms.js"
import { computed, action } from "mobx"
import { computed, action, observable } from "mobx"
import { copyToClipboard } from "@ourworldindata/utils"
import { dump } from "js-yaml"
import { notification } from "antd"
import { notification, Modal } from "antd"
import ReactDiffViewer, { DiffMethod } from "react-diff-viewer"

@observer
class LogRenderer extends React.Component<{
log: Log
previousLog: Log | undefined
applyConfig: (config: any) => void
}> {
@computed get prettyConfig() {
const { log } = this.props
return JSON.stringify(JSON.parse(log.config), undefined, 2)
}

@computed get title() {
const { log } = this.props
@observable isCompareModalOpen = false

titleForLog(log: Log) {
const user = log.userName || log.userId.toString()
return (
<>
Expand All @@ -28,19 +25,69 @@ class LogRenderer extends React.Component<{
)
}

@computed get title() {
return this.titleForLog(this.props.log)
}

@computed get compareModal() {
const { log, previousLog } = this.props

return (
<Modal
open={this.isCompareModalOpen}
centered
width="80vw"
onOk={() => (this.isCompareModalOpen = false)}
onCancel={() => (this.isCompareModalOpen = false)}
cancelButtonProps={{ style: { display: "none" } }}
>
<div style={{ overflowY: "auto", maxHeight: "50vh" }}>
<ReactDiffViewer
oldValue={JSON.stringify(log.config, null, 2)}
newValue={JSON.stringify(previousLog?.config, null, 2)}
leftTitle={
previousLog ? this.titleForLog(previousLog) : ""
}
rightTitle={this.title}
compareMethod={DiffMethod.WORDS}
styles={{
contentText: {
wordBreak: "break-word",
},
}}
/>
</div>
</Modal>
)
}

render() {
const { log } = this.props
const { title } = this

return (
<li className="list-group-item d-flex justify-content-between">
<li
className="list-group-item d-flex justify-content-between"
style={{ alignItems: "center" }}
>
{this.compareModal}
<span>{title}</span>
<button
className="align-self-end btn btn-danger"
onClick={() => this.props.applyConfig(log.config)}
>
Restore
</button>
<div className="d-flex" style={{ gap: 6 }}>
{!!this.props.previousLog && (
<button
className="btn btn-secondary"
onClick={() => (this.isCompareModalOpen = true)}
>
Compare <br /> to previous
</button>
)}
<button
className="btn btn-danger"
onClick={() => this.props.applyConfig(log.config)}
>
Restore
</button>
</div>
</li>
)
}
Expand Down Expand Up @@ -94,6 +141,7 @@ export class EditorHistoryTab extends React.Component<{ editor: ChartEditor }> {
<ul key={i} className="list-group">
<LogRenderer
log={log}
previousLog={this.logs[i + 1]} // Needed for comparison, might be undefined
applyConfig={this.applyConfig}
></LogRenderer>
</ul>
Expand Down
8 changes: 6 additions & 2 deletions adminSiteServer/apiRouter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ import {
TaggableType,
DbChartTagJoin,
pick,
Json,
} from "@ourworldindata/utils"
import {
DbPlainDatasetTag,
Expand Down Expand Up @@ -183,7 +184,7 @@ async function getLogsByChartId(
): Promise<
{
userId: number
config: string
config: Json
userName: string
createdAt: Date
}[]
Expand All @@ -203,7 +204,10 @@ async function getLogsByChartId(
LIMIT 50`,
[chartId]
)
return logs
return logs.map((log) => ({
...log,
config: JSON.parse(log.config),
}))
}

const getReferencesByChartId = async (
Expand Down

0 comments on commit dc69d8e

Please sign in to comment.