From 88f3e97011b4be07f37a6a003a4398717ff1adac Mon Sep 17 00:00:00 2001 From: tutman96 <11356668+tutman96@users.noreply.github.com> Date: Sat, 4 Jan 2025 17:18:25 +0000 Subject: [PATCH] Add enable/disable button --- internal/plugin/install.go | 20 +++ internal/plugin/plugin.go | 36 ++++-- jsonrpc.go | 1 + ui/src/components/PluginConfigureDialog.tsx | 127 ++++++++++++++++++++ ui/src/components/PluginList.tsx | 23 +++- ui/src/hooks/stores.ts | 12 ++ 6 files changed, 204 insertions(+), 15 deletions(-) create mode 100644 ui/src/components/PluginConfigureDialog.tsx diff --git a/internal/plugin/install.go b/internal/plugin/install.go index c860aff..01d8f25 100644 --- a/internal/plugin/install.go +++ b/internal/plugin/install.go @@ -1,5 +1,7 @@ package plugin +import "fmt" + type PluginInstall struct { Enabled bool `json:"enabled"` @@ -29,3 +31,21 @@ func (p *PluginInstall) GetManifest() (*PluginManifest, error) { func (p *PluginInstall) GetExtractedFolder() string { return p.ExtractedVersions[p.Version] } + +func (p *PluginInstall) GetStatus() (*PluginStatus, error) { + manifest, err := p.GetManifest() + if err != nil { + return nil, fmt.Errorf("failed to get plugin manifest: %v", err) + } + + status := "stopped" + if p.Enabled { + status = "running" + } + + return &PluginStatus{ + PluginManifest: *manifest, + Enabled: p.Enabled, + Status: status, + }, nil +} diff --git a/internal/plugin/plugin.go b/internal/plugin/plugin.go index b841f01..a161e68 100644 --- a/internal/plugin/plugin.go +++ b/internal/plugin/plugin.go @@ -135,25 +135,35 @@ func RpcPluginInstall(name string, version string) error { func RpcPluginList() ([]PluginStatus, error) { plugins := make([]PluginStatus, 0, len(pluginDatabase.Plugins)) for pluginName, plugin := range pluginDatabase.Plugins { - manifest, err := plugin.GetManifest() + status, err := plugin.GetStatus() if err != nil { - return nil, fmt.Errorf("failed to get plugin manifest for %s: %v", pluginName, err) + return nil, fmt.Errorf("failed to get plugin status for %s: %v", pluginName, err) } - - status := "stopped" - if plugin.Enabled { - status = "running" - } - - plugins = append(plugins, PluginStatus{ - PluginManifest: *manifest, - Enabled: plugin.Enabled, - Status: status, - }) + plugins = append(plugins, *status) } return plugins, nil } +func RpcUpdateConfig(name string, enabled bool) (*PluginStatus, error) { + pluginInstall, ok := pluginDatabase.Plugins[name] + if !ok { + return nil, fmt.Errorf("plugin not found: %s", name) + } + + pluginInstall.Enabled = enabled + pluginDatabase.Plugins[name] = pluginInstall + + if err := pluginDatabase.Save(); err != nil { + return nil, fmt.Errorf("failed to save plugin database: %v", err) + } + + status, err := pluginInstall.GetStatus() + if err != nil { + return nil, fmt.Errorf("failed to get plugin status for %s: %v", name, err) + } + return status, nil +} + func readManifest(extractFolder string) (*PluginManifest, error) { manifestPath := path.Join(extractFolder, "manifest.json") manifestFile, err := os.Open(manifestPath) diff --git a/jsonrpc.go b/jsonrpc.go index 9f3a9b2..05babd5 100644 --- a/jsonrpc.go +++ b/jsonrpc.go @@ -559,4 +559,5 @@ var rpcHandlers = map[string]RPCHandler{ "pluginExtract": {Func: plugin.RpcPluginExtract, Params: []string{"filename"}}, "pluginInstall": {Func: plugin.RpcPluginInstall, Params: []string{"name", "version"}}, "pluginList": {Func: plugin.RpcPluginList}, + "pluginUpdateConfig": {Func: plugin.RpcUpdateConfig, Params: []string{"name", "enabled"}}, } diff --git a/ui/src/components/PluginConfigureDialog.tsx b/ui/src/components/PluginConfigureDialog.tsx new file mode 100644 index 0000000..c53eb89 --- /dev/null +++ b/ui/src/components/PluginConfigureDialog.tsx @@ -0,0 +1,127 @@ +import { PluginStatus } from "@/hooks/stores"; +import Modal from "@components/Modal"; +import AutoHeight from "@components/AutoHeight"; +import { GridCard } from "@components/Card"; +import LogoBlueIcon from "@/assets/logo-blue.svg"; +import LogoWhiteIcon from "@/assets/logo-white.svg"; +import { ViewHeader } from "./MountMediaDialog"; +import { Button } from "./Button"; +import { useJsonRpc } from "@/hooks/useJsonRpc"; +import { useCallback, useEffect, useState } from "react"; + +export default function PluginConfigureModal({ + plugin, + open, + setOpen, +}: { + plugin: PluginStatus | null; + open: boolean; + setOpen: (open: boolean) => void; +}) { + return ( + setOpen(false)}> + + + ) +} + +function Dialog({ plugin, setOpen }: { plugin: PluginStatus | null, setOpen: (open: boolean) => void }) { + const [send] = useJsonRpc(); + + const [loading, setLoading] = useState(false); + const [error, setError] = useState(null); + + useEffect(() => { + setLoading(false); + }, [plugin]) + + const updatePlugin = useCallback((enabled: boolean) => { + if (!plugin) return; + if (!enabled) { + if (!window.confirm("Are you sure you want to disable this plugin?")) { + return; + } + } + + setLoading(true); + send("pluginUpdateConfig", { name: plugin.name, enabled }, resp => { + if ("error" in resp) { + setError(resp.error.message); + return + } + setOpen(false); + }); + }, [send, plugin, setOpen]) + + return ( + + + + + + + + + + + + {/* Enable/Disable toggle */} + { + updatePlugin(!plugin?.enabled); + }} + /> + + + + + {error && {error}} + + TODO: Plugin configuration goes here + + + + + { + setOpen(false); + }} + /> + + + + + + + + + + ) +} \ No newline at end of file diff --git a/ui/src/components/PluginList.tsx b/ui/src/components/PluginList.tsx index 947e618..d2397f1 100644 --- a/ui/src/components/PluginList.tsx +++ b/ui/src/components/PluginList.tsx @@ -4,6 +4,7 @@ import { PluginStatus, usePluginStore, useUiStore } from "@/hooks/stores"; import { useCallback, useEffect, useState } from "react"; import { cx } from "@/cva.config"; import UploadPluginModal from "@components/UploadPluginDialog"; +import PluginConfigureModal from "./PluginConfigureDialog"; function PluginListStatusIcon({ plugin }: { plugin: PluginStatus }) { let classNames = "bg-slate-500 border-slate-600"; @@ -29,7 +30,11 @@ export default function PluginList() { setIsPluginUploadModalOpen, setPluginUploadModalView, plugins, - setPlugins + setPlugins, + pluginConfigureModalOpen, + setPluginConfigureModalOpen, + configuringPlugin, + setConfiguringPlugin, } = usePluginStore(); const sidebarView = useUiStore(state => state.sidebarView); @@ -74,7 +79,10 @@ export default function PluginList() { size="SM" theme="light" text="Settings" - onClick={() => console.log("Settings clicked")} + onClick={() => { + setConfiguringPlugin(plugin); + setPluginConfigureModalOpen(true); + }} /> @@ -82,6 +90,17 @@ export default function PluginList() { + { + setPluginConfigureModalOpen(open); + if (!open) { + updatePlugins(); + } + }} + plugin={configuringPlugin} + /> + void; + + pluginConfigureModalOpen: boolean; + setPluginConfigureModalOpen: (isOpen: boolean) => void; + + configuringPlugin: PluginStatus | null; + setConfiguringPlugin: (plugin: PluginStatus | null) => void; } export const usePluginStore = create(set => ({ @@ -574,4 +580,10 @@ export const usePluginStore = create(set => ({ plugins: [], setPlugins: plugins => set({ plugins }), + + pluginConfigureModalOpen: false, + setPluginConfigureModalOpen: isOpen => set({ pluginConfigureModalOpen: isOpen }), + + configuringPlugin: null, + setConfiguringPlugin: plugin => set({ configuringPlugin: plugin }), }));
{error}
+ TODO: Plugin configuration goes here +