feat: allow filter by agents in agent runs

This commit is contained in:
Abhishek Kumar 2026-07-02 21:00:35 +05:30
parent 9966940624
commit cd0939d072
5 changed files with 214 additions and 10 deletions

View file

@ -1,10 +1,11 @@
import { AlertCircle, Calendar, CheckSquare, Hash, Radio, RefreshCw, Tag, X } from "lucide-react";
import { AlertCircle, Calendar, CheckSquare, Hash, ListFilter, Radio, RefreshCw, Tag, X } from "lucide-react";
import { useCallback, useEffect, useState } from "react";
import { DateRangeFilter } from "@/components/filters/DateRangeFilter";
import { MultiSelectFilter } from "@/components/filters/MultiSelectFilter";
import { NumberFilter } from "@/components/filters/NumberFilter";
import { NumberRangeFilter } from "@/components/filters/NumberRangeFilter";
import { NumberSelectFilter } from "@/components/filters/NumberSelectFilter";
import { RadioFilter } from "@/components/filters/RadioFilter";
import { TagInputFilter } from "@/components/filters/TagInputFilter";
import { TextFilter } from "@/components/filters/TextFilter";
@ -165,6 +166,8 @@ export const FilterBuilder: React.FC<FilterBuilderProps> = ({
case "number":
case "numberRange":
return <Hash className="h-4 w-4" />;
case "numberSelect":
return <ListFilter className="h-4 w-4" />;
case "radio":
return <Radio className="h-4 w-4" />;
case "tags":
@ -188,6 +191,12 @@ export const FilterBuilder: React.FC<FilterBuilderProps> = ({
const value = filter.value as NumberValue;
return value.value !== null ? value.value.toString() : "No value";
}
case "numberSelect": {
const value = filter.value as NumberValue;
if (value.value === null) return "No value";
return filter.attribute.config.numberSelectOptions?.find(option => option.value === value.value)?.label
|| value.value.toString();
}
case "numberRange":
return formatNumberRange(filter.value as NumberRangeValue, filter.attribute.config.unit);
case "radio": {
@ -244,6 +253,18 @@ export const FilterBuilder: React.FC<FilterBuilderProps> = ({
step={filter.attribute.config.step}
/>
);
case "numberSelect":
return (
<NumberSelectFilter
value={filter.value as NumberValue}
onChange={(value) => updateFilter(index, value)}
error={error}
label={filter.attribute.config.numberSelectLabel}
placeholder={filter.attribute.config.placeholder}
options={filter.attribute.config.numberSelectOptions || []}
isLoading={filter.attribute.config.numberSelectOptionsLoading}
/>
);
case "numberRange":
return (
<NumberRangeFilter

View file

@ -0,0 +1,74 @@
import { Label } from "@/components/ui/label";
import {
Select,
SelectContent,
SelectItem,
SelectTrigger,
SelectValue,
} from "@/components/ui/select";
import type { NumberFilterOption, NumberValue } from "@/types/filters";
interface NumberSelectFilterProps {
value: NumberValue;
onChange: (value: NumberValue) => void;
error?: string;
label?: string;
placeholder?: string;
options: NumberFilterOption[];
isLoading?: boolean;
}
export const NumberSelectFilter: React.FC<NumberSelectFilterProps> = ({
value,
onChange,
error,
label = "Option",
placeholder = "Select an option",
options,
isLoading = false,
}) => {
const selectedOptionExists = options.some(option => option.value === value.value);
const unavailableSelection =
value.value !== null && !selectedOptionExists
? { label: `Unavailable agent (#${value.value})`, value: value.value }
: null;
return (
<div className="space-y-2">
<div className="space-y-2">
<Label>{label}</Label>
<Select
value={value.value === null ? "" : value.value.toString()}
onValueChange={(selectedValue) => {
const numericValue = parseInt(selectedValue, 10);
onChange({ value: Number.isNaN(numericValue) ? null : numericValue });
}}
disabled={isLoading || options.length === 0}
>
<SelectTrigger className={error ? "border-red-500" : ""}>
<SelectValue placeholder={isLoading ? "Loading options..." : placeholder} />
</SelectTrigger>
<SelectContent>
{unavailableSelection && (
<SelectItem value={unavailableSelection.value.toString()} disabled>
{unavailableSelection.label}
</SelectItem>
)}
{options.length === 0 ? (
<div className="px-2 py-1.5 text-sm text-muted-foreground">
No options found
</div>
) : (
options.map((option) => (
<SelectItem key={option.value} value={option.value.toString()}>
{option.label}
</SelectItem>
))
)}
</SelectContent>
</Select>
</div>
{error && <p className="text-xs text-red-500">{error}</p>}
</div>
);
};