Enhance package management UI with selection functionality and batch actions

This commit is contained in:
MayaTheShy
2026-03-22 15:56:16 -04:00
parent ab26539660
commit 31b4fd52c9

View File

@@ -16,25 +16,27 @@ local page = UI.Page {
x = 2, ex = 14, y = 2, ey = -6, x = 2, ex = 14, y = 2, ey = -6,
values = { }, values = { },
columns = { columns = {
{ heading = 'Package', key = 'name' }, { heading = ' Package', key = 'displayName' },
}, },
sortColumn = 'name', sortColumn = 'name',
autospace = true, autospace = true,
help = 'Select a package', help = 'Space to select, Enter to toggle',
}, },
add = UI.Button { installSelected = UI.Button {
x = 2, y = -3, x = 2, y = -3,
text = ' + ', text = ' + ',
event = 'action', event = 'batch_action',
help = 'Install or update', operation = 'install',
operationText = 'Install',
help = 'Install or update selected',
}, },
remove = UI.Button { removeSelected = UI.Button {
x = 8, y = -3, x = 8, y = -3,
text = ' - ', text = ' - ',
event = 'action', event = 'batch_action',
operation = 'uninstall', operation = 'uninstall',
operationText = 'Remove', operationText = 'Remove',
help = 'Remove', help = 'Remove selected',
}, },
updateall = UI.Button { updateall = UI.Button {
ex = -2, y = -3, width = 12, ex = -2, y = -3, width = 12,
@@ -89,7 +91,9 @@ function page:loadPackages()
end end
table.insert(self.grid.values, { table.insert(self.grid.values, {
installed = not not Packages:isInstalled(k), installed = not not Packages:isInstalled(k),
selected = false,
name = k, name = k,
displayName = k,
manifest = manifest, manifest = manifest,
}) })
end end
@@ -104,12 +108,62 @@ function page:loadPackages()
end end
function page.grid:getRowTextColor(row, selected) function page.grid:getRowTextColor(row, selected)
if row.selected then
return colors.cyan
end
if row.installed then if row.installed then
return colors.yellow return colors.yellow
end end
return UI.Grid.getRowTextColor(self, row, selected) return UI.Grid.getRowTextColor(self, row, selected)
end end
function page:getSelectedPackages()
local selected = { }
for _, row in pairs(self.grid.values) do
if row.selected then
table.insert(selected, row)
end
end
return selected
end
function page:getSelectedCount()
local count = 0
for _, row in pairs(self.grid.values) do
if row.selected then
count = count + 1
end
end
return count
end
function page:toggleSelection(row)
row.selected = not row.selected
row.displayName = row.selected and ('\187 ' .. row.name) or row.name
self.grid:draw()
self:updateStatus()
end
function page:clearSelection()
for _, row in pairs(self.grid.values) do
row.selected = false
row.displayName = row.name
end
self.grid:draw()
end
function page:updateStatus()
local count = self:getSelectedCount()
if count > 0 then
self.statusBar:setStatus(count .. ' package(s) selected')
else
local focused = self.grid:getSelected()
if focused then
self.statusBar:setStatus(focused.installed and 'Installed' or '')
end
end
end
function page.action:show() function page.action:show()
self.output.win:clear() self.output.win:clear()
UI.SlideOut.show(self) UI.SlideOut.show(self)
@@ -134,11 +188,7 @@ function page:run(operation, name)
end end
function page:updateSelection(selected) function page:updateSelection(selected)
self.add.operation = selected.installed and 'update' or 'install' -- no-op: buttons are always active for batch operations
self.add.operationText = selected.installed and 'Update' or 'Install'
self.remove.inactive = not selected.installed
self.add:draw()
self.remove:draw()
end end
function page:eventHandler(event) function page:eventHandler(event)
@@ -152,7 +202,14 @@ function page:eventHandler(event)
Ansi.yellow, manifest.title, Ansi.yellow, manifest.title,
Ansi.white, manifest.description)) Ansi.white, manifest.description))
self.description:draw() self.description:draw()
self:updateSelection(event.selected) self:updateStatus()
elseif event.type == 'grid_select' then
-- Space or Enter toggles selection
local row = self.grid:getSelected()
if row then
self:toggleSelection(row)
end
elseif event.type == 'checkbox_change' then elseif event.type == 'checkbox_change' then
config.compression = not config.compression config.compression = not config.compression
@@ -160,34 +217,69 @@ function page:eventHandler(event)
elseif event.type == 'updateall' then elseif event.type == 'updateall' then
self.operation = 'updateall' self.operation = 'updateall'
self.operationTargets = { }
self.action.button.text = ' Begin ' self.action.button.text = ' Begin '
self.action.button.event = 'begin' self.action.button.event = 'begin'
self.action.titleBar.title = 'Update All' self.action.titleBar.title = 'Update All'
self.action:show() self.action:show()
elseif event.type == 'action' then elseif event.type == 'batch_action' then
local selected = self.grid:getSelected() local targets = self:getSelectedPackages()
if selected then local operation = event.button.operation
self.operation = event.button.operation
self.action.button.text = event.button.operationText -- fall back to focused row if nothing selected
self.action.titleBar.title = selected.manifest.title if #targets == 0 then
self.action.button.text = ' Begin ' local focused = self.grid:getSelected()
self.action.button.event = 'begin' if focused then
self.action:show() targets = { focused }
end
end end
if #targets == 0 then return end
-- for install: update already-installed packages, install new ones
if operation == 'install' then
self.operation = 'install'
else
-- filter to only installed packages for uninstall
local installed = { }
for _, t in ipairs(targets) do
if t.installed then
table.insert(installed, t)
end
end
targets = installed
if #targets == 0 then return end
self.operation = 'uninstall'
end
self.operationTargets = targets
local title = #targets == 1
and targets[1].manifest.title
or (#targets .. ' packages')
self.action.button.text = ' Begin '
self.action.button.event = 'begin'
self.action.titleBar.title = string.format('%s %s',
operation == 'install' and 'Install/Update' or 'Remove', title)
self.action:show()
elseif event.type == 'hide-action' then elseif event.type == 'hide-action' then
self.action:hide() self.action:hide()
elseif event.type == 'begin' then elseif event.type == 'begin' then
if self.operation == 'updateall' then if self.operation == 'updateall' then
self:run(self.operation, '') self:run('updateall', '')
else else
local selected = self.grid:getSelected() for _, target in ipairs(self.operationTargets) do
self:run(self.operation, selected.name) local op = self.operation
selected.installed = Packages:isInstalled(selected.name) if op == 'install' and target.installed then
op = 'update'
self:updateSelection(selected) end
self:run(op, target.name)
target.installed = Packages:isInstalled(target.name)
end
self:clearSelection()
self:updateStatus()
end end
self.action.button.text = ' Done ' self.action.button.text = ' Done '