fix(arch-updater): tighten package list UI and fix Dismiss/Update panel behavior (#289)

* fix(arch-updater): tighten package list spacing and icon size

* fix(arch-updater): make Dismiss actually clear the pending list

* fix(arch-updater): make hitting update close the panel

* feat(arch-updater): add per-source icons to the package list header

* feat(arch-updater): add an activity graph to the panel

Tracks the pending-update count across recent checks and when the last
update ran, persisted to disk so it survives restarts. Off also stops
recording history, not just hiding it.

* feat(arch-updater): show per-point detail on activity graph hover

ui.graph has no pointer props of its own, so a row of ghost buttons
sits under the line as per-point hit targets, each with a native
tooltip. History entries now carry a timestamp and whether the check
followed an update run, so hovering a point says when it happened and
either its pending count or "Updated".

* fix(arch-updater): load activity history at startup, not on first check

loadHistoryState() only ran lazily inside recordCheck/recordUpdateRun,
so a freshly started service published an empty history until a check
completed, hiding the graph even when prior sessions had data on disk.

* fix(arch-updater): render activity graph with sharp points, not curves
This commit is contained in:
Yuuto
2026-08-07 22:27:08 -04:00
committed by GitHub
parent 41a5373cd0
commit 4fcd5f1686
7 changed files with 398 additions and 18 deletions
+8 -2
View File
@@ -47,8 +47,8 @@ The panel groups pending packages by source (Pacman, AUR, Flatpak). Click a
source row to expand it into its packages. Each package row has a copy source row to expand it into its packages. Each package row has a copy
button (name and versions) and an open button (its page on archlinux.org, button (name and versions) and an open button (its page on archlinux.org,
the AUR, or Flathub). **Check Updates** queries all sources, **Update** opens the AUR, or Flathub). **Check Updates** queries all sources, **Update** opens
a terminal running the upgrade, **Dismiss** keeps the numbers but returns the a terminal running the upgrade, **Dismiss** clears the pending list and
bar glyph to its resting colour. closes the panel, returning the bar glyph to its resting colour.
Type `/arch` in the launcher for quick actions (check, update, open news), or Type `/arch` in the launcher for quick actions (check, update, open news), or
`/arch <text>` to fuzzy-search the packages from the last check. Activating a `/arch <text>` to fuzzy-search the packages from the last check. Activating a
@@ -78,6 +78,10 @@ Not in the v4 plugin:
- **A generic package-page link** (`archlinux.org/packages`, - **A generic package-page link** (`archlinux.org/packages`,
`aur.archlinux.org`, `flathub.org`) instead of hardcoded per-repo mirror `aur.archlinux.org`, `flathub.org`) instead of hardcoded per-repo mirror
URLs, so it stays correct across Arch-based distros. URLs, so it stays correct across Arch-based distros.
- **An activity graph.** A small trend line of the pending-update count
across the most recent checks, plus when you last ran an update. Persisted
to disk so it survives restarts. On by default, and turning it off also
stops recording the history, not just hiding it.
## Settings ## Settings
@@ -92,6 +96,8 @@ Not in the v4 plugin:
| `show_download_size` | `bool` | `true` | Show the estimated pacman download size (`pacman -Si`) in the panel. | | `show_download_size` | `bool` | `true` | Show the estimated pacman download size (`pacman -Si`) in the panel. |
| `check_arch_news` | `bool` | `true` | Check the Arch Linux news feed and flag unread posts. | | `check_arch_news` | `bool` | `true` | Check the Arch Linux news feed and flag unread posts. |
| `check_reboot_needed` | `bool` | `true` | Flag when the running kernel is no longer installed on disk. | | `check_reboot_needed` | `bool` | `true` | Flag when the running kernel is no longer installed on disk. |
| `show_activity_graph` | `bool` | `true` | Track and show the pending-update trend and last-update time in the panel. Off also stops recording history. |
| `activity_history_length` | `int` | `10` | How many of the most recent checks to keep for the activity graph. |
| `terminal` | `string` | *(empty)* | Terminal command for the update run, e.g. `kitty`. Empty uses Noctalia's detection. | | `terminal` | `string` | *(empty)* | Terminal command for the update run, e.g. `kitty`. Empty uses Noctalia's detection. |
| `assume_yes` | `bool` | `false` | Pass `--noconfirm` / `-y` so package managers do not ask for confirmation. | | `assume_yes` | `bool` | `false` | Pass `--noconfirm` / `-y` so package managers do not ask for confirmation. |
| `update_cmd` | `string` | *(empty)* | Full override for the update command. Empty builds it from the settings above. | | `update_cmd` | `string` | *(empty)* | Full override for the update command. Empty builds it from the settings above. |
+194 -5
View File
@@ -6,7 +6,7 @@
-- --
-- "Check Updates" only queries pacman, the AUR helper and (optionally) -- "Check Updates" only queries pacman, the AUR helper and (optionally)
-- Flatpak. Only then do "Update" (open a terminal and run the upgrade) and -- Flatpak. Only then do "Update" (open a terminal and run the upgrade) and
-- "Dismiss" (keep the numbers, quiet the bar) light up. -- "Dismiss" (clear the pending list and close the panel) light up.
local STATE_KEY = "arch_state" local STATE_KEY = "arch_state"
local REQUEST_KEY = "arch_request" local REQUEST_KEY = "arch_request"
@@ -15,6 +15,7 @@ local snapshot = nil
local expanded = {} -- source key -> the package list is open local expanded = {} -- source key -> the package list is open
local hoverKey = nil -- package row currently under the pointer local hoverKey = nil -- package row currently under the pointer
local hoverText = "" -- what the detail line shows local hoverText = "" -- what the detail line shows
local activityHoverIndex = nil -- activity graph point currently under the pointer
local listOpen = false -- at least one source is expanded this render local listOpen = false -- at least one source is expanded this render
local render local render
@@ -116,6 +117,12 @@ local function sourceLabel(key, entry)
return tr("source." .. key) return tr("source." .. key)
end end
local SOURCE_GLYPHS = { pacman = "package", aur = "cloud", flatpak = "app-window" }
local function sourceGlyph(key)
return SOURCE_GLYPHS[key] or "package"
end
-- pacman, then the AUR helper, then Flatpak. Only sources with pending -- pacman, then the AUR helper, then Flatpak. Only sources with pending
-- packages, biggest first. -- packages, biggest first.
local function orderedSources() local function orderedSources()
@@ -175,13 +182,15 @@ local function packageRow(sourceKey, index, item)
})) }))
end end
table.insert(children, ui.button({ table.insert(children, ui.button({
glyph = "copy", variant = "ghost", controlSize = "sm", tooltip = tr("tip_copy"), glyph = "copy", variant = "ghost", controlSize = "sm", width = 22, height = 22, glyphSize = 12,
tooltip = tr("tip_copy"),
onClick = function() onClick = function()
noctalia.copyToClipboard(detailFor(item), "text/plain") noctalia.copyToClipboard(detailFor(item), "text/plain")
end, end,
})) }))
table.insert(children, ui.button({ table.insert(children, ui.button({
glyph = "external-link", variant = "ghost", controlSize = "sm", tooltip = tr("tip_open_page"), glyph = "external-link", variant = "ghost", controlSize = "sm", width = 22, height = 22, glyphSize = 12,
tooltip = tr("tip_open_page"),
onClick = function() onClick = function()
openPackage(sourceKey, item.name) openPackage(sourceKey, item.name)
end, end,
@@ -224,6 +233,7 @@ local function sourceRows()
end end
table.insert(rows, ui.row(header, { table.insert(rows, ui.row(header, {
ui.glyph({ name = #names == 0 and "point" or (open and "chevron-down" or "chevron-right"), size = 12, color = "on_surface_variant" }), ui.glyph({ name = #names == 0 and "point" or (open and "chevron-down" or "chevron-right"), size = 12, color = "on_surface_variant" }),
ui.glyph({ name = sourceGlyph(source.key), size = 13, color = "on_surface_variant" }),
ui.label({ text = sourceLabel(source.key, source.entry), color = "on_surface", flexGrow = 1 }), ui.label({ text = sourceLabel(source.key, source.entry), color = "on_surface", flexGrow = 1 }),
ui.label({ text = tostring(source.entry.n), color = "primary", fontWeight = "bold" }), ui.label({ text = tostring(source.entry.n), color = "primary", fontWeight = "bold" }),
})) }))
@@ -289,12 +299,182 @@ local function extras()
return lines return lines
end end
-- Normalizes the pending-count history to 0..1 for ui.graph, relative to the
-- min/max in the window (not a fixed scale, since pending counts vary wildly
-- between systems). A flat window (min == max, e.g. every check so far found
-- the same count) centers the line at 0.5 instead of pinning it to the top
-- edge, where it would be indistinguishable from the box border.
local function activityValues(history)
local minN, maxN = tonumber(history[1].n) or 0, tonumber(history[1].n) or 0
for _, entry in ipairs(history) do
local n = tonumber(entry.n) or 0
if n < minN then
minN = n
end
if n > maxN then
maxN = n
end
end
local range = maxN - minN
local values = {}
for _, entry in ipairs(history) do
local n = tonumber(entry.n) or 0
table.insert(values, range > 0 and (n - minN) / range or 0.5)
end
return values
end
local ACTIVITY_GRAPH_SUBDIVISIONS = 8
local function upsampleLinear(values, subdivisions)
if #values < 2 or subdivisions <= 1 then
return values
end
local out = {}
for i = 1, #values - 1 do
local a, b = values[i], values[i + 1]
for s = 0, subdivisions - 1 do
table.insert(out, a + (b - a) * (s / subdivisions))
end
end
table.insert(out, values[#values])
return out
end
local function padGraphLookbehind(values)
if #values == 0 then
return values
end
local out = { values[1], values[1] }
for _, v in ipairs(values) do
table.insert(out, v)
end
return out
end
-- "2 hours ago", "3 days ago", etc. nil for entries migrated from the old
-- history format, which never recorded a timestamp.
local function relativeTime(at)
local t = tonumber(at)
if t == nil then
return nil
end
local diff = os.time() - t
if diff < 60 then
return tr("activity.just_now")
elseif diff < 3600 then
local m = math.floor(diff / 60)
return noctalia.trp("activity.minutes_ago", m, { count = m })
elseif diff < 86400 then
local h = math.floor(diff / 3600)
return noctalia.trp("activity.hours_ago", h, { count = h })
else
local d = math.floor(diff / 86400)
return noctalia.trp("activity.days_ago", d, { count = d })
end
end
-- "Updated · 2 hours ago" for the check that verified an update run, else
-- "3 pending updates · 2 hours ago". Shared by the hover tooltip and the
-- top-right caption so both describe a point the same way.
local function describeEntry(entry)
local n = tonumber(entry.n) or 0
local text = entry.afterUpdate == true and tr("activity.updated")
or noctalia.trp("activity.pending_at", n, { count = n })
local when = relativeTime(entry.at)
if when ~= nil then
text = text .. " · " .. when
end
return text
end
-- ui.graph takes no pointer props of its own (only row/column/box/image/button
-- do), so per-point hover is a row of hit targets placed right under the
-- line. Each is a ghost button so it can carry a native tooltip at the
-- pointer, not just a box for the hit test. It cannot highlight the point on
-- the line itself, only drive the tooltip and the caption above it.
--
-- Real points sit at (k-1)/(#history-1) of the width (see
-- padGraphLookbehind), i.e. #history-1 equal gaps, not #history equal slots
-- - so this builds one equal-width segment per gap rather than per entry,
-- ending each segment exactly on the point at its right edge. That leaves
-- entry 1 (at the left edge, with no gap before it) without its own hover
-- zone, but keeps every other spike landing right at the end of its segment
-- instead of drifting toward the start of an oversized one.
local function activityHoverRow(history)
local segments = {}
for i = 2, #history do
segments[i - 1] = ui.button({
key = "activity-hit-" .. i,
variant = "ghost",
flexGrow = 1,
height = 12,
tooltip = describeEntry(history[i]),
onHover = function(state)
if state == "true" then
activityHoverIndex = i
elseif activityHoverIndex == i then
activityHoverIndex = nil
else
return
end
render()
end,
})
end
return ui.row({ key = "activity-hits", gap = 1 }, segments)
end
-- A small trend graph of pending-update counts across recent checks, plus
-- when the last update ran (or, while hovering a point, that point's own
-- description). Off entirely when show_activity_graph is off, and hidden
-- until there is enough history to draw a line.
local function activitySection()
if snapshot == nil or noctalia.getConfig("show_activity_graph") ~= true then
return nil
end
local history = type(snapshot.history) == "table" and snapshot.history or {}
if #history < 2 then
return nil
end
local hoveredEntry = activityHoverIndex ~= nil and history[activityHoverIndex] or nil
local caption
if hoveredEntry ~= nil then
caption = describeEntry(hoveredEntry)
else
local lastUpdateAt = tonumber(snapshot.lastUpdateAt)
if lastUpdateAt == nil then
caption = tr("activity.never_updated")
else
local days = math.floor((os.time() - lastUpdateAt) / 86400)
caption = days <= 0 and tr("activity.updated_today")
or noctalia.trp("activity.updated_days_ago", days, { count = days })
end
end
return ui.column({ key = "activity", gap = 4 }, {
ui.row({ justify = "space_between", align = "center" }, {
ui.label({ text = tr("activity.title"), fontSize = 11, fontWeight = "bold", color = "on_surface_variant" }),
ui.label({ text = caption, fontSize = 10, color = "on_surface_variant" }),
}),
ui.graph({
values = padGraphLookbehind(upsampleLinear(activityValues(history), ACTIVITY_GRAPH_SUBDIVISIONS)),
color = "primary",
fillOpacity = 0.15,
lineWidth = 2,
height = 36,
}),
activityHoverRow(history),
})
end
local function body() local function body()
local children = {} local children = {}
local rows = sourceRows() local rows = sourceRows()
if #rows > 0 then if #rows > 0 then
table.insert(children, ui.scroll({ key = "sources", flexGrow = 1, gap = 6 }, rows)) table.insert(children, ui.scroll({ key = "sources", flexGrow = 1, gap = 3 }, rows))
else else
table.insert(children, ui.spacer({ key = "filler", flexGrow = 1 })) table.insert(children, ui.spacer({ key = "filler", flexGrow = 1 }))
end end
@@ -323,6 +503,11 @@ local function body()
})) }))
end end
local activity = activitySection()
if activity ~= nil then
table.insert(children, activity)
end
return children return children
end end
@@ -389,9 +574,10 @@ render = function()
}), }),
ui.button({ ui.button({
key = "dismiss" .. (hasUpdates and "" or "-off"), key = "dismiss" .. (hasUpdates and "" or "-off"),
text = tr("action_dismiss"), variant = "ghost", enabled = hasUpdates and snapshot.dismissed ~= true, text = tr("action_dismiss"), variant = "ghost", enabled = hasUpdates,
onClick = function() onClick = function()
request("dismiss") request("dismiss")
panel.close()
end, end,
}), }),
ui.button({ ui.button({
@@ -400,6 +586,7 @@ render = function()
tooltip = tr("tip_update"), tooltip = tr("tip_update"),
onClick = function() onClick = function()
request("update") request("update")
panel.close()
end, end,
}), }),
})) }))
@@ -413,6 +600,7 @@ function onOpen(_context)
expanded = {} expanded = {}
hoverKey = nil hoverKey = nil
hoverText = "" hoverText = ""
activityHoverIndex = nil
render() render()
end end
@@ -424,6 +612,7 @@ noctalia.state.watch(STATE_KEY, function(value)
expanded = {} expanded = {}
hoverKey = nil hoverKey = nil
hoverText = "" hoverText = ""
activityHoverIndex = nil
end end
snapshot = value snapshot = value
render() render()
+20 -1
View File
@@ -1,6 +1,6 @@
id = "yuuto/arch-updater" id = "yuuto/arch-updater"
name = "Arch Updater" name = "Arch Updater"
version = "1.0.1" version = "1.1.0"
plugin_api = 9 plugin_api = 9
author = "yuuto" author = "yuuto"
license = "MIT" license = "MIT"
@@ -86,6 +86,25 @@ label_key = "settings.check_reboot_needed.label"
description_key = "settings.check_reboot_needed.description" description_key = "settings.check_reboot_needed.description"
default = true default = true
# ── Activity ─────────────────────────────────────────────────────────────────
[[setting]]
key = "show_activity_graph"
type = "bool"
label_key = "settings.show_activity_graph.label"
description_key = "settings.show_activity_graph.description"
default = true
[[setting]]
key = "activity_history_length"
type = "int"
label_key = "settings.activity_history_length.label"
description_key = "settings.activity_history_length.description"
default = 10
min = 3
max = 30
visible_when = { key = "show_activity_graph", values = ["true"] }
# ── Update run ─────────────────────────────────────────────────────────────── # ── Update run ───────────────────────────────────────────────────────────────
[[setting]] [[setting]]
+106 -9
View File
@@ -4,8 +4,8 @@
-- --
-- state "arch_state" = { nonce, phase, step, total, pacman, aur, -- state "arch_state" = { nonce, phase, step, total, pacman, aur,
-- flatpak, downloadSizeMiB, rebootRecommended, -- flatpak, downloadSizeMiB, rebootRecommended,
-- newsUnread, newsLatestTitle, dismissed, err, -- newsUnread, newsLatestTitle, err,
-- checkedAt, ignoredCount } -- checkedAt, ignoredCount, history, lastUpdateAt }
-- requests "arch_request" = { nonce, action } -- check|update|dismiss -- requests "arch_request" = { nonce, action } -- check|update|dismiss
-- --
-- Checking runs pacman, then the AUR helper, then Flatpak, then (if pacman -- Checking runs pacman, then the AUR helper, then Flatpak, then (if pacman
@@ -20,6 +20,7 @@ local REQUEST_KEY = "arch_request"
local NEWS_FILE = "news_state.json" local NEWS_FILE = "news_state.json"
local NEWS_URL = "https://archlinux.org/feeds/news/" local NEWS_URL = "https://archlinux.org/feeds/news/"
local NEWS_PAGE = "https://archlinux.org/news/" local NEWS_PAGE = "https://archlinux.org/news/"
local HISTORY_FILE = "history_state.json"
local CHECK_TIMEOUT_MS = 45000 -- pacman/AUR/flatpak checks: each may sync a mirror local CHECK_TIMEOUT_MS = 45000 -- pacman/AUR/flatpak checks: each may sync a mirror
local SIZE_TIMEOUT_MS = 20000 -- pacman -Si: local db, no mirror sync local SIZE_TIMEOUT_MS = 20000 -- pacman -Si: local db, no mirror sync
@@ -40,7 +41,6 @@ local newsUnread = 0
local newsLatestTitle = nil local newsLatestTitle = nil
local newsItems = {} local newsItems = {}
local newsLastSeenGuid = nil local newsLastSeenGuid = nil
local dismissed = false
local errMsg = nil local errMsg = nil
local checkedAt = "" local checkedAt = ""
local stateNonce = 0 local stateNonce = 0
@@ -55,6 +55,10 @@ local startupTicks = 0
local sinceNewsCheck = 0 local sinceNewsCheck = 0
local newsStateLoaded = false local newsStateLoaded = false
local newsDirty = false local newsDirty = false
local history = {} -- { n, at, afterUpdate } per check, oldest first, trimmed to activity_history_length
local lastUpdateAt = nil -- os.time() of the last update run that finished
local historyStateLoaded = false
local checkIsPostUpdate = false -- next finished check followed an update run
local startCheck local startCheck
local checkNews local checkNews
@@ -197,10 +201,11 @@ local function publish()
rebootRecommended = rebootRecommended, rebootRecommended = rebootRecommended,
newsUnread = newsUnread, newsUnread = newsUnread,
newsLatestTitle = newsLatestTitle, newsLatestTitle = newsLatestTitle,
dismissed = dismissed,
err = errMsg, err = errMsg,
checkedAt = checkedAt, checkedAt = checkedAt,
ignoredCount = #ignoreList(), ignoredCount = #ignoreList(),
history = history,
lastUpdateAt = lastUpdateAt,
flatpakEnabled = cfg("flatpak_enabled") == true, flatpakEnabled = cfg("flatpak_enabled") == true,
}) })
end end
@@ -211,6 +216,7 @@ local checkFlatpak
local checkSize local checkSize
local checkReboot local checkReboot
local finishCheck local finishCheck
local recordCheck
local function failCheck(message) local function failCheck(message)
phase = "error" phase = "error"
@@ -423,9 +429,9 @@ finishCheck = function()
total = sources.pacman.n + sources.aur.n + sources.flatpak.n total = sources.pacman.n + sources.aur.n + sources.flatpak.n
step = "" step = ""
phase = total > 0 and "ready" or "clean" phase = total > 0 and "ready" or "clean"
dismissed = false
checkedAt = noctalia.formatTime("%H:%M") checkedAt = noctalia.formatTime("%H:%M")
sinceCheck = 0 sinceCheck = 0
recordCheck()
publish() publish()
if total > 0 and cfg("notify_on_updates") == true then if total > 0 and cfg("notify_on_updates") == true then
noctalia.notify(tr("title"), noctalia.trp("notify_updates", total, { count = total })) noctalia.notify(tr("title"), noctalia.trp("notify_updates", total, { count = total }))
@@ -469,6 +475,92 @@ local function saveNewsState()
end end
end end
-- ── Activity history ─────────────────────────────────────────────────────────
local function historyStatePath()
local dir, err = noctalia.pluginDataDir()
if dir == nil then
noctalia.log("arch-updater: cannot resolve plugin data dir: " .. tostring(err))
return nil
end
return dir .. "/" .. HISTORY_FILE
end
local function loadHistoryState()
if historyStateLoaded then
return
end
historyStateLoaded = true
local path = historyStatePath()
local encoded = path ~= nil and noctalia.readFile(path) or nil
local ok, decoded = pcall(function()
return encoded ~= nil and noctalia.json.decode(encoded) or nil
end)
if ok and type(decoded) == "table" then
if type(decoded.history) == "table" then
-- Migrates the old format (a plain array of counts) to entries with
-- a timestamp and an afterUpdate flag, both unknown for old data.
local migrated = {}
for _, entry in ipairs(decoded.history) do
if type(entry) == "table" then
table.insert(migrated, {
n = tonumber(entry.n) or 0,
at = tonumber(entry.at),
afterUpdate = entry.afterUpdate == true,
})
elseif type(entry) == "number" then
table.insert(migrated, { n = entry, at = nil, afterUpdate = false })
end
end
history = migrated
end
if type(decoded.lastUpdateAt) == "number" then
lastUpdateAt = decoded.lastUpdateAt
end
end
end
local function saveHistoryState()
local path = historyStatePath()
if path == nil then
return
end
local encoded = noctalia.json.encode({ history = history, lastUpdateAt = lastUpdateAt })
if encoded ~= nil then
noctalia.writeFile(path, encoded)
end
end
-- Appends the current total to the activity history, trimmed to the
-- configured length. A no-op when the graph is turned off, so disabling it
-- also stops collecting data, not just hides it.
recordCheck = function()
local wasPostUpdate = checkIsPostUpdate
checkIsPostUpdate = false
if cfg("show_activity_graph") ~= true then
return
end
loadHistoryState()
table.insert(history, { n = total, at = os.time(), afterUpdate = wasPostUpdate })
local maxLen = math.max(3, math.min(30, tonumber(cfg("activity_history_length")) or 10))
while #history > maxLen do
table.remove(history, 1)
end
saveHistoryState()
end
-- Marks the check that follows as the one that verifies an update run, so its
-- history entry can say "Updated" instead of just a pending count.
local function recordUpdateRun()
checkIsPostUpdate = true
if cfg("show_activity_graph") ~= true then
return
end
loadHistoryState()
lastUpdateAt = os.time()
saveHistoryState()
end
local HTML_ENTITIES = { local HTML_ENTITIES = {
["&lt;"] = "<", ["&lt;"] = "<",
["&gt;"] = ">", ["&gt;"] = ">",
@@ -665,6 +757,7 @@ local function pollRun()
return return
end end
if runSeen or runTicks >= RUN_GRACE_SECONDS then if runSeen or runTicks >= RUN_GRACE_SECONDS then
recordUpdateRun()
startCheck() startCheck()
end end
end, updateProcessName) end, updateProcessName)
@@ -681,10 +774,13 @@ local function handle(action)
elseif action == "update" then elseif action == "update" then
runUpdate() runUpdate()
elseif action == "dismiss" then elseif action == "dismiss" then
if not dismissed then sources.pacman = { n = 0, items = {} }
dismissed = true sources.aur = { n = 0, items = {}, helper = sources.aur.helper }
publish() sources.flatpak = { n = 0, items = {} }
end total = 0
downloadSizeMiB = nil
phase = "clean"
publish()
elseif action == "open_news" then elseif action == "open_news" then
openNews() openNews()
end end
@@ -750,4 +846,5 @@ if not noctalia.commandExists("checkupdates") then
phase = "missing" phase = "missing"
errMsg = tr("err_no_checkupdates") errMsg = tr("err_no_checkupdates")
end end
loadHistoryState() -- so the graph shows prior sessions' data before the first check runs
publish() publish()
+35
View File
@@ -3,6 +3,33 @@
"action_dismiss": "Verwerfen", "action_dismiss": "Verwerfen",
"action_open_news": "News öffnen", "action_open_news": "News öffnen",
"action_update": "Aktualisieren", "action_update": "Aktualisieren",
"activity": {
"days_ago": {
"one": "vor 1 Tag",
"other": "vor {count} Tagen"
},
"hours_ago": {
"one": "vor 1 Stunde",
"other": "vor {count} Stunden"
},
"just_now": "gerade eben",
"minutes_ago": {
"one": "vor 1 Minute",
"other": "vor {count} Minuten"
},
"never_updated": "Noch nie aktualisiert",
"pending_at": {
"one": "1 ausstehendes Update",
"other": "{count} ausstehende Updates"
},
"title": "Aktivität",
"updated": "Aktualisiert",
"updated_days_ago": {
"one": "Vor 1 Tag aktualisiert",
"other": "Vor {count} Tagen aktualisiert"
},
"updated_today": "Heute aktualisiert"
},
"caption_checked": "geprüft {time}", "caption_checked": "geprüft {time}",
"caption_ignored": { "caption_ignored": {
"one": "1 Paket ignoriert", "one": "1 Paket ignoriert",
@@ -33,6 +60,10 @@
"press_key": "Beliebige Taste zum Schließen drücken" "press_key": "Beliebige Taste zum Schließen drücken"
}, },
"settings": { "settings": {
"activity_history_length": {
"description": "Wie viele der letzten Prüfungen für das Aktivitätsdiagramm aufbewahrt werden.",
"label": "Länge des Aktivitätsverlaufs"
},
"assume_yes": { "assume_yes": {
"description": "Übergibt --noconfirm / -y, damit Paketmanager nicht nach Bestätigung fragen. Aus bedeutet, du bestätigst jedes Paket im Terminal-Fenster selbst.", "description": "Übergibt --noconfirm / -y, damit Paketmanager nicht nach Bestätigung fragen. Aus bedeutet, du bestätigst jedes Paket im Terminal-Fenster selbst.",
"label": "Automatisch mit Ja bestätigen" "label": "Automatisch mit Ja bestätigen"
@@ -84,6 +115,10 @@
"description": "Sendet eine Desktop-Benachrichtigung, wenn eine Prüfung aktualisierbare Pakete findet.", "description": "Sendet eine Desktop-Benachrichtigung, wenn eine Prüfung aktualisierbare Pakete findet.",
"label": "Bei gefundenen Updates benachrichtigen" "label": "Bei gefundenen Updates benachrichtigen"
}, },
"show_activity_graph": {
"description": "Zeichnet die Anzahl ausstehender Updates über die letzten Prüfungen sowie den letzten Update-Zeitpunkt auf und zeigt sie als kleines Diagramm im Panel. Deaktiviert stoppt auch die Aufzeichnung.",
"label": "Aktivitätsdiagramm anzeigen"
},
"show_count": { "show_count": {
"description": "Zeigt die Anzahl ausstehender Updates neben dem Bar-Symbol.", "description": "Zeigt die Anzahl ausstehender Updates neben dem Bar-Symbol.",
"label": "Anzahl der Updates anzeigen" "label": "Anzahl der Updates anzeigen"
+35
View File
@@ -3,6 +3,33 @@
"action_dismiss": "Dismiss", "action_dismiss": "Dismiss",
"action_open_news": "Open news", "action_open_news": "Open news",
"action_update": "Update", "action_update": "Update",
"activity": {
"days_ago": {
"one": "1 day ago",
"other": "{count} days ago"
},
"hours_ago": {
"one": "1 hour ago",
"other": "{count} hours ago"
},
"just_now": "just now",
"minutes_ago": {
"one": "1 minute ago",
"other": "{count} minutes ago"
},
"never_updated": "Never updated",
"pending_at": {
"one": "1 pending update",
"other": "{count} pending updates"
},
"title": "Activity",
"updated": "Updated",
"updated_days_ago": {
"one": "Updated 1 day ago",
"other": "Updated {count} days ago"
},
"updated_today": "Updated today"
},
"caption_checked": "checked {time}", "caption_checked": "checked {time}",
"caption_ignored": { "caption_ignored": {
"one": "1 package ignored", "one": "1 package ignored",
@@ -36,6 +63,10 @@
"press_key": "Press any key to close" "press_key": "Press any key to close"
}, },
"settings": { "settings": {
"activity_history_length": {
"description": "How many of the most recent checks to keep for the activity graph.",
"label": "Activity history length"
},
"assume_yes": { "assume_yes": {
"description": "Pass --noconfirm / -y so package managers do not ask for confirmation. Off means you confirm each one in the terminal window.", "description": "Pass --noconfirm / -y so package managers do not ask for confirmation. Off means you confirm each one in the terminal window.",
"label": "Answer yes automatically" "label": "Answer yes automatically"
@@ -87,6 +118,10 @@
"description": "Send a desktop notification when a check finds packages to upgrade.", "description": "Send a desktop notification when a check finds packages to upgrade.",
"label": "Notify when updates are found" "label": "Notify when updates are found"
}, },
"show_activity_graph": {
"description": "Track pending-update counts across recent checks and when you last updated, shown as a small graph in the panel. Turning this off also stops recording the history.",
"label": "Show activity graph"
},
"show_count": { "show_count": {
"description": "Show the number of pending updates next to the bar glyph.", "description": "Show the number of pending updates next to the bar glyph.",
"label": "Show the update count" "label": "Show the update count"
-1
View File
@@ -32,7 +32,6 @@ end
local function pending() local function pending()
return snapshot ~= nil return snapshot ~= nil
and snapshot.phase == "ready" and snapshot.phase == "ready"
and snapshot.dismissed ~= true
and (snapshot.total or 0) > 0 and (snapshot.total or 0) > 0
end end