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

Add hide column option to context menu #496

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
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
21 changes: 21 additions & 0 deletions js/core/gridContextMenu.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,13 @@ export class FeatherGridContextMenu extends GridContextMenu {
// Add menu items based on the region of the grid that was clicked on.
switch (hit.region) {
case 'column-header':
this._menu.addItem({
command: FeatherGridContextMenu.CommandID.HideColumn,
args: args,
});
this._menu.addItem({
type: 'separator',
});
this._menu.addItem({
command: FeatherGridContextMenu.CommandID.SortAscending,
args: args,
Expand Down Expand Up @@ -141,6 +148,17 @@ export class FeatherGridContextMenu extends GridContextMenu {
});
break;
case 'corner-header':
this._menu.addItem({
command: FeatherGridContextMenu.CommandID.ShowAllColumns,
args: args,
});
this._menu.addItem({
command: FeatherGridContextMenu.CommandID.HideAllColumns,
args: args,
});
this._menu.addItem({
type: 'separator',
});
this._menu.addItem({
command: FeatherGridContextMenu.CommandID.SortAscending,
args: args,
Expand Down Expand Up @@ -258,6 +276,9 @@ export namespace FeatherGridContextMenu {
SaveSelectionAsCsv = 'saveSelectionAsCsv',
SaveAllAsCsv = 'saveAllAsCsv',
ClearSelection = 'clearSelection',
HideColumn = 'hideColumn',
HideAllColumns = 'hideAllColumns',
ShowAllColumns = 'showAllColumns',
}

/**
Expand Down
30 changes: 29 additions & 1 deletion js/core/transform.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@
* A declarative spec for specifying transformations.
*/
export namespace Transform {
export type TransformSpec = Transform.Sort | Transform.Filter;
export type TransformSpec =
| Transform.Sort
| Transform.Filter
| Transform.Hide;

/**
* A declarative spec for the `Sort` transformation.
Expand Down Expand Up @@ -30,6 +33,31 @@ export namespace Transform {
desc: boolean;
};

/**
* A declarative spec for the `Hide` transformation.
*/
export type Hide = {
/**
* A type alias for this transformation.
*/
type: 'hide';

/**
* The column in the data schema to apply the transformation to.
*/
column: string;

/**
* The column in the data schema to apply the transformation to.
*/
columnIndex?: number;

/**
* Boolean indicating if all columns should be hidden
*/
hideAll: boolean;
};

/**
* A declarative spec for the `Filter` transformation.
*/
Expand Down
54 changes: 53 additions & 1 deletion js/core/transformExecutors.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Dict } from '@jupyter-widgets/base';

import { Transform } from './transform';
import { DataSource } from '../datasource';
import { Transform } from './transform';

import * as moment from 'moment';

Expand All @@ -25,6 +25,58 @@ export namespace TransformExecutor {
export type IData = Readonly<DataSource>;
}

export class HideExecutor extends TransformExecutor {
constructor(options: HideExecutor.IOptions) {
super();
this._options = options;
}

// input has data and schema
public apply(input: TransformExecutor.IData): TransformExecutor.IData {
const newSchema = { ...input.schema };

console.log('input.schema', input.schema);
if (this._options.hideAll) {
newSchema.fields = newSchema.fields.filter(
(field) => field.name === 'index_column',
);
} else {
newSchema.fields = newSchema.fields.filter(
(field) => field.name !== this._options.field,
);
}

return new DataSource(input.data, input.fields, newSchema);
}

protected _options: HideExecutor.IOptions;
}

/**
* The namespace for the `HideExecutor` class statics.
*/
export namespace HideExecutor {
/**
* An options object for initializing a Hide.
*/
export interface IOptions {
/**
* The name of the field to hide in the data source.
*/
field: string;

/**
* The data type of the column associated with this transform.
*/
dType: string;

/**
* Boolean indicating if all columns should be hidden
*/
hideAll: boolean;
}
}

/**
* A transformation that filters a single field by the provided operator and
* value.
Expand Down
35 changes: 31 additions & 4 deletions js/core/transformStateManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,17 @@ import { Transform } from './transform';
import { View } from './view';

import {
SortExecutor,
FilterExecutor,
HideExecutor,
SortExecutor,
TransformExecutor,
} from './transformExecutors';

import { each } from '@lumino/algorithm';

import { JSONExt } from '@lumino/coreutils';

import { Signal, ISignal } from '@lumino/signaling';
import { ISignal, Signal } from '@lumino/signaling';
import { DataSource } from '../datasource';

/**
Expand All @@ -25,6 +26,7 @@ export class TransformStateManager {
this._state[transform.column] = {
sort: undefined,
filter: undefined,
hide: undefined,
};
}

Expand All @@ -41,6 +43,9 @@ export class TransformStateManager {
case 'filter':
this._state[transform.column]['filter'] = transform;
break;
case 'hide':
this._state[transform.column]['hide'] = transform;
break;
default:
throw 'unreachable';
}
Expand Down Expand Up @@ -110,6 +115,7 @@ export class TransformStateManager {
private _createExecutors(data: Readonly<DataSource>): TransformExecutor[] {
const sortExecutors: SortExecutor[] = [];
const filterExecutors: FilterExecutor[] = [];
const hideExecutors: HideExecutor[] = [];

Object.keys(this._state).forEach((column) => {
const transform: TransformStateManager.IColumn = this._state[column];
Expand Down Expand Up @@ -146,10 +152,25 @@ export class TransformStateManager {
});
filterExecutors.push(executor);
}
if (transform.hide) {
let dType = '';
for (const field of data.schema.fields) {
if (field.name === transform.hide.column) {
dType = field.type;
}
}

const executor = new HideExecutor({
field: transform.hide.column,
dType,
hideAll: transform.hide.hideAll,
});
hideExecutors.push(executor);
}
});

// Always put filters first
return [...filterExecutors, ...sortExecutors];
return [...filterExecutors, ...sortExecutors, ...hideExecutors];
}

/**
Expand All @@ -171,10 +192,12 @@ export class TransformStateManager {
columnState.sort = undefined;
} else if (transformType === 'filter') {
columnState.filter = undefined;
} else if (transformType === 'hide') {
columnState.hide = undefined;
} else {
throw 'unreachable';
}
if (!columnState.sort && !columnState.filter) {
if (!columnState.sort && !columnState.filter && !columnState.hide) {
delete this._state[column];
}
this._changed.emit({
Expand Down Expand Up @@ -229,6 +252,9 @@ export class TransformStateManager {
if (this._state[column].filter) {
transforms.push(this._state[column].filter!);
}
if (this._state[column].hide) {
transforms.push(this._state[column].hide!);
}
});
return transforms;
}
Expand All @@ -255,6 +281,7 @@ export namespace TransformStateManager {
export interface IColumn {
filter: Transform.Filter | undefined;
sort: Transform.Sort | undefined;
hide: Transform.Hide | undefined;
}
export interface IState {
[key: string]: IColumn;
Expand Down
1 change: 1 addition & 0 deletions js/core/view.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ export class View {
if (region === 'body') {
return this._data.length;
} else {
// If there are no body rows, return one for the header row
return this._bodyFields[0]?.rows.length ?? 1;
}
}
Expand Down
2 changes: 1 addition & 1 deletion js/core/viewbasedjsonmodel.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import { View } from './view';

import { TransformStateManager } from './transformStateManager';

import { ArrayUtils } from '../utils';
import { DataSource } from '../datasource';
import { ArrayUtils } from '../utils';

/**
* A view based data model implementation for in-memory JSON data.
Expand Down
58 changes: 58 additions & 0 deletions js/feathergrid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1070,6 +1070,64 @@ export class FeatherGrid extends Widget {
this.grid.selectionModel?.clear();
},
});
commands.addCommand(FeatherGridContextMenu.CommandID.HideColumn, {
label: 'Hide Column',
mnemonic: -1,
execute: (args) => {
const command: FeatherGridContextMenu.CommandArgs =
args as FeatherGridContextMenu.CommandArgs;

const colIndex = this._dataModel.getSchemaIndex(
command.region,
command.columnIndex,
);

const column =
this.dataModel.currentView.dataset.schema.fields[colIndex];

this._dataModel.addTransform({
type: 'hide',
column: column.name,
columnIndex: colIndex,
hideAll: false,
});
},
});
commands.addCommand(FeatherGridContextMenu.CommandID.HideAllColumns, {
label: 'Hide All Columns',
mnemonic: -1,
execute: (args) => {
const cellClick: FeatherGridContextMenu.CommandArgs =
args as FeatherGridContextMenu.CommandArgs;
const colIndex = this._dataModel.getSchemaIndex(
cellClick.region,
cellClick.columnIndex,
);

const column =
this.dataModel.currentView.dataset.schema.fields[colIndex];

this._dataModel.addTransform({
type: 'hide',
column: column.name,
columnIndex: colIndex,
hideAll: true,
});
},
});
commands.addCommand(FeatherGridContextMenu.CommandID.ShowAllColumns, {
label: 'Show All Columns',
mnemonic: -1,
execute: () => {
const activeTransforms: Transform.TransformSpec[] =
this._dataModel.activeTransforms;

const newTransforms = activeTransforms.filter(
(val) => val.type !== 'hide',
);
this._dataModel.replaceTransforms(newTransforms);
},
});

return commands;
}
Expand Down
10 changes: 7 additions & 3 deletions tests/js/transformStateManager.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { TransformStateManager } from '../../js/core/transformStateManager';
import { Transform } from '../../js/core/transform';
import { DataGenerator } from './testUtils';
import { TransformStateManager } from '../../js/core/transformStateManager';
import { View } from '../../js/core/view';
import { DataGenerator } from './testUtils';

describe('Test .add()', () => {
const testCases: Transform.TransformSpec[] = [
Expand Down Expand Up @@ -229,10 +229,14 @@ namespace Private {
return { type: 'filter', column: 'test', operator: '<', value: 0 };
}

export function simpleHide(): Transform.Hide {
return { type: 'hide', column: 'test', hideAll: false };
}

/**
* Returns a simple column of transform state.
*/
export function simpleState(): TransformStateManager.IColumn {
return { filter: simpleFilter(), sort: simpleSort() };
return { filter: simpleFilter(), sort: simpleSort(), hide: simpleHide() };
}
}
Loading