Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#6674 add DataGrid sorting feature #6859

Merged
merged 4 commits into from
Feb 14, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 41 additions & 2 deletions js/notebook/src/tableDisplay/dataGrid/BeakerxDataGrid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export class BeakerxDataGrid extends DataGrid {
viewport: Widget;
highlighterManager: HighlighterManager;
columnManager: ColumnManager;
focused: boolean;

headerCellHovered = new Signal<this, ICellData|null>(this);

Expand All @@ -60,9 +61,12 @@ export class BeakerxDataGrid extends DataGrid {
case 'mousemove':
this.handleHeaderCellHover(event as MouseEvent);
break;
case 'mouseout':
this.headerCellHovered.emit(null);
case 'mousedown':
this.handleMouseDown(event as MouseEvent);
break;
case 'wheel':
this.handleMouseWheel(event as MouseEvent);
return;
}

super.handleEvent(event);
Expand Down Expand Up @@ -92,6 +96,10 @@ export class BeakerxDataGrid extends DataGrid {
private init(modelState: IDataModelState) {
this.columnManager = new ColumnManager(modelState, this);
this.model = new BeakerxDataGridModel(modelState, this.columnManager);
this.focused = false;

this.node.removeEventListener('mouseout', this.handleMouseOut.bind(this));
this.node.addEventListener('mouseout', this.handleMouseOut.bind(this));

this.addHighlighterManager(modelState);
this.addCellRenderers();
Expand Down Expand Up @@ -130,6 +138,37 @@ export class BeakerxDataGrid extends DataGrid {
this.headerCellHovered.emit(data);
}

private handleMouseDown(event: MouseEvent) {
this.focused = true;
this.node.classList.add('bko-focused');
this.handleHeaderClick(event);
}

private handleMouseOut(event: MouseEvent) {
this.headerCellHovered.emit(null);
this.node.classList.remove('bko-focused');
this.focused = false;
}

private handleMouseWheel(event: MouseEvent) {
if(!this.focused) {
return;
}

super.handleEvent(event);
}

private handleHeaderClick(event: MouseEvent): void {
const data = this.getHoveredCellData(event.clientX, event.clientY);

if (!data) {
return;
}

const column = this.columnManager.columns[data.type][data.index];
column.toggleSort();
}

private getHoveredCellData(clientX: number, clientY: number): ICellData|null {
if (!this.viewport) {
return null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,9 @@ import { COLUMN_TYPES } from "./DataGridColumn";
import { IDataGridModelColumnState as IColumnsState } from "../model/BeakerxDataGridModel";

export default class ColumnIndexResolver {
hasIndex: boolean;
columnIndexesMap: {};

constructor(hasIndex, indexColumnsState: IColumnsState, bodyColumnsState: IColumnsState) {
this.hasIndex = !!hasIndex;
constructor(indexColumnsState: IColumnsState, bodyColumnsState: IColumnsState) {
this.columnIndexesMap = { [COLUMN_TYPES.index]: {}, [COLUMN_TYPES.body]: {} };

this.mapAllIndexes(indexColumnsState, bodyColumnsState);
Expand All @@ -34,10 +32,7 @@ export default class ColumnIndexResolver {
}

resolveIndex(index: number, columnType: COLUMN_TYPES) {
return this.applyHasIndex(
this.columnIndexesMap[columnType][index],
columnType
);
return this.columnIndexesMap[columnType][index];
}

mapIndexes(columnType: COLUMN_TYPES, columnsState: IColumnsState) {
Expand All @@ -60,10 +55,4 @@ export default class ColumnIndexResolver {

return this.getNexVisibleIndex(index + 1, columnsState);
}

private applyHasIndex(index: number, columnType: COLUMN_TYPES) {
return this.hasIndex && columnType === COLUMN_TYPES.body
? index + 1
: index;
}
}
25 changes: 17 additions & 8 deletions js/notebook/src/tableDisplay/dataGrid/column/ColumnManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/

import { BeakerxDataGridModel, IDataGridModelColumnState } from "../model/BeakerxDataGridModel";
import { COLUMN_TYPES, default as DataGridColumn } from "./DataGridColumn";
import {COLUMN_TYPES, default as DataGridColumn, SORT_ORDER} from "./DataGridColumn";
import { ITriggerOptions } from "../headerMenu/HeaderMenu";
import { CellRenderer } from "@phosphor/datagrid";
import { chain, find } from '@phosphor/algorithm'
Expand All @@ -24,14 +24,15 @@ import { Signal } from '@phosphor/signaling';
import ColumnIndexResolver from "./ColumnIndexResolver";
import IDataModelState from "../interface/IDataGridModelState";

export interface IcolumnsChangedArgs {
export interface IBkoColumnsChangedArgs {
type: COLUMN_CHANGED_TYPES,
value: any,
column: DataGridColumn
}

export enum COLUMN_CHANGED_TYPES {
'columnVisible'
'columnVisible',
'columnSort'
}

export default class ColumnManager {
Expand All @@ -40,13 +41,13 @@ export default class ColumnManager {
modelState: IDataModelState;
columnsState: {};
columns = {};
columnsChanged = new Signal<this, IcolumnsChangedArgs>(this);
columnsChanged = new Signal<this, IBkoColumnsChangedArgs>(this);

constructor(modelState: IDataModelState, dataGrid: BeakerxDataGrid) {
this.dataGrid = dataGrid;
this.modelState = modelState;
this.addColumnsState(modelState);
this.addIndexResolver(modelState);
this.addIndexResolver();
this.connectToColumnsChanged();
}

Expand Down Expand Up @@ -116,9 +117,18 @@ export default class ColumnManager {
Signal.disconnectAll(this.columnsChanged);
}

sortByColumn(column: DataGridColumn, sortOrder: SORT_ORDER) {
this.columnsChanged.emit({
column,
type: COLUMN_CHANGED_TYPES.columnSort,
value: sortOrder
});
this.dataGrid.model.sortByColumn(column);
}

private connectToColumnsChanged() {
this.columnsChanged.connect(
(sender: ColumnManager, data: IcolumnsChangedArgs) => {
(sender: ColumnManager, data: IBkoColumnsChangedArgs) => {
if (data.type !== COLUMN_CHANGED_TYPES.columnVisible) {
return;
}
Expand All @@ -127,9 +137,8 @@ export default class ColumnManager {
});
}

private addIndexResolver(modelState) {
private addIndexResolver() {
this.indexResolver = new ColumnIndexResolver(
modelState.hasIndex,
this.indexColumnsState,
this.bodyColumnsState
);
Expand Down
51 changes: 46 additions & 5 deletions js/notebook/src/tableDisplay/dataGrid/column/DataGridColumn.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,17 @@ import { CellRenderer, DataModel, TextRenderer } from "@phosphor/datagrid";
import { ALL_TYPES, getDisplayType, getTypeByName } from "../dataTypes";
import { minmax, MapIterator } from '@phosphor/algorithm';
import { HIGHLIGHTER_TYPE } from "../interface/IHighlighterState";
import ColumnManager, { COLUMN_CHANGED_TYPES } from "./ColumnManager";
import ColumnManager, { COLUMN_CHANGED_TYPES, IBkoColumnsChangedArgs } from "./ColumnManager";

export enum COLUMN_TYPES {
'index',
'body'
index,
body
}

export enum SORT_ORDER {
ASC,
DESC,
NO_SORT
}

export interface IColumnState {
Expand All @@ -37,7 +43,8 @@ export interface IColumnState {
triggerShown: boolean,
horizontalAlignment: TextRenderer.HorizontalAlignment,
formatForTimes: any,
visible: boolean
visible: boolean,
sortOrder: SORT_ORDER
}

export default class DataGridColumn {
Expand Down Expand Up @@ -67,6 +74,7 @@ export default class DataGridColumn {
this.handleHeaderCellHovered = this.handleHeaderCellHovered.bind(this);
this.createMenu(options.menuOptions);
this.connectToHeaderCellHovered();
this.connectToColumnsChanged();
this.addMinMaxValues();
}

Expand All @@ -92,7 +100,8 @@ export default class DataGridColumn {
triggerShown: false,
horizontalAlignment: this.getInitialAlignment(dataType),
formatForTimes: {},
visible: true
visible: true,
sortOrder: SORT_ORDER.NO_SORT
};
}

Expand Down Expand Up @@ -169,6 +178,26 @@ export default class DataGridColumn {
this.menu.destroy();
}

connectToColumnsChanged() {
this.columnManager.columnsChanged.connect(this.onColumnsChanged.bind(this));
}

private onColumnsChanged(sender: ColumnManager, args: IBkoColumnsChangedArgs) {
if (args.type !== COLUMN_CHANGED_TYPES.columnSort) {
return;
}

if (args.column === this && args.value !== SORT_ORDER.NO_SORT) {
this.setState({ sortOrder: args.value });
this.dataGrid.highlighterManager.addColumnHighlighter(this, HIGHLIGHTER_TYPE.sort);
this.menu.showTrigger();
} else {
this.setState({ sortOrder: SORT_ORDER.NO_SORT });
this.dataGrid.highlighterManager.removeColumnHighlighter(this, HIGHLIGHTER_TYPE.sort);
this.menu.hideTrigger();
}
}

connectToHeaderCellHovered() {
this.dataGrid.headerCellHovered.connect(this.handleHeaderCellHovered);
}
Expand Down Expand Up @@ -221,6 +250,18 @@ export default class DataGridColumn {
this.dataGrid.highlighterManager.toggleColumnHighlighter(this, highlighterType);
}

sort(sortOrder: SORT_ORDER) {
this.columnManager.sortByColumn(this, sortOrder);
}

toggleSort() {
if (this.state.sortOrder !== SORT_ORDER.ASC) {
return this.sort(SORT_ORDER.ASC);
}

this.sort(SORT_ORDER.DESC);
}

private getDataTypeName(): string {
return this.type === COLUMN_TYPES.index
? this.dataGrid.columnManager.columnsState[COLUMN_TYPES.index].types[this.index]
Expand Down
29 changes: 28 additions & 1 deletion js/notebook/src/tableDisplay/dataGrid/headerMenu/HeaderMenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import { BeakerxDataGrid } from "../BeakerxDataGrid";
import Menu from './BkoMenu';
import MenuItem from '../../../shared/interfaces/menuItemInterface';
import MenuInterface from '../../../shared/interfaces/menuInterface';
import DataGridColumn from "../column/DataGridColumn";
import DataGridColumn, {SORT_ORDER} from "../column/DataGridColumn";

export interface ITriggerOptions {
x: number,
Expand All @@ -40,6 +40,8 @@ export default abstract class HeaderMenu implements MenuInterface {
protected column: DataGridColumn;

private TRIGGER_CLASS_OPENED: string = 'opened';
private TRIGGER_CLASS_SORTING_DESC: string = 'sorting_desc';
private TRIGGER_CLASS_SORTING_ASC: string = 'sorting_asc';

static DEFAULT_TRIGGER_HEIGHT: number = 20;

Expand All @@ -61,6 +63,8 @@ export default abstract class HeaderMenu implements MenuInterface {
protected abstract buildMenu(): void

showTrigger(x?): void {
this.assignTriggerSortingCssClass();

if (this.triggerNode.style.visibility === 'visible') {
return;
}
Expand All @@ -74,6 +78,10 @@ export default abstract class HeaderMenu implements MenuInterface {
}

hideTrigger() {
if (this.column.state.sortOrder !== SORT_ORDER.NO_SORT && this.column.state.visible) {
return;
}

this.triggerNode.style.visibility = 'hidden';
}

Expand Down Expand Up @@ -178,6 +186,25 @@ export default abstract class HeaderMenu implements MenuInterface {
return submenu;
}

protected assignTriggerSortingCssClass() {
if (this.column.state.sortOrder === SORT_ORDER.ASC) {
this.triggerNode.classList.remove(this.TRIGGER_CLASS_SORTING_DESC);
this.triggerNode.classList.add(this.TRIGGER_CLASS_SORTING_ASC);

return;
}

if (this.column.state.sortOrder === SORT_ORDER.DESC) {
this.triggerNode.classList.remove(this.TRIGGER_CLASS_SORTING_ASC);
this.triggerNode.classList.add(this.TRIGGER_CLASS_SORTING_DESC);

return;
}

this.triggerNode.classList.remove(this.TRIGGER_CLASS_SORTING_ASC);
this.triggerNode.classList.remove(this.TRIGGER_CLASS_SORTING_DESC);
}

protected addTrigger({
x, y,
width = HeaderMenu.DEFAULT_TRIGGER_HEIGHT,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

import { createFormatMenuItems } from './createFormatMenuItems';
import MenuItem from "../../../shared/interfaces/menuItemInterface";
import DataGridColumn from "../column/DataGridColumn";
import DataGridColumn, {SORT_ORDER} from "../column/DataGridColumn";
import { CENTER, LEFT, RIGHT } from "../column/columnAlignment";
import {HIGHLIGHTER_TYPE} from "../interface/IHighlighterState";

Expand Down Expand Up @@ -46,18 +46,18 @@ export function createColumnMenuItems(column: DataGridColumn): MenuItem[] {
{
title: 'Sort Ascending',
separator: true,
isChecked: (column) => {},
action: (column) => {}
isChecked: (column) => column.state.sortOrder === SORT_ORDER.ASC,
action: (column) => column.sort(SORT_ORDER.ASC)
},
{
title: 'Sort Descending',
isChecked: (column) => {},
action: (column) => {}
isChecked: (column) => column.state.sortOrder === SORT_ORDER.DESC,
action: (column) => column.sort(SORT_ORDER.DESC)
},
{
title: 'No Sort',
isChecked: (column) => {},
action: (column) => {}
isChecked: (column) => column.state.sortOrder === SORT_ORDER.NO_SORT,
action: (column) => column.sort(SORT_ORDER.NO_SORT)
},
{
title: 'Align Left',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import DataGridColumn from "../column/DataGridColumn";
import ThreeColorHeatmapHighlighter from "./ThreeColorHeatmapHighlighter";
import UniqueEntriesHighlighter from "./UniqueEntriesHighlighter";
import ValueHighlighter from "./ValueHighlighter";
import SortHighlighter from "./SortHighlighter";

export default class HighlighterFactory {
static defaultHighlighterState: IHihglighterState = {
Expand All @@ -48,6 +49,8 @@ export default class HighlighterFactory {
return new UniqueEntriesHighlighter(column, config);
case HIGHLIGHTER_TYPE.value:
return new ValueHighlighter(column, config);
case HIGHLIGHTER_TYPE.sort:
return new SortHighlighter(column, config);
}
}
}
Loading