From c31c9fb4ac3370561577bca15eb9517fa232fb35 Mon Sep 17 00:00:00 2001 From: Alan Peixinho Date: Thu, 16 Jul 2026 20:30:11 -0300 Subject: [PATCH] fix:log-crashes-deselecting-tree * Use a proper id, instead of positional index to avoid accessing no longer valid build/boot/test. * Add an autoclose if a log is already opened for a build/boot/test that is from a deselected tree. Signed-off-by: Alan Peixinho --- .../src/components/BootsTable/BootsTable.tsx | 63 +++++++++--------- .../components/BuildsTable/BuildsTable.tsx | 63 +++++++++--------- .../TestsTable/IndividualTestsTable.tsx | 65 +++++++++---------- 3 files changed, 94 insertions(+), 97 deletions(-) diff --git a/dashboard/src/components/BootsTable/BootsTable.tsx b/dashboard/src/components/BootsTable/BootsTable.tsx index ef28fe38c..ffd0d4c3f 100644 --- a/dashboard/src/components/BootsTable/BootsTable.tsx +++ b/dashboard/src/components/BootsTable/BootsTable.tsx @@ -305,10 +305,29 @@ export function BootsTable({ [modelRows], ); - const [currentLog, setLog] = useState(undefined); + const [currentLogId, setLog] = useState(undefined); + + const currentLog = useMemo(() => { + const index = sortedItems.findIndex(item => item.id === currentLogId); + return index === -1 ? undefined : index; + }, [sortedItems, currentLogId]); + + const activeLogId = currentLog !== undefined ? currentLogId ?? '' : ''; const onOpenChange = useCallback(() => setLog(undefined), [setLog]); - const openLogSheet = useCallback((index: number) => setLog(index), [setLog]); + const openLogSheet = useCallback( + (index: number) => setLog(sortedItems[index]?.id), + [setLog, sortedItems], + ); + + useEffect(() => { + if ( + currentLogId !== undefined && + !sortedItems.some(item => item.id === currentLogId) + ) { + setLog(undefined); + } + }, [currentLogId, sortedItems]); const tableRows = useMemo((): JSX.Element[] | JSX.Element => { return modelRows?.length ? ( @@ -332,32 +351,18 @@ export function BootsTable({ }, [modelRows, getRowLink, openLogSheet, currentLog, columns.length]); const handlePreviousItem = useCallback(() => { - setLog(previousLog => { - if (typeof previousLog === 'number' && previousLog > 0) { - return previousLog - 1; - } - - return previousLog; - }); - }, [setLog]); + if (currentLog !== undefined && currentLog > 0) { + setLog(sortedItems[currentLog - 1]?.id); + } + }, [setLog, currentLog, sortedItems]); const handleNextItem = useCallback(() => { - setLog(previousLog => { - if ( - typeof previousLog === 'number' && - previousLog < sortedItems.length - 1 - ) { - return previousLog + 1; - } - - return previousLog; - }); - }, [setLog, sortedItems.length]); + if (currentLog !== undefined && currentLog < sortedItems.length - 1) { + setLog(sortedItems[currentLog + 1]?.id); + } + }, [setLog, currentLog, sortedItems]); - const { data: logData, isLoading } = useLogData( - sortedItems.length > 0 ? sortedItems[currentLog ?? 0].id : '', - 'test', - ); + const { data: logData, isLoading } = useLogData(activeLogId, 'test'); const navigationLogsActions = useMemo( () => ({ @@ -381,13 +386,7 @@ export function BootsTable({ return getRowLink(logData?.id ?? ''); }, [logData?.id, getRowLink]); - const { - data: issues, - status, - error, - } = useTestIssues( - currentLog !== undefined ? sortedItems[currentLog]?.id : '', - ); + const { data: issues, status, error } = useTestIssues(activeLogId); return ( (undefined); + const [currentLogId, setLog] = useState(undefined); + + const currentLog = useMemo(() => { + const index = sortedItems.findIndex(item => item.id === currentLogId); + return index === -1 ? undefined : index; + }, [sortedItems, currentLogId]); + + const activeLogId = currentLog !== undefined ? currentLogId ?? '' : ''; const onOpenChange = useCallback(() => setLog(undefined), [setLog]); - const openLogSheet = useCallback((index: number) => setLog(index), [setLog]); + const openLogSheet = useCallback( + (index: number) => setLog(sortedItems[index]?.id), + [setLog, sortedItems], + ); + + useEffect(() => { + if ( + currentLogId !== undefined && + !sortedItems.some(item => item.id === currentLogId) + ) { + setLog(undefined); + } + }, [currentLogId, sortedItems]); const tableBody = useMemo((): JSX.Element[] | JSX.Element => { { @@ -228,32 +247,18 @@ export function BuildsTable({ }, [modelRows, columns.length, openLogSheet, currentLog, getRowLink]); const handlePreviousItem = useCallback(() => { - setLog(previousLog => { - if (typeof previousLog === 'number' && previousLog > 0) { - return previousLog - 1; - } - - return previousLog; - }); - }, [setLog]); + if (currentLog !== undefined && currentLog > 0) { + setLog(sortedItems[currentLog - 1]?.id); + } + }, [setLog, currentLog, sortedItems]); const handleNextItem = useCallback(() => { - setLog(previousLog => { - if ( - typeof previousLog === 'number' && - previousLog < sortedItems.length - 1 - ) { - return previousLog + 1; - } - - return previousLog; - }); - }, [setLog, sortedItems.length]); + if (currentLog !== undefined && currentLog < sortedItems.length - 1) { + setLog(sortedItems[currentLog + 1]?.id); + } + }, [setLog, currentLog, sortedItems]); - const { data: logData, isLoading } = useLogData( - sortedItems.length > 0 ? sortedItems[currentLog ?? 0]?.id : '', - 'build', - ); + const { data: logData, isLoading } = useLogData(activeLogId, 'build'); const navigationLogsActions = useMemo( () => ({ @@ -277,13 +282,7 @@ export function BuildsTable({ return getRowLink(sortedItems[currentLog ?? 0]?.id ?? ''); }, [currentLog, getRowLink, sortedItems]); - const { - data: issues, - status, - error, - } = useBuildIssues( - currentLog !== undefined ? sortedItems[currentLog]?.id : '', - ); + const { data: issues, status, error } = useBuildIssues(activeLogId); return ( (undefined); + const [currentLogId, setLog] = useState(undefined); + + const currentLog = useMemo(() => { + const index = originalItems.findIndex(item => item.id === currentLogId); + return index === -1 ? undefined : index; + }, [originalItems, currentLogId]); + + const activeLogId = currentLog !== undefined ? currentLogId ?? '' : ''; const onOpenChange = useCallback(() => setLog(undefined), [setLog]); - const openLogSheet = useCallback((index: number) => setLog(index), [setLog]); + const openLogSheet = useCallback( + (index: number) => setLog(originalItems[index]?.id), + [setLog, originalItems], + ); + + useEffect(() => { + if ( + currentLogId !== undefined && + !originalItems.some(item => item.id === currentLogId) + ) { + setLog(undefined); + } + }, [currentLogId, originalItems]); const tableRows = useMemo((): JSX.Element[] => { return virtualItems.map(virtualRow => { @@ -126,32 +145,18 @@ export function IndividualTestsTable({ }, [virtualItems, virtualizer]); const handlePreviousItem = useCallback(() => { - setLog(previousLog => { - if (typeof previousLog === 'number' && previousLog > 0) { - return previousLog - 1; - } - - return previousLog; - }); - }, [setLog]); + if (currentLog !== undefined && currentLog > 0) { + setLog(originalItems[currentLog - 1]?.id); + } + }, [setLog, currentLog, originalItems]); const handleNextItem = useCallback(() => { - setLog(previousLog => { - if ( - typeof previousLog === 'number' && - previousLog < originalItems.length - 1 - ) { - return previousLog + 1; - } - - return previousLog; - }); - }, [setLog, originalItems.length]); + if (currentLog !== undefined && currentLog < originalItems.length - 1) { + setLog(originalItems[currentLog + 1]?.id); + } + }, [setLog, currentLog, originalItems]); - const { data: logData, isLoading } = useLogData( - originalItems.length > 0 ? originalItems[currentLog ?? 0].id : '', - 'test', - ); + const { data: logData, isLoading } = useLogData(activeLogId, 'test'); const navigationLogsActions = useMemo( () => ({ @@ -175,13 +180,7 @@ export function IndividualTestsTable({ return getRowLink(logData?.id ?? ''); }, [logData?.id, getRowLink]); - const { - data: issues, - status, - error, - } = useTestIssues( - currentLog !== undefined ? originalItems[currentLog]?.id : '', - ); + const { data: issues, status, error } = useTestIssues(activeLogId); return (