From e7fcfef8c7156391bfcd85841e9a96eec99fe8ca Mon Sep 17 00:00:00 2001 From: Shine1i Date: Fri, 20 Feb 2026 13:04:57 +0100 Subject: [PATCH] feat: improve dataset column visibility and cell expansion in ExecutionsView - Added column visibility toggles using a dropdown menu for greater customization. - Introduced expandable table cells for long values with "expand/collapse" functionality. - Ensured hidden columns reset on execution change, providing a consistent user experience. --- .../components/executions/executions-view.tsx | 182 ++++++++++++++---- 1 file changed, 142 insertions(+), 40 deletions(-) diff --git a/studio/frontend/src/features/recipe-studio/components/executions/executions-view.tsx b/studio/frontend/src/features/recipe-studio/components/executions/executions-view.tsx index 8e729c3402..00abb420a0 100644 --- a/studio/frontend/src/features/recipe-studio/components/executions/executions-view.tsx +++ b/studio/frontend/src/features/recipe-studio/components/executions/executions-view.tsx @@ -3,6 +3,13 @@ import type { ColumnDef } from "@tanstack/react-table"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; import { DataTable } from "@/components/ui/data-table"; +import { + DropdownMenu, + DropdownMenuCheckboxItem, + DropdownMenuContent, + DropdownMenuLabel, + DropdownMenuTrigger, +} from "@/components/ui/dropdown-menu"; import { Progress } from "@/components/ui/progress"; import { Skeleton } from "@/components/ui/skeleton"; import { @@ -63,6 +70,17 @@ function formatCellValue(value: unknown): string { } } +function isExpandableCellValue(value: string): boolean { + return value.length > 180; +} + +function truncateCellValue(value: string): string { + if (value.length <= 180) { + return value; + } + return `${value.slice(0, 180).trimEnd()}...`; +} + function parseNumber(value: unknown): number | null { return typeof value === "number" && Number.isFinite(value) ? value : null; } @@ -163,6 +181,10 @@ export function ExecutionsView({ }: ExecutionsViewProps): ReactElement { const [detailTab, setDetailTab] = useState("overview"); const [showRaw, setShowRaw] = useState(false); + const [hiddenDatasetColumns, setHiddenDatasetColumns] = useState([]); + const [expandedDatasetCells, setExpandedDatasetCells] = useState< + Record + >({}); const selectedExecution = useMemo( () => executions.find((execution) => execution.id === selectedExecutionId) ?? @@ -181,7 +203,12 @@ export function ExecutionsView({ } }, [detailTab, showRaw]); - const tableColumns = useMemo>[]>(() => { + useEffect(() => { + setHiddenDatasetColumns([]); + setExpandedDatasetCells({}); + }, [selectedExecution?.id]); + + const datasetColumnNames = useMemo(() => { if (!selectedExecution) { return []; } @@ -191,19 +218,60 @@ export function ExecutionsView({ names.add(key); } } - return Array.from(names).map((name) => ({ + return Array.from(names); + }, [selectedExecution]); + + const visibleDatasetColumnNames = useMemo( + () => + datasetColumnNames.filter( + (name) => !hiddenDatasetColumns.includes(name), + ), + [datasetColumnNames, hiddenDatasetColumns], + ); + + const tableColumns = useMemo>[]>(() => { + if (!selectedExecution) { + return []; + } + return visibleDatasetColumnNames.map((name) => ({ accessorKey: name, header: name, - cell: ({ getValue }) => { - const value = getValue(); + cell: ({ getValue, row }) => { + const rawValue = getValue(); + const value = formatCellValue(rawValue); + const canExpand = isExpandableCellValue(value); + const cellId = `${row.id}:${name}`; + const expanded = Boolean(expandedDatasetCells[cellId]); + return ( -

- {formatCellValue(value)} -

+
+ {canExpand ? ( + + ) : ( +

{value}

+ )} +
); }, })); - }, [selectedExecution]); + }, [expandedDatasetCells, selectedExecution, visibleDatasetColumnNames]); const analysisColumns = useMemo( () => parseAnalysisColumns(selectedExecution?.analysis ?? null), @@ -529,41 +597,75 @@ export function ExecutionsView({

Dataset sample

- {canPageDataset && selectedExecution && ( -
- - Page {datasetPage}/{totalPages} - - - -
- )} +
+ {datasetColumnNames.length > 0 && ( + + + + + + Visible columns + {datasetColumnNames.map((columnName) => ( + { + setHiddenDatasetColumns((current) => { + if (checked) { + return current.filter((name) => name !== columnName); + } + return [...current, columnName]; + }); + }} + > + {columnName} + + ))} + + + )} + {canPageDataset && selectedExecution && ( + <> + + Page {datasetPage}/{totalPages} + + + + + )} +
{selectedExecution.dataset.length === 0 ? (

No rows returned.

+ ) : tableColumns.length === 0 ? ( +

+ All columns hidden. Use Columns to show at least one. +

) : (