admin/plugins: show error if github is unreachable
Massimo Melina committed
May 13, 2022 at 01:39 UTC
ec2057155769c5d7fb5768a0bfd29f51f7e6fd1b
6 files changed
+38
-19
admin/src/InstalledPlugins.ts
+8
-2
@@ -3,7 +3,7 @@ import { createElement as h, Fragment } from 'react'
3
import { Alert, Box, Tooltip } from '@mui/material'
4
import { DataGrid } from '@mui/x-data-grid'
5
import { Delete, Error, GitHub, PlayCircle, Settings, StopCircle, SystemUpdateAlt } from '@mui/icons-material'
6
-import { IconBtn } from './misc'
6
+import { IconBtn, xlate } from './misc'
7
import { formDialog, toast } from './dialog'
8
import _ from 'lodash'
9
import { BoolField, Field, MultiSelectField, NumberField, SelectField, StringField } from './Form'
@@ -12,7 +12,7 @@ import { ArrayField } from './ArrayField'
12
export default function InstalledPlugins({ updates }: { updates?: true }) {
13
const { list, setList, error, initializing } = useApiList(updates ? 'get_plugin_updates' : 'get_plugins')
14
if (error)
15
- return h(Alert, { severity: 'error' }, error)
15
+ return showError(error)
16
return h(DataGrid, {
17
rows: list.length ? list : [], // workaround for DataGrid bug causing 'no rows' message to be not displayed after 'loading' was also used
18
loading: initializing,
@@ -140,3 +140,9 @@ export function repoLink(repo?: string) {
140
link: 'https://github.com/' + repo,
141
})
142
}
143
+
144
+export function showError(error: any) {
145
+ return h(Alert, { severity: 'error' }, xlate(error, {
146
+ ENOTFOUND: "Couldn't reach github.com"
147
+ }))
148
+}
admin/src/OnlinePlugins.ts
+2
-3
@@ -1,20 +1,19 @@
1
import { apiCall, useApiList } from './api'
2
import { Fragment, createElement as h, useState } from 'react'
3
-import { Alert } from '@mui/material'
3
import { DataGrid } from '@mui/x-data-grid'
4
import { IconBtn } from './misc'
5
import { Download, Search } from '@mui/icons-material'
6
import { toast } from './dialog'
7
import { StringField } from './Form'
8
import { useDebounce } from 'use-debounce'
10
-import { repoLink } from './InstalledPlugins'
9
+import { repoLink, showError } from './InstalledPlugins'
10
11
export default function OnlinePlugins() {
12
const [search, setSearch] = useState('')
13
const [debouncedSearch] = useDebounce(search, 1000)
14
const { list, error, initializing } = useApiList('search_online_plugins', { text: debouncedSearch })
15
if (error)
17
- return h(Alert, { severity: 'error' }, error)
16
+ return showError(error)
17
return h(Fragment, {},
18
h(StringField, {
19
value: search,
admin/src/api.ts
+2
@@ -139,6 +139,8 @@ export function useApiList<T=any>(cmd:string|Falsy, params: Dict={}, { addId=fal
139
setInitializing(false)
140
return
141
}
142
+ if (data.error)
143
+ return setError(data.error)
144
if (data.add) {
145
const rec = map(data.add)
146
if (addId)
admin/src/misc.ts
+4
@@ -118,3 +118,7 @@ export function findFirst<I=any, O=any>(a: I[], cb:(v:I)=>O): any {
118
return ret
119
}
120
}
121
+
122
+export function xlate(input: any, table: Record<string, any>) {
123
+ return table[input] ?? input
124
+}
server/src/api.plugins.ts
+19
-14
@@ -41,14 +41,18 @@ const apis: ApiHandlers = {
41
const list = sendList()
42
setTimeout(async () => {
43
const repo2id = getRepo2id()
44
- for (const repo in repo2id) {
45
- const online = await readOnlinePlugin(repo)
46
- if (!online.apiRequired || online.badApi) continue
47
- const id = repo2id[repo]
48
- const disk = getPluginInfo(id)
49
- if (online.version! > disk.version)
50
- list.add(online)
51
- }
44
+ for (const repo in repo2id)
45
+ try {
46
+ const online = await readOnlinePlugin(repo)
47
+ if (!online.apiRequired || online.badApi) continue
48
+ const id = repo2id[repo]
49
+ const disk = getPluginInfo(id)
50
+ if (online.version! > disk.version)
51
+ list.add(online)
52
+ }
53
+ catch (err:any) {
54
+ list.error(err.code || err.message)
55
+ }
56
list.end()
57
})
58
return list.return
@@ -108,6 +112,8 @@ const apis: ApiHandlers = {
112
}) )
113
}
114
list.end()
115
+ }, (err: any) => {
116
+ list.error(err.code || err.message)
117
})
118
return list.return
119
},
@@ -180,17 +186,16 @@ async function downloadPlugin(repo: string, overwrite?: boolean) {
186
187
export default apis
188
183
-function apiGithub(uri: string) {
184
- return httpsString('https://api.github.com/'+uri, {
189
+async function apiGithub(uri: string) {
190
+ const res = await httpsString('https://api.github.com/'+uri, {
191
headers: {
192
'User-Agent': 'HFS',
193
Accept: 'application/vnd.github.v3+json',
194
}
189
- }).then(async res => {
190
- if (!res.ok)
191
- throw res.statusCode
192
- return JSON.parse(res.body)
195
})
196
+ if (!res.ok)
197
+ throw res.statusCode
198
+ return JSON.parse(res.body)
199
}
200
201
function readOnlinePlugin(repo: string) {
server/src/apiMiddleware.ts
+3
@@ -78,6 +78,9 @@ export function sendList<T>(addAtStart?: T[]) {
78
end() { // notify end of additions
79
stream.push('end')
80
},
81
+ error(msg: string) {
82
+ stream.push({ error: msg })
83
+ },
84
events(ctx: Koa.Context, eventMap: Parameters<typeof onOff>[1]) {
85
const off = onOff(events, eventMap)
86
ctx.res.once('close', off)