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

Setup resize functionality for table cells

Signed-off-by: Alex Culliere <alozhkin@mirantis.com>
This commit is contained in:
Alex Culliere 2021-02-12 15:21:53 +02:00
parent 62c3501011
commit e7f37b359e
3 changed files with 46 additions and 6 deletions

View File

@ -30,9 +30,21 @@
} }
.TableCell { .TableCell {
position: relative;
&.menu { &.menu {
@include table-cell-action; @include table-cell-action;
} }
.resize-anchor {
position: absolute;
top: 0;
right: 0;
min-width: 5px;
user-select: none;
cursor: col-resize;
background-color: gray;
height: -webkit-fill-available;
}
} }
} }

View File

@ -44,6 +44,7 @@ export interface ItemListLayoutProps<T extends ItemObject = ItemObject> {
preloadStores?: boolean; preloadStores?: boolean;
isClusterScoped?: boolean; isClusterScoped?: boolean;
hideFilters?: boolean; hideFilters?: boolean;
resizable?: boolean;
searchFilters?: SearchFilter<T>[]; searchFilters?: SearchFilter<T>[];
/** @deprecated */ /** @deprecated */
filterItems?: ItemsFilter<T>[]; filterItems?: ItemsFilter<T>[];
@ -97,6 +98,7 @@ const defaultProps: Partial<ItemListLayoutProps> = {
@observer @observer
export class ItemListLayout extends React.Component<ItemListLayoutProps> { export class ItemListLayout extends React.Component<ItemListLayoutProps> {
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
@ -110,6 +112,11 @@ export class ItemListLayout extends React.Component<ItemListLayoutProps> {
this.storage.merge({ showFilters }); this.storage.merge({ showFilters });
} }
constructor(props: ItemListLayoutProps) {
super(props);
this.cellSizes = new Array<number>(props.renderTableHeader.length);
}
async componentDidMount() { async componentDidMount() {
const { isClusterScoped, isConfigurable, tableId, preloadStores } = this.props; const { isClusterScoped, isConfigurable, tableId, preloadStores } = this.props;
@ -212,7 +219,7 @@ export class ItemListLayout extends React.Component<ItemListLayoutProps> {
getRow(uid: string) { getRow(uid: string) {
const { const {
isSelectable, renderTableHeader, renderTableContents, renderItemMenu, isSelectable, renderTableHeader, renderTableContents, renderItemMenu,
store, hasDetailsView, onDetails, store, hasDetailsView, onDetails, resizable,
copyClassNameFromHeadCells, customizeTableRowProps, detailsItem, copyClassNameFromHeadCells, customizeTableRowProps, detailsItem,
} = this.props; } = this.props;
const { isSelected } = store; const { isSelected } = store;
@ -242,13 +249,18 @@ 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];
if (copyClassNameFromHeadCells && headCell) { if (copyClassNameFromHeadCells && headCell) {
cellProps.className = cssNames(cellProps.className, headCell.className); cellProps.className = cssNames(cellProps.className, headCell.className);
} }
if (cellSize !== undefined) {
cellProps.size = cellSize;
}
if (!headCell || !this.isHiddenColumn(headCell)) { if (!headCell || !this.isHiddenColumn(headCell)) {
return <TableCell key={index} {...cellProps} />; return <TableCell resizable key={index} {...cellProps} />;
} }
}) })
} }
@ -381,7 +393,7 @@ export class ItemListLayout extends React.Component<ItemListLayoutProps> {
} }
renderTableHeader() { renderTableHeader() {
const { customizeTableRowProps, renderTableHeader, isSelectable, isConfigurable, store } = this.props; const { customizeTableRowProps, renderTableHeader, isSelectable, isConfigurable, store, resizable } = this.props;
if (!renderTableHeader) { if (!renderTableHeader) {
return; return;
@ -399,8 +411,17 @@ export class ItemListLayout extends React.Component<ItemListLayoutProps> {
/> />
)} )}
{renderTableHeader.map((cellProps, index) => { {renderTableHeader.map((cellProps, index) => {
const cellSize = this.cellSizes[index];
const _cellProps = resizable ?
{ ...cellProps, _onResize: (width: number) => this.cellSizes[index] = width } :
cellProps;
if (cellSize !== undefined) {
_cellProps.size = cellSize;
}
if (!this.isHiddenColumn(cellProps)) { if (!this.isHiddenColumn(cellProps)) {
return <TableCell key={cellProps.id ?? index} {...cellProps} />; return <TableCell resizable key={cellProps.id ?? index} {..._cellProps} />;
} }
})} })}
<TableCell className="menu"> <TableCell className="menu">

View File

@ -12,6 +12,8 @@ export interface TableCellProps extends React.DOMAttributes<HTMLDivElement> {
id?: string; // used for configuration visibility of columns id?: string; // used for configuration visibility of columns
className?: string; className?: string;
title?: ReactNode; title?: ReactNode;
resizable?: boolean; // allow resizing
size?: number; // set horizontal size
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"
@ -20,6 +22,7 @@ export interface TableCellProps extends React.DOMAttributes<HTMLDivElement> {
_sorting?: Partial<TableSortParams>; // <Table> sorting state, don't use this prop outside (!) _sorting?: Partial<TableSortParams>; // <Table> sorting state, don't use this prop outside (!)
_sort?(sortBy: TableSortBy): void; // <Table> sort function, don't use this prop outside (!) _sort?(sortBy: TableSortBy): void; // <Table> sort function, don't use this prop outside (!)
_nowrap?: boolean; // indicator, might come from parent <TableHead>, don't use this prop outside (!) _nowrap?: boolean; // indicator, might come from parent <TableHead>, don't use this prop outside (!)
_onResize?(width: number): void; // <Table> resize callbalck, don't use this prop outside (!)
} }
export class TableCell extends React.Component<TableCellProps> { export class TableCell extends React.Component<TableCellProps> {
@ -65,19 +68,23 @@ export class TableCell extends React.Component<TableCellProps> {
} }
render() { render() {
const { className, checkbox, isChecked, 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, ...cellProps } = this.props;
const classNames = cssNames("TableCell", className, { const classNames = cssNames("TableCell", className, {
checkbox, checkbox,
nowrap: _nowrap, nowrap: _nowrap,
sorting: this.isSortable, sorting: this.isSortable,
}); });
const content = displayBooleans(displayBoolean, title || children); const content = displayBooleans(displayBoolean, title || children);
const cellStyle: React.CSSProperties = size !== undefined ?
{ flexBasis: `${size}px` } :
{};
return ( return (
<div {...cellProps} className={classNames} onClick={this.onClick}> <div 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>}
</div> </div>
); );
} }