fix: clarify system update action and package plan

This commit is contained in:
VAIO73
2026-10-28 17:30:44 +00:00
parent e1be5c22c8
commit 43973e1d06
4 changed files with 31 additions and 7 deletions
+13 -4
View File
@@ -340,6 +340,10 @@ export function HealthStatusModal({ open, onOpenChange, getApiUrl }: HealthStatu
const translateHealthText = (value?: string): string => { const translateHealthText = (value?: string): string => {
if (!value) return "" if (!value) return ""
// Health summaries include the category before the same detail text.
if (value.startsWith("Updates: ")) {
return `${t("healthStatus.categories.updates")}: ${translateHealthText(value.slice(9))}`
}
const exact: Record<string, string> = { const exact: Record<string, string> = {
"No temperature sensor detected - install lm-sensors if hardware supports it": t("healthStatus.details.noTemperatureSensor"), "No temperature sensor detected - install lm-sensors if hardware supports it": t("healthStatus.details.noTemperatureSensor"),
"Sustained high CPU usage": t("healthStatus.details.cpuHighSustained"), "Sustained high CPU usage": t("healthStatus.details.cpuHighSustained"),
@@ -903,9 +907,13 @@ export function HealthStatusModal({ open, onOpenChange, getApiUrl }: HealthStatu
pending prevents the operator from spawning a pending prevents the operator from spawning a
terminal that would only report "System is terminal that would only report "System is
already up to date". */} already up to date". */}
{key === "updates" && <ProxMenuxVersionCard getApiUrl={getApiUrl} />}
{key === "updates" && Number(categoryData?.count ?? 0) > 0 && ( {key === "updates" && Number(categoryData?.count ?? 0) > 0 && (
<div className="flex justify-end px-3 py-2 pt-1"> <p className="px-2 sm:px-3 mt-2 text-[10px] sm:text-xs text-muted-foreground">
{t("healthStatus.packagePlanNote")}
</p>
)}
{key === "updates" && Number(categoryData?.count ?? 0) > 0 && (
<div className="flex justify-end px-2 sm:px-3 pt-3 pb-1">
<Button <Button
size="sm" size="sm"
disabled={hostJobs.some(job => job.state !== "complete")} disabled={hostJobs.some(job => job.state !== "complete")}
@@ -915,13 +923,14 @@ export function HealthStatusModal({ open, onOpenChange, getApiUrl }: HealthStatu
setHostJob({ runId, resume: false, kind: "host" }) setHostJob({ runId, resume: false, kind: "host" })
setShowUpdateTerminal(true) setShowUpdateTerminal(true)
}} }}
className="bg-purple-600/15 hover:bg-purple-600/25 border border-purple-500/40 text-purple-300 hover:text-purple-200" className="h-10 sm:h-[34px] bg-purple-600/15 hover:bg-purple-600/25 border border-purple-500/40 text-purple-300 hover:text-purple-200"
> >
<ArrowUpCircle className="h-4 w-4 mr-1.5" /> <ArrowUpCircle className="h-4 w-4 mr-1.5" />
{t("healthStatus.updateNow")} {t("healthStatus.updateSystem")}
</Button> </Button>
</div> </div>
)} )}
{key === "updates" && <ProxMenuxVersionCard getApiUrl={getApiUrl} />}
</div> </div>
)} )}
</div> </div>
+3 -1
View File
@@ -5470,7 +5470,7 @@
"failedLogins": "{count} failed login attempts in 24h", "failedLogins": "{count} failed login attempts in 24h",
"fail2banBannedIps": "Fail2Ban is currently blocking {count} IP addresses (jails: {jails})", "fail2banBannedIps": "Fail2Ban is currently blocking {count} IP addresses (jails: {jails})",
"uptimeDays": "Uptime: {count} days", "uptimeDays": "Uptime: {count} days",
"pendingPackages": "{count} packages pending", "pendingPackages": "Planned packages: {count} (including new packages)",
"updatedDaysAgo": "Last updated {count} days ago", "updatedDaysAgo": "Last updated {count} days ago",
"startupStoragesChecking": "Checking Proxmox storage after startup: {storages}", "startupStoragesChecking": "Checking Proxmox storage after startup: {storages}",
"startupStorageChecking": "Checking Proxmox storage after startup: {storage}", "startupStorageChecking": "Checking Proxmox storage after startup: {storage}",
@@ -5498,6 +5498,8 @@
}, },
"noIssues": "No issues detected", "noIssues": "No issues detected",
"updateNow": "Update now", "updateNow": "Update now",
"updateSystem": "Update system",
"packagePlanNote": "The plan also includes new packages, such as a new kernel. The overview counts updates to existing packages only.",
"dismissedItems": "Dismissed items ({count})", "dismissedItems": "Dismissed items ({count})",
"permanent": "Permanent", "permanent": "Permanent",
"dismissed": "Dismissed", "dismissed": "Dismissed",
+4 -2
View File
@@ -5303,7 +5303,7 @@
"failedLogins": "Neúspešné prihlásenia za 24 h: {count}", "failedLogins": "Neúspešné prihlásenia za 24 h: {count}",
"fail2banBannedIps": "Fail2Ban momentálne blokuje IP adresy: {count} (pravidlá: {jails})", "fail2banBannedIps": "Fail2Ban momentálne blokuje IP adresy: {count} (pravidlá: {jails})",
"uptimeDays": "Beží {count} dní", "uptimeDays": "Beží {count} dní",
"pendingPackages": "Čakajúce balíky: {count}", "pendingPackages": "Plánované balíky: {count} (vrátane nových)",
"updatedDaysAgo": "Naposledy aktualizované pred {count} dňami", "updatedDaysAgo": "Naposledy aktualizované pred {count} dňami",
"startupStoragesChecking": "Po štarte sa ešte overuje stav Proxmox úložísk: {storages}", "startupStoragesChecking": "Po štarte sa ešte overuje stav Proxmox úložísk: {storages}",
"startupStorageChecking": "Po štarte sa ešte overuje stav Proxmox úložiska: {storage}", "startupStorageChecking": "Po štarte sa ešte overuje stav Proxmox úložiska: {storage}",
@@ -5334,7 +5334,7 @@
"pendingSecurityUpdatesDays": "Čakajúce aktualizácie zabezpečenia: {count} (dni čakania: {days})", "pendingSecurityUpdatesDays": "Čakajúce aktualizácie zabezpečenia: {count} (dni čakania: {days})",
"systemNotUpdatedMonths": "Systém nebol aktualizovaný za {days} dní (>18 mesiacov)", "systemNotUpdatedMonths": "Systém nebol aktualizovaný za {days} dní (>18 mesiacov)",
"systemNotUpdatedYear": "Systém nebol aktualizovaný za {days} dní (>1 rok)", "systemNotUpdatedYear": "Systém nebol aktualizovaný za {days} dní (>1 rok)",
"runningKernelUpdate": "K dispozícii je aktualizácia jadra pre spustenie {kernel}", "runningKernelUpdate": "K dispozícii je aktualizácia pre bežiace jadro {kernel}",
"kernelPveUpdates": "Dostupné aktualizácie jadra: {kernelCount}; dostupné aktualizácie Proxmox: {pveCount}", "kernelPveUpdates": "Dostupné aktualizácie jadra: {kernelCount}; dostupné aktualizácie Proxmox: {pveCount}",
"pendingPackageUpdates": "Čakajúce aktualizácie balíka: {count}", "pendingPackageUpdates": "Čakajúce aktualizácie balíka: {count}",
"noPendingUpdates": "Žiadne čakajúce aktualizácie", "noPendingUpdates": "Žiadne čakajúce aktualizácie",
@@ -5370,6 +5370,8 @@
}, },
"noIssues": "Neboli zistené žiadne problémy", "noIssues": "Neboli zistené žiadne problémy",
"updateNow": "Aktualizovať teraz", "updateNow": "Aktualizovať teraz",
"updateSystem": "Aktualizovať systém",
"packagePlanNote": "Plán zahŕňa aj nové balíky, napríklad nové jadro. Prehľad počíta iba aktualizácie existujúcich balíkov.",
"dismissedItems": "Skryté upozornenia ({count})", "dismissedItems": "Skryté upozornenia ({count})",
"permanent": "Natrvalo", "permanent": "Natrvalo",
"dismissed": "Skryté", "dismissed": "Skryté",
+11
View File
@@ -261,5 +261,16 @@ for (const input of passthrough) {
check(`passthrough ${JSON.stringify(input)}`, () => assert.equal(select(input), input)); check(`passthrough ${JSON.stringify(input)}`, () => assert.equal(select(input), input));
for (const locale of Object.keys(catalogs)) check(`passthrough ${locale} ${JSON.stringify(input)}`, () => assert.equal(render(input, locale), input)); for (const locale of Object.keys(catalogs)) check(`passthrough ${locale} ${JSON.stringify(input)}`, () => assert.equal(render(input, locale), input));
} }
// Real summary contract from health_monitor: category prefix + reason.
for (const [locale, expectedText] of [
['sk', 'Aktualizácie systému: K dispozícii je aktualizácia pre bežiace jadro 7.0.14-25-pve'],
['en', 'System updates: Kernel update available for running 7.0.14-25-pve'],
]) {
check(`prefixed update summary ${locale}`, () => assert.equal(
render('Updates: Kernel update available for running 7.0.14-25-pve', locale), expectedText));
const opaque = 'Repository unavailable; diagnostic: /srv/path {count}\nline 2';
check(`prefixed diagnostic preserved ${locale}`, () => assert.equal(
render('Updates: ' + opaque, locale), translator(locale)('healthStatus.categories.updates') + ': ' + opaque));
}
if (failures) throw new Error(`${failures} health-text assertions failed`); if (failures) throw new Error(`${failures} health-text assertions failed`);
console.log(`PASS: actual health mapper/provider; ${new Set(cases.map(row => row[1])).size} new keys, ${cases.length} message variants, ${Object.keys(catalogs).length} shipped locales and unconditional missing-key fallback`); console.log(`PASS: actual health mapper/provider; ${new Set(cases.map(row => row[1])).size} new keys, ${cases.length} message variants, ${Object.keys(catalogs).length} shipped locales and unconditional missing-key fallback`);