ui/app: per-job overlap policy in job dialog and details panel

- job_dialog.go: add overlap-policy widget.Select with "(Use global
  default)" → empty, "skip", and "queue" options; pre-selects the job's
  current value; on save maps the inherit label back to empty string.
- app/format.go: add DisplayOverlapPolicy(job, globalPolicy) — returns
  the policy name when overridden, else "skip/queue (global default)".
- ui/jobs_view.go: add "Overlap policy" detail row updated in
  updateDetails using DisplayOverlapPolicy.
- settings_view.go: rename "Overlap policy" label to "Default overlap
  policy" to clarify it is the global default jobs can override.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
mixeme
2026-06-24 21:05:50 +03:00
parent 3f3b977fb0
commit 554ce2b93a
4 changed files with 33 additions and 1 deletions
+18
View File
@@ -13,6 +13,10 @@ import (
"fyne.io/fyne/v2/widget"
)
// overlapPolicyInherit is the display label used when a job should inherit the
// global overlap policy. It maps to an empty Job.OverlapPolicy on save.
const overlapPolicyInherit = "(Use global default)"
// showJobDialog opens a create/edit form for a single job. onSave is called
// with the populated job only when the user clicks Save and all fields pass
// validation.
@@ -40,6 +44,15 @@ func showJobDialog(w fyne.Window, title string, current job, onSave func(job)) {
startOnly.SetChecked(current.StartOnly)
enabled := widget.NewCheck("Enabled", nil)
enabled.SetChecked(current.Enabled)
overlapSelect := widget.NewSelect(
[]string{overlapPolicyInherit, string(domain.OverlapPolicySkip), string(domain.OverlapPolicyQueue)},
nil,
)
overlapSelected := overlapPolicyInherit
if current.OverlapPolicy != "" {
overlapSelected = current.OverlapPolicy
}
overlapSelect.SetSelected(overlapSelected)
form := dialog.NewForm(
title,
@@ -52,6 +65,7 @@ func showJobDialog(w fyne.Window, title string, current job, onSave func(job)) {
widget.NewFormItem("Command", commandRow),
widget.NewFormItem("Arguments", argumentsEntry),
widget.NewFormItem("", startOnly),
widget.NewFormItem("Overlap policy", overlapSelect),
widget.NewFormItem("", enabled),
},
func(saved bool) {
@@ -75,6 +89,10 @@ func showJobDialog(w fyne.Window, title string, current job, onSave func(job)) {
current.Arguments = strings.TrimSpace(argumentsEntry.Text)
current.StartOnly = startOnly.Checked
current.Enabled = enabled.Checked
current.OverlapPolicy = overlapSelect.Selected
if current.OverlapPolicy == overlapPolicyInherit {
current.OverlapPolicy = ""
}
// The dialog only edits durable configuration. Runtime status is
// initialized (new jobs) or updated (edits) by the caller against the
// runtime map, keyed by job ID.
+4
View File
@@ -76,6 +76,7 @@ func newJobsView(w fyne.Window, svc *app.Service) (fyne.CanvasObject, func()) {
nextRunLabel := newJobDetailLabel(selectedRuntime.NextRun)
stateLabel := newJobDetailLabel(selectedRuntime.LastState)
statsLabel := newJobDetailLabel(app.DisplayStats(selectedRuntime))
overlapPolicyLabel := newJobDetailLabel(app.DisplayOverlapPolicy(jobs[selected], svc.Store().Config.OverlapPolicy))
schedulerState := widget.NewLabel("Scheduler running")
commandOutput := widget.NewTextGrid()
commandOutput.SetText(selectedRuntime.Output)
@@ -112,6 +113,7 @@ func newJobsView(w fyne.Window, svc *app.Service) (fyne.CanvasObject, func()) {
nextRunLabel.SetText("")
stateLabel.SetText("")
statsLabel.SetText("")
overlapPolicyLabel.SetText("")
commandOutput.SetText("")
selectedLogs = nil
return
@@ -125,6 +127,7 @@ func newJobsView(w fyne.Window, svc *app.Service) (fyne.CanvasObject, func()) {
commandLabel.SetText(current.Command)
argumentsLabel.SetText(app.DisplayArguments(current.Arguments))
runModeLabel.SetText(app.DisplayRunMode(current))
overlapPolicyLabel.SetText(app.DisplayOverlapPolicy(current, svc.Store().Config.OverlapPolicy))
lastRunLabel.SetText(rt.LastRun)
nextRunLabel.SetText(rt.NextRun)
stateLabel.SetText(rt.LastState)
@@ -356,6 +359,7 @@ func newJobsView(w fyne.Window, svc *app.Service) (fyne.CanvasObject, func()) {
detailRow("Command", commandLabel),
detailRow("Arguments", argumentsLabel),
detailRow("Run mode", runModeLabel),
detailRow("Overlap policy", overlapPolicyLabel),
detailRow("Last run", lastRunLabel),
detailRow("Next run", nextRunLabel),
detailRow("State", stateLabel),
+1 -1
View File
@@ -126,7 +126,7 @@ func settingsView(w fyne.Window, svc *app.Service) fyne.CanvasObject {
widget.NewSeparator(),
widget.NewLabelWithStyle("Queue", fyne.TextAlignLeading, fyne.TextStyle{Bold: true}),
settingsRow("Execution mode", container.New(minWidthLayout{width: settingsControlWidth}, executionModeSelect)),
settingsRow("Overlap policy", container.New(minWidthLayout{width: settingsControlWidth}, overlapPolicySelect)),
settingsRow("Default overlap policy", container.New(minWidthLayout{width: settingsControlWidth}, overlapPolicySelect)),
widget.NewSeparator(),
widget.NewLabelWithStyle("Storage", fyne.TextAlignLeading, fyne.TextStyle{Bold: true}),
settingsRow("Config YAML", widget.NewLabel(store.Paths.ConfigPath)),