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