fix(reports): remove truncation cap in range collectors to avoid dropped records

feat(calendar): migrate to react-day-picker v9 and polish UI
- Update classNames and CSS import (style.css)
- Custom Dropdown via shadcn Select
- Nav arrows aligned with caption (around)
- Today highlight with cyan tone, weekdays in sentence case
- Wider layout to avoid overflow; remove inner wrapper

chore(tickets): make 'Patrimônio do computador (se houver)' optional
- Backend hotfix to enforce optional + label on existing tenants
- Hide required asterisk for this field in portal/new-ticket

refactor(new-ticket): remove channel dropdown from admin/agent flow
- Keep default channel as MANUAL

feat(ux): simplify requester section and enlarge combobox trigger
- Remove RequesterPreview redundancy; show company badge in trigger
This commit is contained in:
codex-bot 2025-11-04 11:51:08 -03:00
parent e0ef66555d
commit a8333c010f
28 changed files with 1752 additions and 455 deletions

View file

@ -935,6 +935,13 @@ const DEVICE_TYPE_LABELS: Record<string, string> = {
tablet: "Tablet",
}
const DEVICE_TYPE_FILTER_OPTIONS = [
{ value: "all", label: "Todos os tipos" },
{ value: "desktop", label: DEVICE_TYPE_LABELS.desktop },
{ value: "mobile", label: DEVICE_TYPE_LABELS.mobile },
{ value: "tablet", label: DEVICE_TYPE_LABELS.tablet },
]
function formatDeviceTypeLabel(value?: string | null): string {
if (!value) return "Desconhecido"
const normalized = value.toLowerCase()
@ -1257,6 +1264,7 @@ export function AdminDevicesOverview({ tenantId, initialCompanyFilterSlug = "all
const { devices, isLoading } = useDevicesQuery(tenantId)
const [q, setQ] = useState("")
const [statusFilter, setStatusFilter] = useState<string>("all")
const [deviceTypeFilter, setDeviceTypeFilter] = useState<string>("all")
const [companyFilterSlug, setCompanyFilterSlug] = useState<string>(initialCompanyFilterSlug)
const [companySearch, setCompanySearch] = useState<string>("")
const [isCompanyPopoverOpen, setIsCompanyPopoverOpen] = useState(false)
@ -1595,6 +1603,10 @@ export function AdminDevicesOverview({ tenantId, initialCompanyFilterSlug = "all
const s = resolveDeviceStatus(m).toLowerCase()
if (s !== statusFilter) return false
}
if (deviceTypeFilter !== "all") {
const type = (m.deviceType ?? "desktop").toLowerCase()
if (type !== deviceTypeFilter) return false
}
if (companyFilterSlug !== "all" && (m.companySlug ?? "") !== companyFilterSlug) return false
if (!text) return true
const hay = [
@ -1607,7 +1619,7 @@ export function AdminDevicesOverview({ tenantId, initialCompanyFilterSlug = "all
.toLowerCase()
return hay.includes(text)
})
}, [devices, q, statusFilter, companyFilterSlug, onlyAlerts])
}, [devices, q, statusFilter, companyFilterSlug, onlyAlerts, deviceTypeFilter])
const handleOpenExportDialog = useCallback(() => {
if (filteredDevices.length === 0) {
toast.info("Não há dispositivos para exportar com os filtros atuais.")
@ -1771,10 +1783,7 @@ export function AdminDevicesOverview({ tenantId, initialCompanyFilterSlug = "all
<CardDescription>Sincronizadas via agente local ou Fleet. Atualiza em tempo real.</CardDescription>
</div>
<div className="flex flex-wrap items-center gap-2">
<Button
size="sm"
onClick={handleOpenCreateDevice}
>
<Button size="sm" onClick={handleOpenCreateDevice}>
<Plus className="size-4" />
Novo dispositivo
</Button>
@ -1797,6 +1806,18 @@ export function AdminDevicesOverview({ tenantId, initialCompanyFilterSlug = "all
<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">
@ -2392,12 +2413,12 @@ export function DeviceDetails({ device }: DeviceDetailsProps) {
const isDeactivated = !isActiveLocal || effectiveStatus === "deactivated"
const alertsHistory = useQuery(
api.devices.listAlerts,
device ? { deviceId: device.id as Id<"machines">, limit: 50 } : "skip"
device ? { machineId: device.id as Id<"machines">, limit: 50 } : "skip"
) as DeviceAlertEntry[] | undefined
const deviceAlertsHistory = alertsHistory ?? []
const openTickets = useQuery(
api.devices.listOpenTickets,
device ? { deviceId: device.id as Id<"machines">, limit: 6 } : "skip"
device ? { machineId: device.id as Id<"machines">, limit: 6 } : "skip"
) as DeviceOpenTicketsSummary | undefined
const deviceTickets = openTickets?.tickets ?? []
const totalOpenTickets = openTickets?.totalOpen ?? deviceTickets.length