ui: ajustar tabelas de automações e sidebar
This commit is contained in:
parent
e4d0c95791
commit
469608a10b
3 changed files with 117 additions and 86 deletions
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue