fix(mod-queue): improve alert threshold input validation and add i18n for view selector

This commit is contained in:
plebeius
2026-01-25 16:56:48 +08:00
parent f5c3ccd1f9
commit d86637200b
36 changed files with 182 additions and 38 deletions
+4 -1
View File
@@ -269,5 +269,8 @@
"submitted": "تم الإرسال", "submitted": "تم الإرسال",
"hours": "ساعات", "hours": "ساعات",
"minutes": "دقائق", "minutes": "دقائق",
"alert_threshold": "عتبة التنبيه" "alert_threshold": "عتبة التنبيه",
"modQueue.viewLabel": "View",
"modQueue.compact": "Compact",
"modQueue.feed": "Feed"
} }
+4 -1
View File
@@ -269,5 +269,8 @@
"submitted": "জমা দেওয়া হয়েছে", "submitted": "জমা দেওয়া হয়েছে",
"hours": "ঘণ্টা", "hours": "ঘণ্টা",
"minutes": "মিনিট", "minutes": "মিনিট",
"alert_threshold": "সতর্কতা থ্রেশহোল্ড" "alert_threshold": "সতর্কতা থ্রেশহোল্ড",
"modQueue.viewLabel": "View",
"modQueue.compact": "Compact",
"modQueue.feed": "Feed"
} }
+4 -1
View File
@@ -269,5 +269,8 @@
"submitted": "Odesláno", "submitted": "Odesláno",
"hours": "hodin", "hours": "hodin",
"minutes": "minut", "minutes": "minut",
"alert_threshold": "Práh upozornění" "alert_threshold": "Práh upozornění",
"modQueue.viewLabel": "View",
"modQueue.compact": "Compact",
"modQueue.feed": "Feed"
} }
+4 -1
View File
@@ -269,5 +269,8 @@
"submitted": "Indsendt", "submitted": "Indsendt",
"hours": "timer", "hours": "timer",
"minutes": "minutter", "minutes": "minutter",
"alert_threshold": "Alarmtærskel" "alert_threshold": "Alarmtærskel",
"modQueue.viewLabel": "View",
"modQueue.compact": "Compact",
"modQueue.feed": "Feed"
} }
+4 -1
View File
@@ -269,5 +269,8 @@
"submitted": "Eingereicht", "submitted": "Eingereicht",
"hours": "Stunden", "hours": "Stunden",
"minutes": "Minuten", "minutes": "Minuten",
"alert_threshold": "Alarmschwellenwert" "alert_threshold": "Alarmschwellenwert",
"modQueue.viewLabel": "View",
"modQueue.compact": "Compact",
"modQueue.feed": "Feed"
} }
+4 -1
View File
@@ -269,5 +269,8 @@
"submitted": "Υποβλήθηκε", "submitted": "Υποβλήθηκε",
"hours": "ώρες", "hours": "ώρες",
"minutes": "λεπτά", "minutes": "λεπτά",
"alert_threshold": "Όριο ειδοποίησης" "alert_threshold": "Όριο ειδοποίησης",
"modQueue.viewLabel": "View",
"modQueue.compact": "Compact",
"modQueue.feed": "Feed"
} }
+3
View File
@@ -263,6 +263,9 @@
"alert_threshold": "Alert threshold", "alert_threshold": "Alert threshold",
"hours": "hours", "hours": "hours",
"minutes": "minutes", "minutes": "minutes",
"modQueue.viewLabel": "View",
"modQueue.compact": "Compact",
"modQueue.feed": "Feed",
"no_content": "No content", "no_content": "No content",
"excerpt": "Excerpt", "excerpt": "Excerpt",
"publishing": "Publishing", "publishing": "Publishing",
+4 -1
View File
@@ -269,5 +269,8 @@
"submitted": "Enviado", "submitted": "Enviado",
"hours": "horas", "hours": "horas",
"minutes": "minutos", "minutes": "minutos",
"alert_threshold": "Umbral de alerta" "alert_threshold": "Umbral de alerta",
"modQueue.viewLabel": "View",
"modQueue.compact": "Compact",
"modQueue.feed": "Feed"
} }
+4 -1
View File
@@ -269,5 +269,8 @@
"submitted": "ارسال شده", "submitted": "ارسال شده",
"hours": "ساعت", "hours": "ساعت",
"minutes": "دقیقه", "minutes": "دقیقه",
"alert_threshold": "آستانه هشدار" "alert_threshold": "آستانه هشدار",
"modQueue.viewLabel": "View",
"modQueue.compact": "Compact",
"modQueue.feed": "Feed"
} }
+4 -1
View File
@@ -269,5 +269,8 @@
"submitted": "Lähetetty", "submitted": "Lähetetty",
"hours": "tuntia", "hours": "tuntia",
"minutes": "minuuttia", "minutes": "minuuttia",
"alert_threshold": "Hälytyskynnys" "alert_threshold": "Hälytyskynnys",
"modQueue.viewLabel": "View",
"modQueue.compact": "Compact",
"modQueue.feed": "Feed"
} }
+4 -1
View File
@@ -269,5 +269,8 @@
"submitted": "Isinumite", "submitted": "Isinumite",
"hours": "oras", "hours": "oras",
"minutes": "minuto", "minutes": "minuto",
"alert_threshold": "Alert threshold" "alert_threshold": "Alert threshold",
"modQueue.viewLabel": "View",
"modQueue.compact": "Compact",
"modQueue.feed": "Feed"
} }
+4 -1
View File
@@ -269,5 +269,8 @@
"submitted": "Soumis", "submitted": "Soumis",
"hours": "heures", "hours": "heures",
"minutes": "minutes", "minutes": "minutes",
"alert_threshold": "Seuil d'alerte" "alert_threshold": "Seuil d'alerte",
"modQueue.viewLabel": "View",
"modQueue.compact": "Compact",
"modQueue.feed": "Feed"
} }
+4 -1
View File
@@ -269,5 +269,8 @@
"submitted": "נשלח", "submitted": "נשלח",
"hours": "שעות", "hours": "שעות",
"minutes": "דקות", "minutes": "דקות",
"alert_threshold": "סף התרעה" "alert_threshold": "סף התרעה",
"modQueue.viewLabel": "View",
"modQueue.compact": "Compact",
"modQueue.feed": "Feed"
} }
+4 -1
View File
@@ -269,5 +269,8 @@
"submitted": "सबमिट किया गया", "submitted": "सबमिट किया गया",
"hours": "घंटे", "hours": "घंटे",
"minutes": "मिनट", "minutes": "मिनट",
"alert_threshold": "सतर्कता सीमा" "alert_threshold": "सतर्कता सीमा",
"modQueue.viewLabel": "View",
"modQueue.compact": "Compact",
"modQueue.feed": "Feed"
} }
+4 -1
View File
@@ -269,5 +269,8 @@
"submitted": "Beküldve", "submitted": "Beküldve",
"hours": "óra", "hours": "óra",
"minutes": "perc", "minutes": "perc",
"alert_threshold": "Riasztási küszöb" "alert_threshold": "Riasztási küszöb",
"modQueue.viewLabel": "View",
"modQueue.compact": "Compact",
"modQueue.feed": "Feed"
} }
+4 -1
View File
@@ -269,5 +269,8 @@
"submitted": "Dikirim", "submitted": "Dikirim",
"hours": "jam", "hours": "jam",
"minutes": "menit", "minutes": "menit",
"alert_threshold": "Ambang peringatan" "alert_threshold": "Ambang peringatan",
"modQueue.viewLabel": "View",
"modQueue.compact": "Compact",
"modQueue.feed": "Feed"
} }
+4 -1
View File
@@ -269,5 +269,8 @@
"submitted": "Inviato", "submitted": "Inviato",
"hours": "ore", "hours": "ore",
"minutes": "minuti", "minutes": "minuti",
"alert_threshold": "Soglia di allerta" "alert_threshold": "Soglia di allerta",
"modQueue.viewLabel": "View",
"modQueue.compact": "Compact",
"modQueue.feed": "Feed"
} }
+4 -1
View File
@@ -269,5 +269,8 @@
"submitted": "送信済み", "submitted": "送信済み",
"hours": "時間", "hours": "時間",
"minutes": "分", "minutes": "分",
"alert_threshold": "アラート閾値" "alert_threshold": "アラート閾値",
"modQueue.viewLabel": "View",
"modQueue.compact": "Compact",
"modQueue.feed": "Feed"
} }
+4 -1
View File
@@ -269,5 +269,8 @@
"submitted": "제출됨", "submitted": "제출됨",
"hours": "시간", "hours": "시간",
"minutes": "분", "minutes": "분",
"alert_threshold": "알림 임계값" "alert_threshold": "알림 임계값",
"modQueue.viewLabel": "View",
"modQueue.compact": "Compact",
"modQueue.feed": "Feed"
} }
+4 -1
View File
@@ -269,5 +269,8 @@
"submitted": "सबमिट केले", "submitted": "सबमिट केले",
"hours": "तास", "hours": "तास",
"minutes": "मिनिटे", "minutes": "मिनिटे",
"alert_threshold": "सतर्कता मर्यादा" "alert_threshold": "सतर्कता मर्यादा",
"modQueue.viewLabel": "View",
"modQueue.compact": "Compact",
"modQueue.feed": "Feed"
} }
+4 -1
View File
@@ -269,5 +269,8 @@
"submitted": "Ingediend", "submitted": "Ingediend",
"hours": "uur", "hours": "uur",
"minutes": "minuten", "minutes": "minuten",
"alert_threshold": "Drempelwaarde voor waarschuwing" "alert_threshold": "Drempelwaarde voor waarschuwing",
"modQueue.viewLabel": "View",
"modQueue.compact": "Compact",
"modQueue.feed": "Feed"
} }
+4 -1
View File
@@ -269,5 +269,8 @@
"submitted": "Sendt inn", "submitted": "Sendt inn",
"hours": "timer", "hours": "timer",
"minutes": "minutter", "minutes": "minutter",
"alert_threshold": "Terskel for varsel" "alert_threshold": "Terskel for varsel",
"modQueue.viewLabel": "View",
"modQueue.compact": "Compact",
"modQueue.feed": "Feed"
} }
+4 -1
View File
@@ -269,5 +269,8 @@
"submitted": "Przesłane", "submitted": "Przesłane",
"hours": "godzin", "hours": "godzin",
"minutes": "minut", "minutes": "minut",
"alert_threshold": "Próg alertu" "alert_threshold": "Próg alertu",
"modQueue.viewLabel": "View",
"modQueue.compact": "Compact",
"modQueue.feed": "Feed"
} }
+4 -1
View File
@@ -269,5 +269,8 @@
"submitted": "Enviado", "submitted": "Enviado",
"hours": "horas", "hours": "horas",
"minutes": "minutos", "minutes": "minutos",
"alert_threshold": "Limite de alerta" "alert_threshold": "Limite de alerta",
"modQueue.viewLabel": "View",
"modQueue.compact": "Compact",
"modQueue.feed": "Feed"
} }
+4 -1
View File
@@ -269,5 +269,8 @@
"submitted": "Trimis", "submitted": "Trimis",
"hours": "ore", "hours": "ore",
"minutes": "minute", "minutes": "minute",
"alert_threshold": "Prag de alertă" "alert_threshold": "Prag de alertă",
"modQueue.viewLabel": "View",
"modQueue.compact": "Compact",
"modQueue.feed": "Feed"
} }
+4 -1
View File
@@ -269,5 +269,8 @@
"submitted": "Отправлено", "submitted": "Отправлено",
"hours": "часов", "hours": "часов",
"minutes": "минут", "minutes": "минут",
"alert_threshold": "Порог предупреждения" "alert_threshold": "Порог предупреждения",
"modQueue.viewLabel": "View",
"modQueue.compact": "Compact",
"modQueue.feed": "Feed"
} }
+4 -1
View File
@@ -269,5 +269,8 @@
"submitted": "Dërguar", "submitted": "Dërguar",
"hours": "orë", "hours": "orë",
"minutes": "minuta", "minutes": "minuta",
"alert_threshold": "Pragu i alarmit" "alert_threshold": "Pragu i alarmit",
"modQueue.viewLabel": "View",
"modQueue.compact": "Compact",
"modQueue.feed": "Feed"
} }
+4 -1
View File
@@ -269,5 +269,8 @@
"submitted": "Inskickat", "submitted": "Inskickat",
"hours": "timmar", "hours": "timmar",
"minutes": "minuter", "minutes": "minuter",
"alert_threshold": "Tröskelvärde för varning" "alert_threshold": "Tröskelvärde för varning",
"modQueue.viewLabel": "View",
"modQueue.compact": "Compact",
"modQueue.feed": "Feed"
} }
+4 -1
View File
@@ -269,5 +269,8 @@
"submitted": "సమర్పించబడింది", "submitted": "సమర్పించబడింది",
"hours": "గంటలు", "hours": "గంటలు",
"minutes": "నిమిషాలు", "minutes": "నిమిషాలు",
"alert_threshold": "హెచ్చరిక థ్రెషోల్డ్" "alert_threshold": "హెచ్చరిక థ్రెషోల్డ్",
"modQueue.viewLabel": "View",
"modQueue.compact": "Compact",
"modQueue.feed": "Feed"
} }
+4 -1
View File
@@ -269,5 +269,8 @@
"submitted": "ส่งแล้ว", "submitted": "ส่งแล้ว",
"hours": "ชั่วโมง", "hours": "ชั่วโมง",
"minutes": "นาที", "minutes": "นาที",
"alert_threshold": "เกณฑ์การแจ้งเตือน" "alert_threshold": "เกณฑ์การแจ้งเตือน",
"modQueue.viewLabel": "View",
"modQueue.compact": "Compact",
"modQueue.feed": "Feed"
} }
+4 -1
View File
@@ -269,5 +269,8 @@
"submitted": "Gönderildi", "submitted": "Gönderildi",
"hours": "saat", "hours": "saat",
"minutes": "dakika", "minutes": "dakika",
"alert_threshold": "Uyarı eşiği" "alert_threshold": "Uyarı eşiği",
"modQueue.viewLabel": "View",
"modQueue.compact": "Compact",
"modQueue.feed": "Feed"
} }
+4 -1
View File
@@ -269,5 +269,8 @@
"submitted": "Відправлено", "submitted": "Відправлено",
"hours": "годин", "hours": "годин",
"minutes": "хвилин", "minutes": "хвилин",
"alert_threshold": "Поріг попередження" "alert_threshold": "Поріг попередження",
"modQueue.viewLabel": "View",
"modQueue.compact": "Compact",
"modQueue.feed": "Feed"
} }
+4 -1
View File
@@ -269,5 +269,8 @@
"submitted": "جمع کرایا گیا", "submitted": "جمع کرایا گیا",
"hours": "گھنٹے", "hours": "گھنٹے",
"minutes": "منٹ", "minutes": "منٹ",
"alert_threshold": "انتباہ کی حد" "alert_threshold": "انتباہ کی حد",
"modQueue.viewLabel": "View",
"modQueue.compact": "Compact",
"modQueue.feed": "Feed"
} }
+4 -1
View File
@@ -269,5 +269,8 @@
"submitted": "Đã gửi", "submitted": "Đã gửi",
"hours": "giờ", "hours": "giờ",
"minutes": "phút", "minutes": "phút",
"alert_threshold": "Ngưỡng cảnh báo" "alert_threshold": "Ngưỡng cảnh báo",
"modQueue.viewLabel": "View",
"modQueue.compact": "Compact",
"modQueue.feed": "Feed"
} }
+4 -1
View File
@@ -269,5 +269,8 @@
"submitted": "已提交", "submitted": "已提交",
"hours": "小时", "hours": "小时",
"minutes": "分钟", "minutes": "分钟",
"alert_threshold": "警报阈值" "alert_threshold": "警报阈值",
"modQueue.viewLabel": "View",
"modQueue.compact": "Compact",
"modQueue.feed": "Feed"
} }
+43 -4
View File
@@ -230,10 +230,47 @@ const ImageSizeOptions = () => {
); );
}; };
const MAX_ALERT_THRESHOLD = 10000; // Maximum threshold value in minutes (~166 hours)
const ModQueueAlertThreshold = () => { const ModQueueAlertThreshold = () => {
const { t } = useTranslation(); const { t } = useTranslation();
const { alertThresholdValue, alertThresholdUnit, setAlertThreshold } = useModQueueStore(); const { alertThresholdValue, alertThresholdUnit, setAlertThreshold } = useModQueueStore();
const handleThresholdChange = (e: React.ChangeEvent<HTMLInputElement>) => {
const inputValue = e.target.value.trim();
// Handle empty input - allow it temporarily for better UX
if (inputValue === '') {
return;
}
// Parse safely
const parsedValue = parseInt(inputValue, 10);
// Default to 1 if invalid or NaN
if (isNaN(parsedValue) || parsedValue < 1) {
setAlertThreshold(1, alertThresholdUnit);
return;
}
// Convert to minutes for clamping, then convert back to current unit
const valueInMinutes = alertThresholdUnit === 'hours' ? parsedValue * 60 : parsedValue;
const clampedMinutes = Math.min(valueInMinutes, MAX_ALERT_THRESHOLD);
const finalValue = alertThresholdUnit === 'hours' ? Math.round(clampedMinutes / 60) : clampedMinutes;
setAlertThreshold(finalValue, alertThresholdUnit);
};
const handleThresholdBlur = (e: React.FocusEvent<HTMLInputElement>) => {
const inputValue = e.target.value.trim();
// If empty or invalid, restore to current value or default to 1
if (inputValue === '' || isNaN(parseInt(inputValue, 10))) {
const safeValue = alertThresholdValue >= 1 ? alertThresholdValue : 1;
setAlertThreshold(safeValue, alertThresholdUnit);
}
};
return ( return (
<div className={styles.modQueueControls}> <div className={styles.modQueueControls}>
<label> <label>
@@ -243,7 +280,8 @@ const ModQueueAlertThreshold = () => {
min='1' min='1'
step='1' step='1'
value={alertThresholdValue} value={alertThresholdValue}
onChange={(e) => setAlertThreshold(Number(e.target.value), alertThresholdUnit)} onChange={handleThresholdChange}
onBlur={handleThresholdBlur}
className={styles.alertThresholdInput} className={styles.alertThresholdInput}
/> />
<select <select
@@ -268,14 +306,15 @@ const ModQueueAlertThreshold = () => {
}; };
const ModQueueViewSelector = () => { const ModQueueViewSelector = () => {
const { t } = useTranslation();
const { viewMode, setViewMode } = useModQueueStore(); const { viewMode, setViewMode } = useModQueueStore();
return ( return (
<div className={styles.modQueueControls}> <div className={styles.modQueueControls}>
<label> <label>
View: {t('modQueue.viewLabel')}:
<select value={viewMode} onChange={(e) => setViewMode(e.target.value as 'compact' | 'feed')}> <select value={viewMode} onChange={(e) => setViewMode(e.target.value as 'compact' | 'feed')}>
<option value='compact'>Compact</option> <option value='compact'>{t('modQueue.compact')}</option>
<option value='feed'>Feed</option> <option value='feed'>{t('modQueue.feed')}</option>
</select> </select>
</label> </label>
</div> </div>