From 535650092e63022f29fce6690c8d4b5d1f2ab95d Mon Sep 17 00:00:00 2001 From: Josh Hawkins <32435876+hawkeye217@users.noreply.github.com> Date: Sun, 18 Oct 2026 12:14:10 -0500 Subject: [PATCH] show translated errors for motion search limits --- web/public/locales/en/views/motionSearch.json | 3 +++ .../views/motion-search/MotionSearchView.tsx | 25 +++++++++++++++++++ 2 files changed, 28 insertions(+) diff --git a/web/public/locales/en/views/motionSearch.json b/web/public/locales/en/views/motionSearch.json index 8358bfb75d..7243a89a60 100644 --- a/web/public/locales/en/views/motionSearch.json +++ b/web/public/locales/en/views/motionSearch.json @@ -56,6 +56,9 @@ "noROI": "Please draw a region of interest", "noTimeRange": "Please select a time range", "invalidTimeRange": "End time must be after start time", + "timeRangeTooLong": "Time range must be {{hours}} hours or less", + "alreadyRunning": "You already have a motion search running. Wait for it to finish or cancel it.", + "tooManySearches": "Too many motion searches are running. Try again when one finishes.", "searchFailed": "Search failed: {{message}}", "polygonTooSmall": "Polygon must have at least 3 points", "unknown": "Unknown error" diff --git a/web/src/views/motion-search/MotionSearchView.tsx b/web/src/views/motion-search/MotionSearchView.tsx index 01c3632444..8f1751018c 100644 --- a/web/src/views/motion-search/MotionSearchView.tsx +++ b/web/src/views/motion-search/MotionSearchView.tsx @@ -90,6 +90,7 @@ type MotionSearchViewProps = { }; const DEFAULT_EXPORT_WINDOW_SECONDS = 60; +const MAX_SEARCH_RANGE_HOURS = 48; const NO_REVIEW_EVENTS: ReviewSegment[] = []; export default function MotionSearchView({ @@ -860,6 +861,16 @@ export default function MotionSearchView({ return; } + if ( + searchRange.before - searchRange.after > + MAX_SEARCH_RANGE_HOURS * 3600 + ) { + toast.error( + t("errors.timeRangeTooLong", { hours: MAX_SEARCH_RANGE_HOURS }), + ); + return; + } + setIsSearching(true); setSearchResults([]); setHasSearched(true); @@ -892,6 +903,20 @@ export default function MotionSearchView({ setIsSearching(false); } } catch (error) { + const status = axios.isAxiosError(error) + ? error.response?.status + : undefined; + + if (status === 409 || status === 429) { + toast.error( + t( + status === 409 ? "errors.alreadyRunning" : "errors.tooManySearches", + ), + ); + setIsSearching(false); + return; + } + let errorMessage = t("errors.unknown"); if (axios.isAxiosError<{ message?: string; detail?: string }>(error)) {