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

refactoring & fixes

Signed-off-by: Roman <ixrock@gmail.com>
This commit is contained in:
Roman 2021-03-29 20:21:03 +03:00
parent 85ddcb47b4
commit 3b40f044b4
8 changed files with 135 additions and 66 deletions

View File

@ -14,9 +14,6 @@
.VirtualList { .VirtualList {
height: 100%; height: 100%;
.list {
overflow-x: scroll!important;
.LogRow { .LogRow {
padding: 2px 16px; padding: 2px 16px;
height: 18px; // Must be equal to lineHeight variable in pod-log-list.tsx height: 18px; // Must be equal to lineHeight variable in pod-log-list.tsx
@ -51,7 +48,6 @@
} }
} }
} }
}
&.isLoading { &.isLoading {
cursor: wait; cursor: wait;

View File

@ -407,10 +407,12 @@ export class ItemListLayout extends React.Component<ItemListLayoutProps> {
)} )}
{renderTableHeader.map((cellProps, index) => { {renderTableHeader.map((cellProps, index) => {
if (!this.isHiddenColumn(cellProps)) { if (!this.isHiddenColumn(cellProps)) {
const storageId = cellProps.id ?? cellProps.storageId;
return ( return (
<TableCell <TableCell
key={cellProps.id ?? cellProps.storageId ?? index} key={storageId ?? index}
storageId={cellProps.storageId} storageId={storageId}
tableId={tableId} {...cellProps} tableId={tableId} {...cellProps}
/> />
); );

View File

@ -19,8 +19,37 @@
} }
} }
&.warning {
flex: 0 0 40px !important;
}
&.resizable { &.resizable {
position: relative; // required for resizing-anchor with `position:absolute` position: relative; // required for resizing-anchor with `position:absolute`
min-width: 50px;
> .ResizingAnchor {
width: 18px;
}
.TableHead:hover & {
> .ResizingAnchor {
opacity: .25;
&:hover {
opacity: .75;
}
&:after {
font: 20px "Material Icons";
content: "compress";
position: absolute;
left: -8px;
top: 10px;
transform: rotate(90deg);
transform-origin: center;
}
}
}
&.resizing { &.resizing {
filter: invert(50%); filter: invert(50%);

View File

@ -27,9 +27,9 @@ export interface TableCellProps extends React.DOMAttributes<HTMLDivElement> {
title?: ReactNode; title?: ReactNode;
/** /**
* Allow to resize width and save to local storage, default: true * Allow to resize width and save to local storage, default: true
* (applicable only with props.id)
*/ */
isResizable?: boolean; isResizable?: boolean;
onResizeEnd?: () => void;
checkbox?: boolean; // render cell with a checkbox checkbox?: boolean; // render cell with a checkbox
isChecked?: boolean; // mark checkbox as checked or not isChecked?: boolean; // mark checkbox as checked or not
renderBoolean?: boolean; // show "true" or "false" for all of the children elements are "typeof boolean" renderBoolean?: boolean; // show "true" or "false" for all of the children elements are "typeof boolean"
@ -43,7 +43,7 @@ export interface TableCellProps extends React.DOMAttributes<HTMLDivElement> {
@observer @observer
export class TableCell extends React.Component<TableCellProps> { export class TableCell extends React.Component<TableCellProps> {
private elem: HTMLElement; @observable.ref elem?: HTMLElement;
static defaultProps: TableCellProps = { static defaultProps: TableCellProps = {
isResizable: true, isResizable: true,
@ -97,7 +97,9 @@ export class TableCell extends React.Component<TableCellProps> {
} }
@computed get columnSize(): number { @computed get columnSize(): number {
return getColumnSize(this.props.tableId, this.columnId) ?? 0; const savedSize = getColumnSize(this.props.tableId, this.columnId);
return savedSize ?? this.elem?.offsetWidth;
} }
@computed get isResizable(): boolean { @computed get isResizable(): boolean {
@ -113,6 +115,7 @@ export class TableCell extends React.Component<TableCellProps> {
if (this.isResizable && this.columnSize) { if (this.isResizable && this.columnSize) {
styles.flexGrow = 0; styles.flexGrow = 0;
styles.flexShrink = 0;
styles.flexBasis = this.columnSize; styles.flexBasis = this.columnSize;
} }
@ -123,10 +126,20 @@ export class TableCell extends React.Component<TableCellProps> {
onResize(extent: number) { onResize(extent: number) {
const { tableId } = this.props; const { tableId } = this.props;
const { columnId } = this; const { columnId } = this;
const size = extent || this.elem?.offsetWidth;
// persist state in storage // persist state in storage
setColumnSize({ tableId, columnId, size }); setColumnSize({ tableId, columnId, size: extent });
}
@autobind()
onResizeStart() {
this.isResizing = true;
}
@autobind()
onResizeEnd() {
this.isResizing = false;
this.props.onResizeEnd?.();
} }
@autobind() @autobind()
@ -136,7 +149,7 @@ export class TableCell extends React.Component<TableCellProps> {
render() { render() {
const { const {
className, checkbox, isChecked, isResizable, sortBy, className, checkbox, isChecked, isResizable, sortBy, onResizeEnd,
_sort, _sorting, _nowrap, children, title, tableId, storageId, _sort, _sorting, _nowrap, children, title, tableId, storageId,
renderBoolean: displayBoolean, showWithColumn, renderBoolean: displayBoolean, showWithColumn,
...cellProps ...cellProps
@ -147,7 +160,7 @@ export class TableCell extends React.Component<TableCellProps> {
nowrap: _nowrap, nowrap: _nowrap,
sorting: this.isSortable, sorting: this.isSortable,
resizing: this.isResizing, resizing: this.isResizing,
resizable: isResizable, resizable: this.isResizable,
}); });
const content = displayBooleans(displayBoolean, title || children); const content = displayBooleans(displayBoolean, title || children);
@ -158,12 +171,13 @@ export class TableCell extends React.Component<TableCellProps> {
{this.renderSortIcon()} {this.renderSortIcon()}
{this.isResizable && ( {this.isResizable && (
<ResizingAnchor <ResizingAnchor
minExtent={50}
direction={ResizeDirection.HORIZONTAL} direction={ResizeDirection.HORIZONTAL}
placement={ResizeSide.TRAILING} placement={ResizeSide.TRAILING}
growthDirection={ResizeGrowthDirection.LEFT_TO_RIGHT} growthDirection={ResizeGrowthDirection.LEFT_TO_RIGHT}
getCurrentExtent={() => this.columnSize} getCurrentExtent={() => this.columnSize}
onStart={() => this.isResizing = true} onStart={this.onResizeStart}
onEnd={() => this.isResizing = false} onEnd={this.onResizeEnd}
onDrag={this.onResize} onDrag={this.onResize}
/> />
)} )}

View File

@ -10,6 +10,7 @@ export interface TableHeadProps extends React.DOMAttributes<HTMLDivElement> {
showTopLine?: boolean; // show border line at the top showTopLine?: boolean; // show border line at the top
sticky?: boolean; // keep header on top when scrolling sticky?: boolean; // keep header on top when scrolling
nowrap?: boolean; // white-space: nowrap, align inner <TableCell> in one line nowrap?: boolean; // white-space: nowrap, align inner <TableCell> in one line
style?: React.CSSProperties;
} }
export class TableHead extends React.Component<TableHeadProps> { export class TableHead extends React.Component<TableHeadProps> {

View File

@ -1,7 +1,7 @@
import "./table.scss"; import "./table.scss";
import React from "react"; import React from "react";
import { orderBy } from "lodash"; import { orderBy, throttle } from "lodash";
import { observer } from "mobx-react"; import { observer } from "mobx-react";
import { observable } from "mobx"; import { observable } from "mobx";
import { autobind, cssNames, noop } from "../../utils"; import { autobind, cssNames, noop } from "../../utils";
@ -57,6 +57,8 @@ export const orderByUrlParam = createPageParam({
@observer @observer
export class Table extends React.Component<TableProps> { export class Table extends React.Component<TableProps> {
@observable.ref elemRef = React.createRef<HTMLDivElement>();
static defaultProps: TableProps = { static defaultProps: TableProps = {
scrollable: true, scrollable: true,
autoSize: true, autoSize: true,
@ -73,6 +75,14 @@ export class Table extends React.Component<TableProps> {
this.props.sortByDefault, this.props.sortByDefault,
); );
componentDidMount() {
window.addEventListener("resize", this.refreshDimensions);
}
componentWillUnmount() {
window.removeEventListener("resize", this.refreshDimensions);
}
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)[];
@ -83,6 +93,10 @@ export class Table extends React.Component<TableProps> {
const columns = React.Children.toArray(headElem.props.children) as TableCellElem[]; const columns = React.Children.toArray(headElem.props.children) as TableCellElem[];
return React.cloneElement(headElem, { return React.cloneElement(headElem, {
style: {
...(headElem.props.style ?? {}),
width: this.contentWidth,
},
children: columns.map(elem => { children: columns.map(elem => {
if (elem.props.checkbox) { if (elem.props.checkbox) {
return elem; return elem;
@ -98,6 +112,10 @@ export class Table extends React.Component<TableProps> {
_sort: this.sort, _sort: this.sort,
_sorting: this.sortParams, _sorting: this.sortParams,
_nowrap: headElem.props.nowrap, _nowrap: headElem.props.nowrap,
onResizeEnd: () => {
elem.props.onResizeEnd?.();
this.refreshDimensions();
}
}); });
}) })
}); });
@ -180,6 +198,10 @@ export class Table extends React.Component<TableProps> {
getRow={getTableRow} getRow={getTableRow}
selectedItemId={selectedItemId} selectedItemId={selectedItemId}
className={className} className={className}
// must match to table's content width for proper scrolling header and virtual-list items.
// required if some column(s) are resized and overall content-area more than 100%.
// why: table & virtual-list has own scrolling areas and table-head is sticky..
width={this.contentWidth}
/> />
); );
} }
@ -187,16 +209,25 @@ export class Table extends React.Component<TableProps> {
return rows; return rows;
} }
render() { @observable refreshKey: number;
const { selectable, scrollable, sortable, autoSize, virtual } = this.props;
let { className } = this.props;
className = cssNames("Table flex column", className, { get contentWidth() {
return this.elemRef.current?.scrollWidth;
}
refreshDimensions = throttle(() => {
// using "full refresh" with changing "key" as this.forceUpdate() don't update some internals
this.refreshKey = Math.random();
}, 250);
render() {
const { selectable, scrollable, sortable, autoSize, virtual, className } = this.props;
const classNames = cssNames("Table flex column", className, {
selectable, scrollable, sortable, autoSize, virtual, selectable, scrollable, sortable, autoSize, virtual,
}); });
return ( return (
<div className={className}> <div key={this.refreshKey} className={classNames} ref={this.elemRef}>
{this.renderHead()} {this.renderHead()}
{this.renderRows()} {this.renderRows()}
</div> </div>

View File

@ -1,7 +1,4 @@
.VirtualList { .VirtualList {
overflow: hidden; overflow-x: hidden !important;
> .list {
overflow-y: overlay !important; overflow-y: overlay !important;
} }
}

View File

@ -32,7 +32,7 @@ interface State {
} }
const defaultProps: Partial<Props> = { const defaultProps: Partial<Props> = {
width: "100%", width: "auto",
initialOffset: 1, initialOffset: 1,
readyOffset: 10, readyOffset: 10,
onScroll: noop onScroll: noop
@ -52,7 +52,7 @@ export class VirtualList extends Component<Props, State> {
componentDidMount() { componentDidMount() {
this.setListHeight(); this.setListHeight();
this.scrollToSelectedItem(); this.scrollToSelectedItem();
new ResizeSensor(this.parentRef.current as any as Element, this.setListHeight); new ResizeSensor(this.parentRef.current, this.setListHeight);
this.setState({ overscanCount: this.props.readyOffset }); this.setState({ overscanCount: this.props.readyOffset });
} }
@ -100,9 +100,8 @@ export class VirtualList extends Component<Props, State> {
}; };
return ( return (
<div className={cssNames("VirtualList", className)} ref={this.parentRef}>
<VariableSizeList <VariableSizeList
className="list" className={cssNames("VirtualList", className)}
width={width} width={width}
height={height} height={height}
itemSize={this.getItemSize} itemSize={this.getItemSize}
@ -110,12 +109,12 @@ export class VirtualList extends Component<Props, State> {
itemData={rowData} itemData={rowData}
overscanCount={overscanCount} overscanCount={overscanCount}
ref={this.listRef} ref={this.listRef}
innerRef={this.parentRef}
outerRef={outerRef} outerRef={outerRef}
onScroll={onScroll} onScroll={onScroll}
> >
{Row} {Row}
</VariableSizeList> </VariableSizeList>
</div>
); );
} }
} }