admin/plugins: button-link to repo

Massimo Melina committed May 12, 2022 at 23:18 UTC dea5be1550f44655f37e9671879b56b0cd48a905
3 files changed +43 -18
admin/src/InstalledPlugins.ts
+11 -2
@@ -2,7 +2,7 @@ import { apiCall, useApiList } from './api'
2 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, PlayCircle, Settings, StopCircle, SystemUpdateAlt } from '@mui/icons-material'
5 +import { Delete, Error, GitHub, PlayCircle, Settings, StopCircle, SystemUpdateAlt } from '@mui/icons-material'
6 import { IconBtn } from './misc'
7 import { formDialog, toast } from './dialog'
8 import _ from 'lodash'
@@ -31,7 +31,8 @@ export default function InstalledPlugins({ updates }: { updates?: true }) {
31 renderCell({ row, value }) {
32 return h(Fragment, {},
33 value,
34 - typeof row.badApi === 'string' && h(Tooltip, { title: row.badApi, children: h(Error, { color: 'warning', sx: { ml: 1 } }) })
34 + typeof row.badApi === 'string' && h(Tooltip, { title: row.badApi, children: h(Error, { color: 'warning', sx: { ml: 1 } }) }),
35 + repoLink(row.repo),
36 )
37 }
38 },
@@ -134,3 +135,11 @@ const type2comp = {
135 multiselect: MultiSelectField,
136 array: ArrayField,
137 }
138 +
139 +export function repoLink(repo?: string) {
140 + return repo && h(IconBtn, {
141 + icon: GitHub,
142 + title: "Open web page",
143 + link: 'https://github.com/' + repo,
144 + })
145 +}
admin/src/OnlinePlugins.ts
+18 -13
@@ -2,11 +2,12 @@ import { apiCall, useApiList } from './api'
2 import { Fragment, createElement as h, useState } from 'react'
3 import { Alert } from '@mui/material'
4 import { DataGrid } from '@mui/x-data-grid'
5 -import { IconBtn, spinner } from './misc'
6 -import { Download, Search } from '@mui/icons-material'
5 +import { IconBtn } from './misc'
6 +import { Download, GitHub, Search } from '@mui/icons-material'
7 import { confirmDialog, toast } from './dialog'
8 import { StringField } from './Form'
9 import { useDebounce } from 'use-debounce'
10 +import { repoLink } from './InstalledPlugins'
11
12 export default function OnlinePlugins() {
13 const [search, setSearch] = useState('')
@@ -47,17 +48,21 @@ export default function OnlinePlugins() {
48 hideSortIcons: true,
49 disableColumnMenu: true,
50 renderCell({ row }) {
50 - return row.downloading ? spinner() : h(IconBtn, {
51 - icon: Download,
52 - title: "Download",
53 - disabled: row.installed && "Already installed",
54 - async onClick() {
55 - if (!await confirmDialog("WARNING - Proceed only if you trust this author and this plugin")) return
56 - const { id } = row
57 - return apiCall('download_plugin', { id })
58 - .then(() => toast("Plugin downloaded: " + id))
59 - }
60 - })
51 + const { id } = row
52 + return h('div', {},
53 + repoLink(id),
54 + h(IconBtn, {
55 + icon: Download,
56 + title: "Download",
57 + progress: row.downloading,
58 + disabled: row.installed && "Already installed",
59 + async onClick() {
60 + if (!await confirmDialog("WARNING - Proceed only if you trust this author and this plugin")) return
61 + return apiCall('download_plugin', { id })
62 + .then(() => toast("Plugin downloaded: " + id))
63 + }
64 + })
65 + )
66 }
67 },
68 ]
admin/src/misc.ts
+14 -3
@@ -28,13 +28,15 @@ export function modifiedSx(is: boolean) {
28 return is ? { outline: '2px solid' } : undefined
29 }
30
31 -interface IconBtnProps { title?: string, icon: SvgIconComponent, disabled?: boolean | string, [rest:string]:any }
32 -export function IconBtn({ title, icon, onClick, disabled, ...rest }: IconBtnProps) {
31 +interface IconBtnProps { title?: string, icon: SvgIconComponent, disabled?: boolean | string, progress?: boolean | number, link?: string, [rest:string]:any }
32 +export function IconBtn({ title, icon, onClick, disabled, progress=false, link, ...rest }: IconBtnProps) {
33 const [loading, setLoading] = useStateMounted(false)
34 if (typeof disabled === 'string')
35 title = disabled
36 + if (link)
37 + onClick = () => window.open(link)
38 let ret: ReturnType<FC> = h(IconButton, {
37 - disabled: loading || Boolean(disabled),
39 + disabled: loading || progress !== false || Boolean(disabled),
40 ...rest,
41 onClick() {
42 const ret = onClick?.apply(this,arguments)
@@ -44,6 +46,15 @@ export function IconBtn({ title, icon, onClick, disabled, ...rest }: IconBtnProp
46 }
47 }
48 }, h(icon))
49 + if (progress || loading)
50 + ret = h(Box, { position:'relative' },
51 + h(CircularProgress, {
52 + ...(typeof progress === 'number' ? { value: progress, variant: 'determinate' } : null),
53 + size: 48,
54 + style: { position:'absolute' }
55 + }),
56 + ret
57 + )
58 if (title)
59 ret = h(Tooltip, { title, children: h('span',{},ret) })
60 return ret