Add USB policy improvements and emprestimos details modal

- Add cron job to cleanup stale pending USB policies every 30 min
- Add cleanupStalePendingPolicies mutation to usbPolicy.ts
- Add USB policy fields to machines listByTenant query
- Display USB status chip in device details and bulk control modal
- Add details modal for emprestimos with all loan information
- Add observacoesDevolucao field to preserve original observations
- Fix status text size in details modal title

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
rever-tecnologia 2025-12-05 08:24:56 -03:00
parent e493ec9d5d
commit 7469d3b5e6
7 changed files with 346 additions and 66 deletions

View file

@ -2270,6 +2270,14 @@ export function AdminDevicesOverview({
<div className="max-h-48 space-y-1 overflow-y-auto rounded-md border border-slate-200 p-2">
{windowsDevices.map((device) => {
const checked = usbPolicySelection.includes(device.id)
const policyLabels: Record<string, string> = {
ALLOW: "Permitido",
BLOCK_ALL: "Bloqueado",
READONLY: "Leitura",
}
const currentPolicy = device.usbPolicy ? policyLabels[device.usbPolicy] ?? device.usbPolicy : null
const isPending = device.usbPolicyStatus === "PENDING"
const isFailed = device.usbPolicyStatus === "FAILED"
return (
<label
key={device.id}
@ -2286,6 +2294,16 @@ export function AdminDevicesOverview({
<span className="flex-1 truncate">
{device.displayName ?? device.hostname}
</span>
{currentPolicy && (
<span className={cn(
"rounded-full px-1.5 py-0.5 text-[10px] font-medium",
isFailed ? "bg-red-100 text-red-700" :
isPending ? "bg-amber-100 text-amber-700" :
"bg-slate-100 text-slate-600"
)}>
{currentPolicy}{isPending ? " ..." : isFailed ? " !" : ""}
</span>
)}
<span className="text-xs text-muted-foreground">
{device.companyName ?? "—"}
</span>
@ -3166,6 +3184,30 @@ export function DeviceDetails({ device }: DeviceDetailsProps) {
icon: <Key className="size-4 text-neutral-500" />,
})
}
const isWindowsDevice = (device?.osName ?? "").toLowerCase().includes("windows")
if (isWindowsDevice && device?.usbPolicy) {
const policyLabels: Record<string, string> = {
ALLOW: "Permitido",
BLOCK_ALL: "Bloqueado",
READONLY: "Somente leitura",
}
const statusLabels: Record<string, string> = {
PENDING: "Pendente",
APPLIED: "Aplicado",
FAILED: "Falhou",
}
const policyLabel = policyLabels[device.usbPolicy] ?? device.usbPolicy
const statusLabel = device.usbPolicyStatus ? ` (${statusLabels[device.usbPolicyStatus] ?? device.usbPolicyStatus})` : ""
const isPending = device.usbPolicyStatus === "PENDING"
const isFailed = device.usbPolicyStatus === "FAILED"
chips.push({
key: "usb-policy",
label: "USB",
value: `${policyLabel}${statusLabel}`,
icon: <Usb className={`size-4 ${isFailed ? "text-red-500" : isPending ? "text-amber-500" : "text-neutral-500"}`} />,
tone: isFailed ? "warning" : isPending ? "warning" : undefined,
})
}
return chips
}, [
osNameDisplay,
@ -3179,6 +3221,8 @@ export function DeviceDetails({ device }: DeviceDetailsProps) {
personaLabel,
device?.osName,
remoteAccessEntries,
device?.usbPolicy,
device?.usbPolicyStatus,
])
const companyName = device?.companyName ?? device?.companySlug ?? null