diff --git a/dataloom-frontend/src/Components/Table.jsx b/dataloom-frontend/src/Components/Table.jsx index e0b0172f..8c1a6e8c 100644 --- a/dataloom-frontend/src/Components/Table.jsx +++ b/dataloom-frontend/src/Components/Table.jsx @@ -1,6 +1,6 @@ import ContextMenu from "./ContextMenu"; import { useContextMenu } from "../hooks/useContextMenu"; -import { useState, useEffect } from "react"; +import { useState, useEffect, useMemo } from "react"; import { transformProject } from "../api"; import { useProjectContext } from "../context/ProjectContext"; import { @@ -36,6 +36,7 @@ const Table = ({ projectId, data: externalData }) => { const [columns, setColumns] = useState([]); const [editingCell, setEditingCell] = useState(null); const [editValue, setEditValue] = useState(""); + const [sortConfig, setSortConfig] = useState(null); const { isOpen, position, contextData, open, close } = useContextMenu(); const [inputConfig, setInputConfig] = useState(null); @@ -63,6 +64,48 @@ const Table = ({ projectId, data: externalData }) => { updateData(columns, rows, newDtypes); }; + const handleSort = (columnIndex) => { + let direction = "ascending"; + if (sortConfig && sortConfig.key === columnIndex && sortConfig.direction === "ascending") { + direction = "descending"; + } else if (sortConfig && sortConfig.key === columnIndex && sortConfig.direction === "descending") { + direction = null; + } + + if (direction) { + setSortConfig({ key: columnIndex, direction }); + } else { + setSortConfig(null); + } + }; + + const sortedData = useMemo(() => { + let sortableData = [...data]; + if (sortConfig !== null) { + sortableData.sort((a, b) => { + let aValue = a[sortConfig.key]; + let bValue = b[sortConfig.key]; + + // Attempt to parse as numbers for natural numerical sorting + const numA = Number(aValue); + const numB = Number(bValue); + if (aValue !== "" && bValue !== "" && !isNaN(numA) && !isNaN(numB)) { + aValue = numA; + bValue = numB; + } + + if (aValue < bValue) { + return sortConfig.direction === "ascending" ? -1 : 1; + } + if (aValue > bValue) { + return sortConfig.direction === "ascending" ? 1 : -1; + } + return 0; + }); + } + return sortableData; + }, [data, sortConfig]); + const handleAddRow = async (index) => { try { const response = await transformProject(projectId, { @@ -231,9 +274,19 @@ const Table = ({ projectId, data: externalData }) => { className="py-1.5 px-3 border-b border-gray-200 text-left text-xs font-medium text-gray-500 uppercase tracking-wider" onContextMenu={(e) => open(e, { type: "column", columnIndex })} > - ))} @@ -241,7 +294,7 @@ const Table = ({ projectId, data: externalData }) => { - {data.map((row, rowIndex) => ( + {sortedData.map((row, rowIndex) => (