Files
seaweedfs/weed/admin/view/app/plugin_scheduler_status_templ.go
T
Chris LuandDevin 4ed9595a58 admin: explain detection cooldowns and skipped scans (#12185)
* plugin: describe detection cooldowns and report skipped scans

* admin: expose cooldown eligibility and preserve skipped detection outcomes

* admin: show cooldown eligibility alongside maintenance lock waits

* plugin: retain cooldown activity for older admin servers

* admin: keep manual detection skips out of scheduler run state

* plugin: refresh descriptors on reconnect without downgrading saved schemas

* plugin: allow valid schema refreshes to repair corrupt descriptors

* admin: store eligible_after activity detail as RFC3339

* worker: report admin_script interval skips as skipped detection

* worker: report admin_script interval skips after the last completed job

* admin: show the selected job's cooldown while scheduling is disabled

* admin: report an unsigned interval skip instead of a completed scan

* worker: populate new DetectionComplete fields in Rust senders

Generated with [Devin](https://devin.ai)

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>

---------

Co-authored-by: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
2026-10-28 22:55:36 -07:00

38 lines
4.9 KiB
Go

// Code generated by templ - DO NOT EDIT.
// templ: version: v0.3.1100
package app
//lint:file-ignore SA4006 This context is only used if a nested component is present.
import "github.com/a-h/templ"
import templruntime "github.com/a-h/templ/runtime"
func PluginSchedulerStatus() templ.Component {
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
return templ_7745c5c3_CtxErr
}
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
if !templ_7745c5c3_IsBuffer {
defer func() {
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
if templ_7745c5c3_Err == nil {
templ_7745c5c3_Err = templ_7745c5c3_BufErr
}
}()
}
ctx = templ.InitializeContext(ctx)
ctx = templ.ClearChildren(ctx)
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<div id=\"plugin-scheduler-blockers\" aria-live=\"polite\"></div><script>\n window.renderPluginSchedulerStatus = function(data) {\n const root = document.getElementById('plugin-scheduler-blockers');\n if (!root) return;\n root.replaceChildren();\n const lock = data.lock || {};\n const waiters = lock.waiters || [];\n if (waiters.length) {\n const alert = document.createElement('div');\n alert.className = 'alert alert-warning';\n const title = document.createElement('strong');\n title.textContent = 'Waiting for the maintenance lock';\n alert.appendChild(title);\n const owner = document.createElement('div');\n owner.textContent = lock.holder ? 'Lock owner: ' + lock.holder : (lock.holder_error || 'Lock owner not reported');\n if (lock.holder_message) owner.textContent += ' — ' + lock.holder_message;\n alert.appendChild(owner);\n waiters.forEach(function(waiter) {\n const line = document.createElement('div');\n const since = new Date(waiter.since);\n const now = new Date((data.scheduler || {}).now || Date.now());\n const seconds = Math.max(0, Math.floor((now - since) / 1000));\n line.textContent = waiter.reason + ' · since ' + since.toLocaleString() +\n ' (local time) · waiting ' + Math.floor(seconds / 60) + 'm ' + (seconds % 60) + 's';\n alert.appendChild(line);\n });\n const note = document.createElement('div');\n note.className = 'small mt-1';\n note.textContent = 'This lane cannot advance until the lock becomes available. A scheduled check time is not a guaranteed start time.';\n alert.appendChild(note);\n root.appendChild(alert);\n }\n const scheduler = data.scheduler || {};\n const now = new Date(scheduler.now || Date.now());\n (scheduler.job_types || []).forEach(function(job) {\n if (data.job_type ? job.job_type !== data.job_type : !job.enabled) return;\n const until = job.detection_eligible_at ? new Date(job.detection_eligible_at) : null;\n const cooling = until && until > now;\n if (!job.cooldown_error && !cooling && !(data.job_type && job.cooldown_seconds)) return;\n const box = document.createElement('div');\n box.className = 'alert ' + (job.cooldown_error ? 'alert-warning' : 'alert-info');\n const title = document.createElement('strong');\n title.textContent = job.job_type + ': ' + (job.cooldown_error || (cooling ? 'Cooldown after successful job' : until ? 'Cooldown elapsed' : 'No successful job yet'));\n box.appendChild(title);\n const line = document.createElement('div');\n const seconds = job.cooldown_seconds || 0;\n const duration = seconds >= 3600 ? (seconds / 3600) + ' hours' : seconds >= 60 ? (seconds / 60) + ' minutes' : seconds + ' seconds';\n line.textContent = 'Configured cooldown: ' + duration + ' (' + seconds + ' seconds).';\n if (job.last_successful_run_at) line.textContent += ' Last success: ' + new Date(job.last_successful_run_at).toLocaleString() + '.';\n if (until) line.textContent += ' Eligible after: ' + until.toLocaleString() + '.';\n if (cooling) line.textContent += ' Remaining: ' + Math.ceil((until - now) / 60000) + ' minutes.';\n box.appendChild(line);\n const note = document.createElement('div');\n note.className = 'small mt-1';\n note.textContent = 'Applies across this job type. Locks and other jobs in the lane can delay the actual start.';\n box.appendChild(note);\n root.appendChild(box);\n });\n };\n </script>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
return nil
})
}
var _ = templruntime.GeneratedTemplate