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:
parent
3fc9436a2e
commit
d5719f29b8
@ -51,26 +51,14 @@ interface Props extends OptionalProps {
|
|||||||
interface OptionalProps {
|
interface OptionalProps {
|
||||||
maxCpu?: number;
|
maxCpu?: number;
|
||||||
maxMemory?: number;
|
maxMemory?: number;
|
||||||
showTitle?: boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class PodDetailsList extends React.Component<Props> {
|
export class PodDetailsList extends React.Component<Props> {
|
||||||
static defaultProps: OptionalProps = {
|
|
||||||
showTitle: true
|
|
||||||
};
|
|
||||||
|
|
||||||
private metricsWatcher = interval(120, () => {
|
private metricsWatcher = interval(120, () => {
|
||||||
podsStore.loadKubeMetrics(this.props.owner.getNs());
|
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() {
|
componentDidMount() {
|
||||||
this.metricsWatcher.start(true);
|
this.metricsWatcher.start(true);
|
||||||
disposeOnUnmount(this, [
|
disposeOnUnmount(this, [
|
||||||
@ -144,27 +132,43 @@ export class PodDetailsList extends React.Component<Props> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { pods, showTitle } = this.props;
|
const { pods } = this.props;
|
||||||
const virtual = pods.length > 100;
|
|
||||||
|
|
||||||
if (!pods.length && !podsStore.isLoaded) return (
|
if (!podsStore.isLoaded) {
|
||||||
<div className="PodDetailsList flex justify-center"><Spinner/></div>
|
return (
|
||||||
);
|
<div className="PodDetailsList flex justify-center">
|
||||||
if (!pods.length) return null;
|
<Spinner />
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pods.length) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const virtual = pods.length > 20;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="PodDetailsList flex column">
|
<div className="PodDetailsList flex column">
|
||||||
{showTitle && <DrawerTitle title="Pods"/>}
|
<DrawerTitle title="Pods" />
|
||||||
<Table
|
<Table
|
||||||
tableId="workloads_pod_details_list"
|
tableId="workloads_pod_details_list"
|
||||||
items={pods}
|
items={pods}
|
||||||
selectable
|
selectable
|
||||||
virtual={virtual}
|
|
||||||
scrollable={false}
|
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" }}
|
sortByDefault={{ sortBy: sortBy.cpu, orderBy: "desc" }}
|
||||||
sortSyncWithUrl={false}
|
sortSyncWithUrl={false}
|
||||||
getTableRow={this.getTableRow}
|
getTableRow={this.getTableRow}
|
||||||
|
renderRow={!virtual && (pod => this.getTableRow(pod.getId()))}
|
||||||
className="box grow"
|
className="box grow"
|
||||||
>
|
>
|
||||||
<TableHead>
|
<TableHead>
|
||||||
@ -176,9 +180,6 @@ export class PodDetailsList extends React.Component<Props> {
|
|||||||
<TableCell className="memory" sortBy={sortBy.memory}>Memory</TableCell>
|
<TableCell className="memory" sortBy={sortBy.memory}>Memory</TableCell>
|
||||||
<TableCell className="status">Status</TableCell>
|
<TableCell className="status">Status</TableCell>
|
||||||
</TableHead>
|
</TableHead>
|
||||||
{
|
|
||||||
!virtual && pods.map(pod => this.getTableRow(pod.getId()))
|
|
||||||
}
|
|
||||||
</Table>
|
</Table>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -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
|
onSort?: (params: TableSortParams) => void; // callback on sort change, default: global sync with url
|
||||||
noItems?: React.ReactNode; // Show no items state table list is empty
|
noItems?: React.ReactNode; // Show no items state table list is empty
|
||||||
selectedItemId?: string; // Allows to scroll list to selected item
|
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;
|
customRowHeights?: (item: Item, lineHeight: number, paddings: number) => number;
|
||||||
getTableRow?: (uid: string) => React.ReactElement<TableRowProps>;
|
getTableRow?: (uid: string) => React.ReactElement<TableRowProps>;
|
||||||
renderRow?: (item: Item) => 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> = {
|
static defaultProps: TableProps<any> = {
|
||||||
scrollable: true,
|
scrollable: true,
|
||||||
autoSize: true,
|
autoSize: true,
|
||||||
rowPadding: "8px",
|
rowPadding: 8,
|
||||||
rowLineHeight: "17px",
|
rowLineHeight: 17,
|
||||||
sortSyncWithUrl: true,
|
sortSyncWithUrl: true,
|
||||||
|
customRowHeights: (item, lineHeight, paddings) => lineHeight + paddings,
|
||||||
};
|
};
|
||||||
|
|
||||||
constructor(props: TableProps<Item>) {
|
constructor(props: TableProps<Item>) {
|
||||||
@ -185,7 +203,10 @@ export class Table<Item> extends React.Component<TableProps<Item>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderRows() {
|
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();
|
const content = this.getContent();
|
||||||
let rows: React.ReactElement<TableRowProps>[] = content.filter(elem => elem.type === TableRow);
|
let rows: React.ReactElement<TableRowProps>[] = content.filter(elem => elem.type === TableRow);
|
||||||
let sortedItems = rows.length ? rows.map(row => row.props.sortItem) : [...items];
|
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);
|
sortedItems = this.getSorted(sortedItems);
|
||||||
|
|
||||||
if (rows.length) {
|
if (rows.length) {
|
||||||
rows = sortedItems.map(item => rows.find(row => {
|
rows = sortedItems.map(item => rows.find(row => item == row.props.sortItem));
|
||||||
return item == row.props.sortItem;
|
|
||||||
}));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -205,15 +224,7 @@ export class Table<Item> extends React.Component<TableProps<Item>> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (virtual) {
|
if (virtual) {
|
||||||
const lineHeight = parseFloat(rowLineHeight);
|
const rowHeights = sortedItems.map(item => customRowHeights(item, rowLineHeight, rowPadding * 2));
|
||||||
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);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<VirtualList
|
<VirtualList
|
||||||
@ -222,6 +233,7 @@ export class Table<Item> extends React.Component<TableProps<Item>> {
|
|||||||
getRow={getTableRow}
|
getRow={getTableRow}
|
||||||
selectedItemId={selectedItemId}
|
selectedItemId={selectedItemId}
|
||||||
className={className}
|
className={className}
|
||||||
|
fixedHeight={virtualHeight}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -44,6 +44,12 @@ interface Props<T extends ItemObject = any> {
|
|||||||
getRow?: (uid: string | number) => React.ReactElement<any>;
|
getRow?: (uid: string | number) => React.ReactElement<any>;
|
||||||
onScroll?: (props: ListOnScrollProps) => void;
|
onScroll?: (props: ListOnScrollProps) => void;
|
||||||
outerRef?: React.Ref<any>
|
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 {
|
interface State {
|
||||||
@ -98,34 +104,45 @@ export class VirtualList extends Component<Props, State> {
|
|||||||
this.listRef.current?.scrollToItem(index, align);
|
this.listRef.current?.scrollToItem(index, align);
|
||||||
};
|
};
|
||||||
|
|
||||||
render() {
|
renderList(height: number | undefined) {
|
||||||
const { width, className, items, getRow, onScroll, outerRef } = this.props;
|
const { width, items, getRow, onScroll, outerRef } = this.props;
|
||||||
const { overscanCount } = this.state;
|
const { overscanCount } = this.state;
|
||||||
const rowData: RowData = {
|
|
||||||
items,
|
return (
|
||||||
getRow
|
<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 (
|
return (
|
||||||
<div className={cssNames("VirtualList", className)}>
|
<div className={cssNames("VirtualList", className)}>
|
||||||
<AutoSizer disableWidth>
|
{
|
||||||
{({ height }) => (
|
typeof fixedHeight === "number"
|
||||||
<VariableSizeList
|
? this.renderList(fixedHeight)
|
||||||
className="list"
|
: (
|
||||||
width={width}
|
<AutoSizer disableWidth>
|
||||||
height={height}
|
{({ height }) => this.renderList(height)}
|
||||||
itemSize={this.getItemSize}
|
</AutoSizer>
|
||||||
itemCount={items.length}
|
)
|
||||||
itemData={rowData}
|
}
|
||||||
overscanCount={overscanCount}
|
|
||||||
ref={this.listRef}
|
|
||||||
outerRef={outerRef}
|
|
||||||
onScroll={onScroll}
|
|
||||||
>
|
|
||||||
{Row}
|
|
||||||
</VariableSizeList>
|
|
||||||
)}
|
|
||||||
</AutoSizer>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user