mirror of https://github.com/jetkvm/kvm.git
Better handle install and re-install lifecycle. Also display all the juicy bits about the plugin
This commit is contained in:
parent
2e24916331
commit
16064aa876
|
@ -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 {
|
||||||
|
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
@ -129,15 +160,15 @@ function Dialog({ plugin, setOpen }: { plugin: PluginStatus | null, setOpen: (op
|
||||||
{error && <p className="text-red-500 dark:text-red-400">{error}</p>}
|
{error && <p className="text-red-500 dark:text-red-400">{error}</p>}
|
||||||
{plugin?.message && (
|
{plugin?.message && (
|
||||||
<>
|
<>
|
||||||
<p className="text-sm text-gray-500 dark:text-gray-400">
|
<p className="text-sm text-gray-500 dark:text-gray-400">
|
||||||
Plugin message:
|
Plugin message:
|
||||||
</p>
|
</p>
|
||||||
<Card className={cx(
|
<Card className={cx(
|
||||||
"text-gray-500 dark:text-gray-400 p-4 border",
|
"text-gray-500 dark:text-gray-400 p-4 border",
|
||||||
plugin.status === "error" && "border-red-200 bg-red-50 text-red-800 dark:text-red-400",
|
plugin.status === "error" && "border-red-200 bg-red-50 text-red-800 dark:text-red-400",
|
||||||
)}>
|
)}>
|
||||||
{plugin.message}
|
{plugin.message}
|
||||||
</Card>
|
</Card>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<p className="text-sm text-gray-500 dark:text-gray-400 py-10">
|
<p className="text-sm text-gray-500 dark:text-gray-400 py-10">
|
||||||
|
@ -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"
|
||||||
|
|
|
@ -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">
|
||||||
|
|
|
@ -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")
|
||||||
|
|
|
@ -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 => ({
|
||||||
|
|
Loading…
Reference in New Issue