chore: sync staging
This commit is contained in:
parent
c5ddd54a3e
commit
561b19cf66
610 changed files with 105285 additions and 1206 deletions
|
|
@ -1796,105 +1796,116 @@ export function AdminDevicesOverview({ tenantId, initialCompanyFilterSlug = "all
|
|||
</div>
|
||||
</CardHeader>
|
||||
<CardContent className="overflow-hidden">
|
||||
<div className="mb-3 flex flex-wrap items-center gap-2">
|
||||
<div className="min-w-[220px] flex-1">
|
||||
<Input value={q} onChange={(e) => setQ(e.target.value)} placeholder="Buscar hostname, e-mail, MAC, serial..." />
|
||||
<div className="mb-3 flex flex-col gap-3">
|
||||
<div className="flex flex-wrap gap-3">
|
||||
<label className="flex min-w-[260px] flex-1 flex-col gap-1 text-xs font-semibold uppercase tracking-wide text-neutral-500">
|
||||
Buscar hostname, e-mail, MAC, serial...
|
||||
<Input value={q} onChange={(e) => setQ(e.target.value)} placeholder="Digite para filtrar" />
|
||||
</label>
|
||||
<label className="flex w-auto min-w-[170px] max-w-[220px] flex-col gap-1 text-xs font-semibold uppercase tracking-wide text-neutral-500">
|
||||
Todos status
|
||||
<Select value={statusFilter} onValueChange={setStatusFilter}>
|
||||
<SelectTrigger className="justify-between text-sm">
|
||||
<SelectValue placeholder="Status" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="all">Todos status</SelectItem>
|
||||
<SelectItem value="online">Online</SelectItem>
|
||||
<SelectItem value="offline">Offline</SelectItem>
|
||||
<SelectItem value="stale">Sem sinal</SelectItem>
|
||||
<SelectItem value="unknown">Desconhecido</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</label>
|
||||
<label className="flex w-auto min-w-[180px] max-w-[240px] flex-col gap-1 text-xs font-semibold uppercase tracking-wide text-neutral-500">
|
||||
Todos os tipos
|
||||
<Select value={deviceTypeFilter} onValueChange={setDeviceTypeFilter}>
|
||||
<SelectTrigger className="justify-between text-sm">
|
||||
<SelectValue placeholder="Tipo de dispositivo" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{DEVICE_TYPE_FILTER_OPTIONS.map((option) => (
|
||||
<SelectItem key={option.value} value={option.value}>
|
||||
{option.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
</label>
|
||||
</div>
|
||||
<Select value={statusFilter} onValueChange={setStatusFilter}>
|
||||
<SelectTrigger className="min-w-36">
|
||||
<SelectValue placeholder="Status" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
<SelectItem value="all">Todos status</SelectItem>
|
||||
<SelectItem value="online">Online</SelectItem>
|
||||
<SelectItem value="offline">Offline</SelectItem>
|
||||
<SelectItem value="stale">Sem sinal</SelectItem>
|
||||
<SelectItem value="unknown">Desconhecido</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Select value={deviceTypeFilter} onValueChange={setDeviceTypeFilter}>
|
||||
<SelectTrigger className="min-w-40">
|
||||
<SelectValue placeholder="Tipo de dispositivo" />
|
||||
</SelectTrigger>
|
||||
<SelectContent>
|
||||
{DEVICE_TYPE_FILTER_OPTIONS.map((option) => (
|
||||
<SelectItem key={option.value} value={option.value}>
|
||||
{option.label}
|
||||
</SelectItem>
|
||||
))}
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<Popover open={isCompanyPopoverOpen} onOpenChange={setIsCompanyPopoverOpen}>
|
||||
<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("")
|
||||
setIsCompanyPopoverOpen(false)
|
||||
}}
|
||||
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("")
|
||||
setIsCompanyPopoverOpen(false)
|
||||
}}
|
||||
className="block w-full px-3 py-2 text-left text-sm hover:bg-slate-100"
|
||||
>
|
||||
{c.name}
|
||||
</button>
|
||||
))}
|
||||
<div className="flex flex-wrap items-center gap-3">
|
||||
<Popover open={isCompanyPopoverOpen} onOpenChange={setIsCompanyPopoverOpen}>
|
||||
<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("")
|
||||
setIsCompanyPopoverOpen(false)
|
||||
}}
|
||||
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("")
|
||||
setIsCompanyPopoverOpen(false)
|
||||
}}
|
||||
className="block w-full px-3 py-2 text-left text-sm hover:bg-slate-100"
|
||||
>
|
||||
{c.name}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</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")
|
||||
setCompanyFilterSlug("all")
|
||||
setCompanySearch("")
|
||||
setOnlyAlerts(false)
|
||||
setIsCompanyPopoverOpen(false)
|
||||
}}
|
||||
>
|
||||
Limpar
|
||||
</Button>
|
||||
<Button size="sm" variant="outline" className="gap-2" onClick={handleOpenExportDialog}>
|
||||
<Download className="size-4" />
|
||||
Exportar XLSX
|
||||
</Button>
|
||||
</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")
|
||||
setCompanyFilterSlug("all")
|
||||
setCompanySearch("")
|
||||
setOnlyAlerts(false)
|
||||
setIsCompanyPopoverOpen(false)
|
||||
}}
|
||||
>
|
||||
Limpar
|
||||
</Button>
|
||||
<Button size="sm" variant="outline" className="gap-2" onClick={handleOpenExportDialog}>
|
||||
<Download className="size-4" />
|
||||
Exportar XLSX
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
{isLoading ? (
|
||||
<LoadingState />
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue