fix(manage): require whole-number status history days in both editors

Addresses coderabbit review on #746: the bounds checks allowed decimals.
Number.isInteger is now part of the validity deriveds in the monitor-level
status history card, and the pages editor gains the same guard (it previously
saved display settings with no validation at all) plus step=1 and error
styling on the inputs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Raj Nandan Sharma
2026-06-07 13:28:08 +05:30
parent af4684a90f
commit 951ab06f7e
2 changed files with 34 additions and 4 deletions
@@ -25,16 +25,22 @@
let saving = $state(false);
const isDesktopValid = $derived(
statusHistoryDays.desktop >= GC.STATUS_HISTORY_DAYS_MIN && statusHistoryDays.desktop <= GC.STATUS_HISTORY_DAYS_MAX
Number.isInteger(statusHistoryDays.desktop) &&
statusHistoryDays.desktop >= GC.STATUS_HISTORY_DAYS_MIN &&
statusHistoryDays.desktop <= GC.STATUS_HISTORY_DAYS_MAX
);
const isMobileValid = $derived(
statusHistoryDays.mobile >= GC.STATUS_HISTORY_DAYS_MIN && statusHistoryDays.mobile <= GC.STATUS_HISTORY_DAYS_MAX
Number.isInteger(statusHistoryDays.mobile) &&
statusHistoryDays.mobile >= GC.STATUS_HISTORY_DAYS_MIN &&
statusHistoryDays.mobile <= GC.STATUS_HISTORY_DAYS_MAX
);
const isValid = $derived(isDesktopValid && isMobileValid);
async function save() {
if (!isValid) {
toast.error(`Days must be between ${GC.STATUS_HISTORY_DAYS_MIN} and ${GC.STATUS_HISTORY_DAYS_MAX}`);
toast.error(
`Days must be a whole number between ${GC.STATUS_HISTORY_DAYS_MIN} and ${GC.STATUS_HISTORY_DAYS_MAX}`
);
return;
}
@@ -101,6 +107,7 @@
<Input
id="monitor-history-desktop"
type="number"
step="1"
min={GC.STATUS_HISTORY_DAYS_MIN}
max={GC.STATUS_HISTORY_DAYS_MAX}
bind:value={statusHistoryDays.desktop}
@@ -113,6 +120,7 @@
<Input
id="monitor-history-mobile"
type="number"
step="1"
min={GC.STATUS_HISTORY_DAYS_MIN}
max={GC.STATUS_HISTORY_DAYS_MAX}
bind:value={statusHistoryDays.mobile}
@@ -122,7 +130,8 @@
</div>
</div>
<p class="text-muted-foreground text-xs">
This overrides the page-level default for this monitor. Values must be between {GC.STATUS_HISTORY_DAYS_MIN} and {GC.STATUS_HISTORY_DAYS_MAX}.
This overrides the page-level default for this monitor. Values must be whole numbers between {GC.STATUS_HISTORY_DAYS_MIN}
and {GC.STATUS_HISTORY_DAYS_MAX}.
</p>
</Card.Content>
<Card.Footer class="flex justify-end">
@@ -86,6 +86,16 @@
// Page settings state
let pageSettings = $state<PageSettingsType>(structuredClone(defaultPageSettings));
const isHistoryDesktopValid = $derived(
Number.isInteger(pageSettings.monitor_status_history_days.desktop) &&
pageSettings.monitor_status_history_days.desktop >= GC.STATUS_HISTORY_DAYS_MIN &&
pageSettings.monitor_status_history_days.desktop <= GC.STATUS_HISTORY_DAYS_MAX
);
const isHistoryMobileValid = $derived(
Number.isInteger(pageSettings.monitor_status_history_days.mobile) &&
pageSettings.monitor_status_history_days.mobile >= GC.STATUS_HISTORY_DAYS_MIN &&
pageSettings.monitor_status_history_days.mobile <= GC.STATUS_HISTORY_DAYS_MAX
);
let savingDisplaySettings = $state(false);
let savingSeoSettings = $state(false);
@@ -479,6 +489,13 @@
async function savePageSettings(source: "display" | "seo") {
if (!currentPage) return;
if (source === "display" && (!isHistoryDesktopValid || !isHistoryMobileValid)) {
toast.error(
`Days must be a whole number between ${GC.STATUS_HISTORY_DAYS_MIN} and ${GC.STATUS_HISTORY_DAYS_MAX}`
);
return;
}
if (source === "display") savingDisplaySettings = true;
else savingSeoSettings = true;
try {
@@ -788,9 +805,11 @@
<Input
id="history-desktop"
type="number"
step="1"
min={GC.STATUS_HISTORY_DAYS_MIN}
max={GC.STATUS_HISTORY_DAYS_MAX}
bind:value={pageSettings.monitor_status_history_days.desktop}
class={isHistoryDesktopValid ? "" : "border-destructive"}
/>
<p class="text-muted-foreground text-xs">Number of days shown on desktop screens</p>
</div>
@@ -799,9 +818,11 @@
<Input
id="history-mobile"
type="number"
step="1"
min={GC.STATUS_HISTORY_DAYS_MIN}
max={GC.STATUS_HISTORY_DAYS_MAX}
bind:value={pageSettings.monitor_status_history_days.mobile}
class={isHistoryMobileValid ? "" : "border-destructive"}
/>
<p class="text-muted-foreground text-xs">Number of days shown on mobile screens</p>
</div>