ui: ajustar tabelas de automações e sidebar

This commit is contained in:
esdrasrenan 2025-12-13 11:59:34 -03:00
parent e4d0c95791
commit 469608a10b
3 changed files with 117 additions and 86 deletions

View file

@ -83,10 +83,9 @@ const navigation: NavigationGroup[] = [
children: [ children: [
{ title: "Todos os tickets", url: "/tickets", icon: ClipboardList, requiredRole: "staff" }, { title: "Todos os tickets", url: "/tickets", icon: ClipboardList, requiredRole: "staff" },
{ title: "Resolvidos", url: "/tickets/resolved", icon: ShieldCheck, requiredRole: "staff" }, { title: "Resolvidos", url: "/tickets/resolved", icon: ShieldCheck, requiredRole: "staff" },
{ title: "Modo Play", url: "/play", icon: PlayCircle, requiredRole: "staff" },
], ],
}, },
{ title: "Automações", url: "/automations", icon: Waypoints, requiredRole: "agent" },
{ title: "Modo Play", url: "/play", icon: PlayCircle, requiredRole: "staff" },
{ title: "Agenda", url: "/agenda", icon: CalendarDays, requiredRole: "staff" }, { title: "Agenda", url: "/agenda", icon: CalendarDays, requiredRole: "staff" },
{ title: "Dispositivos", url: "/admin/devices", icon: MonitorCog, requiredRole: "admin" }, { title: "Dispositivos", url: "/admin/devices", icon: MonitorCog, requiredRole: "admin" },
{ title: "Empréstimos", url: "/emprestimos", icon: Package, requiredRole: "staff" }, { title: "Empréstimos", url: "/emprestimos", icon: Package, requiredRole: "staff" },
@ -108,7 +107,7 @@ const navigation: NavigationGroup[] = [
}, },
{ {
title: "Administração", title: "Administração",
requiredRole: "admin", requiredRole: "agent",
items: [ items: [
{ {
title: "Cadastros", title: "Cadastros",
@ -124,6 +123,7 @@ const navigation: NavigationGroup[] = [
{ title: "Templates de relatórios", url: "/admin/report-templates", icon: LayoutTemplate, requiredRole: "admin" }, { title: "Templates de relatórios", url: "/admin/report-templates", icon: LayoutTemplate, requiredRole: "admin" },
], ],
}, },
{ title: "Automações", url: "/automations", icon: Waypoints, requiredRole: "agent" },
{ {
title: "Orquestração", title: "Orquestração",
url: "/admin/channels", url: "/admin/channels",

View file

@ -37,7 +37,11 @@ const EVENT_LABELS: Record<string, string> = {
} }
function formatDateTime(timestamp: number) { function formatDateTime(timestamp: number) {
return new Date(timestamp).toLocaleString("pt-BR") const date = new Date(timestamp)
return {
date: date.toLocaleDateString("pt-BR"),
time: date.toLocaleTimeString("pt-BR", { hour: "2-digit", minute: "2-digit", second: "2-digit" }),
}
} }
function statusBadge(status: AutomationRunRow["status"]) { function statusBadge(status: AutomationRunRow["status"]) {
@ -85,7 +89,7 @@ export function AutomationRunsDialog({
const rows = (results ?? []) as unknown as AutomationRunRow[] const rows = (results ?? []) as unknown as AutomationRunRow[]
return ( return (
<DialogContent className="max-w-5xl"> <DialogContent className="max-w-6xl">
<DialogHeader className="gap-4 pb-2"> <DialogHeader className="gap-4 pb-2">
<div className="flex flex-wrap items-center justify-between gap-3"> <div className="flex flex-wrap items-center justify-between gap-3">
<div className="space-y-1"> <div className="space-y-1">
@ -116,15 +120,15 @@ export function AutomationRunsDialog({
</DialogHeader> </DialogHeader>
<div className="space-y-3"> <div className="space-y-3">
<div className="overflow-x-auto"> <div className="rounded-3xl border border-slate-200 bg-white/90 shadow-sm overflow-hidden">
<Table className="w-full" style={{ tableLayout: "fixed", minWidth: "980px" }}> <Table className="w-full table-fixed">
<colgroup> <colgroup>
<col style={{ width: "210px" }} /> <col style={{ width: "16%" }} />
<col style={{ width: "260px" }} /> <col style={{ width: "22%" }} />
<col style={{ width: "120px" }} /> <col style={{ width: "12%" }} />
<col style={{ width: "140px" }} /> <col style={{ width: "14%" }} />
<col style={{ width: "110px" }} /> <col style={{ width: "10%" }} />
<col style={{ width: "280px" }} /> <col style={{ width: "26%" }} />
</colgroup> </colgroup>
<TableHeader className="bg-slate-100/80"> <TableHeader className="bg-slate-100/80">
<TableRow className="bg-transparent text-[11px] uppercase tracking-wide text-neutral-600 hover:bg-transparent"> <TableRow className="bg-transparent text-[11px] uppercase tracking-wide text-neutral-600 hover:bg-transparent">
@ -171,6 +175,9 @@ export function AutomationRunsDialog({
const badge = statusBadge(run.status) const badge = statusBadge(run.status)
const eventLabel = EVENT_LABELS[run.eventType] ?? run.eventType const eventLabel = EVENT_LABELS[run.eventType] ?? run.eventType
const actionsCount = run.actionsApplied?.length ?? 0 const actionsCount = run.actionsApplied?.length ?? 0
const actionsLabel =
actionsCount === 1 ? "Aplicou 1 ação" : `Aplicou ${actionsCount} ações`
const createdAtLabel = formatDateTime(run.createdAt)
const details = const details =
run.status === "ERROR" run.status === "ERROR"
? run.error ?? "Erro desconhecido" ? run.error ?? "Erro desconhecido"
@ -179,12 +186,17 @@ export function AutomationRunsDialog({
? "Ignorada" ? "Ignorada"
: "Condições não atendidas" : "Condições não atendidas"
: actionsCount > 0 : actionsCount > 0
? `Aplicou ${actionsCount} ação(ões)` ? actionsLabel
: "Sem alterações" : "Sem alterações"
return ( return (
<TableRow key={run.id} className="transition-colors hover:bg-cyan-50/30"> <TableRow key={run.id} className="transition-colors hover:bg-cyan-50/30">
<TableCell className="text-center text-sm text-neutral-700">{formatDateTime(run.createdAt)}</TableCell> <TableCell className="text-center text-sm text-neutral-700">
<div className="space-y-0.5">
<div className="font-medium text-neutral-900">{createdAtLabel.date}</div>
<div className="text-xs text-neutral-600">{createdAtLabel.time}</div>
</div>
</TableCell>
<TableCell className="text-center text-sm text-neutral-700"> <TableCell className="text-center text-sm text-neutral-700">
{run.ticket ? ( {run.ticket ? (
<div className="space-y-0.5"> <div className="space-y-0.5">
@ -197,7 +209,11 @@ export function AutomationRunsDialog({
"—" "—"
)} )}
</TableCell> </TableCell>
<TableCell className="text-center text-sm text-neutral-700">{eventLabel}</TableCell> <TableCell className="text-center text-sm text-neutral-700">
<span className="truncate" title={eventLabel}>
{eventLabel}
</span>
</TableCell>
<TableCell className="text-center"> <TableCell className="text-center">
<Badge variant={badge.variant} className="rounded-full"> <Badge variant={badge.variant} className="rounded-full">
{badge.label} {badge.label}
@ -238,4 +254,3 @@ export function AutomationRunsDialog({
</DialogContent> </DialogContent>
) )
} }

View file

@ -51,8 +51,12 @@ function triggerLabel(trigger: string) {
} }
function formatLastRun(timestamp: number | null) { function formatLastRun(timestamp: number | null) {
if (!timestamp) return "—" if (!timestamp) return null
return new Date(timestamp).toLocaleString("pt-BR") const date = new Date(timestamp)
return {
date: date.toLocaleDateString("pt-BR"),
time: date.toLocaleTimeString("pt-BR", { hour: "2-digit", minute: "2-digit", second: "2-digit" }),
}
} }
function formatConditionsSummary(conditions: unknown | null) { function formatConditionsSummary(conditions: unknown | null) {
@ -229,17 +233,17 @@ export function AutomationsManager() {
Nenhuma automação cadastrada. Nenhuma automação cadastrada.
</p> </p>
) : ( ) : (
<div className="overflow-x-auto"> <div className="rounded-3xl border border-slate-200 bg-white/90 shadow-sm overflow-hidden">
<Table className="w-full" style={{ tableLayout: "fixed", minWidth: "980px" }}> <Table className="w-full table-fixed">
<colgroup> <colgroup>
<col style={{ width: "320px" }} /> <col style={{ width: "24%" }} />
<col style={{ width: "190px" }} /> <col style={{ width: "16%" }} />
<col style={{ width: "120px" }} /> <col style={{ width: "10%" }} />
<col style={{ width: "100px" }} /> <col style={{ width: "7%" }} />
<col style={{ width: "120px" }} /> <col style={{ width: "8%" }} />
<col style={{ width: "230px" }} /> <col style={{ width: "15%" }} />
<col style={{ width: "140px" }} /> <col style={{ width: "13%" }} />
<col style={{ width: "70px" }} /> <col style={{ width: "7%" }} />
</colgroup> </colgroup>
<TableHeader className="bg-slate-100/80"> <TableHeader className="bg-slate-100/80">
<TableRow className="bg-transparent text-[11px] uppercase tracking-wide text-neutral-600 hover:bg-transparent"> <TableRow className="bg-transparent text-[11px] uppercase tracking-wide text-neutral-600 hover:bg-transparent">
@ -270,14 +274,16 @@ export function AutomationsManager() {
</TableRow> </TableRow>
</TableHeader> </TableHeader>
<TableBody> <TableBody>
{filtered.map((row) => ( {filtered.map((row) => {
const lastRun = formatLastRun(row.lastRunAt)
return (
<TableRow key={row.id} className="transition-colors hover:bg-cyan-50/30"> <TableRow key={row.id} className="transition-colors hover:bg-cyan-50/30">
<TableCell className="text-center font-semibold text-neutral-900 truncate" title={row.name}> <TableCell className="text-center font-semibold text-neutral-900 truncate" title={row.name}>
{row.name} {row.name}
</TableCell> </TableCell>
<TableCell className="text-center"> <TableCell className="text-center">
<div className="flex items-center justify-center gap-2"> <div className="flex items-center justify-center gap-2">
<Badge variant="secondary" className="rounded-full"> <Badge variant="secondary" className="rounded-full max-w-full truncate">
{triggerLabel(row.trigger)} {triggerLabel(row.trigger)}
</Badge> </Badge>
{row.timing === "DELAYED" && row.delayMs ? ( {row.timing === "DELAYED" && row.delayMs ? (
@ -292,7 +298,16 @@ export function AutomationsManager() {
</TableCell> </TableCell>
<TableCell className="text-center text-sm text-neutral-700">{row.actions?.length ?? 0}</TableCell> <TableCell className="text-center text-sm text-neutral-700">{row.actions?.length ?? 0}</TableCell>
<TableCell className="text-center text-sm text-neutral-700">{row.runCount ?? 0}</TableCell> <TableCell className="text-center text-sm text-neutral-700">{row.runCount ?? 0}</TableCell>
<TableCell className="text-center text-sm text-neutral-700">{formatLastRun(row.lastRunAt)}</TableCell> <TableCell className="text-center text-sm text-neutral-700">
{lastRun ? (
<div className="space-y-0.5">
<div className="font-medium text-neutral-900">{lastRun.date}</div>
<div className="text-xs text-neutral-600">{lastRun.time}</div>
</div>
) : (
"—"
)}
</TableCell>
<TableCell className="text-center"> <TableCell className="text-center">
<div className="flex items-center justify-center gap-2"> <div className="flex items-center justify-center gap-2">
<Switch <Switch
@ -327,7 +342,8 @@ export function AutomationsManager() {
</DropdownMenu> </DropdownMenu>
</TableCell> </TableCell>
</TableRow> </TableRow>
))} )
})}
</TableBody> </TableBody>
</Table> </Table>
</div> </div>