diff --git a/cmd/verstak-gui/bindings_plugins.go b/cmd/verstak-gui/bindings_plugins.go index 5ed371c..f592779 100644 --- a/cmd/verstak-gui/bindings_plugins.go +++ b/cmd/verstak-gui/bindings_plugins.go @@ -18,6 +18,8 @@ type PluginDTO struct { Author string `json:"author,omitempty"` Description string `json:"description,omitempty"` Active bool `json:"active"` + Installed bool `json:"installed"` + HasInstall bool `json:"hasInstall"` HasPanel bool `json:"hasPanel"` HasSettings bool `json:"hasSettings"` UIContribs UIContribDTO `json:"uiContribs"` @@ -89,6 +91,8 @@ func (a *App) ListPlugins() []PluginDTO { Author: p.Meta.Author, Description: p.Meta.Description, Active: active, + Installed: p.Installed, + HasInstall: p.HasInstall, HasPanel: hasPanel, UIContribs: contribs, }) @@ -97,11 +101,22 @@ func (a *App) ListPlugins() []PluginDTO { } // SetPluginEnabled persists the enabled/disabled state and applies it to the runtime. +// Returns error if the plugin is not installed but has install lifecycle. func (a *App) SetPluginEnabled(name string, enabled bool) error { if a.plugins == nil { return fmt.Errorf("plugin manager not ready") } + if enabled { + if err := a.plugins.Enable(name); err != nil { + return err + } + } else { + if err := a.plugins.Disable(name); err != nil { + return err + } + } + appCfg, _ := config.LoadAppConfig() if appCfg == nil { appCfg = config.DefaultAppConfig() @@ -207,26 +222,39 @@ func (a *App) ReloadPlugins() error { log.Print("[plugins] reload requested") a.plugins.CloseRuntimes() - appCfg, _ := config.LoadAppConfig() - if appCfg == nil { - appCfg = config.DefaultAppConfig() - } - enabledSet := make(map[string]bool) - for _, name := range appCfg.EnabledPlugins { - enabledSet[name] = true - } a.plugins.Discover() - a.plugins.InitRuntimes() + + appCfg, _ := config.LoadAppConfig() + a.plugins.SyncConfig(appCfg) // Apply enable/disable state from config: deactivate everything not in enabled set for _, p := range a.plugins.Plugins() { - if !enabledSet[p.Meta.Name] { + if !p.Active || !p.Installed { a.plugins.DeactivatePlugin(p.Meta.Name) } } + a.plugins.InitRuntimes() a.plugins.CallInitHooks() a.plugins.StartSchedulers() log.Print("[plugins] reload complete") return nil } + +// InstallPlugin creates plugin's database tables and defaults via on_install hook. +// Does NOT activate the plugin — use SetPluginEnabled after. +func (a *App) InstallPlugin(name string) error { + if a.plugins == nil { + return fmt.Errorf("plugin manager not ready") + } + return a.plugins.Install(name) +} + +// UninstallPlugin drops plugin's database tables and cleans data via on_uninstall hook. +// Disables the plugin first if active. Does NOT delete plugin files from disk. +func (a *App) UninstallPlugin(name string) error { + if a.plugins == nil { + return fmt.Errorf("plugin manager not ready") + } + return a.plugins.Uninstall(name) +} diff --git a/contrib/plugins/calendar/main.lua b/contrib/plugins/calendar/main.lua index 98777f7..fbfa82b 100644 --- a/contrib/plugins/calendar/main.lua +++ b/contrib/plugins/calendar/main.lua @@ -649,10 +649,9 @@ end -- Hooks -------------------------------------------------------------------------------- -function on_init() - print("Calendar: on_init — running migration") +function on_install() + print("Calendar: on_install — creating tables") - -- Run migration SQL local ok, err = pcall(function() verstak.db.exec([[ CREATE TABLE IF NOT EXISTS categories ( @@ -696,13 +695,40 @@ function on_init() if not ok then print("Calendar: migration error: " .. tostring(err)) + error(err) else print("Calendar: migration complete") end - -- Ensure default categories + -- Insert default categories M.ensure_categories() + print("Calendar: install complete") +end + +function on_uninstall() + print("Calendar: on_uninstall — dropping tables") + + local ok, err = pcall(function() + verstak.db.exec("DROP TABLE IF EXISTS events") + verstak.db.exec("DROP TABLE IF EXISTS categories") + end) + + if not ok then + print("Calendar: uninstall error: " .. tostring(err)) + else + print("Calendar: tables dropped") + end + + -- Clean up config + pcall(verstak.config.set, "categories", nil) + + print("Calendar: uninstall complete") +end + +function on_init() + print("Calendar: on_init — registering API") + -- Register global API for panel access _G.calendar = M diff --git a/contrib/plugins/calendar/panels/calendar.html b/contrib/plugins/calendar/panels/calendar.html index b08cdd2..4eed23c 100644 --- a/contrib/plugins/calendar/panels/calendar.html +++ b/contrib/plugins/calendar/panels/calendar.html @@ -3,143 +3,983 @@
-