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.