From 55ddd5db5cae6522b267449982a26d6727c0aef8 Mon Sep 17 00:00:00 2001 From: Rohit Date: Tue, 28 Jan 2025 00:46:04 +0530 Subject: [PATCH 1/4] feat: sort func for runs table --- src/components/run/RunsTable.tsx | 137 +++++++++++++++++++++++++++---- 1 file changed, 122 insertions(+), 15 deletions(-) diff --git a/src/components/run/RunsTable.tsx b/src/components/run/RunsTable.tsx index a83f391f..82acf89b 100644 --- a/src/components/run/RunsTable.tsx +++ b/src/components/run/RunsTable.tsx @@ -9,7 +9,7 @@ import TableContainer from '@mui/material/TableContainer'; import TableHead from '@mui/material/TableHead'; import TablePagination from '@mui/material/TablePagination'; import TableRow from '@mui/material/TableRow'; -import { Accordion, AccordionSummary, AccordionDetails, Typography, Box, TextField, CircularProgress } from '@mui/material'; +import { Accordion, AccordionSummary, AccordionDetails, Typography, Box, TextField, CircularProgress, Tooltip } from '@mui/material'; import ExpandMoreIcon from '@mui/icons-material/ExpandMore'; import SearchIcon from '@mui/icons-material/Search'; import { useNavigate } from 'react-router-dom'; @@ -17,6 +17,7 @@ import { useGlobalInfoStore } from "../../context/globalInfo"; import { getStoredRuns } from "../../api/storage"; import { RunSettings } from "./RunSettings"; import { CollapsibleRow } from "./ColapsibleRow"; +import { ArrowDownward, ArrowUpward, UnfoldMore } from '@mui/icons-material'; export const columns: readonly Column[] = [ { id: 'runStatus', label: 'Status', minWidth: 80 }, @@ -27,6 +28,15 @@ export const columns: readonly Column[] = [ { id: 'delete', label: 'Delete', minWidth: 80 }, ]; +type SortDirection = 'asc' | 'desc' | 'none'; + +interface AccordionSortConfig { + [robotMetaId: string]: { + field: keyof Data | null; + direction: SortDirection; + }; +} + interface Column { id: 'runStatus' | 'name' | 'startedAt' | 'finishedAt' | 'delete' | 'settings'; label: string; @@ -69,6 +79,26 @@ export const RunsTable: React.FC = ({ const { t } = useTranslation(); const navigate = useNavigate(); + const [accordionSortConfigs, setAccordionSortConfigs] = useState({}); + + const handleSort = useCallback((columnId: keyof Data, robotMetaId: string) => { + setAccordionSortConfigs(prevConfigs => { + const currentConfig = prevConfigs[robotMetaId] || { field: null, direction: 'none' }; + const newDirection: SortDirection = + currentConfig.field !== columnId ? 'asc' : + currentConfig.direction === 'none' ? 'asc' : + currentConfig.direction === 'asc' ? 'desc' : 'none'; + + return { + ...prevConfigs, + [robotMetaId]: { + field: newDirection === 'none' ? null : columnId, + direction: newDirection, + } + }; + }); + }, []); + const translatedColumns = useMemo(() => columns.map(column => ({ ...column, @@ -157,12 +187,12 @@ export const RunsTable: React.FC = ({ }, [notify, t, fetchRuns]); // Filter rows based on search term - const filteredRows = useMemo(() => - rows.filter((row) => + const filteredRows = useMemo(() => { + let result = rows.filter((row) => row.name.toLowerCase().includes(searchTerm.toLowerCase()) - ), - [rows, searchTerm] - ); + ); + return result; + }, [rows, searchTerm]); // Group filtered rows by robot meta id const groupedRows = useMemo(() => @@ -176,11 +206,27 @@ export const RunsTable: React.FC = ({ [filteredRows] ); - const renderTableRows = useCallback((data: Data[]) => { + const renderTableRows = useCallback((data: Data[], robotMetaId: string) => { const start = page * rowsPerPage; const end = start + rowsPerPage; + + let sortedData = [...data]; + const sortConfig = accordionSortConfigs[robotMetaId]; - return data + if (sortConfig?.field === 'startedAt' || sortConfig?.field === 'finishedAt') { + if (sortConfig.direction !== 'none') { + sortedData.sort((a, b) => { + const dateA = new Date(a[sortConfig.field!].replace(/(\d+)\/(\d+)\//, '$2/$1/')); + const dateB = new Date(b[sortConfig.field!].replace(/(\d+)\/(\d+)\//, '$2/$1/')); + + return sortConfig.direction === 'asc' + ? dateA.getTime() - dateB.getTime() + : dateB.getTime() - dateA.getTime(); + }); + } + } + + return sortedData .slice(start, end) .map((row) => ( = ({ runningRecordingName={runningRecordingName} /> )); - }, [page, rowsPerPage, runId, runningRecordingName, currentInterpretationLog, abortRunHandler, handleDelete]); + }, [page, rowsPerPage, runId, runningRecordingName, currentInterpretationLog, abortRunHandler, handleDelete, accordionSortConfigs]); + + const renderSortIcon = useCallback((column: Column, robotMetaId: string) => { + const sortConfig = accordionSortConfigs[robotMetaId]; + if (column.id !== 'startedAt' && column.id !== 'finishedAt') return null; + + if (sortConfig?.field !== column.id) { + return ( + + ); + } + + return sortConfig.direction === 'asc' + ? + : sortConfig.direction === 'desc' + ? + : ; + }, [accordionSortConfigs]); if (isLoading) { return ( @@ -221,10 +293,10 @@ export const RunsTable: React.FC = ({ - {Object.entries(groupedRows).map(([id, data]) => ( + {Object.entries(groupedRows).map(([robotMetaId, data]) => ( handleAccordionChange(id, isExpanded)} + key={robotMetaId} + onChange={(event, isExpanded) => handleAccordionChange(robotMetaId, isExpanded)} TransitionProps={{ unmountOnExit: true }} // Optimize accordion rendering > }> @@ -239,15 +311,50 @@ export const RunsTable: React.FC = ({ { + if (column.id === 'startedAt' || column.id === 'finishedAt') { + handleSort(column.id, robotMetaId); + } + }} > - {column.label} + + + {column.label} + + {renderSortIcon(column, robotMetaId)} + + + ))} - {renderTableRows(data)} + {renderTableRows(data, robotMetaId)} From 2d93465a758221df9e93043c4f687c23d1121268 Mon Sep 17 00:00:00 2001 From: Rohit Date: Tue, 28 Jan 2025 00:49:08 +0530 Subject: [PATCH 2/4] feat: rm fallback tooltip --- src/components/run/RunsTable.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/run/RunsTable.tsx b/src/components/run/RunsTable.tsx index 82acf89b..8151186d 100644 --- a/src/components/run/RunsTable.tsx +++ b/src/components/run/RunsTable.tsx @@ -324,7 +324,7 @@ export const RunsTable: React.FC = ({ From f8fcc856d769c44cca0079b2b202ce60ac42acda Mon Sep 17 00:00:00 2001 From: Rohit Date: Tue, 28 Jan 2025 00:49:36 +0530 Subject: [PATCH 3/4] feat: add translation for runstable tooltip --- public/locales/de.json | 1 + public/locales/en.json | 1 + public/locales/es.json | 1 + public/locales/ja.json | 1 + public/locales/zh.json | 1 + 5 files changed, 5 insertions(+) diff --git a/public/locales/de.json b/public/locales/de.json index 5c3139f7..613ddfef 100644 --- a/public/locales/de.json +++ b/public/locales/de.json @@ -62,6 +62,7 @@ "delete": "Löschen", "settings": "Einstellungen", "search": "Ausführungen suchen...", + "sort_tooltip": "Zum Sortieren klicken", "notifications": { "no_runs": "Keine Ausführungen gefunden. Bitte versuchen Sie es erneut.", "delete_success": "Ausführung erfolgreich gelöscht" diff --git a/public/locales/en.json b/public/locales/en.json index c0cd154c..85bd3148 100644 --- a/public/locales/en.json +++ b/public/locales/en.json @@ -63,6 +63,7 @@ "delete":"Delete", "settings":"Settings", "search":"Search Runs...", + "sort_tooltip": "Click to sort", "notifications": { "no_runs": "No runs found. Please try again.", "delete_success": "Run deleted successfully" diff --git a/public/locales/es.json b/public/locales/es.json index ae61ea14..46bded05 100644 --- a/public/locales/es.json +++ b/public/locales/es.json @@ -63,6 +63,7 @@ "delete": "Eliminar", "settings": "Ajustes", "search": "Buscar ejecuciones...", + "sort_tooltip": "Haga clic para ordenar", "notifications": { "no_runs": "No se encontraron ejecuciones. Por favor, inténtelo de nuevo.", "delete_success": "Ejecución eliminada con éxito" diff --git a/public/locales/ja.json b/public/locales/ja.json index 1ffa1757..ad78c8f5 100644 --- a/public/locales/ja.json +++ b/public/locales/ja.json @@ -63,6 +63,7 @@ "delete": "削除", "settings": "設定", "search": "実行を検索...", + "sort_tooltip": "クリックして並べ替え", "notifications": { "no_runs": "実行が見つかりません。もう一度お試しください。", "delete_success": "実行が正常に削除されました" diff --git a/public/locales/zh.json b/public/locales/zh.json index 7bd985d2..cd1a4f9f 100644 --- a/public/locales/zh.json +++ b/public/locales/zh.json @@ -63,6 +63,7 @@ "delete": "删除", "settings": "设置", "search": "搜索运行记录...", + "sort_tooltip": "点击排序", "notifications": { "no_runs": "未找到运行记录。请重试。", "delete_success": "运行记录删除成功" From 48cbedc40c3337a3afc4a0ce88f09db7c0586230 Mon Sep 17 00:00:00 2001 From: Rohit Date: Tue, 28 Jan 2025 11:53:47 +0530 Subject: [PATCH 4/4] feat: better datetime parsing --- src/components/run/RunsTable.tsx | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/components/run/RunsTable.tsx b/src/components/run/RunsTable.tsx index 8151186d..92233214 100644 --- a/src/components/run/RunsTable.tsx +++ b/src/components/run/RunsTable.tsx @@ -206,6 +206,18 @@ export const RunsTable: React.FC = ({ [filteredRows] ); + const parseDateString = (dateStr: string): Date => { + try { + if (dateStr.includes('PM') || dateStr.includes('AM')) { + return new Date(dateStr); + } + + return new Date(dateStr.replace(/(\d+)\/(\d+)\//, '$2/$1/')) + } catch { + return new Date(0); + } + }; + const renderTableRows = useCallback((data: Data[], robotMetaId: string) => { const start = page * rowsPerPage; const end = start + rowsPerPage; @@ -216,8 +228,8 @@ export const RunsTable: React.FC = ({ if (sortConfig?.field === 'startedAt' || sortConfig?.field === 'finishedAt') { if (sortConfig.direction !== 'none') { sortedData.sort((a, b) => { - const dateA = new Date(a[sortConfig.field!].replace(/(\d+)\/(\d+)\//, '$2/$1/')); - const dateB = new Date(b[sortConfig.field!].replace(/(\d+)\/(\d+)\//, '$2/$1/')); + const dateA = parseDateString(a[sortConfig.field!]); + const dateB = parseDateString(b[sortConfig.field!]); return sortConfig.direction === 'asc' ? dateA.getTime() - dateB.getTime()