From 9bbe29259c9c43530f8dc34c5b3699d08bed97d6 Mon Sep 17 00:00:00 2001 From: 1fanwang <1fannnw@gmail.com> Date: Sat, 20 Jun 2026 22:32:30 -0700 Subject: [PATCH] fix(launchplan): render the full launch plan list instead of clipping it The launch plan table and card views virtualized against document.getElementById('scroll-element'), which is null in this layout, so the virtualizer had no scroll container and rendered the wrong number of rows. The table view also read result?.length (the lodash `result` function, always truthy) instead of results?.length. Render the results directly with stable keys. Signed-off-by: 1fanwang <1fannnw@gmail.com> --- .../LaunchPlanCardList/LaunchPlanCardView.tsx | 21 +++------- .../LaunchPlanTable/LaunchPlanTableView.tsx | 20 +++------ .../test/LaunchPlanTableView.test.tsx | 41 +++++++++++++++++++ 3 files changed, 51 insertions(+), 31 deletions(-) create mode 100644 packages/oss-console/src/components/LaunchPlan/test/LaunchPlanTableView.test.tsx diff --git a/packages/oss-console/src/components/LaunchPlan/LaunchPlanCardList/LaunchPlanCardView.tsx b/packages/oss-console/src/components/LaunchPlan/LaunchPlanCardList/LaunchPlanCardView.tsx index e26c19819..9788adcda 100644 --- a/packages/oss-console/src/components/LaunchPlan/LaunchPlanCardList/LaunchPlanCardView.tsx +++ b/packages/oss-console/src/components/LaunchPlan/LaunchPlanCardList/LaunchPlanCardView.tsx @@ -1,7 +1,6 @@ -import React, { useRef } from 'react'; +import React from 'react'; import { LargeLoadingComponent } from '@clients/primitives/LoadingSpinner'; import { NoResults } from '@clients/primitives/NoResults'; -import { useVirtualizer } from '@tanstack/react-virtual'; import { SearchResult } from '../../common/SearchableList'; import { NamedEntity } from '../../../models/Common/types'; import LaunchPlanListCard from './LaunchPlanListCard'; @@ -12,26 +11,16 @@ interface LaunchPlanCardViewProps { } const LaunchPlanCardView: React.FC = ({ results, loading }) => { - const parentRef = useRef(document.getElementById('scroll-element')); - - const rowVirtualizer = useVirtualizer({ - count: results?.length ? results.length + 1 : 0, - getScrollElement: () => parentRef.current, - estimateSize: () => 100, - overscan: 15, - }); - - const items = rowVirtualizer.getVirtualItems(); - return loading ? ( ) : results.length === 0 ? ( ) : ( <> - {items.map((virtualRow) => ( - - ))} + {results.map((searchResult, index) => { + const { key, ...rest } = searchResult; + return ; + })} ); }; diff --git a/packages/oss-console/src/components/LaunchPlan/LaunchPlanTable/LaunchPlanTableView.tsx b/packages/oss-console/src/components/LaunchPlan/LaunchPlanTable/LaunchPlanTableView.tsx index 8bb8bfc65..74def5c1a 100644 --- a/packages/oss-console/src/components/LaunchPlan/LaunchPlanTable/LaunchPlanTableView.tsx +++ b/packages/oss-console/src/components/LaunchPlan/LaunchPlanTable/LaunchPlanTableView.tsx @@ -1,4 +1,4 @@ -import React, { useRef } from 'react'; +import React from 'react'; import Table from '@mui/material/Table'; import TableBody from '@mui/material/TableBody'; import TableCell from '@mui/material/TableCell'; @@ -8,8 +8,6 @@ import TableRow from '@mui/material/TableRow'; import { LargeLoadingComponent } from '@clients/primitives/LoadingSpinner'; import { TableNoRowsCell } from '@clients/primitives/TableNoRowsCell'; import { noLaunchPlansFoundString } from '@clients/common/constants'; -import { useVirtualizer } from '@tanstack/react-virtual'; -import result from 'lodash/result'; import { SearchResult } from '../../common/useSearchableListState'; import { NamedEntity } from '../../../models/Common/types'; import { LaunchPlanTableRow } from './LaunchPlanTableRow'; @@ -20,17 +18,6 @@ export interface LaunchPlanTableViewProps { } export const LaunchPlanTableView = ({ results, loading }: LaunchPlanTableViewProps) => { - const parentRef = useRef(document.getElementById('scroll-element')); - - const rowVirtualizer = useVirtualizer({ - count: result?.length ? results.length + 1 : 0, - getScrollElement: () => parentRef.current, - estimateSize: () => 100, - overscan: 15, - }); - - const items = rowVirtualizer.getVirtualItems(); - return ( ) : ( - items.map((virtualRow) => ) + results.map((searchResult, index) => { + const { key, ...rest } = searchResult; + return ; + }) )} diff --git a/packages/oss-console/src/components/LaunchPlan/test/LaunchPlanTableView.test.tsx b/packages/oss-console/src/components/LaunchPlan/test/LaunchPlanTableView.test.tsx new file mode 100644 index 000000000..0682c0992 --- /dev/null +++ b/packages/oss-console/src/components/LaunchPlan/test/LaunchPlanTableView.test.tsx @@ -0,0 +1,41 @@ +import * as React from 'react'; +import { ThemeProvider } from '@mui/material/styles'; +import { render, screen } from '@testing-library/react'; +import { muiTheme } from '@clients/theme/Theme/muiTheme'; +import { LaunchPlanTableView } from '../LaunchPlanTable/LaunchPlanTableView'; +import { SearchResult } from '../../common/useSearchableListState'; +import { NamedEntity } from '../../../models/Common/types'; + +// The real row pulls in routing + queries; mock it so the test isolates the view's row rendering. +jest.mock('../LaunchPlanTable/LaunchPlanTableRow', () => ({ + LaunchPlanTableRow: () => ( + + row + + ), +})); + +const makeResults = (n: number): SearchResult[] => + Array.from({ length: n }, (_, i) => ({ + key: `lp-${i}`, + value: { id: { name: `lp-${i}` } }, + })) as unknown as SearchResult[]; + +const renderTable = (results: SearchResult[], loading = false) => + render( + + + , + ); + +describe('LaunchPlanTableView', () => { + it('renders one row per result without clipping the list', () => { + renderTable(makeResults(3)); + expect(screen.getAllByTestId('lp-row')).toHaveLength(3); + }); + + it('renders the empty state when there are no results', () => { + renderTable(makeResults(0)); + expect(screen.queryAllByTestId('lp-row')).toHaveLength(0); + }); +});