feat: data table improvements — SLA column, pagination, column resize, ordinal dates

- Call Recordings: pagination (15/page), column toggle, sortable SLA/duration/date, ordinal dates, SSE refresh
- Missed Calls: full rewrite matching data table pattern (pagination, column toggle, sort, SLA from entity)
- Call History: SLA column from entity field
- Table component: ResizableTableContainer + ColumnResizer for all tables
- Date formatting: formatDateOrdinal utility (1st April, 2nd March, etc.)
- SLA reads from platform call.sla field (seeded for 200 records)
- AI button long-press triggers OTP-gated cache clear for re-analysis

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-01 16:51:45 +05:30
parent b90740e009
commit 4f5370abdc
8 changed files with 461 additions and 160 deletions

View File

@@ -17,7 +17,9 @@ import {
Cell as AriaCell,
Collection as AriaCollection,
Column as AriaColumn,
ColumnResizer as AriaColumnResizer,
Group as AriaGroup,
ResizableTableContainer as AriaResizableTableContainer,
Row as AriaRow,
Table as AriaTable,
TableBody as AriaTableBody,
@@ -115,9 +117,9 @@ const TableRoot = ({ className, size = "md", ...props }: TableRootProps) => {
return (
<TableContext.Provider value={{ size: context?.size ?? size }}>
<div className="flex-1 overflow-auto min-h-0">
<AriaResizableTableContainer className="flex-1 overflow-auto min-h-0">
<AriaTable className={(state) => cx("w-full", typeof className === "function" ? className(state) : className)} {...props} />
</div>
</AriaResizableTableContainer>
</TableContext.Provider>
);
};
@@ -168,9 +170,10 @@ TableHeader.displayName = "TableHeader";
interface TableHeadProps extends AriaColumnProps, Omit<ThHTMLAttributes<HTMLTableCellElement>, "children" | "className" | "style" | "id"> {
label?: string;
tooltip?: string;
resizable?: boolean;
}
const TableHead = ({ className, tooltip, label, children, ...props }: TableHeadProps) => {
const TableHead = ({ className, tooltip, label, children, resizable = true, ...props }: TableHeadProps) => {
const { selectionBehavior } = useTableOptions();
return (
@@ -186,8 +189,8 @@ const TableHead = ({ className, tooltip, label, children, ...props }: TableHeadP
}
>
{(state) => (
<AriaGroup className="flex items-center gap-1">
<div className="flex items-center gap-1">
<AriaGroup className="flex items-center gap-1" role="presentation">
<div className="flex flex-1 items-center gap-1 truncate">
{label && <span className="text-xs font-semibold whitespace-nowrap text-quaternary">{label}</span>}
{typeof children === "function" ? children(state) : children}
</div>
@@ -206,6 +209,12 @@ const TableHead = ({ className, tooltip, label, children, ...props }: TableHeadP
) : (
<FontAwesomeIcon icon={faSort} className="text-fg-quaternary" />
))}
{resizable && (
<AriaColumnResizer
className="absolute right-0 top-0 bottom-0 w-px bg-transparent cursor-col-resize touch-none box-border px-[3px] bg-clip-content hover:bg-brand-solid focus-visible:bg-brand-solid"
/>
)}
</AriaGroup>
)}
</AriaColumn>