Machines: replace OS filter with searchable company dropdown; remove OS filter logic

This commit is contained in:
codex-bot 2025-10-21 09:52:36 -03:00
parent 904c2ef457
commit e04888ff4d

View file

@ -37,6 +37,7 @@ import { Badge } from "@/components/ui/badge"
import { Button } from "@/components/ui/button" import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input" import { Input } from "@/components/ui/input"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"
import { Checkbox } from "@/components/ui/checkbox" import { Checkbox } from "@/components/ui/checkbox"
import { Card, CardAction, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" import { Card, CardAction, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card"
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog" import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog"
@ -972,8 +973,8 @@ export function AdminMachinesOverview({ tenantId }: { tenantId: string }) {
const machines = useMachinesQuery(tenantId) const machines = useMachinesQuery(tenantId)
const [q, setQ] = useState("") const [q, setQ] = useState("")
const [statusFilter, setStatusFilter] = useState<string>("all") const [statusFilter, setStatusFilter] = useState<string>("all")
const [osFilter, setOsFilter] = useState<string>("all") const [companyFilterSlug, setCompanyFilterSlug] = useState<string>("all")
const [companyQuery, setCompanyQuery] = useState<string>("") const [companySearch, setCompanySearch] = useState<string>("")
const [onlyAlerts, setOnlyAlerts] = useState<boolean>(false) const [onlyAlerts, setOnlyAlerts] = useState<boolean>(false)
const { convexUserId } = useAuth() const { convexUserId } = useAuth()
const companies = useQuery( const companies = useQuery(
@ -986,13 +987,7 @@ export function AdminMachinesOverview({ tenantId }: { tenantId: string }) {
return map return map
}, [companies]) }, [companies])
const osOptions = useMemo(() => { const companyOptions = useMemo(() => (companies ?? []).map((c) => ({ slug: c.slug ?? c.id, name: c.name })).sort((a,b)=>a.name.localeCompare(b.name,"pt-BR")), [companies])
const set = new Set<string>()
machines.forEach((m) => m.osName && set.add(m.osName))
return Array.from(set).sort()
}, [machines])
const companyNameOptions = useMemo(() => (companies ?? []).map((c) => c.name).sort((a,b)=>a.localeCompare(b,"pt-BR")), [companies])
const filteredMachines = useMemo(() => { const filteredMachines = useMemo(() => {
const text = q.trim().toLowerCase() const text = q.trim().toLowerCase()
@ -1002,11 +997,7 @@ const filteredMachines = useMemo(() => {
const s = resolveMachineStatus(m).toLowerCase() const s = resolveMachineStatus(m).toLowerCase()
if (s !== statusFilter) return false if (s !== statusFilter) return false
} }
if (osFilter !== "all" && (m.osName ?? "").toLowerCase() !== osFilter.toLowerCase()) return false if (companyFilterSlug !== "all" && (m.companySlug ?? "") !== companyFilterSlug) return false
if (companyQuery && companyQuery.trim().length > 0) {
const name = companyNameBySlug.get(m.companySlug ?? "")?.toLowerCase() ?? ""
if (!name.includes(companyQuery.trim().toLowerCase())) return false
}
if (!text) return true if (!text) return true
const hay = [ const hay = [
m.hostname, m.hostname,
@ -1018,7 +1009,7 @@ const filteredMachines = useMemo(() => {
.toLowerCase() .toLowerCase()
return hay.includes(text) return hay.includes(text)
}) })
}, [machines, q, statusFilter, osFilter, companyQuery, onlyAlerts, companyNameBySlug]) }, [machines, q, statusFilter, companyFilterSlug, onlyAlerts])
return ( return (
<div className="grid gap-6"> <div className="grid gap-6">
@ -1044,47 +1035,53 @@ const filteredMachines = useMemo(() => {
<SelectItem value="unknown">Desconhecido</SelectItem> <SelectItem value="unknown">Desconhecido</SelectItem>
</SelectContent> </SelectContent>
</Select> </Select>
<Select value={osFilter} onValueChange={setOsFilter}> <Popover>
<SelectTrigger className="min-w-40"> <PopoverTrigger asChild>
<SelectValue placeholder="Sistema" /> <Button variant="outline" className="min-w-56 justify-between">
</SelectTrigger> {(() => {
<SelectContent> if (companyFilterSlug === "all") return "Todas empresas"
<SelectItem value="all">Todos sistemas</SelectItem> const found = companyOptions.find((c) => c.slug === companyFilterSlug)
{osOptions.map((os) => ( return found?.name ?? companyFilterSlug
<SelectItem key={os} value={os}>{os}</SelectItem> })()}
))} <span className="ml-2 text-slate-400"></span>
</SelectContent> </Button>
</Select> </PopoverTrigger>
<div className="relative"> <PopoverContent className="w-72 p-2" align="start">
<Input <div className="space-y-2">
value={companyQuery} <Input
onChange={(e) => setCompanyQuery(e.target.value)} value={companySearch}
placeholder="Buscar empresa" onChange={(e) => setCompanySearch(e.target.value)}
className="min-w-[220px]" placeholder="Buscar empresa..."
/> />
{companyQuery && companyNameOptions.filter((c) => c.toLowerCase().includes(companyQuery.toLowerCase())).slice(0,6).length > 0 ? ( <div className="max-h-64 overflow-auto rounded-md border border-slate-200">
<div className="absolute z-10 mt-1 max-h-52 w-full overflow-auto rounded-md border bg-white p-1 shadow-sm"> <button
{companyNameOptions type="button"
.filter((c) => c.toLowerCase().includes(companyQuery.toLowerCase())) onClick={() => { setCompanyFilterSlug("all"); setCompanySearch("") }}
.slice(0, 8) className="block w-full px-3 py-2 text-left text-sm hover:bg-slate-100"
.map((c) => ( >
<button Todas empresas
key={c} </button>
type="button" {companyOptions
onClick={() => setCompanyQuery(c)} .filter((c) => c.name.toLowerCase().includes(companySearch.toLowerCase()))
className="w-full rounded px-2 py-1 text-left text-sm hover:bg-slate-100" .map((c) => (
> <button
{c} key={c.slug}
</button> type="button"
))} onClick={() => { setCompanyFilterSlug(c.slug); setCompanySearch("") }}
className="block w-full px-3 py-2 text-left text-sm hover:bg-slate-100"
>
{c.name}
</button>
))}
</div>
</div> </div>
) : null} </PopoverContent>
</div> </Popover>
<label className="inline-flex items-center gap-2 rounded-md border border-slate-200 bg-slate-50/80 px-3 py-1.5 text-sm"> <label className="inline-flex items-center gap-2 rounded-md border border-slate-200 bg-slate-50/80 px-3 py-1.5 text-sm">
<Checkbox checked={onlyAlerts} onCheckedChange={(v) => setOnlyAlerts(Boolean(v))} /> <Checkbox checked={onlyAlerts} onCheckedChange={(v) => setOnlyAlerts(Boolean(v))} />
<span>Somente com alertas</span> <span>Somente com alertas</span>
</label> </label>
<Button variant="outline" onClick={() => { setQ(""); setStatusFilter("all"); setOsFilter("all"); setCompanyQuery(""); setOnlyAlerts(false) }}>Limpar</Button> <Button variant="outline" onClick={() => { setQ(""); setStatusFilter("all"); setCompanyFilterSlug("all"); setCompanySearch(""); setOnlyAlerts(false) }}>Limpar</Button>
</div> </div>
{machines.length === 0 ? ( {machines.length === 0 ? (
<EmptyState /> <EmptyState />