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:
parent
e7f37b359e
commit
42f68b5db3
@ -80,6 +80,10 @@ export interface ItemListLayoutProps<T extends ItemObject = ItemObject> {
|
|||||||
renderFooter?: (parent: ItemListLayout) => React.ReactNode;
|
renderFooter?: (parent: ItemListLayout) => React.ReactNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ItemListLayoutState {
|
||||||
|
cellSizes: number[];
|
||||||
|
}
|
||||||
|
|
||||||
const defaultProps: Partial<ItemListLayoutProps> = {
|
const defaultProps: Partial<ItemListLayoutProps> = {
|
||||||
showHeader: true,
|
showHeader: true,
|
||||||
isSearchable: true,
|
isSearchable: true,
|
||||||
@ -96,9 +100,8 @@ const defaultProps: Partial<ItemListLayoutProps> = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class ItemListLayout extends React.Component<ItemListLayoutProps> {
|
export class ItemListLayout extends React.Component<ItemListLayoutProps, ItemListLayoutState> {
|
||||||
static defaultProps = defaultProps as object;
|
static defaultProps = defaultProps as object;
|
||||||
private cellSizes: Array<number>;
|
|
||||||
|
|
||||||
private storage = createStorage("item_list_layout", {
|
private storage = createStorage("item_list_layout", {
|
||||||
showFilters: false, // setup defaults
|
showFilters: false, // setup defaults
|
||||||
@ -114,7 +117,10 @@ export class ItemListLayout extends React.Component<ItemListLayoutProps> {
|
|||||||
|
|
||||||
constructor(props: ItemListLayoutProps) {
|
constructor(props: ItemListLayoutProps) {
|
||||||
super(props);
|
super(props);
|
||||||
this.cellSizes = new Array<number>(props.renderTableHeader.length);
|
|
||||||
|
this.state = {
|
||||||
|
cellSizes: new Array<number>(props.renderTableHeader.length)
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
async componentDidMount() {
|
async componentDidMount() {
|
||||||
@ -215,6 +221,13 @@ export class ItemListLayout extends React.Component<ItemListLayoutProps> {
|
|||||||
return this.applyFilters(filterItems.concat(this.props.filterItems), items);
|
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()
|
@autobind()
|
||||||
getRow(uid: string) {
|
getRow(uid: string) {
|
||||||
const {
|
const {
|
||||||
@ -249,7 +262,7 @@ export class ItemListLayout extends React.Component<ItemListLayoutProps> {
|
|||||||
renderTableContents(item).map((content, index) => {
|
renderTableContents(item).map((content, index) => {
|
||||||
const cellProps: TableCellProps = isReactNode(content) ? { children: content } : content;
|
const cellProps: TableCellProps = isReactNode(content) ? { children: content } : content;
|
||||||
const headCell = renderTableHeader?.[index];
|
const headCell = renderTableHeader?.[index];
|
||||||
const cellSize = this.cellSizes[index];
|
const cellSize = this.state.cellSizes[index];
|
||||||
|
|
||||||
if (copyClassNameFromHeadCells && headCell) {
|
if (copyClassNameFromHeadCells && headCell) {
|
||||||
cellProps.className = cssNames(cellProps.className, headCell.className);
|
cellProps.className = cssNames(cellProps.className, headCell.className);
|
||||||
@ -259,8 +272,12 @@ export class ItemListLayout extends React.Component<ItemListLayoutProps> {
|
|||||||
cellProps.size = cellSize;
|
cellProps.size = cellSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (resizable) {
|
||||||
|
cellProps._onResize = width => this.handleCellResize(index, width);
|
||||||
|
}
|
||||||
|
|
||||||
if (!headCell || !this.isHiddenColumn(headCell)) {
|
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) => {
|
{renderTableHeader.map((cellProps, index) => {
|
||||||
const cellSize = this.cellSizes[index];
|
const cellSize = this.state.cellSizes[index];
|
||||||
const _cellProps = resizable ?
|
const _cellProps = resizable ?
|
||||||
{ ...cellProps, _onResize: (width: number) => this.cellSizes[index] = width } :
|
{ ...cellProps, _onResize: (width: number) => this.handleCellResize(index, width), resizable } :
|
||||||
cellProps;
|
cellProps;
|
||||||
|
|
||||||
if (cellSize !== undefined) {
|
if (cellSize !== undefined) {
|
||||||
@ -421,7 +438,7 @@ export class ItemListLayout extends React.Component<ItemListLayoutProps> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!this.isHiddenColumn(cellProps)) {
|
if (!this.isHiddenColumn(cellProps)) {
|
||||||
return <TableCell resizable key={cellProps.id ?? index} {..._cellProps} />;
|
return <TableCell key={cellProps.id ?? index} {..._cellProps} />;
|
||||||
}
|
}
|
||||||
})}
|
})}
|
||||||
<TableCell className="menu">
|
<TableCell className="menu">
|
||||||
|
|||||||
@ -46,6 +46,7 @@ export class KubeObjectListLayout extends React.Component<KubeObjectListLayoutPr
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<ItemListLayout
|
<ItemListLayout
|
||||||
|
resizable
|
||||||
{...layoutProps}
|
{...layoutProps}
|
||||||
className={cssNames("KubeObjectListLayout", className)}
|
className={cssNames("KubeObjectListLayout", className)}
|
||||||
store={store}
|
store={store}
|
||||||
|
|||||||
@ -2,6 +2,7 @@ import "./table-cell.scss";
|
|||||||
import type { TableSortBy, TableSortParams } from "./table";
|
import type { TableSortBy, TableSortParams } from "./table";
|
||||||
|
|
||||||
import React, { ReactNode } from "react";
|
import React, { ReactNode } from "react";
|
||||||
|
import { throttle } from "lodash";
|
||||||
import { autobind, cssNames, displayBooleans } from "../../utils";
|
import { autobind, cssNames, displayBooleans } from "../../utils";
|
||||||
import { Icon } from "../icon";
|
import { Icon } from "../icon";
|
||||||
import { Checkbox } from "../checkbox";
|
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 (!)
|
_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> {
|
export class TableCell extends React.Component<TableCellProps> {
|
||||||
|
private resizeHandlerState?: ResizeHandlerState;
|
||||||
|
private cellContainer: React.RefObject<HTMLDivElement> = React.createRef();
|
||||||
|
|
||||||
@autobind()
|
@autobind()
|
||||||
onClick(evt: React.MouseEvent<HTMLDivElement>) {
|
onClick(evt: React.MouseEvent<HTMLDivElement>) {
|
||||||
if (this.props.onClick) {
|
if (this.props.onClick) {
|
||||||
@ -37,6 +47,10 @@ export class TableCell extends React.Component<TableCellProps> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
this.removeMouseEventListeners();
|
||||||
|
}
|
||||||
|
|
||||||
get isSortable() {
|
get isSortable() {
|
||||||
const { _sorting, sortBy } = this.props;
|
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() {
|
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, {
|
const classNames = cssNames("TableCell", className, {
|
||||||
checkbox,
|
checkbox,
|
||||||
nowrap: _nowrap,
|
nowrap: _nowrap,
|
||||||
@ -78,13 +118,21 @@ export class TableCell extends React.Component<TableCellProps> {
|
|||||||
const cellStyle: React.CSSProperties = size !== undefined ?
|
const cellStyle: React.CSSProperties = size !== undefined ?
|
||||||
{ flexBasis: `${size}px` } :
|
{ flexBasis: `${size}px` } :
|
||||||
{};
|
{};
|
||||||
|
const resizeHandlers: React.DetailedHTMLProps<React.HTMLAttributes<HTMLSpanElement>, HTMLSpanElement> = {
|
||||||
|
onMouseDown: event => {
|
||||||
|
this.addMouseEventListeners();
|
||||||
|
this.resizeHandlerState = {
|
||||||
|
mousePosX: event.pageX
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={cellStyle} {...cellProps} className={classNames} onClick={this.onClick}>
|
<div ref={this.cellContainer} style={cellStyle} {...cellProps} className={classNames} onClick={this.onClick}>
|
||||||
{this.renderCheckbox()}
|
{this.renderCheckbox()}
|
||||||
{_nowrap ? <div className="content">{content}</div> : content}
|
{_nowrap ? <div className="content">{content}</div> : content}
|
||||||
{this.renderSortIcon()}
|
{this.renderSortIcon()}
|
||||||
{resizable && <span className="resize-anchor"></span>}
|
{resizable && <span {...resizeHandlers} className="resize-anchor"></span>}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user