diff --git a/src/components/LXCList.js b/src/components/LXCList.js
index cf3ef0d..b0c08c2 100644
--- a/src/components/LXCList.js
+++ b/src/components/LXCList.js
@@ -8,30 +8,51 @@ import StatusBadge from './StatusBadge';
*/
export default function LXCList({ lxc, onPowerAction, onOpenConsole }) {
const [expandedNodes, setExpandedNodes] = useState({});
+ const [filter, setFilter] = useState('');
if (!lxc?.length) {
return
No LXCs found.
;
}
- const groups = Object.groupBy(lxc, (l) => l.node);
+ const filtered = filter
+ ? lxc.filter((item) =>
+ [item.name, item.node, item.status].some((v) => v.toLowerCase().includes(filter.toLowerCase())
+ ))
+ : lxc;
+
+ const groups = Object.groupBy(filtered, (item) => item.node);
const sortedNodes = Object.keys(groups).sort();
- function toggleNode(node) {
- setExpandedNodes((prev) => ({ ...prev, [node]: !prev[node] }));
- }
+ const total = filtered.length;
+ const running = filtered.filter((item) => item.status === 'running').length;
return (
+ {filter && (
+
+ {running} running / {total - running} stopped
+ ·
+ {total} of {lxc.length}
+
+ )}
+
+
setFilter(e.target.value)}
+ className="w-full rounded-md border border-border-card bg-bg-card px-3 py-2 text-sm text-text-primary placeholder-text-secondary focus:border-accent focus:outline-none"
+ />
+
{sortedNodes.map((node) => {
- const running = groups[node].filter((l) => l.status === 'running');
- const stopped = groups[node].filter((l) => l.status !== 'running');
+ const running = groups[node].filter((item) => item.status === 'running');
+ const stopped = groups[node].filter((item) => item.status !== 'running');
const expanded = expandedNodes[node] ?? false;
return (
- {/* Node header */}
- {/* Node body */}
{expanded && (
<>
{running.length > 0 && (
@@ -69,24 +89,9 @@ export default function LXCList({ lxc, onPowerAction, onOpenConsole }) {
{formatBytes(item.disk?.used || 0)} |
|
-
-
-
+
+
+
|
))}
@@ -118,18 +123,8 @@ export default function LXCList({ lxc, onPowerAction, onOpenConsole }) {
{formatBytes(item.disk?.used || 0)} |
|
-
-
+
+
|
))}
@@ -143,6 +138,10 @@ export default function LXCList({ lxc, onPowerAction, onOpenConsole }) {
);
})}
+
+ {!total && (
+
No matches for "{filter}"
+ )}
);
}
diff --git a/src/components/VMList.js b/src/components/VMList.js
index 65a2f7f..5543cfd 100644
--- a/src/components/VMList.js
+++ b/src/components/VMList.js
@@ -8,24 +8,41 @@ import StatusBadge from './StatusBadge';
*/
export default function VMList({ vms, onPowerAction, onOpenConsole }) {
const [expandedNodes, setExpandedNodes] = useState({});
+ const [filter, setFilter] = useState('');
if (!vms?.length) {
return No VMs found.
;
}
- const groups = Object.groupBy(vms, (vm) => vm.node);
+ const filtered = filter
+ ? vms.filter((vm) =>
+ [vm.name, vm.node, vm.status].some((v) => v.toLowerCase().includes(filter.toLowerCase())))
+ : vms;
+
+ const groups = Object.groupBy(filtered, (vm) => vm.node);
const sortedNodes = Object.keys(groups).sort();
- function toggleNode(node) {
- setExpandedNodes((prev) => ({ ...prev, [node]: !prev[node] }));
- }
-
- function allExpanded() {
- return sortedNodes.every((n) => expandedNodes[n]);
- }
+ const total = filtered.length;
+ const running = filtered.filter((vm) => vm.status === 'running').length;
return (
+ {filter && (
+
+ {running} running / {total - running} stopped
+ ·
+ {total} of {vms.length}
+
+ )}
+
+
setFilter(e.target.value)}
+ className="w-full rounded-md border border-border-card bg-bg-card px-3 py-2 text-sm text-text-primary placeholder-text-secondary focus:border-accent focus:outline-none"
+ />
+
{sortedNodes.map((node) => {
const running = groups[node].filter((vm) => vm.status === 'running');
const stopped = groups[node].filter((vm) => vm.status !== 'running');
@@ -33,9 +50,8 @@ export default function VMList({ vms, onPowerAction, onOpenConsole }) {
return (
- {/* Node header */}
- {/* Node body */}
{expanded && (
<>
{running.length > 0 && (
@@ -73,24 +88,9 @@ export default function VMList({ vms, onPowerAction, onOpenConsole }) {
{formatBytes(vm.disk?.used || 0)} |
|
-
-
-
+
+
+
|
))}
@@ -122,18 +122,8 @@ export default function VMList({ vms, onPowerAction, onOpenConsole }) {
{formatBytes(vm.disk?.used || 0)} |
|
-
-
+
+
|
))}
@@ -147,6 +137,10 @@ export default function VMList({ vms, onPowerAction, onOpenConsole }) {
);
})}
+
+ {!total && (
+
No matches for "{filter}"
+ )}
);
}