mirror of
https://github.com/MODSetter/SurfSense.git
synced 2026-05-06 06:12: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;
|
onRefresh: () => void;
|
||||||
id: string;
|
id: string;
|
||||||
}) {
|
}) {
|
||||||
|
const [expandedRows, setExpandedRows] = useState<Record<string, boolean>>({});
|
||||||
|
|
||||||
|
const toggleRowExpanded = (rowId: string) => {
|
||||||
|
setExpandedRows((prev) => ({ ...prev, [rowId]: !prev[rowId] }));
|
||||||
|
};
|
||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<motion.div
|
<motion.div
|
||||||
|
|
@ -878,56 +884,107 @@ function LogsTable({
|
||||||
</TableHeader>
|
</TableHeader>
|
||||||
<TableBody>
|
<TableBody>
|
||||||
<AnimatePresence mode="popLayout">
|
<AnimatePresence mode="popLayout">
|
||||||
{table.getRowModel().rows?.length ? (
|
{table.getRowModel().rows?.length ? (
|
||||||
table.getRowModel().rows.map((row: any, index: number) => (
|
table.getRowModel().rows.map((row: any, index: number) => (
|
||||||
<motion.tr
|
<motion.tr
|
||||||
key={row.id}
|
key={row.id}
|
||||||
initial={{ opacity: 0, y: 10 }}
|
initial={{ opacity: 0, y: 10 }}
|
||||||
animate={{
|
animate={{
|
||||||
opacity: 1,
|
opacity: 1,
|
||||||
y: 0,
|
y: 0,
|
||||||
transition: {
|
transition: {
|
||||||
type: "spring",
|
type: "spring",
|
||||||
stiffness: 300,
|
stiffness: 300,
|
||||||
damping: 30,
|
damping: 30,
|
||||||
delay: index * 0.03,
|
delay: index * 0.03,
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
exit={{ opacity: 0, y: -10 }}
|
exit={{ opacity: 0, y: -10 }}
|
||||||
className={cn(
|
className={cn(
|
||||||
"border-b transition-colors hover:bg-muted/50",
|
"border-b transition-colors hover:bg-muted/50",
|
||||||
row.getIsSelected() ? "bg-muted/50" : ""
|
row.getIsSelected() ? "bg-muted/50" : ""
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{row.getVisibleCells().map((cell: any) => {
|
{row.getVisibleCells().map((cell: any) => {
|
||||||
const isCreatedAt = cell.column.id === "created_at";
|
const isCreatedAt = cell.column.id === "created_at";
|
||||||
const isMessage = cell.column.id === "message";
|
const isMessage = cell.column.id === "message";
|
||||||
return (
|
const isExpanded = Boolean(expandedRows[row.id]);
|
||||||
<TableCell
|
|
||||||
key={cell.id}
|
// If this is the Message column, render custom inline expandable content
|
||||||
// overflow-hidden on cells prevents long content from pushing other columns when using table-fixed
|
if (isMessage) {
|
||||||
className={cn(
|
const message = row.getValue("message") as string;
|
||||||
"px-4 py-3 align-top overflow-hidden",
|
const taskName = row.original.log_metadata?.task_name;
|
||||||
// keep Created At compact and prevent wrapping
|
const createdAt = row.getValue("created_at") as string;
|
||||||
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)
|
return (
|
||||||
isMessage ? "overflow-hidden" : ""
|
<TableCell
|
||||||
)}
|
key={cell.id}
|
||||||
>
|
className={cn(
|
||||||
{flexRender(cell.column.columnDef.cell, cell.getContext())}
|
"px-4 py-3 align-top",
|
||||||
</TableCell>
|
// 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
|
||||||
</motion.tr>
|
isCreatedAt ? "whitespace-nowrap text-xs text-muted-foreground text-right" : ""
|
||||||
))
|
)}
|
||||||
) : (
|
>
|
||||||
<TableRow>
|
{/* Click the preview to toggle expand/collapse */}
|
||||||
<TableCell colSpan={columns.length} className="h-24 text-center">
|
<button
|
||||||
No logs found.
|
type="button"
|
||||||
</TableCell>
|
className={cn(
|
||||||
</TableRow>
|
"flex flex-col gap-1 text-left bg-transparent p-0",
|
||||||
)}
|
!isExpanded ? "max-w-[400px]" : ""
|
||||||
</AnimatePresence>
|
)}
|
||||||
|
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>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
</motion.div>
|
</motion.div>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue