diff --git a/frontend/src/components/SearchField.jsx b/frontend/src/components/SearchField.jsx index 28418c102..1395d6460 100644 --- a/frontend/src/components/SearchField.jsx +++ b/frontend/src/components/SearchField.jsx @@ -124,6 +124,7 @@ const SearchField = () => { status: [], type: [], node: [], + role: [], other: [] }; @@ -134,6 +135,8 @@ const SearchField = () => { categories.type.push(term); } else if (term.startsWith('node:')) { categories.node.push(term); + } else if (term.startsWith('role:')) { + categories.role.push(term); } else { categories.other.push(term); } @@ -245,27 +248,34 @@ const SearchField = () => { {/* Filter bubble button - always shown */} - - + 0) ? 'primary.main' : 'inherit', + opacity: openFilters ? 1 : 0.7, + '&:hover': { + opacity: 1, + } + }} > - - - - + + + {/* Filter popover with search terms */} @@ -377,6 +387,30 @@ const SearchField = () => { )} + {/* Role filters */} + {filteredCategories.role.length > 0 && ( + + + Role Filters: + + + {filteredCategories.role.map((term) => ( + removeSearchTerm(term)} + sx={{ + fontSize: '0.75rem', + height: 24 + }} + /> + ))} + + + )} + {/* Text search terms */} {filteredCategories.other.length > 0 && ( @@ -427,28 +461,6 @@ const SearchField = () => { Use filters to quickly find the exact systems you're looking for. Combine multiple filters for more specific results. - {/* Filter by node examples */} - - - Filter by node location: - - - } - onClick={() => { - setSearchTerm("node:"); - setAddedPrefix(true); - setFilterAnchorEl(null); - }} - sx={exampleChipStyle} - /> - - - {/* Filter by status examples */} @@ -482,6 +494,15 @@ const SearchField = () => { onClick={() => handleExampleClick("status:paused")} sx={exampleChipStyle} /> + } + onClick={() => handleExampleClick("status:suspended")} + sx={exampleChipStyle} + /> @@ -509,13 +530,150 @@ const SearchField = () => { onClick={() => handleExampleClick("type:ct")} sx={exampleChipStyle} /> + } + onClick={() => handleExampleClick("type:qemu")} + sx={exampleChipStyle} + /> + } + onClick={() => handleExampleClick("type:lxc")} + sx={exampleChipStyle} + /> + {/* Filter by node examples */} + + + Filter by node location: + + + } + onClick={() => { + setSearchTerm("node:"); + setAddedPrefix(true); + setFilterAnchorEl(null); + }} + sx={exampleChipStyle} + /> + + + + {/* Filter by role examples */} + + + Filter by HA status: + + + } + onClick={() => { + setSearchTerm("role:"); + setAddedPrefix(true); + setFilterAnchorEl(null); + }} + sx={exampleChipStyle} + /> + } + onClick={() => handleExampleClick("role:primary")} + sx={exampleChipStyle} + /> + } + onClick={() => handleExampleClick("role:secondary")} + sx={exampleChipStyle} + /> + } + onClick={() => handleExampleClick("role:migrating")} + sx={exampleChipStyle} + /> + } + onClick={() => handleExampleClick("role:error")} + sx={exampleChipStyle} + /> + } + onClick={() => handleExampleClick("role:fence")} + sx={exampleChipStyle} + /> + } + onClick={() => handleExampleClick("role:recovery")} + sx={exampleChipStyle} + /> + } + onClick={() => handleExampleClick("role:-")} + sx={exampleChipStyle} + /> + } + onClick={() => handleExampleClick("role")} + sx={{ + ...exampleChipStyle, + border: `1px dashed ${theme.palette.info.main}`, + }} + /> + + + {/* Filter by resources examples */} - Filter by resource usage thresholds: + Filter by resource usage: { onClick={() => handleExampleClick("cpu>50")} sx={exampleChipStyle} /> + } + onClick={() => handleExampleClick("cpu<30")} + sx={exampleChipStyle} + /> + } + onClick={() => handleExampleClick("cpu=50")} + sx={exampleChipStyle} + /> { sx={exampleChipStyle} /> } - onClick={() => handleExampleClick("disk>90")} + onClick={() => handleExampleClick("memory<=25")} + sx={exampleChipStyle} + /> + } + onClick={() => handleExampleClick("disk>=90")} sx={exampleChipStyle} /> { onClick={() => handleExampleClick("network>100")} sx={exampleChipStyle} /> + + Supports {'>'}{'<'} {'>='} {'<='} = operators + + + + + {/* OR search examples */} + + + OR search (matches either term): + + + handleExampleClick("web database")} + sx={exampleChipStyle} + /> + handleExampleClick("vm|ct")} + sx={exampleChipStyle} + /> + + Use spaces or | for OR logic + @@ -581,12 +797,54 @@ const SearchField = () => { onClick={() => handleExampleClick("database")} sx={exampleChipStyle} /> + } + onClick={() => handleExampleClick("nginx")} + sx={exampleChipStyle} + /> + + + + {/* Common combined searches */} + + + Common combined searches: + + + { + addSearchTerm("status:running"); + addSearchTerm("type:vm"); + setFilterAnchorEl(null); + }} + sx={exampleChipStyle} + /> + { + addSearchTerm("role:primary"); + addSearchTerm("cpu>50"); + setFilterAnchorEl(null); + }} + sx={exampleChipStyle} + /> - Tip: You can combine multiple filters (e.g., "type:vm status:running cpu{'>'}50"). + Tip: Each filter adds AND logic. Add multiple filters for precise results.