forked from owid/owid-grapher
-
Notifications
You must be signed in to change notification settings - Fork 0
/
SourceEditPage.tsx
193 lines (177 loc) · 6.14 KB
/
SourceEditPage.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
import * as React from "react"
import { observer } from "mobx-react"
import { observable, computed, runInAction } from "mobx"
import { Prompt } from "react-router-dom"
import { format } from "timeago.js"
import { AdminAppContext, AdminAppContextType } from "./AdminAppContext"
import { AdminLayout } from "./AdminLayout"
import { BindString } from "./Forms"
import { VariableList, VariableListItem } from "./VariableList"
interface SourcePageData {
id: number
name: string
updatedAt: string
namespace: string
description: {
dataPublishedBy?: string
dataPublisherSource?: string
link?: string
retrievedDate?: string
additionalInfo?: string
}
variables: VariableListItem[]
}
class SourceEditable {
@observable name: string = ""
@observable description = {
dataPublishedBy: undefined,
dataPublisherSource: undefined,
link: undefined,
retrievedDate: undefined,
additionalInfo: undefined,
}
constructor(json: SourcePageData) {
for (const key in this) {
if (key === "description")
Object.assign(this.description, json.description)
else if (key in json) this[key] = (json as any)[key]
}
}
}
@observer
class SourceEditor extends React.Component<{ source: SourcePageData }> {
@observable newSource!: SourceEditable
@observable isDeleted: boolean = false
// Store the original source to determine when it is modified
UNSAFE_componentWillMount() {
this.UNSAFE_componentWillReceiveProps()
}
UNSAFE_componentWillReceiveProps() {
this.newSource = new SourceEditable(this.props.source)
this.isDeleted = false
}
@computed get isModified(): boolean {
return (
JSON.stringify(this.newSource) !==
JSON.stringify(new SourceEditable(this.props.source))
)
}
async save() {
const { source } = this.props
console.log(this.newSource)
const json = await this.context.admin.requestJSON(
`/api/sources/${source.id}`,
{ source: this.newSource },
"PUT"
)
if (json.success) {
Object.assign(this.props.source, this.newSource)
}
}
render() {
const { source } = this.props
const { newSource } = this
const isBulkImport = source.namespace !== "owid"
return (
<main className="SourceEditPage">
<Prompt
when={this.isModified}
message="Are you sure you want to leave? Unsaved changes will be lost."
/>
<section>
<h1>Source: {source.name}</h1>
<p>Last updated {format(source.updatedAt)}</p>
</section>
<section>
<form
onSubmit={(e) => {
e.preventDefault()
this.save()
}}
>
{isBulkImport && (
<p>
This source is associated with a bulk import, so
we can't change it manually.
</p>
)}
<BindString
field="name"
store={newSource}
label="Name"
disabled={true}
/>
<BindString
field="dataPublishedBy"
store={newSource.description}
label="Data published by"
disabled={true}
/>
<BindString
field="dataPublisherSource"
store={newSource.description}
label="Data publisher's source"
disabled={true}
/>
<BindString
field="link"
store={newSource.description}
label="Link"
disabled={true}
/>
<BindString
field="retrievedDate"
store={newSource.description}
label="Retrieved"
disabled={true}
/>
<BindString
field="additionalInfo"
store={newSource.description}
label="Additional information"
textarea
disabled={true}
/>
<input
type="submit"
className="btn btn-success"
value="Update source"
disabled={true}
/>
</form>
</section>
<section>
<h3>Variables</h3>
<VariableList variables={source.variables} />
</section>
</main>
)
}
}
@observer
export class SourceEditPage extends React.Component<{ sourceId: number }> {
static contextType = AdminAppContext
context!: AdminAppContextType
@observable source?: SourcePageData
render() {
return (
<AdminLayout title={this.source && this.source.name}>
{this.source && <SourceEditor source={this.source} />}
</AdminLayout>
)
}
async getData() {
const json = await this.context.admin.getJSON(
`/api/sources/${this.props.sourceId}.json`
)
runInAction(() => {
this.source = json.source as SourcePageData
})
}
componentDidMount() {
this.UNSAFE_componentWillReceiveProps()
}
UNSAFE_componentWillReceiveProps() {
this.getData()
}
}