mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-02 12:22:40 +02:00
feat: add expandable message rows in LogsTable for better readability
This commit is contained in:
parent
6f7e8e003f
commit
b9fc41fd19
1 changed files with 107 additions and 50 deletions
|
|
@ -777,6 +777,12 @@ function LogsTable({
|
|||
onRefresh: () => void;
|
||||
id: string;
|
||||
}) {
|
||||
const [expandedRows, setExpandedRows] = useState<Record<string, boolean>>({});
|
||||
|
||||
const toggleRowExpanded = (rowId: string) => {
|
||||
setExpandedRows((prev) => ({ ...prev, [rowId]: !prev[rowId] }));
|
||||
};
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<motion.div
|
||||
|
|
@ -878,56 +884,107 @@ function LogsTable({
|
|||
</TableHeader>
|
||||
<TableBody>
|
||||
<AnimatePresence mode="popLayout">
|
||||
{table.getRowModel().rows?.length ? (
|
||||
table.getRowModel().rows.map((row: any, index: number) => (
|
||||
<motion.tr
|
||||
key={row.id}
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
animate={{
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
transition: {
|
||||
type: "spring",
|
||||
stiffness: 300,
|
||||
damping: 30,
|
||||
delay: index * 0.03,
|
||||
},
|
||||
}}
|
||||
exit={{ opacity: 0, y: -10 }}
|
||||
className={cn(
|
||||
"border-b transition-colors hover:bg-muted/50",
|
||||
row.getIsSelected() ? "bg-muted/50" : ""
|
||||
)}
|
||||
>
|
||||
{row.getVisibleCells().map((cell: any) => {
|
||||
const isCreatedAt = cell.column.id === "created_at";
|
||||
const isMessage = cell.column.id === "message";
|
||||
return (
|
||||
<TableCell
|
||||
key={cell.id}
|
||||
// overflow-hidden on cells prevents long content from pushing other columns when using table-fixed
|
||||
className={cn(
|
||||
"px-4 py-3 align-top overflow-hidden",
|
||||
// keep Created At compact and prevent wrapping
|
||||
isCreatedAt ? "whitespace-nowrap text-xs text-muted-foreground text-right" : "",
|
||||
// ensure Message cell uses the cell-level clipping (Message markup still has its max-w)
|
||||
isMessage ? "overflow-hidden" : ""
|
||||
)}
|
||||
>
|
||||
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||
</TableCell>
|
||||
);
|
||||
})}
|
||||
</motion.tr>
|
||||
))
|
||||
) : (
|
||||
<TableRow>
|
||||
<TableCell colSpan={columns.length} className="h-24 text-center">
|
||||
No logs found.
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
{table.getRowModel().rows?.length ? (
|
||||
table.getRowModel().rows.map((row: any, index: number) => (
|
||||
<motion.tr
|
||||
key={row.id}
|
||||
initial={{ opacity: 0, y: 10 }}
|
||||
animate={{
|
||||
opacity: 1,
|
||||
y: 0,
|
||||
transition: {
|
||||
type: "spring",
|
||||
stiffness: 300,
|
||||
damping: 30,
|
||||
delay: index * 0.03,
|
||||
},
|
||||
}}
|
||||
exit={{ opacity: 0, y: -10 }}
|
||||
className={cn(
|
||||
"border-b transition-colors hover:bg-muted/50",
|
||||
row.getIsSelected() ? "bg-muted/50" : ""
|
||||
)}
|
||||
>
|
||||
{row.getVisibleCells().map((cell: any) => {
|
||||
const isCreatedAt = cell.column.id === "created_at";
|
||||
const isMessage = cell.column.id === "message";
|
||||
const isExpanded = Boolean(expandedRows[row.id]);
|
||||
|
||||
// If this is the Message column, render custom inline expandable content
|
||||
if (isMessage) {
|
||||
const message = row.getValue("message") as string;
|
||||
const taskName = row.original.log_metadata?.task_name;
|
||||
const createdAt = row.getValue("created_at") as string;
|
||||
|
||||
return (
|
||||
<TableCell
|
||||
key={cell.id}
|
||||
className={cn(
|
||||
"px-4 py-3 align-top",
|
||||
// allow expanded message to wrap; when collapsed keep clipping so it doesn't push other columns
|
||||
isExpanded ? "whitespace-normal" : "overflow-hidden",
|
||||
// keep Created At behavior unaffected
|
||||
isCreatedAt ? "whitespace-nowrap text-xs text-muted-foreground text-right" : ""
|
||||
)}
|
||||
>
|
||||
{/* Click the preview to toggle expand/collapse */}
|
||||
<button
|
||||
type="button"
|
||||
className={cn(
|
||||
"flex flex-col gap-1 text-left bg-transparent p-0",
|
||||
!isExpanded ? "max-w-[400px]" : ""
|
||||
)}
|
||||
onClick={() => toggleRowExpanded(row.id)}
|
||||
aria-expanded={isExpanded}
|
||||
>
|
||||
{taskName && (
|
||||
<div
|
||||
className="text-xs text-muted-foreground font-mono bg-muted/50 px-2 py-1 rounded inline-block max-w-[220px] truncate"
|
||||
title={taskName}
|
||||
>
|
||||
{taskName}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{isExpanded ? (
|
||||
/* Expanded: show full message, wrapped, preserve whitespace */
|
||||
<div className="text-sm whitespace-pre-wrap break-words">
|
||||
{message}
|
||||
</div>
|
||||
) : (
|
||||
/* Collapsed: truncated preview (preserve existing behavior & max-w) */
|
||||
<div className="text-sm truncate" title={message}>
|
||||
{message.length > 100 ? `${message.substring(0, 100)}...` : message}
|
||||
</div>
|
||||
)}
|
||||
</button>
|
||||
</TableCell>
|
||||
);
|
||||
}
|
||||
|
||||
// Default rendering for other columns
|
||||
return (
|
||||
<TableCell
|
||||
key={cell.id}
|
||||
className={cn(
|
||||
"px-4 py-3 align-middle overflow-hidden",
|
||||
isCreatedAt ? "whitespace-nowrap text-xs text-muted-foreground text-right" : ""
|
||||
)}
|
||||
>
|
||||
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
||||
</TableCell>
|
||||
);
|
||||
})}
|
||||
</motion.tr>
|
||||
))
|
||||
) : (
|
||||
<TableRow>
|
||||
<TableCell colSpan={columns.length} className="h-24 text-center">
|
||||
No logs found.
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</TableBody>
|
||||
</Table>
|
||||
</motion.div>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue