feat(app): show attempt count column on the Skipped Packages tab

attemptCount goes through SkippedPackageItem and SkippedRow into a new
column on the data table. Badge color cues:
  - outline (1)        first failure, will auto-retry next cycle
  - secondary (2-4)    has retried but still below cap
  - destructive (>=5)  hit the cap; will not auto-retry until reset

The "Skipped" column is renamed to "Last Skipped" since the timestamp
now reflects the most recent attempt, not the first.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-05-22 23:08:08 +02:00
parent 379bf246cd
commit 3b327eb3f3
3 changed files with 18 additions and 1 deletions

View File

@@ -20,6 +20,7 @@ export interface SkippedRow {
sourceChannel: { id: string; title: string };
isMultipart: boolean;
partCount: number;
attemptCount: number;
createdAt: string;
}
@@ -107,9 +108,22 @@ export function getSkippedColumns({
),
accessorFn: (row) => row.sourceChannel.title,
},
{
accessorKey: "attemptCount",
header: ({ column }) => <DataTableColumnHeader column={column} title="Attempts" />,
cell: ({ row }) => {
const count = row.original.attemptCount;
const variant = count >= 5 ? "destructive" : count > 1 ? "secondary" : "outline";
return (
<Badge variant={variant} className="text-[10px]">
{count}
</Badge>
);
},
},
{
accessorKey: "createdAt",
header: ({ column }) => <DataTableColumnHeader column={column} title="Skipped" />,
header: ({ column }) => <DataTableColumnHeader column={column} title="Last Skipped" />,
cell: ({ row }) => (
<span className="text-sm text-muted-foreground">
{new Date(row.original.createdAt).toLocaleDateString()}

View File

@@ -589,6 +589,7 @@ export async function listSkippedPackages(options: {
sourceMessageId: s.sourceMessageId.toString(),
isMultipart: s.isMultipart,
partCount: s.partCount,
attemptCount: s.attemptCount,
createdAt: s.createdAt.toISOString(),
}));

View File

@@ -55,6 +55,8 @@ export interface SkippedPackageItem {
sourceMessageId: string;
isMultipart: boolean;
partCount: number;
/** How many times the worker has tried this source message across cycles. */
attemptCount: number;
createdAt: string;
}