From e2cf03793dce14c016e1566fe26591fb9082d1d1 Mon Sep 17 00:00:00 2001 From: Chuck Date: Fri, 30 Jan 2026 14:29:25 -0500 Subject: [PATCH 1/3] fix(web): handle string boolean values in schedule-picker widget MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The normalizeSchedule function used strict equality (===) to check the enabled field, which would fail if the config value was a string "true" instead of boolean true. This could cause the checkbox to always appear unchecked even when the setting was enabled. Added coerceToBoolean helper that properly handles: - Boolean true/false (returns as-is) - String "true", "1", "on" (case-insensitive) → true - String "false" or other values → false Applied to both main schedule enabled and per-day enabled fields. Co-Authored-By: Claude Opus 4.5 --- .../static/v3/js/widgets/schedule-picker.js | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/web_interface/static/v3/js/widgets/schedule-picker.js b/web_interface/static/v3/js/widgets/schedule-picker.js index b19e20887..01b5e3856 100644 --- a/web_interface/static/v3/js/widgets/schedule-picker.js +++ b/web_interface/static/v3/js/widgets/schedule-picker.js @@ -99,6 +99,20 @@ }; } + /** + * Coerce a value to boolean, handling string 'true'/'false' values + * that may come from config files or form submissions. + */ + function coerceToBoolean(value) { + if (typeof value === 'boolean') { + return value; + } + if (typeof value === 'string') { + return value.toLowerCase() === 'true' || value === '1' || value.toLowerCase() === 'on'; + } + return Boolean(value); + } + /** * Merge user value with defaults */ @@ -109,7 +123,7 @@ } const schedule = { - enabled: value.enabled === true, + enabled: coerceToBoolean(value.enabled), mode: value.mode === 'per_day' ? 'per_day' : 'global', start_time: value.start_time || defaults.start_time, end_time: value.end_time || defaults.end_time, @@ -119,8 +133,10 @@ // Merge days DAYS.forEach(day => { const dayConfig = (value.days && value.days[day]) || defaults.days[day]; + // Use coerceToBoolean but default to true if enabled is undefined + const dayEnabled = dayConfig.enabled === undefined ? true : coerceToBoolean(dayConfig.enabled); schedule.days[day] = { - enabled: dayConfig.enabled !== false, + enabled: dayEnabled, start_time: dayConfig.start_time || defaults.days[day].start_time, end_time: dayConfig.end_time || defaults.days[day].end_time }; From fde7856b8f0c40e9e37fd356c57a811e35280db3 Mon Sep 17 00:00:00 2001 From: Chuck Date: Fri, 30 Jan 2026 14:53:36 -0500 Subject: [PATCH 2/3] fix: trim whitespace in coerceToBoolean string handling --- web_interface/static/v3/js/widgets/schedule-picker.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/web_interface/static/v3/js/widgets/schedule-picker.js b/web_interface/static/v3/js/widgets/schedule-picker.js index 01b5e3856..3915582cf 100644 --- a/web_interface/static/v3/js/widgets/schedule-picker.js +++ b/web_interface/static/v3/js/widgets/schedule-picker.js @@ -108,7 +108,8 @@ return value; } if (typeof value === 'string') { - return value.toLowerCase() === 'true' || value === '1' || value.toLowerCase() === 'on'; + const trimmed = value.trim().toLowerCase(); + return trimmed === 'true' || trimmed === '1' || trimmed === 'on'; } return Boolean(value); } From e070d134ef87730d89d1b1d78ce40c2ec97cb995 Mon Sep 17 00:00:00 2001 From: Chuck Date: Fri, 30 Jan 2026 15:12:12 -0500 Subject: [PATCH 3/3] fix: normalize mode value to handle per_day and per-day variants --- .../static/v3/js/widgets/schedule-picker.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/web_interface/static/v3/js/widgets/schedule-picker.js b/web_interface/static/v3/js/widgets/schedule-picker.js index 3915582cf..514170cbb 100644 --- a/web_interface/static/v3/js/widgets/schedule-picker.js +++ b/web_interface/static/v3/js/widgets/schedule-picker.js @@ -114,6 +114,18 @@ return Boolean(value); } + /** + * Normalize mode value to handle both 'per_day' and 'per-day' variants. + */ + function normalizeMode(mode) { + if (!mode || typeof mode !== 'string') { + return 'global'; + } + // Normalize: replace hyphens with underscores and check for per_day + const normalized = mode.trim().toLowerCase().replace(/-/g, '_'); + return normalized === 'per_day' ? 'per_day' : 'global'; + } + /** * Merge user value with defaults */ @@ -125,7 +137,7 @@ const schedule = { enabled: coerceToBoolean(value.enabled), - mode: value.mode === 'per_day' ? 'per_day' : 'global', + mode: normalizeMode(value.mode), start_time: value.start_time || defaults.start_time, end_time: value.end_time || defaults.end_time, days: {}