Add 'In Progress' tab to history sidebar

Features:
- New "In Progress" tab shows running/pending jobs
- Displays active jobs without opening full queue
- Tab positioned first for quick visibility
- Shows "Running..." or "Pending" status
- No delete button on active jobs (only completed/failed)

Implementation:
- Updated BuildHistorySidebar to accept activeJobs parameter
- Converts queue.Job to ui.HistoryEntry for display
- Filters running/pending jobs from queue
- Conditional delete button (nil check)
- Dynamic status text based on job state

UX Improvements:
- Quick glance at current activity without queue view
- Three-tab layout: In Progress → Completed → Failed
- Consistent styling with existing history entries
- Tappable entries to view full job details

This allows users to monitor active conversions directly
from the history sidebar, reducing the need to constantly
check the full job queue view.
This commit is contained in:
Stu Leak 2025-12-18 18:02:03 -05:00
parent f6729a07ea
commit dad5d34d34
2 changed files with 56 additions and 11 deletions

View File

@ -153,6 +153,7 @@ func sortedKeys(m map[string][]fyne.CanvasObject) []string {
// BuildHistorySidebar creates the history sidebar with tabs
func BuildHistorySidebar(
entries []HistoryEntry,
activeJobs []HistoryEntry,
onEntryClick func(HistoryEntry),
onEntryDelete func(HistoryEntry),
titleColor, bgColor, textColor color.Color,
@ -168,11 +169,13 @@ func BuildHistorySidebar(
}
// Build lists
inProgressList := buildHistoryList(activeJobs, onEntryClick, nil, bgColor, textColor) // No delete for active jobs
completedList := buildHistoryList(completedEntries, onEntryClick, onEntryDelete, bgColor, textColor)
failedList := buildHistoryList(failedEntries, onEntryClick, onEntryDelete, bgColor, textColor)
// Tabs
// Tabs - In Progress first for quick visibility
tabs := container.NewAppTabs(
container.NewTabItem("In Progress", container.NewVScroll(inProgressList)),
container.NewTabItem("Completed", container.NewVScroll(completedList)),
container.NewTabItem("Failed", container.NewVScroll(failedList)),
)
@ -220,20 +223,37 @@ func buildHistoryItem(
// Capture entry for closures
capturedEntry := entry
// Delete button - small "×" button
deleteBtn := widget.NewButton("×", func() {
onEntryDelete(capturedEntry)
})
deleteBtn.Importance = widget.LowImportance
// Build header row with badge and optional delete button
headerItems := []fyne.CanvasObject{badge, layout.NewSpacer()}
if onEntryDelete != nil {
// Delete button - small "×" button (only for completed/failed)
deleteBtn := widget.NewButton("×", func() {
onEntryDelete(capturedEntry)
})
deleteBtn.Importance = widget.LowImportance
headerItems = append(headerItems, deleteBtn)
}
// Title
titleLabel := widget.NewLabel(utils.ShortenMiddle(entry.Title, 25))
titleLabel.TextStyle = fyne.TextStyle{Bold: true}
// Timestamp
timeStr := "Unknown"
if entry.CompletedAt != nil {
timeStr = entry.CompletedAt.Format("Jan 2, 15:04")
// Timestamp or status info
var timeStr string
if entry.Status == queue.JobStatusRunning || entry.Status == queue.JobStatusPending {
// For in-progress jobs, show status
if entry.Status == queue.JobStatusRunning {
timeStr = "Running..."
} else {
timeStr = "Pending"
}
} else {
// For completed/failed jobs, show timestamp
if entry.CompletedAt != nil {
timeStr = entry.CompletedAt.Format("Jan 2, 15:04")
} else {
timeStr = "Unknown"
}
}
timeLabel := widget.NewLabel(timeStr)
timeLabel.TextStyle = fyne.TextStyle{Monospace: true}
@ -246,7 +266,7 @@ func buildHistoryItem(
content := container.NewBorder(
nil, nil, statusRect, nil,
container.NewVBox(
container.NewHBox(badge, layout.NewSpacer(), deleteBtn),
container.NewHBox(headerItems...),
titleLabel,
timeLabel,
),

25
main.go
View File

@ -1372,8 +1372,33 @@ func (s *appState) showMainMenu() {
// Build sidebar if visible
var sidebar fyne.CanvasObject
if s.sidebarVisible {
// Get active jobs from queue (running/pending)
var activeJobs []ui.HistoryEntry
if s.jobQueue != nil {
for _, job := range s.jobQueue.List() {
if job.Status == queue.JobStatusRunning || job.Status == queue.JobStatusPending {
// Convert queue.Job to ui.HistoryEntry
entry := ui.HistoryEntry{
ID: job.ID,
Type: job.Type,
Status: job.Status,
Title: job.Title,
InputFile: job.InputFile,
OutputFile: job.OutputFile,
LogPath: job.LogPath,
Config: job.Config,
CreatedAt: job.CreatedAt,
StartedAt: job.StartedAt,
Error: job.Error,
}
activeJobs = append(activeJobs, entry)
}
}
}
sidebar = ui.BuildHistorySidebar(
s.historyEntries,
activeJobs,
s.showHistoryDetails,
s.deleteHistoryEntry,
titleColor,