columns.tsx•7.11 kB
import { ColumnDef } from '@tanstack/react-table';
import { t } from 'i18next';
import { ChevronDown } from 'lucide-react';
import { Dispatch, SetStateAction } from 'react';
import { Button } from '@/components/ui/button';
import { Checkbox } from '@/components/ui/checkbox';
import { RowDataWithActions } from '@/components/ui/data-table';
import { DataTableColumnHeader } from '@/components/ui/data-table/data-table-column-header';
import {
DropdownMenu,
DropdownMenuContent,
DropdownMenuItem,
DropdownMenuTrigger,
} from '@/components/ui/dropdown-menu';
import { StatusIconWithText } from '@/components/ui/status-icon-with-text';
import { flowRunUtils } from '@/features/flow-runs/lib/flow-run-utils';
import { formatUtils } from '@/lib/utils';
import { FlowRun, FlowRunStatus, SeekPage } from '@activepieces/shared';
type SelectedRow = {
id: string;
status: FlowRunStatus;
};
type RunsTableColumnsProps = {
data: SeekPage<FlowRun> | undefined;
selectedRows: SelectedRow[];
setSelectedRows: Dispatch<SetStateAction<SelectedRow[]>>;
selectedAll: boolean;
setSelectedAll: Dispatch<SetStateAction<boolean>>;
excludedRows: Set<string>;
setExcludedRows: Dispatch<SetStateAction<Set<string>>>;
};
export const runsTableColumns = ({
setSelectedRows,
selectedRows,
selectedAll,
setSelectedAll,
excludedRows,
setExcludedRows,
data,
}: RunsTableColumnsProps): ColumnDef<RowDataWithActions<FlowRun>>[] => [
{
id: 'select',
header: ({ table }) => (
<div className="flex items-center">
<Checkbox
checked={selectedAll || table.getIsAllPageRowsSelected()}
variant="secondary"
onCheckedChange={(value) => {
const isChecked = !!value;
table.toggleAllPageRowsSelected(isChecked);
if (isChecked) {
const currentPageRows = table.getRowModel().rows.map((row) => ({
id: row.original.id,
status: row.original.status,
}));
setSelectedRows((prev) => {
const uniqueRows = new Map<string, SelectedRow>([
...prev.map((row) => [row.id, row] as [string, SelectedRow]),
...currentPageRows.map(
(row) => [row.id, row] as [string, SelectedRow],
),
]);
return Array.from(uniqueRows.values());
});
} else {
setSelectedAll(false);
setSelectedRows([]);
setExcludedRows(new Set());
}
}}
/>
{selectedRows.length > 0 && (
<DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="ghost" size="sm">
<ChevronDown className="h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent className="z-50">
<DropdownMenuItem
className="cursor-pointer"
onClick={() => {
const currentPageRows = table
.getRowModel()
.rows.map((row) => ({
id: row.original.id,
status: row.original.status,
}));
setSelectedRows(currentPageRows);
setSelectedAll(false);
setExcludedRows(new Set());
table.toggleAllPageRowsSelected(true);
}}
>
{t('Select shown')}
</DropdownMenuItem>
<DropdownMenuItem
className="cursor-pointer"
onClick={() => {
if (data?.data) {
const allRows = data.data.map((row) => ({
id: row.id,
status: row.status,
}));
setSelectedRows(allRows);
setSelectedAll(true);
setExcludedRows(new Set());
table.toggleAllPageRowsSelected(true);
}
}}
>
{t('Select all')}
</DropdownMenuItem>
</DropdownMenuContent>
</DropdownMenu>
)}
</div>
),
cell: ({ row }) => {
const isExcluded = excludedRows.has(row.original.id);
const isSelected = selectedAll
? !isExcluded
: selectedRows.some(
(selectedRow) => selectedRow.id === row.original.id,
);
return (
<Checkbox
variant="secondary"
checked={isSelected}
onCheckedChange={(value) => {
const isChecked = !!value;
if (selectedAll) {
if (isChecked) {
const newExcluded = new Set(excludedRows);
newExcluded.delete(row.original.id);
setExcludedRows(newExcluded);
} else {
setExcludedRows(new Set([...excludedRows, row.original.id]));
}
} else {
if (isChecked) {
setSelectedRows((prev) => [
...prev,
{
id: row.original.id,
status: row.original.status,
},
]);
} else {
setSelectedRows((prev) =>
prev.filter(
(selectedRow) => selectedRow.id !== row.original.id,
),
);
}
}
row.toggleSelected(isChecked);
}}
/>
);
},
},
{
accessorKey: 'flowId',
header: ({ column }) => (
<DataTableColumnHeader column={column} title={t('Flow')} />
),
cell: ({ row }) => {
return (
<div className="text-left">{row.original.flowVersion?.displayName}</div>
);
},
},
{
accessorKey: 'status',
header: ({ column }) => (
<DataTableColumnHeader column={column} title={t('Status')} />
),
cell: ({ row }) => {
const status = row.original.status;
const { variant, Icon } = flowRunUtils.getStatusIcon(status);
return (
<div className="text-left">
<StatusIconWithText
icon={Icon}
text={formatUtils.convertEnumToHumanReadable(status)}
variant={variant}
/>
</div>
);
},
},
{
accessorKey: 'created',
header: ({ column }) => (
<DataTableColumnHeader column={column} title={t('Start Time')} />
),
cell: ({ row }) => {
return (
<div className="text-left">
{formatUtils.formatDate(new Date(row.original.startTime))}
</div>
);
},
},
{
accessorKey: 'duration',
header: ({ column }) => (
<DataTableColumnHeader column={column} title={t('Duration')} />
),
cell: ({ row }) => {
return (
<div className="text-left">
{row.original.finishTime &&
formatUtils.formatDuration(row.original.duration)}
</div>
);
},
},
];