|
1 | | -import React from 'react'; |
| 1 | +import React, { useState, useEffect } from 'react'; |
2 | 2 | import CrossIcon from 'react-icons/lib/md/clear'; |
3 | 3 | import RefreshIcon from 'react-icons/lib/md/refresh'; |
4 | 4 | import ArrowDropDown from 'react-icons/lib/md/keyboard-arrow-down'; |
@@ -30,210 +30,192 @@ interface Props { |
30 | 30 | onRefresh: (dep: string, version?: string) => void; |
31 | 31 | } |
32 | 32 |
|
33 | | -interface State { |
34 | | - version: null | string; |
35 | | - open: boolean; |
36 | | - versions: string[]; |
37 | | -} |
| 33 | +const client = algoliasearch('OFCNCOG2CU', '00383ecd8441ead30b1b0ff981c426f5'); |
| 34 | +const index = client.initIndex('npm-search'); |
38 | 35 |
|
39 | | -export class Dependency extends React.PureComponent<Props, State> { |
40 | | - state: State = { |
41 | | - version: null, |
42 | | - open: false, |
43 | | - versions: [], |
44 | | - }; |
| 36 | +export const Dependency = ({ |
| 37 | + dependencies, |
| 38 | + dependency, |
| 39 | + onRemove, |
| 40 | + onRefresh, |
| 41 | +}: Props) => { |
| 42 | + const [version, setVersion] = useState(null); |
| 43 | + const [open, setOpen] = useState(false); |
| 44 | + const [versions, setVersions] = useState([]); |
45 | 45 |
|
46 | | - setVersionsForLatestPkg(pkg: string) { |
47 | | - const that = this; |
| 46 | + const setVersionsForLatestPkg = (pkg: string) => { |
48 | 47 | fetch(`/api/v1/dependencies/${pkg}`) |
49 | 48 | .then(response => response.json()) |
50 | | - .then(data => that.setState({ version: data.data.version })) |
| 49 | + .then(data => setVersion(data.data.version)) |
51 | 50 | .catch(err => { |
52 | 51 | if (process.env.NODE_ENV === 'development') { |
53 | 52 | console.error(err); // eslint-disable-line no-console |
54 | 53 | } |
55 | 54 | }); |
56 | | - } |
57 | | - |
58 | | - UNSAFE_componentWillMount() { |
59 | | - const { dependencies, dependency } = this.props; |
60 | | - const client = algoliasearch( |
61 | | - 'OFCNCOG2CU', |
62 | | - '00383ecd8441ead30b1b0ff981c426f5' |
63 | | - ); |
64 | | - const index = client.initIndex('npm-search'); |
| 55 | + }; |
65 | 56 |
|
| 57 | + useEffect(() => { |
66 | 58 | // @ts-ignore |
67 | 59 | index.getObject(dependency, ['versions']).then(({ versions: results }) => { |
68 | | - const versions = Object.keys(results).sort((a, b) => { |
| 60 | + const orderedVersions = Object.keys(results).sort((a, b) => { |
69 | 61 | try { |
70 | 62 | return compareVersions(b, a); |
71 | 63 | } catch (e) { |
72 | 64 | return 0; |
73 | 65 | } |
74 | 66 | }); |
75 | | - this.setState({ |
76 | | - versions, |
77 | | - }); |
| 67 | + setVersions(orderedVersions); |
78 | 68 | }); |
79 | 69 |
|
80 | 70 | try { |
81 | 71 | const versionRegex = /^\d{1,3}\.\d{1,3}.\d{1,3}$/; |
82 | | - const version = dependencies[dependency]; |
83 | | - if (!versionRegex.test(version)) { |
84 | | - this.setVersionsForLatestPkg(`${dependency}@${version}`); |
| 72 | + const propVersion = dependencies[dependency]; |
| 73 | + if (!versionRegex.test(propVersion)) { |
| 74 | + setVersionsForLatestPkg(`${dependency}@${propVersion}`); |
85 | 75 | } |
86 | 76 | } catch (e) { |
87 | 77 | console.error(e); |
88 | 78 | } |
89 | | - } |
| 79 | + // eslint-disable-next-line react-hooks/exhaustive-deps |
| 80 | + }, []); |
90 | 81 |
|
91 | | - handleRemove = e => { |
| 82 | + const handleRemove = e => { |
92 | 83 | if (e) { |
93 | 84 | e.preventDefault(); |
94 | 85 | e.stopPropagation(); |
95 | 86 | } |
96 | | - this.props.onRemove(this.props.dependency); |
| 87 | + onRemove(dependency); |
97 | 88 | }; |
98 | 89 |
|
99 | | - handleRefresh = e => { |
| 90 | + const handleRefresh = e => { |
100 | 91 | if (e) { |
101 | 92 | e.preventDefault(); |
102 | 93 | e.stopPropagation(); |
103 | 94 | } |
104 | | - this.props.onRefresh(this.props.dependency); |
| 95 | + onRefresh(dependency); |
105 | 96 | }; |
106 | 97 |
|
107 | | - handleOpen = () => this.setState(({ open }) => ({ open: !open })); |
108 | | - |
109 | | - render() { |
110 | | - const { dependencies, dependency } = this.props; |
| 98 | + if (typeof dependencies[dependency] !== 'string') { |
| 99 | + return null; |
| 100 | + } |
111 | 101 |
|
112 | | - if (typeof dependencies[dependency] !== 'string') { |
113 | | - return null; |
114 | | - } |
| 102 | + return ( |
| 103 | + <> |
| 104 | + <ListAction |
| 105 | + justify="space-between" |
| 106 | + align="center" |
| 107 | + css={css({ |
| 108 | + position: 'relative', |
| 109 | + '.actions': { |
| 110 | + backgroundColor: 'sideBar.background', |
| 111 | + display: 'none', |
| 112 | + }, |
| 113 | + ':hover .actions': { |
| 114 | + backgroundColor: 'list.hoverBackground', |
| 115 | + display: 'flex', |
| 116 | + }, |
| 117 | + })} |
| 118 | + > |
| 119 | + <Link |
| 120 | + href={`https://www.npmjs.com/package/${dependency}`} |
| 121 | + target="_blank" |
| 122 | + css={{ position: 'absolute', zIndex: 2 }} |
| 123 | + > |
| 124 | + {dependency} |
| 125 | + </Link> |
115 | 126 |
|
116 | | - const { version, open, versions } = this.state; |
117 | | - return ( |
118 | | - <> |
119 | | - <ListAction |
120 | | - justify="space-between" |
| 127 | + <Stack |
121 | 128 | align="center" |
| 129 | + justify="flex-end" |
122 | 130 | css={css({ |
123 | | - position: 'relative', |
124 | | - '.actions': { |
125 | | - backgroundColor: 'sideBar.background', |
126 | | - display: 'none', |
127 | | - }, |
128 | | - ':hover .actions': { |
129 | | - backgroundColor: 'list.hoverBackground', |
130 | | - display: 'flex', |
131 | | - }, |
| 131 | + position: 'absolute', |
| 132 | + right: 2, |
| 133 | + flexGrow: 0, |
| 134 | + flexShrink: 1, |
| 135 | + width: '100%', |
132 | 136 | })} |
133 | 137 | > |
134 | | - <Link |
135 | | - href={`https://www.npmjs.com/package/${dependency}`} |
136 | | - target="_blank" |
137 | | - css={{ position: 'absolute' }} |
138 | | - > |
139 | | - {dependency} |
140 | | - </Link> |
141 | | - |
142 | | - <Stack |
143 | | - align="center" |
144 | | - justify="flex-end" |
145 | | - css={css({ |
146 | | - position: 'absolute', |
147 | | - right: 2, |
148 | | - flexGrow: 0, |
149 | | - flexShrink: 1, |
150 | | - width: '100%', |
151 | | - })} |
152 | | - > |
153 | | - <Text variant="muted" maxWidth="30%"> |
154 | | - {formatVersion(dependencies[dependency])}{' '} |
155 | | - {version && <span>({formatVersion(version)})</span>} |
156 | | - </Text> |
157 | | - </Stack> |
158 | | - |
159 | | - <Stack |
160 | | - className="actions" |
161 | | - align="center" |
162 | | - justify="flex-end" |
163 | | - css={css({ |
164 | | - position: 'absolute', |
165 | | - right: 0, |
166 | | - width: '150px', // overlay on text |
167 | | - })} |
| 138 | + <Text variant="muted" maxWidth="30%"> |
| 139 | + {formatVersion(dependencies[dependency])}{' '} |
| 140 | + {version && <span>({formatVersion(version)})</span>} |
| 141 | + </Text> |
| 142 | + </Stack> |
| 143 | + |
| 144 | + <Stack |
| 145 | + className="actions" |
| 146 | + align="center" |
| 147 | + justify="flex-end" |
| 148 | + css={css({ |
| 149 | + position: 'absolute', |
| 150 | + right: 0, |
| 151 | + width: '150px', // overlay on text |
| 152 | + })} |
| 153 | + > |
| 154 | + <Select |
| 155 | + css={{ width: '80px' }} |
| 156 | + value={versions.find(v => v === dependencies[dependency])} |
| 157 | + onChange={e => onRefresh(dependency, e.target.value)} |
168 | 158 | > |
169 | | - <Select |
170 | | - css={{ width: '80px' }} |
171 | | - defaultValue={versions.find(v => v === dependencies[dependency])} |
172 | | - onChange={e => { |
173 | | - this.props.onRefresh(dependency, e.target.value); |
174 | | - }} |
175 | | - > |
176 | | - {versions.map(a => ( |
177 | | - <option key={a}>{a}</option> |
178 | | - ))} |
179 | | - </Select> |
180 | | - |
181 | | - <SingletonTooltip> |
182 | | - {singleton => ( |
183 | | - <> |
184 | | - <Tooltip |
185 | | - content={open ? 'Hide sizes' : 'Show sizes'} |
186 | | - style={{ outline: 'none' }} |
187 | | - singleton={singleton} |
| 159 | + {versions.map(a => ( |
| 160 | + <option key={a}>{a}</option> |
| 161 | + ))} |
| 162 | + </Select> |
| 163 | + |
| 164 | + <SingletonTooltip> |
| 165 | + {singleton => ( |
| 166 | + <> |
| 167 | + <Tooltip |
| 168 | + content={open ? 'Hide sizes' : 'Show sizes'} |
| 169 | + style={{ outline: 'none' }} |
| 170 | + singleton={singleton} |
| 171 | + > |
| 172 | + <Button |
| 173 | + variant="link" |
| 174 | + onClick={() => setOpen(!open)} |
| 175 | + css={css({ minWidth: 5 })} |
188 | 176 | > |
189 | | - <Button |
190 | | - variant="link" |
191 | | - onClick={this.handleOpen} |
192 | | - css={css({ minWidth: 5 })} |
193 | | - > |
194 | | - {open ? <ArrowDropUp /> : <ArrowDropDown />} |
195 | | - </Button> |
196 | | - </Tooltip> |
197 | | - <Tooltip |
198 | | - content="Update to latest" |
199 | | - style={{ outline: 'none' }} |
200 | | - singleton={singleton} |
| 177 | + {open ? <ArrowDropUp /> : <ArrowDropDown />} |
| 178 | + </Button> |
| 179 | + </Tooltip> |
| 180 | + <Tooltip |
| 181 | + content="Update to latest" |
| 182 | + style={{ outline: 'none' }} |
| 183 | + singleton={singleton} |
| 184 | + > |
| 185 | + <Button |
| 186 | + variant="link" |
| 187 | + onClick={handleRefresh} |
| 188 | + css={css({ minWidth: 5 })} |
201 | 189 | > |
202 | | - <Button |
203 | | - variant="link" |
204 | | - onClick={this.handleRefresh} |
205 | | - css={css({ minWidth: 5 })} |
206 | | - > |
207 | | - <RefreshIcon /> |
208 | | - </Button> |
209 | | - </Tooltip> |
210 | | - <Tooltip |
211 | | - content="Remove" |
212 | | - style={{ outline: 'none' }} |
213 | | - singleton={singleton} |
| 190 | + <RefreshIcon /> |
| 191 | + </Button> |
| 192 | + </Tooltip> |
| 193 | + <Tooltip |
| 194 | + content="Remove" |
| 195 | + style={{ outline: 'none' }} |
| 196 | + singleton={singleton} |
| 197 | + > |
| 198 | + <Button |
| 199 | + variant="link" |
| 200 | + onClick={handleRemove} |
| 201 | + css={css({ minWidth: 5 })} |
214 | 202 | > |
215 | | - <Button |
216 | | - variant="link" |
217 | | - onClick={this.handleRemove} |
218 | | - css={css({ minWidth: 5 })} |
219 | | - > |
220 | | - <CrossIcon /> |
221 | | - </Button> |
222 | | - </Tooltip> |
223 | | - </> |
224 | | - )} |
225 | | - </SingletonTooltip> |
226 | | - </Stack> |
227 | | - </ListAction> |
228 | | - {open ? ( |
229 | | - <SidebarRow marginX={2}> |
230 | | - <BundleSizes |
231 | | - dependency={dependency} |
232 | | - version={dependencies[dependency]} |
233 | | - /> |
234 | | - </SidebarRow> |
235 | | - ) : null} |
236 | | - </> |
237 | | - ); |
238 | | - } |
239 | | -} |
| 203 | + <CrossIcon /> |
| 204 | + </Button> |
| 205 | + </Tooltip> |
| 206 | + </> |
| 207 | + )} |
| 208 | + </SingletonTooltip> |
| 209 | + </Stack> |
| 210 | + </ListAction> |
| 211 | + {open ? ( |
| 212 | + <SidebarRow marginX={2}> |
| 213 | + <BundleSizes |
| 214 | + dependency={dependency} |
| 215 | + version={dependencies[dependency]} |
| 216 | + /> |
| 217 | + </SidebarRow> |
| 218 | + ) : null} |
| 219 | + </> |
| 220 | + ); |
| 221 | +}; |
0 commit comments