From 0d4daaeb28e4a0835ba3b84cb0fe170dbae619fb Mon Sep 17 00:00:00 2001 From: Allison Truhlar Date: Thu, 30 Apr 2026 13:18:21 -0400 Subject: [PATCH] feat: hint when zone search results are hidden by group filter --- .../src/components/ui/Sidebar/Sidebar.tsx | 4 +- .../components/ui/Sidebar/ZonesBrowser.tsx | 49 ++++++++++++++++--- .../src/hooks/useFilteredZonesAndFavorites.ts | 29 ++++++++++- 3 files changed, 74 insertions(+), 8 deletions(-) diff --git a/frontend/src/components/ui/Sidebar/Sidebar.tsx b/frontend/src/components/ui/Sidebar/Sidebar.tsx index 9a4879aaf..db5b67f26 100644 --- a/frontend/src/components/ui/Sidebar/Sidebar.tsx +++ b/frontend/src/components/ui/Sidebar/Sidebar.tsx @@ -14,7 +14,8 @@ export default function Sidebar() { filteredZonesMap, filteredZoneFavorites, filteredFileSharePathFavorites, - filteredFolderFavorites + filteredFolderFavorites, + hasResultsOutsideGroups } = useFilteredZonesAndFavorites(); return ( @@ -54,6 +55,7 @@ export default function Sidebar() { /> diff --git a/frontend/src/components/ui/Sidebar/ZonesBrowser.tsx b/frontend/src/components/ui/Sidebar/ZonesBrowser.tsx index 34ce2d7e0..a214fddaf 100644 --- a/frontend/src/components/ui/Sidebar/ZonesBrowser.tsx +++ b/frontend/src/components/ui/Sidebar/ZonesBrowser.tsx @@ -1,6 +1,7 @@ import { Collapse, Typography, List } from '@material-tailwind/react'; import { HiChevronRight } from 'react-icons/hi'; import { HiSquares2X2 } from 'react-icons/hi2'; +import toast from 'react-hot-toast'; import { ZonesAndFileSharePathsMap } from '@/shared.types'; import { useZoneAndFspMapContext } from '@/contexts/ZonesAndFspMapContext'; @@ -12,13 +13,15 @@ import { Link } from 'react-router'; export default function ZonesBrowser({ searchQuery, - filteredZonesMap + filteredZonesMap, + hasResultsOutsideGroups }: { readonly searchQuery: string; readonly filteredZonesMap: ZonesAndFileSharePathsMap; + readonly hasResultsOutsideGroups: boolean; }) { const { zonesAndFspQuery } = useZoneAndFspMapContext(); - const { isFilteredByGroups } = usePreferencesContext(); + const { isFilteredByGroups, toggleFilterByGroups } = usePreferencesContext(); const { openZones, toggleOpenZones } = useOpenZones(); const displayZones: ZonesAndFileSharePathsMap = @@ -65,11 +68,45 @@ export default function ZonesBrowser({ Object.keys(displayZones).length === 0 ? (
- No zones match your filter '{searchQuery}' - - - Try broadening your search to see more results + No zones match your filter '{searchQuery}' + {hasResultsOutsideGroups ? ( +
+ + Results exist in Zones outside your groups. + + + Change your zone display preferences to view: + +
+ { + const result = await toggleFilterByGroups(); + if (result.success) { + toast.success('All Zones are now visible'); + } else { + toast.error(result.error); + } + }} + type="checkbox" + /> + + Display Zones for your groups only + +
+
+ ) : ( + + Try broadening your search to see more results + + )}
) : ( Object.entries(displayZones).map(([key, value]) => { diff --git a/frontend/src/hooks/useFilteredZonesAndFavorites.ts b/frontend/src/hooks/useFilteredZonesAndFavorites.ts index 32d45f381..f9a10d511 100644 --- a/frontend/src/hooks/useFilteredZonesAndFavorites.ts +++ b/frontend/src/hooks/useFilteredZonesAndFavorites.ts @@ -35,11 +35,14 @@ export default function useSearchFilter() { const [filteredFolderFavorites, setFilteredFolderFavorites] = useState< FolderFavorite[] >([]); + const [hasResultsOutsideGroups, setHasResultsOutsideGroups] = + useState(false); const filterZonesMap = useCallback( (query: string) => { if (!zonesAndFspQuery.isSuccess) { setFilteredZonesMap({}); + setHasResultsOutsideGroups(false); return; } @@ -92,7 +95,28 @@ export default function useSearchFilter() { }) .filter(Boolean); // Remove null entries - setFilteredZonesMap(Object.fromEntries(matches as [string, Zone][])); + const filteredResult = Object.fromEntries(matches as [string, Zone][]); + setFilteredZonesMap(filteredResult); + + // Check if there would be results without group filtering + if (isFilteredByGroups && Object.keys(filteredResult).length === 0) { + const unfilteredMatches = Object.entries(zonesAndFspQuery.data).some( + ([key, value]) => { + if (key.startsWith('zone')) { + const zone = value as Zone; + const zoneNameMatches = zone.name.toLowerCase().includes(query); + const hasMatchingFsps = zone.fileSharePaths.some(fsp => + fsp.name.toLowerCase().includes(query) + ); + return zoneNameMatches || hasMatchingFsps; + } + return false; + } + ); + setHasResultsOutsideGroups(unfilteredMatches); + } else { + setHasResultsOutsideGroups(false); + } }, [zonesAndFspQuery, isFilteredByGroups, profile] ); @@ -147,6 +171,7 @@ export default function useSearchFilter() { filterAllFavorites(searchQuery); } else if (searchQuery === '' && isFilteredByGroups && profile?.groups) { // When search query is empty but group filtering is enabled, apply group filter + setHasResultsOutsideGroups(false); if (!zonesAndFspQuery.isSuccess) { setFilteredZonesMap({}); setFilteredZoneFavorites([]); @@ -189,6 +214,7 @@ export default function useSearchFilter() { setFilteredZoneFavorites([]); setFilteredFileSharePathFavorites([]); setFilteredFolderFavorites([]); + setHasResultsOutsideGroups(false); } }, [ searchQuery, @@ -208,6 +234,7 @@ export default function useSearchFilter() { filteredZoneFavorites, filteredFileSharePathFavorites, filteredFolderFavorites, + hasResultsOutsideGroups, handleSearchChange, clearSearch };