admin/plugin/online: offer to start plugin after installation

Massimo Melina committed Aug 7, 2022 at 17:13 UTC 03643b0681be507a37677f8949efe4a54bcedd0a
5 files changed +28 -19
admin/src/InstalledPlugins.ts
+6 -3
@@ -67,9 +67,7 @@ export default function InstalledPlugins({ updates }: { updates?: true }) {
67 } : {
68 icon: PlayCircle,
69 title: `Start ${id}`,
70 - onClick: () =>
71 - apiCall('set_plugin', { id, enabled: true }).then(() =>
72 - toast("Plugin is starting", h(PlayCircle, { color: 'success' }))),
70 + onClick: () => startPlugin(id),
71 }),
72 h(IconBtn, {
73 icon: Settings,
@@ -153,3 +151,8 @@ export function UpdateButton({ id, then }: { id: string, then: (id:string)=>void
151 }
152 })
153 }
154 +
155 +export function startPlugin(id: string) {
156 + return apiCall('set_plugin', { id, enabled: true }).then(() =>
157 + toast("Plugin is starting", h(PlayCircle, { color: 'success' })))
158 +}
admin/src/OnlinePlugins.ts
+7 -5
@@ -3,12 +3,13 @@ import { Fragment, createElement as h, useState } from 'react'
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'
6 +import { confirmDialog } from './dialog'
7 import { StringField } from '@hfs/mui-grid-form'
8 import { useDebounce } from 'use-debounce'
9 -import { repoLink, showError, UpdateButton } from './InstalledPlugins'
9 +import { repoLink, showError, startPlugin, UpdateButton } from './InstalledPlugins'
10 import { state, useSnapState } from './state'
11 import _ from 'lodash'
12 +import md from './md'
13
14 export default function OnlinePlugins() {
15 const [search, setSearch] = useState('')
@@ -79,14 +80,15 @@ export default function OnlinePlugins() {
80 }
81 }) : h(IconBtn, {
82 icon: Download,
82 - title: "Download",
83 + title: "Install",
84 progress: row.downloading,
85 disabled: row.installed && "Already installed",
86 tooltipProps: { placement:'bottom-end' }, // workaround problem with horizontal scrolling by moving the tooltip leftward
87 confirm: "WARNING - Proceed only if you trust this author and this plugin",
88 async onClick() {
88 - await apiCall('download_plugin', { id, branch })
89 - toast("Plugin downloaded: " + id)
89 + const { id: installedId } = await apiCall('download_plugin', { id, branch })
90 + if (await confirmDialog(md(`Plugin /${id}/ installed.\nDo you want to start it now?`)))
91 + await startPlugin(installedId)
92 }
93 })
94 )
admin/src/dialog.ts
+11 -8
@@ -79,7 +79,8 @@ export async function alertDialog(msg: ReactElement | string | Error, options?:
79 sx: { position: 'absolute', right: 0, top: 0, opacity: .5 }
80 }, h(Close)),
81 opt.icon ?? h(type2ico[type], { color: type, fontSize: 'large' }),
82 - isValidElement(msg) ? msg : h(Box, { fontSize: 'large', mb: 1 }, String(msg)),
82 + isValidElement(msg) ? msg
83 + : h(Box, { fontSize: 'large', mb: 1, lineHeight: '1.8em' }, String(msg)),
84 )
85 }
86 })
@@ -87,7 +88,7 @@ export async function alertDialog(msg: ReactElement | string | Error, options?:
88 }
89
90 interface ConfirmOptions { href?: string }
90 -export async function confirmDialog(msg: string, { href }: ConfirmOptions={}) : Promise<boolean> {
91 +export async function confirmDialog(msg: string | ReactElement, { href }: ConfirmOptions={}) : Promise<boolean> {
92 return new Promise(resolve => newDialog({
93 className: 'dialog-confirm',
94 icon: '?',
@@ -96,12 +97,14 @@ export async function confirmDialog(msg: string, { href }: ConfirmOptions={}) :
97 }) )
98
99 function Content() {
99 - return h('div', {},
100 - h('p', {}, msg),
101 - h('a', {
102 - href,
103 - onClick: () => closeDialog(true),
104 - }, h(Button, {}, 'Confirm'))
100 + return h(Fragment, {},
101 + h(Box, { mb: 2 }, msg),
102 + h(Box, { textAlign: 'right' },
103 + h('a', {
104 + href,
105 + onClick: () => closeDialog(true),
106 + }, h(Button, {}, 'Confirm'))
107 + ),
108 )
109 }
110 }
server/src/api.plugins.ts
+2 -2
@@ -116,8 +116,8 @@ const apis: ApiHandlers = {
116 },
117
118 async download_plugin(pl) {
119 - await downloadPlugin(pl.id, pl.branch)
120 - return {}
119 + const res = await downloadPlugin(pl.id, pl.branch)
120 + return typeof res === 'string' ? getPluginInfo(res) : res
121 },
122
123 async update_plugin(pl) {
server/src/github.ts
+2 -1
@@ -28,7 +28,7 @@ export async function downloadPlugin(repo: string, branch='', overwrite?: boolea
28 branch = rec.default_branch
29 const short = repo.split('/')[1] // second part, repo without the owner
30 const folder2repo = getFolder2repo()
31 - const folder = overwrite ? _.findKey(folder2repo, x => x===repo) // use existing folder
31 + const folder = overwrite ? _.findKey(folder2repo, x => x===repo)! // use existing folder
32 : short in folder2repo ? repo.replace('/','-') // longer form only if another plugin is using short form
33 : short
34 const installPath = PLUGINS_PATH + '/' + folder
@@ -39,6 +39,7 @@ export async function downloadPlugin(repo: string, branch='', overwrite?: boolea
39 path.startsWith(rootWithinZip) && installPath + '/' + path.slice(rootWithinZip.length) )
40 downloadProgress(repo, undefined)
41 await rescan() // workaround: for some reason, operations are not triggering the rescan of the watched folder. Let's invoke it.
42 + return folder
43 }
44
45 export function getRepoInfo(id: string) {