columns resize

This commit is contained in:
Jan Prochazka 2020-05-10 18:52:14 +02:00
parent 836db096a9
commit a41538b452
9 changed files with 90 additions and 41 deletions

View File

@ -19,6 +19,7 @@ export interface GridReferenceDefinition {
export interface GridConfig extends GridConfigColumns { export interface GridConfig extends GridConfigColumns {
filters: { [uniqueName: string]: string }; filters: { [uniqueName: string]: string };
focusedColumn?: string; focusedColumn?: string;
columnWidths: { [uniqueName: string]: number };
sort: { sort: {
uniqueName: string; uniqueName: string;
order: 'ASC' | 'DESC'; order: 'ASC' | 'DESC';
@ -37,6 +38,7 @@ export function createGridConfig(): GridConfig {
expandedColumns: [], expandedColumns: [],
addedColumns: [], addedColumns: [],
filters: {}, filters: {},
columnWidths: {},
sort: [], sort: [],
focusedColumn: null, focusedColumn: null,
}; };

View File

@ -38,12 +38,13 @@ export function combineReferenceActions(a: ReferenceActionResult, b: ReferenceAc
return 'noAction'; return 'noAction';
} }
export type ChangeCacheFunc = (changeFunc: (config: GridCache) => GridCache) => void; export type ChangeCacheFunc = (changeFunc: (cache: GridCache) => GridCache) => void;
export type ChangeConfigFunc = (changeFunc: (config: GridConfig) => GridConfig) => void;
export abstract class GridDisplay { export abstract class GridDisplay {
constructor( constructor(
public config: GridConfig, public config: GridConfig,
protected setConfig: (config: GridConfig) => void, protected setConfig: ChangeConfigFunc,
public cache: GridCache, public cache: GridCache,
protected setCache: ChangeCacheFunc, protected setCache: ChangeCacheFunc,
public driver?: EngineDriver public driver?: EngineDriver
@ -67,10 +68,10 @@ export abstract class GridDisplay {
} }
focusColumn(uniqueName: string) { focusColumn(uniqueName: string) {
this.setConfig({ this.setConfig((cfg) => ({
...this.config, ...cfg,
focusedColumn: uniqueName, focusedColumn: uniqueName,
}); }));
} }
get focusedColumn() { get focusedColumn() {
@ -96,30 +97,30 @@ export abstract class GridDisplay {
includeInColumnSet(field: keyof GridConfigColumns, uniqueName: string, isIncluded: boolean) { includeInColumnSet(field: keyof GridConfigColumns, uniqueName: string, isIncluded: boolean) {
// console.log('includeInColumnSet', field, uniqueName, isIncluded); // console.log('includeInColumnSet', field, uniqueName, isIncluded);
if (isIncluded) { if (isIncluded) {
this.setConfig({ this.setConfig((cfg) => ({
...this.config, ...cfg,
[field]: [...(this.config[field] || []), uniqueName], [field]: [...(cfg[field] || []), uniqueName],
}); }));
} else { } else {
this.setConfig({ this.setConfig((cfg) => ({
...this.config, ...cfg,
[field]: (this.config[field] || []).filter((x) => x != uniqueName), [field]: (cfg[field] || []).filter((x) => x != uniqueName),
}); }));
} }
} }
showAllColumns() { showAllColumns() {
this.setConfig({ this.setConfig((cfg) => ({
...this.config, ...cfg,
hiddenColumns: [], hiddenColumns: [],
}); }));
} }
hideAllColumns() { hideAllColumns() {
this.setConfig({ this.setConfig((cfg) => ({
...this.config, ...cfg,
hiddenColumns: this.columns.map((x) => x.uniqueName), hiddenColumns: this.columns.map((x) => x.uniqueName),
}); }));
} }
get hiddenColumnIndexes() { get hiddenColumnIndexes() {
@ -203,21 +204,21 @@ export abstract class GridDisplay {
} }
setFilter(uniqueName, value) { setFilter(uniqueName, value) {
this.setConfig({ this.setConfig((cfg) => ({
...this.config, ...cfg,
filters: { filters: {
...this.config.filters, ...cfg.filters,
[uniqueName]: value, [uniqueName]: value,
}, },
}); }));
this.reload(); this.reload();
} }
setSort(uniqueName, order) { setSort(uniqueName, order) {
this.setConfig({ this.setConfig((cfg) => ({
...this.config, ...cfg,
sort: [{ uniqueName, order }], sort: [{ uniqueName, order }],
}); }));
this.reload(); this.reload();
} }
@ -230,10 +231,10 @@ export abstract class GridDisplay {
} }
clearFilters() { clearFilters() {
this.setConfig({ this.setConfig((cfg) => ({
...this.config, ...cfg,
filters: {}, filters: {},
}); }));
this.reload(); this.reload();
} }
@ -314,6 +315,23 @@ export abstract class GridDisplay {
return sql; return sql;
} }
resizeColumn(uniqueName: string, computedSize: number, diff: number) {
this.setConfig((cfg) => {
const columnWidths = {
...cfg.columnWidths,
};
if (columnWidths[uniqueName]) {
columnWidths[uniqueName] += diff;
} else {
columnWidths[uniqueName] = computedSize + diff;
}
return {
...cfg,
columnWidths,
};
});
}
getCountQuery() { getCountQuery() {
const select = this.createSelect(); const select = this.createSelect();
select.columns = [ select.columns = [

View File

@ -1,4 +1,4 @@
import { GridDisplay, ChangeCacheFunc } from './GridDisplay'; import { GridDisplay, ChangeCacheFunc, ChangeConfigFunc } from './GridDisplay';
import { QueryResultColumn } from '@dbgate/types'; import { QueryResultColumn } from '@dbgate/types';
import { GridConfig, GridCache } from './GridConfig'; import { GridConfig, GridCache } from './GridConfig';
@ -7,7 +7,7 @@ export class JslGridDisplay extends GridDisplay {
jslid, jslid,
columns: QueryResultColumn[], columns: QueryResultColumn[],
config: GridConfig, config: GridConfig,
setConfig: (config: GridConfig) => void, setConfig: ChangeConfigFunc,
cache: GridCache, cache: GridCache,
setCache: ChangeCacheFunc setCache: ChangeCacheFunc
) { ) {

View File

@ -6,6 +6,7 @@ import {
DisplayColumn, DisplayColumn,
ReferenceActionResult, ReferenceActionResult,
DisplayedColumnInfo, DisplayedColumnInfo,
ChangeConfigFunc,
} from './GridDisplay'; } from './GridDisplay';
import { TableInfo, EngineDriver, ViewInfo, ColumnInfo, NamedObjectInfo } from '@dbgate/types'; import { TableInfo, EngineDriver, ViewInfo, ColumnInfo, NamedObjectInfo } from '@dbgate/types';
import { GridConfig, GridCache, createGridCache } from './GridConfig'; import { GridConfig, GridCache, createGridCache } from './GridConfig';
@ -19,7 +20,7 @@ export class TableGridDisplay extends GridDisplay {
public tableName: NamedObjectInfo, public tableName: NamedObjectInfo,
driver: EngineDriver, driver: EngineDriver,
config: GridConfig, config: GridConfig,
setConfig: (config: GridConfig) => void, setConfig: ChangeConfigFunc,
cache: GridCache, cache: GridCache,
setCache: ChangeCacheFunc, setCache: ChangeCacheFunc,
protected getTableInfo: ({ schemaName, pureName }) => Promise<TableInfo> protected getTableInfo: ({ schemaName, pureName }) => Promise<TableInfo>

View File

@ -1,5 +1,5 @@
import _ from 'lodash'; import _ from 'lodash';
import { GridDisplay, ChangeCacheFunc } from './GridDisplay'; import { GridDisplay, ChangeCacheFunc, ChangeConfigFunc } from './GridDisplay';
import { EngineDriver, ViewInfo, ColumnInfo } from '@dbgate/types'; import { EngineDriver, ViewInfo, ColumnInfo } from '@dbgate/types';
import { GridConfig, GridCache } from './GridConfig'; import { GridConfig, GridCache } from './GridConfig';
@ -8,7 +8,7 @@ export class ViewGridDisplay extends GridDisplay {
public view: ViewInfo, public view: ViewInfo,
driver: EngineDriver, driver: EngineDriver,
config: GridConfig, config: GridConfig,
setConfig: (config: GridConfig) => void, setConfig: ChangeConfigFunc,
cache: GridCache, cache: GridCache,
setCache: ChangeCacheFunc setCache: ChangeCacheFunc
) { ) {

View File

@ -3,10 +3,12 @@ import styled from 'styled-components';
import ColumnLabel from './ColumnLabel'; import ColumnLabel from './ColumnLabel';
import DropDownButton from '../widgets/DropDownButton'; import DropDownButton from '../widgets/DropDownButton';
import { DropDownMenuItem } from '../modals/DropDownMenu'; import { DropDownMenuItem } from '../modals/DropDownMenu';
import { useSplitterDrag } from '../widgets/Splitter';
import { FontIcon } from '../icons'; import { FontIcon } from '../icons';
const HeaderDiv = styled.div` const HeaderDiv = styled.div`
display: flex; display: flex;
flex-wrap: nowrap;
`; `;
const LabelDiv = styled.div` const LabelDiv = styled.div`
@ -15,13 +17,22 @@ const LabelDiv = styled.div`
// padding-left: 2px; // padding-left: 2px;
padding: 2px; padding: 2px;
margin: auto; margin: auto;
white-space: nowrap;
`; `;
const IconWrapper = styled.span` const IconWrapper = styled.span`
margin-left: 3px; margin-left: 3px;
`; `;
export default function ColumnHeaderControl({ column, setSort, order }) { const ResizeHandle = styled.div`
background-color: #ccc;
width: 2px;
cursor: col-resize;
z-index: 1;
`;
export default function ColumnHeaderControl({ column, setSort, onResize, order }) {
const onResizeDown = useSplitterDrag('clientX', onResize);
return ( return (
<HeaderDiv> <HeaderDiv>
<LabelDiv> <LabelDiv>
@ -43,6 +54,7 @@ export default function ColumnHeaderControl({ column, setSort, order }) {
<DropDownMenuItem onClick={() => setSort('DESC')}>Sort descending</DropDownMenuItem> <DropDownMenuItem onClick={() => setSort('DESC')}>Sort descending</DropDownMenuItem>
</DropDownButton> </DropDownButton>
)} )}
<ResizeHandle className="resizeHandleControl" onMouseDown={onResizeDown} />
</HeaderDiv> </HeaderDiv>
); );
} }

View File

@ -6,6 +6,7 @@ import { SequenceIcon, ForeignKeyIcon } from '../icons';
const Label = styled.span` const Label = styled.span`
font-weight: ${props => (props.notNull ? 'bold' : 'normal')}; font-weight: ${props => (props.notNull ? 'bold' : 'normal')};
white-space: nowrap;
`; `;
/** @param column {import('@dbgate/datalib').DisplayColumn|import('@dbgate/types').ColumnInfo} */ /** @param column {import('@dbgate/datalib').DisplayColumn|import('@dbgate/types').ColumnInfo} */

View File

@ -509,7 +509,9 @@ export default function DataGridCore(props) {
function handleGridMouseDown(event) { function handleGridMouseDown(event) {
if (event.target.closest('.buttonLike')) return; if (event.target.closest('.buttonLike')) return;
if (event.target.closest('.resizeHandleControl')) return;
if (event.target.closest('input')) return; if (event.target.closest('input')) return;
// event.target.closest('table').focus(); // event.target.closest('table').focus();
event.preventDefault(); event.preventDefault();
// @ts-ignore // @ts-ignore
@ -1044,6 +1046,7 @@ export default function DataGridCore(props) {
column={col} column={col}
setSort={display.sortable ? (order) => display.setSort(col.uniqueName, order) : null} setSort={display.sortable ? (order) => display.setSort(col.uniqueName, order) : null}
order={display.getSortOrder(col.uniqueName)} order={display.getSortOrder(col.uniqueName)}
onResize={(diff) => display.resizeColumn(col.uniqueName, col.widthNumber, diff)}
/> />
</TableHeaderCell> </TableHeaderCell>
))} ))}

View File

@ -1,8 +1,9 @@
import _ from 'lodash'; import _ from 'lodash';
import { SeriesSizes } from './SeriesSizes'; import { SeriesSizes } from './SeriesSizes';
import { CellAddress } from './selection'; import { CellAddress } from './selection';
import { GridDisplay } from '@dbgate/datalib';
export function countColumnSizes(loadedRows, columns, containerWidth, display) { export function countColumnSizes(loadedRows, columns, containerWidth, display: GridDisplay) {
const columnSizes = new SeriesSizes(); const columnSizes = new SeriesSizes();
if (!loadedRows || !columns) return columnSizes; if (!loadedRows || !columns) return columnSizes;
@ -25,12 +26,17 @@ export function countColumnSizes(loadedRows, columns, containerWidth, display) {
//this.columnSizes.PutSizeOverride(col, this.columns[col].Name.length * 8); //this.columnSizes.PutSizeOverride(col, this.columns[col].Name.length * 8);
const column = columns[colIndex]; const column = columns[colIndex];
if (display.config.columnWidths[column.uniqueName]) {
columnSizes.putSizeOverride(colIndex, display.config.columnWidths[column.uniqueName]);
continue;
}
// if (column.columnClientObject != null && column.columnClientObject.notNull) context.font = "bold 14px Helvetica"; // if (column.columnClientObject != null && column.columnClientObject.notNull) context.font = "bold 14px Helvetica";
// else context.font = "14px Helvetica"; // else context.font = "14px Helvetica";
context.font = 'bold 14px Helvetica'; context.font = 'bold 14px Helvetica';
let text = column.headerText; const text = column.headerText;
let headerWidth = context.measureText(text).width + 64; const headerWidth = context.measureText(text).width + 64;
// if (column.columnClientObject != null && column.columnClientObject.icon != null) headerWidth += 16; // if (column.columnClientObject != null && column.columnClientObject.icon != null) headerWidth += 16;
// if (this.getFilterOnColumn(column.uniquePath)) headerWidth += 16; // if (this.getFilterOnColumn(column.uniquePath)) headerWidth += 16;
@ -47,9 +53,14 @@ export function countColumnSizes(loadedRows, columns, containerWidth, display) {
context.font = '14px Helvetica'; context.font = '14px Helvetica';
for (let row of loadedRows.slice(0, 20)) { for (let row of loadedRows.slice(0, 20)) {
for (let colIndex = 0; colIndex < columns.length; colIndex++) { for (let colIndex = 0; colIndex < columns.length; colIndex++) {
let uqName = columns[colIndex].uniqueName; const uqName = columns[colIndex].uniqueName;
let text = row[uqName];
let width = context.measureText(text).width + 8; if (display.config.columnWidths[uqName]) {
continue;
}
const text = row[uqName];
const width = context.measureText(text).width + 8;
// console.log('colName', colName, text, width); // console.log('colName', colName, text, width);
columnSizes.putSizeOverride(colIndex, width); columnSizes.putSizeOverride(colIndex, width);
// let colName = this.columns[colIndex].uniquePath; // let colName = this.columns[colIndex].uniquePath;
@ -103,6 +114,7 @@ export function countVisibleRealColumns(columnSizes, firstVisibleColumnScrollInd
realColumns.push({ realColumns.push({
...col, ...col,
colIndex, colIndex,
widthNumber,
widthPx: `${widthNumber}px`, widthPx: `${widthNumber}px`,
}); });
} }