fix: melhora UX de softwares e campos personalizados
All checks were successful
All checks were successful
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:
parent
73de65bbaf
commit
f9deb408dc
2 changed files with 29 additions and 6 deletions
|
|
@ -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}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue