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

Refactoring VirtualList types

Signed-off-by: Alex Andreev <alex.andreev.email@gmail.com>
This commit is contained in:
Alex Andreev 2020-11-27 14:38:14 +03:00
parent 588c6d7fec
commit ae4dc3023c
7 changed files with 38 additions and 42 deletions

View File

@ -36,3 +36,4 @@ export * from "../../renderer/components/+events/kube-event-details";
export * from "../../renderer/components/status-brick"; export * from "../../renderer/components/status-brick";
export { terminalStore, createTerminalTab } from "../../renderer/components/dock/terminal.store"; export { terminalStore, createTerminalTab } from "../../renderer/components/dock/terminal.store";
export { createPodLogsTab } from "../../renderer/components/dock/pod-logs.store"; export { createPodLogsTab } from "../../renderer/components/dock/pod-logs.store";
export { ItemObject } from "../../renderer/item.store";

View File

@ -73,9 +73,7 @@ export class ClusterIssues extends React.Component<Props> {
} }
@autobind() @autobind()
getTableRow(uid: string) { getTableRow(warning: IWarning) {
const { warnings } = this;
const warning = warnings.find(warn => warn.getId() == uid);
const { getId, getName, message, kind, selfLink } = warning; const { getId, getName, message, kind, selfLink } = warning;
return ( return (
<TableRow <TableRow

View File

@ -4,7 +4,6 @@ import React from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { EndpointSubset, Endpoint, EndpointAddress} from "../../api/endpoints"; import { EndpointSubset, Endpoint, EndpointAddress} from "../../api/endpoints";
import { _i18n } from "../../i18n"; import { _i18n } from "../../i18n";
import { DrawerItem, DrawerTitle } from "../drawer";
import { Trans } from "@lingui/macro"; import { Trans } from "@lingui/macro";
import { Table, TableCell, TableHead, TableRow } from "../table"; import { Table, TableCell, TableHead, TableRow } from "../table";
import { autobind } from "../../utils"; import { autobind } from "../../utils";
@ -20,16 +19,12 @@ interface Props {
@observer @observer
export class EndpointSubsetList extends React.Component<Props> { export class EndpointSubsetList extends React.Component<Props> {
getAddressTableRow(ip: string) { getAddressTableRow(address: EndpointAddress) {
const { subset } = this.props;
const address = subset.getAddresses().find(address => address.getId() == ip);
return this.renderAddressTableRow(address); return this.renderAddressTableRow(address);
} }
@autobind() @autobind()
getNotReadyAddressTableRow(ip: string) { getNotReadyAddressTableRow(address: EndpointAddress) {
const { subset} = this.props;
const address = subset.getNotReadyAddresses().find(address => address.getId() == ip);
return this.renderAddressTableRow(address); return this.renderAddressTableRow(address);
} }
@ -52,7 +47,7 @@ export class EndpointSubsetList extends React.Component<Props> {
<TableCell className="target">Target</TableCell> <TableCell className="target">Target</TableCell>
</TableHead> </TableHead>
{ {
!virtual && addresses.map(address => this.getAddressTableRow(address.getId())) !virtual && addresses.map(address => this.getAddressTableRow(address))
} }
</Table> </Table>
</div> </div>
@ -105,7 +100,7 @@ export class EndpointSubsetList extends React.Component<Props> {
<TableCell className="host"><Trans>Hostname</Trans></TableCell> <TableCell className="host"><Trans>Hostname</Trans></TableCell>
<TableCell className="target">Target</TableCell> <TableCell className="target">Target</TableCell>
</TableHead> </TableHead>
{ !addressesVirtual && addresses.map(address => this.getAddressTableRow(address.getId())) } { !addressesVirtual && addresses.map(this.getAddressTableRow) }
</Table> </Table>
</div> </div>
)} )}
@ -126,7 +121,7 @@ export class EndpointSubsetList extends React.Component<Props> {
<TableCell className="host"><Trans>Hostname</Trans></TableCell> <TableCell className="host"><Trans>Hostname</Trans></TableCell>
<TableCell className="target">Target</TableCell> <TableCell className="target">Target</TableCell>
</TableHead> </TableHead>
{ !notReadyAddressesVirtual && notReadyAddresses.map(address => this.getNotReadyAddressTableRow(address.getId())) } { !notReadyAddressesVirtual && notReadyAddresses.map(this.getNotReadyAddressTableRow) }
</Table> </Table>
</div> </div>
)} )}

View File

@ -95,9 +95,7 @@ export class PodDetailsList extends React.Component<Props> {
} }
@autobind() @autobind()
getTableRow(uid: string) { getTableRow(pod: Pod) {
const { pods } = this.props;
const pod = pods.find(pod => pod.getId() == uid);
const metrics = podsStore.getPodKubeMetrics(pod); const metrics = podsStore.getPodKubeMetrics(pod);
return ( return (
<TableRow <TableRow
@ -146,7 +144,7 @@ export class PodDetailsList extends React.Component<Props> {
<TableCell className="status"><Trans>Status</Trans></TableCell> <TableCell className="status"><Trans>Status</Trans></TableCell>
</TableHead> </TableHead>
{ {
!virtual && pods.map(pod => this.getTableRow(pod.getId())) !virtual && pods.map(pod => this.getTableRow(pod))
} }
</Table> </Table>
</div> </div>

View File

@ -198,15 +198,13 @@ export class ItemListLayout extends React.Component<ItemListLayoutProps> {
} }
@autobind() @autobind()
getRow(uid: string) { getRow(item: ItemObject) {
const { const {
isSelectable, renderTableHeader, renderTableContents, renderItemMenu, isSelectable, renderTableHeader, renderTableContents, renderItemMenu,
store, hasDetailsView, onDetails, store, hasDetailsView, onDetails,
copyClassNameFromHeadCells, customizeTableRowProps, detailsItem, copyClassNameFromHeadCells, customizeTableRowProps, detailsItem,
} = this.props; } = this.props;
const { isSelected } = store; const { isSelected } = store;
const item = this.items.find(item => item.getId() == uid);
if (!item) return;
const itemId = item.getId(); const itemId = item.getId();
return ( return (
<TableRow <TableRow
@ -411,7 +409,7 @@ export class ItemListLayout extends React.Component<ItemListLayoutProps> {
</TableHead> </TableHead>
)} )}
{ {
!virtual && items.map(item => this.getRow(item.getId())) !virtual && items.map((item) => this.getRow(item))
} }
</Table> </Table>
)} )}

View File

@ -9,8 +9,9 @@ import { TableHead, TableHeadElem, TableHeadProps } from "./table-head";
import { TableCellElem } from "./table-cell"; import { TableCellElem } from "./table-cell";
import { VirtualList } from "../virtual-list"; import { VirtualList } from "../virtual-list";
import { navigation, setQueryParams } from "../../navigation"; import { navigation, setQueryParams } from "../../navigation";
import orderBy from "lodash/orderBy";
import { ItemObject } from "../../item.store"; import { ItemObject } from "../../item.store";
import orderBy from "lodash/orderBy";
import debounce from "lodash/debounce";
// todo: refactor + decouple search from location // todo: refactor + decouple search from location
@ -20,7 +21,7 @@ export type TableSortParams = { sortBy: TableSortBy; orderBy: TableOrderBy };
export type TableSortCallback<D = any> = (data: D) => string | number | (string | number)[]; export type TableSortCallback<D = any> = (data: D) => string | number | (string | number)[];
export interface TableProps extends React.DOMAttributes<HTMLDivElement> { export interface TableProps extends React.DOMAttributes<HTMLDivElement> {
items?: any[]; // Raw items data items?: ItemObject[]; // Raw items data
className?: string; className?: string;
autoSize?: boolean; // Setup auto-sizing for all columns (flex: 1 0) autoSize?: boolean; // Setup auto-sizing for all columns (flex: 1 0)
selectable?: boolean; // Highlight rows on hover selectable?: boolean; // Highlight rows on hover
@ -40,7 +41,7 @@ export interface TableProps extends React.DOMAttributes<HTMLDivElement> {
rowPadding?: string; rowPadding?: string;
rowLineHeight?: string; rowLineHeight?: string;
customRowHeights?: (item: object, lineHeight: number, paddings: number) => number; customRowHeights?: (item: object, lineHeight: number, paddings: number) => number;
getTableRow?: (uid: string | number) => React.ReactElement<TableRowProps>; getTableRow?: (item: ItemObject) => React.ReactElement<TableRowProps>;
} }
@observer @observer
@ -55,6 +56,8 @@ export class Table extends React.Component<TableProps> {
@observable sortParamsLocal = this.props.sortByDefault; @observable sortParamsLocal = this.props.sortByDefault;
private virtualListRef = React.createRef<VirtualList>();
@computed get sortParams(): Partial<TableSortParams> { @computed get sortParams(): Partial<TableSortParams> {
if (this.props.sortSyncWithUrl) { if (this.props.sortSyncWithUrl) {
const sortBy = navigation.searchParams.get("sortBy"); const sortBy = navigation.searchParams.get("sortBy");
@ -64,6 +67,19 @@ export class Table extends React.Component<TableProps> {
return this.sortParamsLocal || {}; return this.sortParamsLocal || {};
} }
componentDidMount() {
this.scrollToSelectedItem();
}
scrollToSelectedItem = debounce(() => {
const { items, selectedItemId, sortable } = this.props;
if (!selectedItemId) return;
const sortedItems = sortable ? this.getSorted(items) : items;
const index = sortedItems.findIndex(item => item.getId() == selectedItemId);
if (index === -1) return;
this.virtualListRef.current.scrollToItem(index, "start");
});
renderHead() { renderHead() {
const { sortable, children } = this.props; const { sortable, children } = this.props;
const content = React.Children.toArray(children) as (TableRowElem | TableHeadElem)[]; const content = React.Children.toArray(children) as (TableRowElem | TableHeadElem)[];
@ -162,6 +178,7 @@ export class Table extends React.Component<TableProps> {
getRow={getTableRow} getRow={getTableRow}
selectedItemId={selectedItemId} selectedItemId={selectedItemId}
className={className} className={className}
ref={this.virtualListRef}
/> />
); );
} }

View File

@ -6,22 +6,19 @@ import React, { Component } from "react";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { Align, ListChildComponentProps, ListOnScrollProps, VariableSizeList } from "react-window"; import { Align, ListChildComponentProps, ListOnScrollProps, VariableSizeList } from "react-window";
import { cssNames, noop } from "../../utils"; import { cssNames, noop } from "../../utils";
import { TableRowProps } from "../table/table-row";
import { ItemObject } from "../../item.store";
import throttle from "lodash/throttle"; import throttle from "lodash/throttle";
import debounce from "lodash/debounce";
import isEqual from "lodash/isEqual"; import isEqual from "lodash/isEqual";
import ResizeSensor from "css-element-queries/src/ResizeSensor"; import ResizeSensor from "css-element-queries/src/ResizeSensor";
interface Props<T = ItemObject | any> { interface Props {
items: T[]; items: any[];
rowHeights: number[]; rowHeights: number[];
className?: string; className?: string;
width?: number | string; width?: number | string;
initialOffset?: number; initialOffset?: number;
readyOffset?: number; readyOffset?: number;
selectedItemId?: string; selectedItemId?: string;
getRow?: (uid: string | number) => React.ReactElement<any>; getRow: (item: any) => React.ReactElement<any>;
onScroll?: (props: ListOnScrollProps) => void; onScroll?: (props: ListOnScrollProps) => void;
outerRef?: React.Ref<any> outerRef?: React.Ref<any>
} }
@ -51,7 +48,6 @@ export class VirtualList extends Component<Props, State> {
componentDidMount() { componentDidMount() {
this.setListHeight(); this.setListHeight();
this.scrollToSelectedItem();
new ResizeSensor(this.parentRef.current as any as Element, this.setListHeight); new ResizeSensor(this.parentRef.current as any as Element, this.setListHeight);
this.setState({ overscanCount: this.props.readyOffset }); this.setState({ overscanCount: this.props.readyOffset });
} }
@ -75,13 +71,6 @@ export class VirtualList extends Component<Props, State> {
getItemSize = (index: number) => this.props.rowHeights[index]; getItemSize = (index: number) => this.props.rowHeights[index];
scrollToSelectedItem = debounce(() => {
if (!this.props.selectedItemId) return;
const { items, selectedItemId } = this.props;
const index = items.findIndex(item => item.getId() == selectedItemId);
if (index === -1) return;
this.listRef.current.scrollToItem(index, "start");
});
scrollToItem = (index: number, align: Align) => { scrollToItem = (index: number, align: Align) => {
this.listRef.current.scrollToItem(index, align); this.listRef.current.scrollToItem(index, align);
@ -115,8 +104,8 @@ export class VirtualList extends Component<Props, State> {
} }
interface RowData { interface RowData {
items: ItemObject[]; items: any[];
getRow?: (uid: string | number) => React.ReactElement<TableRowProps>; getRow?: (item: any) => React.ReactElement;
} }
interface RowProps extends ListChildComponentProps { interface RowProps extends ListChildComponentProps {
@ -126,8 +115,8 @@ interface RowProps extends ListChildComponentProps {
const Row = observer((props: RowProps) => { const Row = observer((props: RowProps) => {
const { index, style, data } = props; const { index, style, data } = props;
const { items, getRow } = data; const { items, getRow } = data;
const uid = items[index]?.getId ? items[index].getId() : index; const item = items[index];
const row = getRow(uid); const row = getRow(item);
if (!row) return null; if (!row) return null;
return React.cloneElement(row, { return React.cloneElement(row, {
style: Object.assign({}, row.props.style, style) style: Object.assign({}, row.props.style, style)