feat: filter the fleet by tag and target workflows by tag selector

This commit is contained in:
2026-08-04 13:42:47 +01:00
parent fa1fd14ed1
commit 2de7ac116b
5 changed files with 200 additions and 6 deletions
+45
View File
@@ -0,0 +1,45 @@
"use client";
import { useQuery } from "@tanstack/react-query";
import { api } from "@/lib/api";
export function TagFilterBar({ value, onChange }: { value: Record<string, string>; onChange: (v: Record<string, string>) => void }) {
const { data: known } = useQuery({ queryKey: ["server-tags"], queryFn: () => api.listKnownTags(), staleTime: 60_000 });
const keys = Object.keys(known ?? {}).sort();
if (keys.length === 0) return null;
const active = Object.entries(value);
return (
<div className="mb-4 flex flex-wrap items-center gap-2">
{keys.map((k) => (
<select
key={k}
value={value[k] ?? ""}
onChange={(e) => {
const next = { ...value };
if (e.target.value) next[k] = e.target.value;
else delete next[k];
onChange(next);
}}
className="rounded-lg border border-border bg-surface-2 px-2 py-1 font-mono text-xs text-text-primary focus:border-accent/50 focus:outline-none"
>
<option value="">{k}: any</option>
{(known?.[k] ?? []).map((v) => (
<option key={v} value={v}>{`${k}: ${v}`}</option>
))}
</select>
))}
{active.length > 0 && (
<button
type="button"
onClick={() => onChange({})}
className="text-xs text-text-secondary hover:text-accent focus:outline-none focus-visible:ring-2 focus-visible:ring-accent"
>
Clear {active.length} {active.length === 1 ? "filter" : "filters"}
</button>
)}
</div>
);
}
@@ -15,7 +15,7 @@ export function EditWorkflowModal({ open, workflow, onSaved, onClose }: { open:
const [targets, setTargets] = useState<string[]>(workflow.target_server_ids);
const [busy, setBusy] = useState(false);
const [error, setError] = useState<string | null>(null);
const { data: servers } = useQuery({ queryKey: ["servers"], queryFn: api.listServers });
const { data: servers } = useQuery({ queryKey: ["servers"], queryFn: () => api.listServers() });
useEffect(() => {
if (open) {