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:
@@ -92,6 +92,16 @@ func DisplayStats(rt *domain.JobRuntime) string {
|
||||
rt.RunCount, rt.FailCount, rt.LastDurationMS, rt.AvgDurationMS, rt.MaxDurationMS)
|
||||
}
|
||||
|
||||
// DisplayOverlapPolicy formats a job's effective overlap policy for the details
|
||||
// panel. When the job has its own policy it is shown as-is; when empty (inherit
|
||||
// global), the global default is shown with "(global default)" appended.
|
||||
func DisplayOverlapPolicy(job domain.Job, globalPolicy domain.OverlapPolicy) string {
|
||||
if p := domain.OverlapPolicy(strings.TrimSpace(job.OverlapPolicy)); p != "" {
|
||||
return string(p)
|
||||
}
|
||||
return string(globalPolicy) + " (global default)"
|
||||
}
|
||||
|
||||
// DisplayIndex returns the position of jobIndex in the given slice of indexes,
|
||||
// or 0 if not found.
|
||||
func DisplayIndex(indexes []int, jobIndex int) int {
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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)),
|
||||
|
||||
Reference in New Issue
Block a user