fix: melhora UX de softwares e campos personalizados
All checks were successful
CI/CD Web + Desktop / Detect changes (push) Successful in 5s
CI/CD Web + Desktop / Deploy (VPS Linux) (push) Successful in 3m4s
CI/CD Web + Desktop / Deploy Convex functions (push) Has been skipped
Quality Checks / Lint, Test and Build (push) Successful in 3m20s

Softwares instalados:
- Corrige contador de paginação (mostra 1-30, 31-60, etc.)
- Remove tooltip do botão de limpar pesquisa

Campos personalizados:
- Adiciona mensagem indicando tipo de dispositivo (desktop/celular)
- Melhora mensagem quando não há campos disponíveis
- Adiciona botão X para limpar valor de campos texto/número

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
rever-tecnologia 2025-12-18 08:44:57 -03:00
parent 73de65bbaf
commit f9deb408dc
2 changed files with 29 additions and 6 deletions

View file

@ -6013,7 +6013,14 @@ export function DeviceDetails({ device }: DeviceDetailsProps) {
<DialogContent className="max-w-2xl space-y-4"> <DialogContent className="max-w-2xl space-y-4">
<DialogHeader> <DialogHeader>
<DialogTitle>Campos personalizados {device.displayName ?? device.hostname ?? "Dispositivo"}</DialogTitle> <DialogTitle>Campos personalizados {device.displayName ?? device.hostname ?? "Dispositivo"}</DialogTitle>
<DialogDescription>Adicione e ajuste informações complementares deste dispositivo.</DialogDescription> <DialogDescription>
Adicione e ajuste informações complementares deste dispositivo.
{device.deviceType && device.deviceType !== "all" && (
<span className="mt-1 block text-xs text-slate-400">
Exibindo campos para {device.deviceType === "mobile" ? "celulares" : device.deviceType === "desktop" ? "desktops" : device.deviceType}.
</span>
)}
</DialogDescription>
</DialogHeader> </DialogHeader>
<div className="space-y-3"> <div className="space-y-3">
<div className="flex items-center justify-between"> <div className="flex items-center justify-between">
@ -6080,7 +6087,10 @@ export function DeviceDetails({ device }: DeviceDetailsProps) {
) : null} ) : null}
{editableFields.length === 0 ? ( {editableFields.length === 0 ? (
<div className="rounded-md border border-dashed border-slate-200 p-4 text-sm text-muted-foreground">Nenhum campo disponível para este tipo de dispositivo.</div> <div className="rounded-md border border-dashed border-slate-200 p-4 text-center">
<p className="text-sm text-muted-foreground">Nenhum campo disponível para {device.deviceType === "mobile" ? "celulares" : device.deviceType === "desktop" ? "desktops" : "este tipo de dispositivo"}.</p>
<p className="mt-1 text-xs text-slate-400">Clique em "Novo campo" para criar um campo específico para este dispositivo.</p>
</div>
) : ( ) : (
<div className="grid gap-3"> <div className="grid gap-3">
{editableFields.map((field) => { {editableFields.map((field) => {
@ -6090,9 +6100,23 @@ export function DeviceDetails({ device }: DeviceDetailsProps) {
<div key={field.id} className="grid gap-1"> <div key={field.id} className="grid gap-1">
<label className="text-xs font-semibold uppercase tracking-wide text-neutral-500">{field.label}</label> <label className="text-xs font-semibold uppercase tracking-wide text-neutral-500">{field.label}</label>
{field.type === "text" ? ( {field.type === "text" ? (
<Input value={(value as string) ?? ""} onChange={(e) => setValue(e.target.value)} /> <div className="flex items-center gap-2">
<Input value={(value as string) ?? ""} onChange={(e) => setValue(e.target.value)} className="flex-1" />
{value && (
<Button type="button" variant="ghost" size="icon" onClick={() => setValue("")} className="size-9 shrink-0 text-slate-400 hover:text-slate-600">
<X className="size-4" />
</Button>
)}
</div>
) : field.type === "number" ? ( ) : field.type === "number" ? (
<Input type="number" value={value == null ? "" : String(value)} onChange={(e) => setValue(e.target.value === "" ? null : Number(e.target.value))} /> <div className="flex items-center gap-2">
<Input type="number" value={value == null ? "" : String(value)} onChange={(e) => setValue(e.target.value === "" ? null : Number(e.target.value))} className="flex-1" />
{value != null && (
<Button type="button" variant="ghost" size="icon" onClick={() => setValue(null)} className="size-9 shrink-0 text-slate-400 hover:text-slate-600">
<X className="size-4" />
</Button>
)}
</div>
) : field.type === "date" ? ( ) : field.type === "date" ? (
<DatePicker <DatePicker
value={value ? String(value).slice(0, 10) : null} value={value ? String(value).slice(0, 10) : null}

View file

@ -105,7 +105,6 @@ export function DeviceSoftwareList({ machineId }: DeviceSoftwareListProps) {
size="icon" size="icon"
onClick={() => handleSearch("")} onClick={() => handleSearch("")}
className="size-10 shrink-0" className="size-10 shrink-0"
title="Limpar pesquisa"
> >
<Eraser className="size-4" /> <Eraser className="size-4" />
</Button> </Button>
@ -166,7 +165,7 @@ export function DeviceSoftwareList({ machineId }: DeviceSoftwareListProps) {
<div className="flex items-center justify-between text-xs text-neutral-500"> <div className="flex items-center justify-between text-xs text-neutral-500">
<span> <span>
Mostrando {result.items.length} de {result.total} softwares Mostrando {pageIndex * 30 + 1}-{Math.min((pageIndex + 1) * 30, result.total)} de {result.total} softwares
</span> </span>
<div className="flex gap-1"> <div className="flex gap-1">
<Button <Button