import * as React from "react"; import { Box, Button, Paper, TextField, Autocomplete, Select, MenuItem, FormControl, InputLabel, Typography, } from "@mui/material"; import FilterListIcon from "@mui/icons-material/FilterList"; import { ResourceField, ResourceMode } from "../types/config"; function getDisplayValue(item: any, field: ResourceField): string { if (!item) return ""; const df = field.displayField; if (!df) return item.name || item.title || item.label || String(item.id ?? ""); if (Array.isArray(df)) { return df.map((k) => item[k]).filter((v) => v != null).join(" "); } return item[df] ?? String(item.id ?? ""); } function extractOptions( fieldName: string, field: ResourceField, data: any[] ): string[] { const values = new Set(); if (field.options) { return field.options; } if (!data) return []; for (const item of data) { const v = item[fieldName]; if (v == null) continue; if (field.type === "array" && Array.isArray(v)) { for (const el of v) { if (el != null && typeof el === "object") { const d = getDisplayValue(el, field); if (d) values.add(d); } else if (el != null) { values.add(String(el)); } } } else if (typeof v === "object") { const d = getDisplayValue(v, field); if (d) values.add(d); } else { values.add(String(v)); } } return Array.from(values).sort(); } function renderFilterInput( fieldName: string, field: ResourceField, options: string[], value: any, onChange: (key: string, val: any) => void ) { const isRange = field.type === "number" || field.type === "datetime" || field.type === "date"; if (isRange) { const rangeVal = (value as { min?: string; max?: string; start?: string; end?: string }) || {}; const isDate = field.type === "datetime" || field.type === "date"; const inputType = isDate ? "datetime-local" : "number"; if (isDate) { return ( {field.label} onChange("start", e.target.value || undefined)} InputLabelProps={{ shrink: true }} sx={{ width: 190 }} /> onChange("end", e.target.value || undefined)} InputLabelProps={{ shrink: true }} sx={{ width: 190 }} /> ); } return ( {field.label} onChange("min", e.target.value || undefined)} sx={{ width: 120 }} /> onChange("max", e.target.value || undefined)} sx={{ width: 120 }} /> ); } if (field.type === "boolean") { return ( {field.label} ); } if (options.length <= 20) { return ( onChange("value", val || undefined)} renderInput={(params) => ( )} sx={{ minWidth: 180 }} size="small" /> ); } return ( onChange("value", e.target.value || undefined)} size="small" sx={{ minWidth: 180 }} /> ); } export interface FilterBarProps { fields: Record; filterableFields: string[]; mode: ResourceMode; data?: any[]; appliedValues: Record; onApply: (values: Record) => void; onClear: () => void; } export default function FilterBar({ fields, filterableFields, data, appliedValues, onApply, onClear, }: FilterBarProps) { const [open, setOpen] = React.useState(false); const [draft, setDraft] = React.useState>(() => ({ ...appliedValues })); React.useEffect(() => { if (!open) setDraft({ ...appliedValues }); }, [appliedValues, open]); if (!filterableFields || filterableFields.length === 0) return null; const activeCount = Object.keys(appliedValues).filter((k) => { const v = appliedValues[k]; if (v == null || v === "") return false; if (typeof v === "object" && Object.values(v).every((x) => x == null || x === "")) return false; return true; }).length; const handleApply = () => onApply({ ...draft }); const handleClear = () => { setDraft({}); onClear(); }; const updateDraft = (fieldName: string, key: string, val: any) => { setDraft((prev) => { if (key === "value") { return { ...prev, [fieldName]: val }; } const existing = prev[fieldName] || {}; return { ...prev, [fieldName]: { ...existing, [key]: val } }; }); }; return ( setOpen((o) => !o)} > {open ? "Hide Filters" : "Show Filters"} {activeCount > 0 && ( {activeCount} active )} {open && ( {filterableFields.map((fieldName) => { const field = fields[fieldName]; if (!field) return null; const options = extractOptions(fieldName, field, data ?? []); const raw = draft[fieldName]; return ( {renderFilterInput(fieldName, field, options, raw, (key, val) => updateDraft(fieldName, key, val) )} ); })} )} ); }