fix: distinguish current and historical stopped schedule state

This commit is contained in:
VAIO73
2026-10-16 17:21:34 +00:00
parent 413ac5e80e
commit d25747646e
5 changed files with 31 additions and 11 deletions
@@ -217,6 +217,10 @@ class CommandDescriptionsTests(unittest.TestCase):
"reasonStoppedContainer", "reasonStoppedContainer",
english["vmLxc"]["scheduled"]["reasonStoppedContainer"], english["vmLxc"]["scheduled"]["reasonStoppedContainer"],
) )
messages["vmLxc"]["scheduled"].setdefault(
"reasonStoppedContainerHistorical",
english["vmLxc"]["scheduled"]["reasonStoppedContainerHistorical"],
)
messages["vmLxc"]["scheduled"].setdefault( messages["vmLxc"]["scheduled"].setdefault(
"runSkippedStatus", "runSkippedStatus",
english["vmLxc"]["scheduled"]["runSkippedStatus"], english["vmLxc"]["scheduled"]["runSkippedStatus"],
+3 -1
View File
@@ -2450,7 +2450,9 @@ const handleDownloadLogs = async (vmid: number, vmName: string) => {
if (!scheduleLastRunAt || !selectedVM) return null if (!scheduleLastRunAt || !selectedVM) return null
const spacing = indented ? "pl-4" : "" const spacing = indented ? "pl-4" : ""
const scheduleLastRunReasonText = scheduleLastRunReasonCode === "stopped_container" const scheduleLastRunReasonText = scheduleLastRunReasonCode === "stopped_container"
? t("vmLxc.scheduled.reasonStoppedContainer") ? selectedVM.status === "stopped"
? t("vmLxc.scheduled.reasonStoppedContainer")
: t("vmLxc.scheduled.reasonStoppedContainerHistorical")
: scheduleLastRunReason : scheduleLastRunReason
return ( return (
<div className={`space-y-1.5 ${spacing}`}> <div className={`space-y-1.5 ${spacing}`}>
+2 -1
View File
@@ -1289,7 +1289,8 @@
"runDeferred": "held for safety", "runDeferred": "held for safety",
"runSkipped": "nothing pending", "runSkipped": "nothing pending",
"runSkippedStatus": "run skipped", "runSkippedStatus": "run skipped",
"reasonStoppedContainer": "Container was stopped; scheduled update was skipped.", "reasonStoppedContainer": "Container is stopped; scheduled update was skipped.",
"reasonStoppedContainerHistorical": "Container was stopped when the scheduled update was due to run.",
"releaseDelaySummary": "{days}-day release hold", "releaseDelaySummary": "{days}-day release hold",
"releaseDelayLabel": "Wait after a new app release", "releaseDelayLabel": "Wait after a new app release",
"releaseDelayNone": "No waiting period", "releaseDelayNone": "No waiting period",
+2 -1
View File
@@ -1289,7 +1289,8 @@
"runDeferred": "odložené z bezpečnostných dôvodov", "runDeferred": "odložené z bezpečnostných dôvodov",
"runSkipped": "nič nečaká", "runSkipped": "nič nečaká",
"runSkippedStatus": "spustenie bolo preskočené", "runSkippedStatus": "spustenie bolo preskočené",
"reasonStoppedContainer": "Kontajner bol vypnutý; plánovaná aktualizácia sa preskočila.", "reasonStoppedContainer": "Kontajner je vypnutý; plánovaná aktualizácia sa preskočila.",
"reasonStoppedContainerHistorical": "Kontajner bol vypnutý, keď sa mala spustiť plánovaná aktualizácia.",
"releaseDelaySummary": "odklad {days} deň/dní", "releaseDelaySummary": "odklad {days} deň/dní",
"releaseDelayLabel": "Počkať po novej verzii aplikácie", "releaseDelayLabel": "Počkať po novej verzii aplikácie",
"releaseDelayNone": "Bez čakacej doby", "releaseDelayNone": "Bez čakacej doby",
@@ -63,7 +63,7 @@ for (const locale of ['en', 'sk']) {
return String(message ?? key).replace(/\{([^}]+)\}/g, (_, name) => String(variables[name] ?? `{${name}}`)) return String(message ?? key).replace(/\{([^}]+)\}/g, (_, name) => String(variables[name] ?? `{${name}}`))
} }
const context = { const context = {
exports: {}, t, selectedVM: { vmid: 100 }, scheduleLastRunAt: '2026-10-16T05:10:02Z', exports: {}, t, selectedVM: { vmid: 100, status: 'stopped' }, scheduleLastRunAt: '2026-10-16T05:10:02Z',
scheduleLastRunStatus: 'skipped', scheduleLastRunReasonCode: 'stopped_container', scheduleLastRunStatus: 'skipped', scheduleLastRunReasonCode: 'stopped_container',
scheduleLastRunReason: 'container is stopped; scheduled update was skipped', scheduleLastRunReason: 'container is stopped; scheduled update was skipped',
scheduleLastRunRebootRequired: false, scheduleLastRunRebootPackages: [], scheduleLastRunLog: null, scheduleLastRunRebootRequired: false, scheduleLastRunRebootPackages: [], scheduleLastRunLog: null,
@@ -72,17 +72,29 @@ for (const locale of ['en', 'sk']) {
} }
const render = compile(context) const render = compile(context)
const translated = flattenText(render(true)) const translated = flattenText(render(true))
const expected = t('vmLxc.scheduled.reasonStoppedContainer') const expectedCurrentReason = t('vmLxc.scheduled.reasonStoppedContainer')
const expectedHistoricalReason = t('vmLxc.scheduled.reasonStoppedContainerHistorical')
const skippedLabel = t('vmLxc.scheduled.runSkippedStatus') const skippedLabel = t('vmLxc.scheduled.runSkippedStatus')
const expectedHistoricalReason = locale === 'sk' const expectedCurrentText = locale === 'sk'
? 'Kontajner bol vypnutý; plánovaná aktualizácia sa preskočila.' ? 'Kontajner je vypnutý; plánovaná aktualizácia sa preskočila.'
: 'Container was stopped; scheduled update was skipped.' : 'Container is stopped; scheduled update was skipped.'
assert.equal(expected, expectedHistoricalReason, const expectedHistoricalText = locale === 'sk'
`${locale}: stopped reason must describe the historical scheduled run, not current container state`) ? 'Kontajner bol vypnutý, keď sa mala spustiť plánovaná aktualizácia.'
assert(translated.includes(expected), `${locale}: known reason code must use the locale catalog`) : 'Container was stopped when the scheduled update was due to run.'
assert.equal(expectedCurrentReason, expectedCurrentText,
`${locale}: stopped CT must describe its current stopped state`)
assert.equal(expectedHistoricalReason, expectedHistoricalText,
`${locale}: running CT must describe the stopped state at the prior scheduled run`)
assert(translated.includes(expectedCurrentReason), `${locale}: currently stopped CT must use the present-state catalog`)
assert(!translated.includes(expectedHistoricalReason), `${locale}: currently stopped CT must not use historical wording`)
assert(translated.includes(skippedLabel), `${locale}: skipped run must not claim that no updates are pending`) assert(translated.includes(skippedLabel), `${locale}: skipped run must not claim that no updates are pending`)
assert(!translated.includes(context.scheduleLastRunReason), `${locale}: raw stopped reason must not leak into UI`) assert(!translated.includes(context.scheduleLastRunReason), `${locale}: raw stopped reason must not leak into UI`)
context.selectedVM.status = 'running'
const historical = flattenText(render(true))
assert(historical.includes(expectedHistoricalReason), `${locale}: running CT must use historical wording for a past skipped run`)
assert(!historical.includes(expectedCurrentReason), `${locale}: running CT must not claim it is currently stopped`)
context.scheduleLastRunReasonCode = 'unknown_reason' context.scheduleLastRunReasonCode = 'unknown_reason'
const fallback = flattenText(render(true)) const fallback = flattenText(render(true))
assert(fallback.includes(context.scheduleLastRunReason), `${locale}: unknown code must retain the raw diagnostic`) assert(fallback.includes(context.scheduleLastRunReason), `${locale}: unknown code must retain the raw diagnostic`)