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

Make column resize sorta-functioning

Signed-off-by: Alex Culliere <alozhkin@mirantis.com>
This commit is contained in:
Alex Culliere 2021-02-12 16:34:25 +02:00
parent e7f37b359e
commit 42f68b5db3
3 changed files with 77 additions and 11 deletions

View File

@ -80,6 +80,10 @@ export interface ItemListLayoutProps<T extends ItemObject = ItemObject> {
renderFooter?: (parent: ItemListLayout) => React.ReactNode;
}
interface ItemListLayoutState {
cellSizes: number[];
}
const defaultProps: Partial<ItemListLayoutProps> = {
showHeader: true,
isSearchable: true,
@ -96,9 +100,8 @@ const defaultProps: Partial<ItemListLayoutProps> = {
};
@observer
export class ItemListLayout extends React.Component<ItemListLayoutProps> {
export class ItemListLayout extends React.Component<ItemListLayoutProps, ItemListLayoutState> {
static defaultProps = defaultProps as object;
private cellSizes: Array<number>;
private storage = createStorage("item_list_layout", {
showFilters: false, // setup defaults
@ -114,7 +117,10 @@ export class ItemListLayout extends React.Component<ItemListLayoutProps> {
constructor(props: ItemListLayoutProps) {
super(props);
this.cellSizes = new Array<number>(props.renderTableHeader.length);
this.state = {
cellSizes: new Array<number>(props.renderTableHeader.length)
};
}
async componentDidMount() {
@ -215,6 +221,13 @@ export class ItemListLayout extends React.Component<ItemListLayoutProps> {
return this.applyFilters(filterItems.concat(this.props.filterItems), items);
}
handleCellResize(index: number, width: number) {
const cellSizes = [...this.state.cellSizes];
cellSizes[index] = width;
this.setState({ cellSizes });
}
@autobind()
getRow(uid: string) {
const {
@ -249,7 +262,7 @@ export class ItemListLayout extends React.Component<ItemListLayoutProps> {
renderTableContents(item).map((content, index) => {
const cellProps: TableCellProps = isReactNode(content) ? { children: content } : content;
const headCell = renderTableHeader?.[index];
const cellSize = this.cellSizes[index];
const cellSize = this.state.cellSizes[index];
if (copyClassNameFromHeadCells && headCell) {
cellProps.className = cssNames(cellProps.className, headCell.className);
@ -259,8 +272,12 @@ export class ItemListLayout extends React.Component<ItemListLayoutProps> {
cellProps.size = cellSize;
}
if (resizable) {
cellProps._onResize = width => this.handleCellResize(index, width);
}
if (!headCell || !this.isHiddenColumn(headCell)) {
return <TableCell resizable key={index} {...cellProps} />;
return <TableCell resizable={resizable} key={index} {...cellProps} />;
}
})
}
@ -411,9 +428,9 @@ export class ItemListLayout extends React.Component<ItemListLayoutProps> {
/>
)}
{renderTableHeader.map((cellProps, index) => {
const cellSize = this.cellSizes[index];
const cellSize = this.state.cellSizes[index];
const _cellProps = resizable ?
{ ...cellProps, _onResize: (width: number) => this.cellSizes[index] = width } :
{ ...cellProps, _onResize: (width: number) => this.handleCellResize(index, width), resizable } :
cellProps;
if (cellSize !== undefined) {
@ -421,7 +438,7 @@ export class ItemListLayout extends React.Component<ItemListLayoutProps> {
}
if (!this.isHiddenColumn(cellProps)) {
return <TableCell resizable key={cellProps.id ?? index} {..._cellProps} />;
return <TableCell key={cellProps.id ?? index} {..._cellProps} />;
}
})}
<TableCell className="menu">

View File

@ -46,6 +46,7 @@ export class KubeObjectListLayout extends React.Component<KubeObjectListLayoutPr
return (
<ItemListLayout
resizable
{...layoutProps}
className={cssNames("KubeObjectListLayout", className)}
store={store}

View File

@ -2,6 +2,7 @@ import "./table-cell.scss";
import type { TableSortBy, TableSortParams } from "./table";
import React, { ReactNode } from "react";
import { throttle } from "lodash";
import { autobind, cssNames, displayBooleans } from "../../utils";
import { Icon } from "../icon";
import { Checkbox } from "../checkbox";
@ -25,7 +26,16 @@ export interface TableCellProps extends React.DOMAttributes<HTMLDivElement> {
_onResize?(width: number): void; // <Table> resize callbalck, don't use this prop outside (!)
}
type ResizeHandlerState = {
mousePosX: number,
currentColumn?: HTMLDivElement;
nextColumn?: HTMLDivElement;
};
export class TableCell extends React.Component<TableCellProps> {
private resizeHandlerState?: ResizeHandlerState;
private cellContainer: React.RefObject<HTMLDivElement> = React.createRef();
@autobind()
onClick(evt: React.MouseEvent<HTMLDivElement>) {
if (this.props.onClick) {
@ -37,6 +47,10 @@ export class TableCell extends React.Component<TableCellProps> {
}
}
componentWillUnmount() {
this.removeMouseEventListeners();
}
get isSortable() {
const { _sorting, sortBy } = this.props;
@ -67,8 +81,34 @@ export class TableCell extends React.Component<TableCellProps> {
}
}
addMouseEventListeners() {
document.addEventListener("mousemove", this.mouseMoveHandler.bind(this));
document.addEventListener("mouseup", this.mouseUpHandler.bind(this));
}
removeMouseEventListeners() {
document.removeEventListener("mousemove", this.mouseMoveHandler.bind(this));
document.removeEventListener("mouseup", this.mouseUpHandler.bind(this));
}
mouseMoveHandler(event: MouseEvent) {
if (!this.resizeHandlerState) {
return;
}
const diffPosX = event.pageX - this.resizeHandlerState.mousePosX;
const currentWidth = this.cellContainer.current.offsetWidth;
this.props?._onResize(currentWidth + diffPosX);
}
mouseUpHandler() {
this.removeMouseEventListeners();
this.resizeHandlerState = undefined;
}
render() {
const { className, checkbox, isChecked, resizable, size, sortBy, _sort, _sorting, _nowrap, children, title, renderBoolean: displayBoolean, showWithColumn, ...cellProps } = this.props;
const { className, checkbox, isChecked, resizable, size, sortBy, _sort, _sorting, _nowrap, children, title, renderBoolean: displayBoolean, showWithColumn, _onResize, ...cellProps } = this.props;
const classNames = cssNames("TableCell", className, {
checkbox,
nowrap: _nowrap,
@ -78,13 +118,21 @@ export class TableCell extends React.Component<TableCellProps> {
const cellStyle: React.CSSProperties = size !== undefined ?
{ flexBasis: `${size}px` } :
{};
const resizeHandlers: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> = {
onMouseDown: event => {
this.addMouseEventListeners();
this.resizeHandlerState = {
mousePosX: event.pageX
};
}
};
return (
<div style={cellStyle} {...cellProps} className={classNames} onClick={this.onClick}>
<div ref={this.cellContainer} style={cellStyle} {...cellProps} className={classNames} onClick={this.onClick}>
{this.renderCheckbox()}
{_nowrap ? <div className="content">{content}</div> : content}
{this.renderSortIcon()}
{resizable && <span className="resize-anchor"></span>}
{resizable && <span {...resizeHandlers} className="resize-anchor"></span>}
</div>
);
}