feat: add shelly plugin (#2)
* feat: add shelly plugin * docs: document click action * add license * feat: add setting to hide when there are no updates * remove some tags * address tags feedback * Update tags in plugin.toml for clarity --------- Co-authored-by: Lemmy <studio@quadbyte.net>
This commit is contained in:
@@ -0,0 +1,28 @@
|
|||||||
|
# Shelly
|
||||||
|
|
||||||
|
Shelly is a plugin that uses the [Shelly Arch Package Manager](https://github.com/Seafoam-Labs/Shelly-ALPM) to display package update information in a bar widget.
|
||||||
|
|
||||||
|
## Plugin
|
||||||
|
|
||||||
|
| Field | Value |
|
||||||
|
| ------- | --------------------------------------- |
|
||||||
|
| ID | `joshuaslate/shelly` |
|
||||||
|
| Entries | Service: `poller`; bar widget: `shelly` |
|
||||||
|
|
||||||
|
## Requirements
|
||||||
|
|
||||||
|
Install the Shelly Arch Package Manager from the [AUR](https://aur.archlinux.org/packages/shelly).
|
||||||
|
|
||||||
|
Test that it works by running `shelly check-updates` in a terminal. If it returns a list of packages, then it is working correctly.
|
||||||
|
|
||||||
|
## Settings
|
||||||
|
|
||||||
|
| Setting | Type | Default | Description |
|
||||||
|
| ---------------------- | -------- | ------------ | -------------------------------------------------------------------------------------------------- |
|
||||||
|
| `interval` | `int` | `300` | The interval (in seconds) between update checks |
|
||||||
|
| `notify` | `bool` | `false` | Whether or not you want to receive notifications when there are new package updates available |
|
||||||
|
| `color` | `color` | `on_surface` | The text color for the bar widget |
|
||||||
|
| `glyph_color` | `color` | `on_surface` | The color of the glyph on the bar widget |
|
||||||
|
| `glyph` | `glyph` | `package` | Bar widget icon. |
|
||||||
|
| `click_action` | `select` | `open_gui` | The action to perform when the bar widget is clicked. Options: `open_gui`, `open_updater`, `none`. |
|
||||||
|
| `hide_when_up_to_date` | `bool` | `false` | Whether or not to hide the bar widget when there are no package updates available |
|
||||||
@@ -0,0 +1,74 @@
|
|||||||
|
id = "joshuaslate/shelly"
|
||||||
|
name = "Shelly"
|
||||||
|
icon = "package"
|
||||||
|
version = "1.0.0"
|
||||||
|
min_noctalia = "5.0.0"
|
||||||
|
license = "MIT"
|
||||||
|
author = "joshuaslate"
|
||||||
|
dependencies = ["shelly"]
|
||||||
|
description = "A plugin that provides a widget for displaying system update information."
|
||||||
|
tags = ["system", "arch"]
|
||||||
|
deprecated = false
|
||||||
|
|
||||||
|
[[setting]]
|
||||||
|
key = "interval"
|
||||||
|
type = "int"
|
||||||
|
label_key = "settings.interval.label"
|
||||||
|
description_key = "settings.interval.description"
|
||||||
|
default = 300
|
||||||
|
min = 0
|
||||||
|
|
||||||
|
[[setting]]
|
||||||
|
key = "notify"
|
||||||
|
type = "bool"
|
||||||
|
label_key = "settings.notify.label"
|
||||||
|
description_key = "settings.notify.description"
|
||||||
|
default = false
|
||||||
|
|
||||||
|
[[service]]
|
||||||
|
id = "update_poller"
|
||||||
|
entry = "poller.luau"
|
||||||
|
|
||||||
|
[[widget]]
|
||||||
|
id = "shelly"
|
||||||
|
entry = "widget.luau"
|
||||||
|
|
||||||
|
[[widget.setting]]
|
||||||
|
key = "hide_when_up_to_date"
|
||||||
|
type = "bool"
|
||||||
|
label_key = "settings.hide_when_up_to_date.label"
|
||||||
|
description_key = "settings.hide_when_up_to_date.description"
|
||||||
|
default = false
|
||||||
|
|
||||||
|
[[widget.setting]]
|
||||||
|
key = "color"
|
||||||
|
type = "color"
|
||||||
|
label_key = "settings.color.label"
|
||||||
|
description_key = "settings.color.description"
|
||||||
|
default = "on_surface"
|
||||||
|
|
||||||
|
[[widget.setting]]
|
||||||
|
key = "glyph"
|
||||||
|
type = "glyph"
|
||||||
|
label_key = "settings.glyph.label"
|
||||||
|
description_key = "settings.glyph.description"
|
||||||
|
default = "package"
|
||||||
|
|
||||||
|
[[widget.setting]]
|
||||||
|
key = "glyph_color"
|
||||||
|
type = "color"
|
||||||
|
label_key = "settings.glyph_color.label"
|
||||||
|
description_key = "settings.glyph_color.description"
|
||||||
|
default = "on_surface"
|
||||||
|
|
||||||
|
[[widget.setting]]
|
||||||
|
key = "click_action"
|
||||||
|
type = "select"
|
||||||
|
label_key = "settings.click_action.label"
|
||||||
|
description_key = "settings.click_action.description"
|
||||||
|
default = "open_gui"
|
||||||
|
options = [
|
||||||
|
{ value = "none", label_key = "settings.click_action.options.none" },
|
||||||
|
{ value = "open_gui", label_key = "settings.click_action.options.open_gui" },
|
||||||
|
{ value = "open_updater", label_key = "settings.click_action.options.open_updater" }
|
||||||
|
]
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
--!nonstrict
|
||||||
|
|
||||||
|
type Update = { Name: string, Version: string, OldVersion: string?, DownloadSize: string? }
|
||||||
|
|
||||||
|
type UpdateResult = {
|
||||||
|
Packages: { [number]: Update },
|
||||||
|
Aur: { [number]: Update },
|
||||||
|
Flatpak: { [number]: Update },
|
||||||
|
}
|
||||||
|
|
||||||
|
local updates: UpdateResult = { Packages = {}, Aur = {}, Flatpak = {} }
|
||||||
|
local updateError: string | nil = nil
|
||||||
|
local updateInterval = (noctalia.getConfig("interval") or 300)*1000
|
||||||
|
local isPolling = false
|
||||||
|
|
||||||
|
noctalia.setUpdateInterval(updateInterval)
|
||||||
|
|
||||||
|
function refresh()
|
||||||
|
isPolling = true
|
||||||
|
|
||||||
|
noctalia.runAsync("shelly check-updates --json", function(result)
|
||||||
|
isPolling = false
|
||||||
|
|
||||||
|
if result.exitCode ~= 0 then
|
||||||
|
updateError = result.stderr
|
||||||
|
noctalia.state.set("updates", nil)
|
||||||
|
noctalia.state.set("update_error", updateError)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local decoded = noctalia.json.decode(result.stdout)
|
||||||
|
if type(decoded) ~= "table" then
|
||||||
|
updateError = noctalia.tr("bar.tooltip.error.decode_json")
|
||||||
|
noctalia.state.set("update_error", updateError)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
updates = {
|
||||||
|
Packages = decoded.Packages or {},
|
||||||
|
Aur = decoded.Aur or {},
|
||||||
|
Flatpak = decoded.Flatpak or {},
|
||||||
|
}
|
||||||
|
|
||||||
|
noctalia.state.set("updates", updates)
|
||||||
|
noctalia.state.set("update_error", nil)
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
function update()
|
||||||
|
if isPolling then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
refresh()
|
||||||
|
end
|
||||||
|
|
||||||
|
refresh()
|
||||||
Binary file not shown.
|
After Width: | Height: | Size: 42 KiB |
@@ -0,0 +1,68 @@
|
|||||||
|
{
|
||||||
|
"title": "Shelly",
|
||||||
|
"notify": {
|
||||||
|
"new_updates": {
|
||||||
|
"title": "New Updates Available",
|
||||||
|
"description": "There are {count} new updates available for your system."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"bar": {
|
||||||
|
"text": {
|
||||||
|
"error": "?",
|
||||||
|
"updates": {
|
||||||
|
"one": "{count} Update",
|
||||||
|
"other": "{count} Updates"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"tooltip": {
|
||||||
|
"aur_title": "AUR",
|
||||||
|
"flatpak_title": "Flatpak",
|
||||||
|
"packages_title": "Packages",
|
||||||
|
"no_updates": "System is up to date",
|
||||||
|
"error": {
|
||||||
|
"decode_json": "Failed to decode output from `shelly check-updates --json`"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"click_handler": {
|
||||||
|
"error": {
|
||||||
|
"missing_gui": "Shelly GUI is not installed. Please install it to use this feature.",
|
||||||
|
"missing_cli": "Shelly CLI is not installed. Please install it to use this feature."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"interval": {
|
||||||
|
"label": "Refresh Seconds",
|
||||||
|
"description": "How often the service checks for updates in the background."
|
||||||
|
},
|
||||||
|
"notify": {
|
||||||
|
"label": "Notify",
|
||||||
|
"description": "Whether to show a notification when new updates are available."
|
||||||
|
},
|
||||||
|
"click_action": {
|
||||||
|
"label": "Click Action",
|
||||||
|
"description": "What happens when you click on the bar.",
|
||||||
|
"options": {
|
||||||
|
"none": "Nothing",
|
||||||
|
"open_gui": "Open Shelly GUI",
|
||||||
|
"open_updater": "Start Update in Terminal"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"hide_when_up_to_date": {
|
||||||
|
"label": "Hide When Up-to-Date",
|
||||||
|
"description": "Whether to hide the bar when there are no updates available."
|
||||||
|
},
|
||||||
|
"color": {
|
||||||
|
"label": "Color",
|
||||||
|
"description": "The color of the bar text."
|
||||||
|
},
|
||||||
|
"glyph": {
|
||||||
|
"label": "Glyph",
|
||||||
|
"description": "The glyph shown before the label."
|
||||||
|
},
|
||||||
|
"glyph_color": {
|
||||||
|
"label": "Glyph Color",
|
||||||
|
"description": "The color of the glyph."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,116 @@
|
|||||||
|
--!nonstrict
|
||||||
|
local glyph = barWidget.getConfig("glyph")
|
||||||
|
local color = barWidget.getConfig("color") or "on_surface"
|
||||||
|
local glyphColor = barWidget.getConfig("glyph_color") or color
|
||||||
|
local updateError = noctalia.state.get("update_error")
|
||||||
|
local notifyOnNewUpdates = barWidget.getConfig("notify")
|
||||||
|
local hideWhenUpToDate = barWidget.getConfig("hide_when_up_to_date")
|
||||||
|
local click_action = barWidget.getConfig("click_action") or "open_gui"
|
||||||
|
local updates = noctalia.state.get("updates") or { Packages = {}, Aur = {}, Flatpak = {} }
|
||||||
|
|
||||||
|
local function countUpdates(scopedUpdates)
|
||||||
|
return #scopedUpdates.Packages + #scopedUpdates.Aur + #scopedUpdates.Flatpak
|
||||||
|
end
|
||||||
|
|
||||||
|
local function getUpdateLabel(update)
|
||||||
|
if update.OldVersion then
|
||||||
|
return string.format("%s → %s", update.OldVersion, update.Version)
|
||||||
|
else
|
||||||
|
return update.Version
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function appendUpdateSection(rows, title, list)
|
||||||
|
if #list == 0 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
table.insert(rows, {
|
||||||
|
key = title,
|
||||||
|
value = string.format("%d", #list),
|
||||||
|
})
|
||||||
|
|
||||||
|
for _, pkg in ipairs(list) do
|
||||||
|
table.insert(rows, {
|
||||||
|
key = " " .. pkg.Name,
|
||||||
|
value = getUpdateLabel(pkg),
|
||||||
|
})
|
||||||
|
|
||||||
|
if pkg.DownloadSize then
|
||||||
|
table.insert(rows, {
|
||||||
|
key = "",
|
||||||
|
value = pkg.DownloadSize,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function updateTooltip(count)
|
||||||
|
if updateError then
|
||||||
|
barWidget.setTooltip(updateError)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if count == 0 then
|
||||||
|
barWidget.setTooltip(noctalia.tr("bar.tooltip.no_updates"))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local rows = {}
|
||||||
|
|
||||||
|
appendUpdateSection(rows, noctalia.tr("bar.tooltip.packages_title"), updates.Packages)
|
||||||
|
appendUpdateSection(rows, noctalia.tr("bar.tooltip.aur_title"), updates.Aur)
|
||||||
|
appendUpdateSection(rows, noctalia.tr("bar.tooltip.flatpak_title"), updates.Flatpak)
|
||||||
|
|
||||||
|
barWidget.setTooltip(rows)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function render()
|
||||||
|
local container = barWidget.isVertical() and ui.column or ui.row
|
||||||
|
|
||||||
|
local count = countUpdates(updates)
|
||||||
|
|
||||||
|
barWidget.render(container({ gap = 6, align = "center", visible = not hideWhenUpToDate or count > 0 }, {
|
||||||
|
ui.glyph({ name = glyph, size = 14, color = glyphColor, visible = glyph ~= "" }),
|
||||||
|
ui.label({ text = noctalia.trp("bar.text.updates", count), color = color }),
|
||||||
|
}))
|
||||||
|
|
||||||
|
updateTooltip(count)
|
||||||
|
end
|
||||||
|
|
||||||
|
noctalia.state.watch("updates", function(value)
|
||||||
|
local prevCount = countUpdates(updates)
|
||||||
|
local newCount = countUpdates(value)
|
||||||
|
|
||||||
|
updates = value
|
||||||
|
|
||||||
|
if notifyOnNewUpdates and newCount > prevCount then
|
||||||
|
noctalia.notify(noctalia.tr("notify.new_updates.title"), noctalia.trp("notify.new_updates.description", newCount))
|
||||||
|
end
|
||||||
|
|
||||||
|
render()
|
||||||
|
end)
|
||||||
|
|
||||||
|
function onClick()
|
||||||
|
if click_action == "open_gui" then
|
||||||
|
local cmd = "shelly-ui"
|
||||||
|
|
||||||
|
if not noctalia.commandExists(cmd) then
|
||||||
|
noctalia.notifyError("Shelly", noctalia.tr("bar.click_handler.error.missing_gui"))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
noctalia.runAsync(cmd)
|
||||||
|
elseif click_action == "open_updater" then
|
||||||
|
local cmd = "shelly"
|
||||||
|
|
||||||
|
if not noctalia.commandExists(cmd) then
|
||||||
|
noctalia.notifyError("Shelly", noctalia.tr("bar.click_handler.error.missing_cli"))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
noctalia.runInTerminal(cmd .. " upgrade-all")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
render()
|
||||||
Reference in New Issue
Block a user