forked from owid/owid-grapher
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathTagsIndexPage.tsx
197 lines (179 loc) · 6.3 KB
/
TagsIndexPage.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
194
195
196
197
import * as React from "react"
import { observer } from "mobx-react"
import { observable, computed, action, runInAction } from "mobx"
import * as lodash from "lodash"
import { Redirect } from "react-router-dom"
import { AdminLayout } from "./AdminLayout"
import { FieldsRow, Modal, TextField } from "./Forms"
import { TagBadge, Tag } from "./TagBadge"
import { AdminAppContext, AdminAppContextType } from "./AdminAppContext"
interface TagListItem {
id: number
name: string
parentId: number
specialType?: string
}
@observer
class AddTagModal extends React.Component<{
parentId?: number
onClose: () => void
}> {
static contextType = AdminAppContext
context!: AdminAppContextType
@observable tagName: string = ""
@observable newTagId?: number
@computed get tag() {
if (!this.tagName) return undefined
return {
parentId: this.props.parentId,
name: this.tagName,
}
}
async submit() {
if (this.tag) {
const resp = await this.context.admin.requestJSON(
"/api/tags/new",
{ tag: this.tag },
"POST"
)
if (resp.success) {
this.newTagId = resp.tagId
}
}
}
@action.bound onTagName(tagName: string) {
this.tagName = tagName
}
render() {
return (
<Modal onClose={this.props.onClose}>
<form
onSubmit={(e) => {
e.preventDefault()
this.submit()
}}
>
<div className="modal-header">
<h5 className="modal-title">Add category</h5>
</div>
<div className="modal-body">
<TextField
label="Category Name"
value={this.tagName}
onValue={this.onTagName}
autofocus
required
/>
</div>
<div className="modal-footer">
<input
type="submit"
className="btn btn-primary"
value="Add tag"
/>
</div>
</form>
{this.newTagId !== undefined && (
<Redirect to={`/tags/${this.newTagId}`} />
)}
</Modal>
)
}
}
@observer
export class TagsIndexPage extends React.Component {
static contextType = AdminAppContext
context!: AdminAppContextType
@observable tags: TagListItem[] = []
@observable isAddingTag: boolean = false
@observable addTagParentId?: number
@computed get categoriesById(): lodash.Dictionary<TagListItem> {
return lodash.keyBy(this.tags, (t) => t.id)
}
@computed get parentCategories(): {
id: number
name: string
specialType?: string
children: TagListItem[]
}[] {
const parentCategories = this.tags
.filter((c) => !c.parentId)
.map((c) => ({
id: c.id,
name: c.name,
specialType: c.specialType,
children: this.tags.filter((c2) => c2.parentId === c.id),
}))
return parentCategories
}
@action.bound onNewTag(parentId?: number) {
this.addTagParentId = parentId
this.isAddingTag = true
}
render() {
const { parentCategories } = this
return (
<AdminLayout title="Categories">
<main className="TagsIndexPage">
<FieldsRow>
<span>Showing {this.tags.length} tags</span>
</FieldsRow>
<p>
Tags are a way of organizing data. Each chart and
dataset can be assigned any number of tags. A tag may be
listed under another parent tag.
</p>
<div className="cardHolder">
<section>
<h4>Top-Level Categories</h4>
{parentCategories.map((parent) => (
<TagBadge key={parent.id} tag={parent as Tag} />
))}
<button
className="btn btn-default"
onClick={() => this.onNewTag()}
>
+ New Tag
</button>
</section>
{parentCategories.map((parent) => (
<section key={`${parent.id}-section`}>
<h4>{parent.name}</h4>
{parent.specialType === "systemParent" && (
<p>
These are special categories that are
assigned automatically.
</p>
)}
{parent.children.map((tag) => (
<TagBadge key={tag.id} tag={tag as Tag} />
))}
<button
className="btn btn-default"
onClick={() => this.onNewTag(parent.id)}
>
+ New Tag
</button>
</section>
))}
</div>
</main>
{this.isAddingTag && (
<AddTagModal
parentId={this.addTagParentId}
onClose={action(() => (this.isAddingTag = false))}
/>
)}
</AdminLayout>
)
}
async getData() {
const json = await this.context.admin.getJSON("/api/tags.json")
runInAction(() => {
this.tags = json.tags
})
}
componentDidMount() {
this.getData()
}
}