1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

Fix PodDetailsList being empty over 100 pods (#4096)

This commit is contained in:
Sebastian Malton 2021-10-21 09:38:48 -04:00 committed by GitHub
parent 3fc9436a2e
commit d5719f29b8
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 96 additions and 66 deletions

View File

@ -51,26 +51,14 @@ interface Props extends OptionalProps {
interface OptionalProps {
maxCpu?: number;
maxMemory?: number;
showTitle?: boolean;
}
@observer
export class PodDetailsList extends React.Component<Props> {
static defaultProps: OptionalProps = {
showTitle: true
};
private metricsWatcher = interval(120, () => {
podsStore.loadKubeMetrics(this.props.owner.getNs());
});
private sortingCallbacks = {
[sortBy.name]: (pod: Pod) => pod.getName(),
[sortBy.namespace]: (pod: Pod) => pod.getNs(),
[sortBy.cpu]: (pod: Pod) => podsStore.getPodKubeMetrics(pod).cpu,
[sortBy.memory]: (pod: Pod) => podsStore.getPodKubeMetrics(pod).memory,
};
componentDidMount() {
this.metricsWatcher.start(true);
disposeOnUnmount(this, [
@ -144,27 +132,43 @@ export class PodDetailsList extends React.Component<Props> {
}
render() {
const { pods, showTitle } = this.props;
const virtual = pods.length > 100;
const { pods } = this.props;
if (!pods.length && !podsStore.isLoaded) return (
<div className="PodDetailsList flex justify-center"><Spinner/></div>
);
if (!pods.length) return null;
if (!podsStore.isLoaded) {
return (
<div className="PodDetailsList flex justify-center">
<Spinner />
</div>
);
}
if (!pods.length) {
return null;
}
const virtual = pods.length > 20;
return (
<div className="PodDetailsList flex column">
{showTitle && <DrawerTitle title="Pods"/>}
<DrawerTitle title="Pods" />
<Table
tableId="workloads_pod_details_list"
items={pods}
selectable
virtual={virtual}
scrollable={false}
sortable={this.sortingCallbacks}
virtual={virtual}
// 660 is the exact hight required for 20 items with the default paddings
virtualHeight={660}
sortable={{
[sortBy.name]: pod => pod.getName(),
[sortBy.namespace]: pod => pod.getNs(),
[sortBy.cpu]: pod => podsStore.getPodKubeMetrics(pod).cpu,
[sortBy.memory]: pod => podsStore.getPodKubeMetrics(pod).memory,
}}
sortByDefault={{ sortBy: sortBy.cpu, orderBy: "desc" }}
sortSyncWithUrl={false}
getTableRow={this.getTableRow}
renderRow={!virtual && (pod => this.getTableRow(pod.getId()))}
className="box grow"
>
<TableHead>
@ -176,9 +180,6 @@ export class PodDetailsList extends React.Component<Props> {
<TableCell className="memory" sortBy={sortBy.memory}>Memory</TableCell>
<TableCell className="status">Status</TableCell>
</TableHead>
{
!virtual && pods.map(pod => this.getTableRow(pod.getId()))
}
</Table>
</div>
);

View File

@ -57,9 +57,26 @@ export interface TableProps<Item> extends React.DOMAttributes<HTMLDivElement> {
onSort?: (params: TableSortParams) => void; // callback on sort change, default: global sync with url
noItems?: React.ReactNode; // Show no items state table list is empty
selectedItemId?: string; // Allows to scroll list to selected item
virtual?: boolean; // Use virtual list component to render only visible rows
rowPadding?: string;
rowLineHeight?: string;
/**
* Use virtual list component to render only visible rows. By default uses a
* auto sizer to fill available height
*/
virtual?: boolean;
/**
* Only used when virtual is true. Sets the virtual list to be a fixed height.
* Needed when used in contexts that already have a parent component that
* is `overflow-y: scroll`,
*/
virtualHeight?: number;
/**
* Row padding in pixels
*/
rowPadding?: number;
/**
* Row line height in pixels
*/
rowLineHeight?: number;
customRowHeights?: (item: Item, lineHeight: number, paddings: number) => number;
getTableRow?: (uid: string) => React.ReactElement<TableRowProps>;
renderRow?: (item: Item) => React.ReactElement<TableRowProps>;
@ -78,9 +95,10 @@ export class Table<Item> extends React.Component<TableProps<Item>> {
static defaultProps: TableProps<any> = {
scrollable: true,
autoSize: true,
rowPadding: "8px",
rowLineHeight: "17px",
rowPadding: 8,
rowLineHeight: 17,
sortSyncWithUrl: true,
customRowHeights: (item, lineHeight, paddings) => lineHeight + paddings,
};
constructor(props: TableProps<Item>) {
@ -185,7 +203,10 @@ export class Table<Item> extends React.Component<TableProps<Item>> {
}
renderRows() {
const { noItems, virtual, customRowHeights, rowLineHeight, rowPadding, items, getTableRow, selectedItemId, className } = this.props;
const {
noItems, virtual, customRowHeights, rowLineHeight, rowPadding, items,
getTableRow, selectedItemId, className, virtualHeight
} = this.props;
const content = this.getContent();
let rows: React.ReactElement<TableRowProps>[] = content.filter(elem => elem.type === TableRow);
let sortedItems = rows.length ? rows.map(row => row.props.sortItem) : [...items];
@ -194,9 +215,7 @@ export class Table<Item> extends React.Component<TableProps<Item>> {
sortedItems = this.getSorted(sortedItems);
if (rows.length) {
rows = sortedItems.map(item => rows.find(row => {
return item == row.props.sortItem;
}));
rows = sortedItems.map(item => rows.find(row => item == row.props.sortItem));
}
}
@ -205,15 +224,7 @@ export class Table<Item> extends React.Component<TableProps<Item>> {
}
if (virtual) {
const lineHeight = parseFloat(rowLineHeight);
const padding = parseFloat(rowPadding);
let rowHeights: number[] = Array(items.length).fill(lineHeight + padding * 2);
if (customRowHeights) {
rowHeights = sortedItems.map(item => {
return customRowHeights(item, lineHeight, padding * 2);
});
}
const rowHeights = sortedItems.map(item => customRowHeights(item, rowLineHeight, rowPadding * 2));
return (
<VirtualList
@ -222,6 +233,7 @@ export class Table<Item> extends React.Component<TableProps<Item>> {
getRow={getTableRow}
selectedItemId={selectedItemId}
className={className}
fixedHeight={virtualHeight}
/>
);
}

View File

@ -44,6 +44,12 @@ interface Props<T extends ItemObject = any> {
getRow?: (uid: string | number) => React.ReactElement<any>;
onScroll?: (props: ListOnScrollProps) => void;
outerRef?: React.Ref<any>
/**
* If specified then AutoSizer will not be used and instead a fixed height
* virtual list will be rendered
*/
fixedHeight?: number;
}
interface State {
@ -98,34 +104,45 @@ export class VirtualList extends Component<Props, State> {
this.listRef.current?.scrollToItem(index, align);
};
render() {
const { width, className, items, getRow, onScroll, outerRef } = this.props;
renderList(height: number | undefined) {
const { width, items, getRow, onScroll, outerRef } = this.props;
const { overscanCount } = this.state;
const rowData: RowData = {
items,
getRow
};
return (
<VariableSizeList
className="list"
width={width}
height={height}
itemSize={this.getItemSize}
itemCount={items.length}
itemData={{
items,
getRow
}}
overscanCount={overscanCount}
ref={this.listRef}
outerRef={outerRef}
onScroll={onScroll}
>
{Row}
</VariableSizeList>
);
}
render() {
const { className, fixedHeight } = this.props;
return (
<div className={cssNames("VirtualList", className)}>
<AutoSizer disableWidth>
{({ height }) => (
<VariableSizeList
className="list"
width={width}
height={height}
itemSize={this.getItemSize}
itemCount={items.length}
itemData={rowData}
overscanCount={overscanCount}
ref={this.listRef}
outerRef={outerRef}
onScroll={onScroll}
>
{Row}
</VariableSizeList>
)}
</AutoSizer>
{
typeof fixedHeight === "number"
? this.renderList(fixedHeight)
: (
<AutoSizer disableWidth>
{({ height }) => this.renderList(height)}
</AutoSizer>
)
}
</div>
);
}