Better handle install and re-install lifecycle. Also display all the juicy bits about the plugin

This commit is contained in:
tutman96 2025-01-06 18:56:29 +00:00
parent 2e24916331
commit 16064aa876
6 changed files with 70 additions and 27 deletions

View File

@ -19,7 +19,7 @@ type PluginInstall struct {
ExtractedVersions map[string]string `json:"extracted_versions"` ExtractedVersions map[string]string `json:"extracted_versions"`
manifest *PluginManifest manifest *PluginManifest
runningVersion *string runningVersion string
processManager *ProcessManager processManager *ProcessManager
rpcServer *PluginRpcServer rpcServer *PluginRpcServer
} }
@ -84,10 +84,7 @@ func (p *PluginInstall) ReconcileSubprocess() error {
return fmt.Errorf("failed to get plugin manifest: %v", err) return fmt.Errorf("failed to get plugin manifest: %v", err)
} }
versionRunning := "" versionRunning := p.runningVersion
if p.runningVersion != nil {
versionRunning = *p.runningVersion
}
versionShouldBeRunning := p.Version versionShouldBeRunning := p.Version
if !p.Enabled { if !p.Enabled {
@ -105,7 +102,7 @@ func (p *PluginInstall) ReconcileSubprocess() error {
log.Printf("Stopping plugin %s running version %s", manifest.Name, versionRunning) log.Printf("Stopping plugin %s running version %s", manifest.Name, versionRunning)
p.processManager.Disable() p.processManager.Disable()
p.processManager = nil p.processManager = nil
p.runningVersion = nil p.runningVersion = ""
err = p.rpcServer.Stop() err = p.rpcServer.Stop()
if err != nil { if err != nil {
return fmt.Errorf("failed to stop rpc server: %v", err) return fmt.Errorf("failed to stop rpc server: %v", err)
@ -146,7 +143,11 @@ func (p *PluginInstall) ReconcileSubprocess() error {
}) })
p.processManager.StartMonitor() p.processManager.StartMonitor()
p.processManager.Enable() p.processManager.Enable()
p.runningVersion = &p.Version p.runningVersion = p.Version
// Clear out manifest so the new version gets pulled next time
p.manifest = nil
log.Printf("Started plugin %s version %s", manifest.Name, p.Version) log.Printf("Started plugin %s version %s", manifest.Name, p.Version)
return nil return nil
} }
@ -155,7 +156,7 @@ func (p *PluginInstall) Shutdown() {
if p.processManager != nil { if p.processManager != nil {
p.processManager.Disable() p.processManager.Disable()
p.processManager = nil p.processManager = nil
p.runningVersion = nil p.runningVersion = ""
} }
if p.rpcServer != nil { if p.rpcServer != nil {

View File

@ -120,7 +120,6 @@ func RpcPluginExtract(filename string) (*PluginManifest, error) {
} }
func RpcPluginInstall(name string, version string) error { func RpcPluginInstall(name string, version string) error {
// TODO: find the plugin version in the plugins.json file
pluginInstall, ok := pluginDatabase.Plugins[name] pluginInstall, ok := pluginDatabase.Plugins[name]
if !ok { if !ok {
return fmt.Errorf("plugin not found: %s", name) return fmt.Errorf("plugin not found: %s", name)
@ -136,8 +135,6 @@ func RpcPluginInstall(name string, version string) error {
return fmt.Errorf("plugin version not found: %s", version) return fmt.Errorf("plugin version not found: %s", version)
} }
// TODO: If there is a running plugin with the same name, stop it and start the new version
pluginInstall.Version = version pluginInstall.Version = version
pluginInstall.Enabled = true pluginInstall.Enabled = true
pluginDatabase.Plugins[name] = pluginInstall pluginDatabase.Plugins[name] = pluginInstall
@ -151,7 +148,7 @@ func RpcPluginInstall(name string, version string) error {
return fmt.Errorf("failed to start plugin %s: %v", name, err) return fmt.Errorf("failed to start plugin %s: %v", name, err)
} }
// TODO: Determine if the old version should be removed // TODO: Determine if the old extract should be removed
return nil return nil
} }

View File

@ -1,4 +1,4 @@
import { PluginStatus } from "@/hooks/stores"; import { PluginStatus, usePluginStore } from "@/hooks/stores";
import Modal from "@components/Modal"; import Modal from "@components/Modal";
import AutoHeight from "@components/AutoHeight"; import AutoHeight from "@components/AutoHeight";
import Card, { GridCard } from "@components/Card"; import Card, { GridCard } from "@components/Card";
@ -33,6 +33,8 @@ function Dialog({ plugin, setOpen }: { plugin: PluginStatus | null, setOpen: (op
const [loading, setLoading] = useState(false); const [loading, setLoading] = useState(false);
const [error, setError] = useState<string | null>(null); const [error, setError] = useState<string | null>(null);
const {setIsPluginUploadModalOpen} = usePluginStore();
useEffect(() => { useEffect(() => {
setLoading(false); setLoading(false);
}, [plugin]) }, [plugin])
@ -73,6 +75,11 @@ function Dialog({ plugin, setOpen }: { plugin: PluginStatus | null, setOpen: (op
}); });
}, [send, plugin, setOpen]) }, [send, plugin, setOpen])
const uploadPlugin = useCallback(() => {
setOpen(false);
setIsPluginUploadModalOpen(true);
}, [setIsPluginUploadModalOpen, setOpen])
return ( return (
<AutoHeight> <AutoHeight>
<div className="mx-auto max-w-4xl px-4 transition-all duration-300 ease-in-out"> <div className="mx-auto max-w-4xl px-4 transition-all duration-300 ease-in-out">
@ -118,6 +125,30 @@ function Dialog({ plugin, setOpen }: { plugin: PluginStatus | null, setOpen: (op
</div> </div>
</div> </div>
<div className="grid grid-cols-[auto,1fr] gap-x-4 text-sm text-black dark:text-white">
<span className="font-semibold">
Name
</span>
<span>{plugin?.name}</span>
<span className="font-semibold">
Active Version
</span>
<span>{plugin?.version}</span>
<span className="font-semibold">
Description
</span>
<span>{plugin?.description}</span>
<span className="font-semibold">
Homepage
</span>
<a href={plugin?.homepage} target="_blank" rel="noopener noreferrer" className="text-blue-600 hover:text-blue-800 dark:text-blue-500 dark:hover:text-blue-400">
{plugin?.homepage}
</a>
</div>
<div className="h-[1px] w-full bg-slate-800/10 dark:bg-slate-300/20" /> <div className="h-[1px] w-full bg-slate-800/10 dark:bg-slate-300/20" />
<div <div
@ -154,6 +185,13 @@ function Dialog({ plugin, setOpen }: { plugin: PluginStatus | null, setOpen: (op
}} }}
> >
<div className="flex items-center w-full space-x-2"> <div className="flex items-center w-full space-x-2">
<Button
size="MD"
theme="primary"
text="Upload New Version"
disabled={loading}
onClick={uploadPlugin}
/>
<Button <Button
size="MD" size="MD"
theme="blank" theme="blank"

View File

@ -67,7 +67,7 @@ export default function PluginList() {
theme="light" theme="light"
text="Settings" text="Settings"
onClick={() => { onClick={() => {
setConfiguringPlugin(plugin); setConfiguringPlugin(plugin.name);
setPluginConfigureModalOpen(true); setPluginConfigureModalOpen(true);
}} }}
/> />
@ -85,7 +85,7 @@ export default function PluginList() {
updatePlugins(); updatePlugins();
} }
}} }}
plugin={plugins.find(p => p.name == configuringPlugin?.name) ?? null} plugin={plugins.find(p => p.name == configuringPlugin) ?? null}
/> />
<div className="flex items-center gap-x-2"> <div className="flex items-center gap-x-2">

View File

@ -45,6 +45,8 @@ function Dialog({ setOpen }: { setOpen: (open: boolean) => void }) {
setPluginUploadFilename, setPluginUploadFilename,
pluginUploadManifest, pluginUploadManifest,
setPluginUploadManifest, setPluginUploadManifest,
setConfiguringPlugin,
setPluginConfigureModalOpen,
} = usePluginStore(); } = usePluginStore();
const [send] = useJsonRpc(); const [send] = useJsonRpc();
const [extractError, setExtractError] = useState<string | null>(null); const [extractError, setExtractError] = useState<string | null>(null);
@ -112,7 +114,12 @@ function Dialog({ setOpen }: { setOpen: (open: boolean) => void }) {
onInstall={() => { onInstall={() => {
setOpen(false) setOpen(false)
setPluginUploadFilename(null) setPluginUploadFilename(null)
// TODO: Open plugin settings dialog if (pluginUploadManifest) {
setConfiguringPlugin(pluginUploadManifest.name)
setPluginConfigureModalOpen(true)
}
setPluginUploadManifest(null)
setPluginUploadModalView("upload")
}} }}
onBack={() => { onBack={() => {
setPluginUploadModalView("upload") setPluginUploadModalView("upload")

View File

@ -562,8 +562,8 @@ interface PluginState {
pluginConfigureModalOpen: boolean; pluginConfigureModalOpen: boolean;
setPluginConfigureModalOpen: (isOpen: boolean) => void; setPluginConfigureModalOpen: (isOpen: boolean) => void;
configuringPlugin: PluginStatus | null; configuringPlugin: string | null;
setConfiguringPlugin: (plugin: PluginStatus | null) => void; setConfiguringPlugin: (pluginName: string | null) => void;
} }
export const usePluginStore = create<PluginState>(set => ({ export const usePluginStore = create<PluginState>(set => ({