From fbad0e9a563927cda3d8e68a98047bc582c78237 Mon Sep 17 00:00:00 2001 From: Jason Staack Date: Sat, 21 Mar 2026 19:59:29 -0500 Subject: [PATCH] feat(19-01): add device type icon and filter to fleet table - Add DeviceTypeIcon component (Router for RouterOS, Network for SNMP) - Add Type column to desktop table between Status and Hostname - Add type icon to mobile DeviceCard view - Show em-dash for RouterOS version on SNMP devices - Add device type filter dropdown to DeviceFilters (All / RouterOS / SNMP) - Pass device_type through URL search params to API query - Update colSpan from 11 to 12 for empty/loading states Co-Authored-By: Claude Opus 4.6 (1M context) --- .../src/components/fleet/DeviceFilters.tsx | 23 +++++++++++++--- frontend/src/components/fleet/FleetTable.tsx | 27 ++++++++++++++----- .../tenants/$tenantId/devices/index.tsx | 2 ++ 3 files changed, 43 insertions(+), 9 deletions(-) diff --git a/frontend/src/components/fleet/DeviceFilters.tsx b/frontend/src/components/fleet/DeviceFilters.tsx index e1c2b77..dc507d0 100644 --- a/frontend/src/components/fleet/DeviceFilters.tsx +++ b/frontend/src/components/fleet/DeviceFilters.tsx @@ -22,7 +22,7 @@ export function DeviceFilters({ tenantId }: DeviceFiltersProps) { // Use relative navigation for filter params const navigate = useNavigate() // Safely get search params - let searchObj: { search?: string; status?: string; page?: number; page_size?: number } = {} + let searchObj: { search?: string; status?: string; device_type?: string; page?: number; page_size?: number } = {} try { // eslint-disable-next-line react-hooks/rules-of-hooks searchObj = useSearch({ from: '/_authenticated/tenants/$tenantId/devices/' }) as typeof searchObj @@ -32,6 +32,7 @@ export function DeviceFilters({ tenantId }: DeviceFiltersProps) { const searchText = searchObj.search ?? '' const statusFilter = searchObj.status ?? '' + const deviceTypeFilter = searchObj.device_type ?? '' const debounceRef = useRef | null>(null) const inputRef = useRef(null) @@ -65,11 +66,15 @@ export function DeviceFilters({ tenantId }: DeviceFiltersProps) { updateFilter({ status: value === 'all' ? undefined : value }) } - const hasFilters = !!(searchText || statusFilter) + const handleDeviceType = (value: string) => { + updateFilter({ device_type: value === 'all' ? undefined : value }) + } + + const hasFilters = !!(searchText || statusFilter || deviceTypeFilter) const clearFilters = () => { if (inputRef.current) inputRef.current.value = '' - updateFilter({ search: undefined, status: undefined }) + updateFilter({ search: undefined, status: undefined, device_type: undefined }) } return ( @@ -100,6 +105,18 @@ export function DeviceFilters({ tenantId }: DeviceFiltersProps) { + {/* Device type filter */} + + {hasFilters && (