-
Notifications
You must be signed in to change notification settings - Fork 206
/
Copy pathLangList.js
127 lines (120 loc) · 3.44 KB
/
LangList.js
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
import React, { useEffect, useState, useMemo } from 'react'
import { css } from 'glamor'
import sortBy from 'lodash/sortBy'
import fromPairs from 'lodash/fromPairs'
import graphql from '@octokit/graphql'
import LangProgress from './LangCard'
import SortSelector from './SortSelector'
function getLangProgress(lang, issue) {
const { body, createdAt, lastEditedAt = createdAt, ...issueProps } = issue
let coreCompletion = 0;
let otherCompletion = 0;
body.split(/^##\s+/gm).forEach(section => {
const [heading, ...content] = section.split('\n')
const items = content.filter(line => {
return /[-*] *\[[ x]\]/.test(line)
})
const finishedItems = items.filter(line => /[-*] \[x\]/.test(line));
if (/MAIN_CONTENT/.test(heading)) {
coreCompletion = finishedItems.length / items.length;
} else if (/SECONDARY_CONTENT/.test(heading)) {
otherCompletion = finishedItems.length / items.length;
}
});
return {
...lang,
...issueProps,
createdAt,
lastEditedAt,
coreCompletion,
otherCompletion,
}
}
async function getProgressList(langs) {
// TODO this search requires looking for issues with the string "Translation Progress"
// in the title. Maybe we should replace it with something more robust.
const { search } = await graphql(
`
query($limit: Int!) {
search(
type: ISSUE
query: "org:reactjs Translation Progress in:title is:open"
first: $limit
) {
nodes {
... on Issue {
title
body
createdAt
lastEditedAt
number
repository {
name
}
}
}
}
}
`,
{
headers: {
authorization: `token ${process.env.REACT_APP_GITHUB_AUTH_TOKEN}`,
},
limit: langs.length + 15, // padding in case of extra issues
},
)
console.log(search.nodes)
const issuesMap = fromPairs(
search.nodes
.filter(issue => !!issue && issue.repository)
.map(issue => [issue.repository.name.toLowerCase(), issue]),
)
return langs.map(lang => {
const issue = issuesMap[`${lang.code.toLowerCase()}.react.dev`]
return issue ? getLangProgress(lang, issue) : null
}).filter(Boolean)
}
const sortOptions = [
{ key: 'code', label: 'Lang Code' },
{ key: 'enName', label: 'English Name' },
{ key: ['coreCompletion', 'otherCompletion'], label: 'Completion' },
{ key: 'createdAt', label: 'Start Date' },
{ key: 'lastEditedAt', label: 'Last Updated' },
]
export default function LangList({ langs }) {
const [progressList, setProgressList] = useState(langs)
const [sortKey, setSortKey] = useState('code')
useEffect(() => {
getProgressList(langs).then(setProgressList)
}, [langs])
const style = css({
width: '100%',
display: 'flex',
flexWrap: 'wrap',
justifyContent: 'center',
})
const sortedList = useMemo(() => {
const sorted = sortBy(progressList, sortKey)
if (
(Array.isArray(sortKey) && sortKey.includes('coreCompletion')) ||
sortKey === 'lastEditedAt'
) {
sorted.reverse()
}
return sorted
}, [progressList, sortKey])
return (
<div>
<SortSelector
options={sortOptions}
value={sortKey}
onSelect={setSortKey}
/>
<div {...style}>
{sortedList.map(lang => (
<LangProgress key={lang.code} {...lang} />
))}
</div>
</div>
)
}