Skip to content

Commit f50f8aa

Browse files
author
gjmooney
committed
Add hide column option to context menu
Signed-off-by: gjmooney <[email protected]>
1 parent 6ebe802 commit f50f8aa

7 files changed

+170
-7
lines changed

js/core/gridContextMenu.ts

+21
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,13 @@ export class FeatherGridContextMenu extends GridContextMenu {
9797
// Add menu items based on the region of the grid that was clicked on.
9898
switch (hit.region) {
9999
case 'column-header':
100+
this._menu.addItem({
101+
command: FeatherGridContextMenu.CommandID.HideColumn,
102+
args: args,
103+
});
104+
this._menu.addItem({
105+
type: 'separator',
106+
});
100107
this._menu.addItem({
101108
command: FeatherGridContextMenu.CommandID.SortAscending,
102109
args: args,
@@ -141,6 +148,17 @@ export class FeatherGridContextMenu extends GridContextMenu {
141148
});
142149
break;
143150
case 'corner-header':
151+
this._menu.addItem({
152+
command: FeatherGridContextMenu.CommandID.ShowAllColumns,
153+
args: args,
154+
});
155+
this._menu.addItem({
156+
command: FeatherGridContextMenu.CommandID.HideAllColumns,
157+
args: args,
158+
});
159+
this._menu.addItem({
160+
type: 'separator',
161+
});
144162
this._menu.addItem({
145163
command: FeatherGridContextMenu.CommandID.SortAscending,
146164
args: args,
@@ -258,6 +276,9 @@ export namespace FeatherGridContextMenu {
258276
SaveSelectionAsCsv = 'saveSelectionAsCsv',
259277
SaveAllAsCsv = 'saveAllAsCsv',
260278
ClearSelection = 'clearSelection',
279+
HideColumn = 'hideColumn',
280+
HideAllColumns = 'hideAllColumns',
281+
ShowAllColumns = 'showAllColumns',
261282
}
262283

263284
/**

js/core/transform.ts

+24-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22
* A declarative spec for specifying transformations.
33
*/
44
export namespace Transform {
5-
export type TransformSpec = Transform.Sort | Transform.Filter;
5+
export type TransformSpec =
6+
| Transform.Sort
7+
| Transform.Filter
8+
| Transform.Hide;
69

710
/**
811
* A declarative spec for the `Sort` transformation.
@@ -30,6 +33,26 @@ export namespace Transform {
3033
desc: boolean;
3134
};
3235

36+
/**
37+
* A declarative spec for the `Hide` transformation.
38+
*/
39+
export type Hide = {
40+
/**
41+
* A type alias for this trasformation.
42+
*/
43+
type: 'hide';
44+
45+
/**
46+
* The column in the data schema to apply the transformation to.
47+
*/
48+
columnIndex: number;
49+
50+
/**
51+
* Boolean indicating if all columns should be hidden
52+
*/
53+
hideAll: boolean;
54+
};
55+
3356
/**
3457
* A declarative spec for the `Filter` transformation.
3558
*/

js/core/transformExecutors.ts

+47-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { Dict } from '@jupyter-widgets/base';
22

3-
import { Transform } from './transform';
43
import { DataSource } from '../datasource';
4+
import { Transform } from './transform';
55

66
import * as moment from 'moment';
77

@@ -25,6 +25,52 @@ export namespace TransformExecutor {
2525
export type IData = Readonly<DataSource>;
2626
}
2727

28+
export class HideExecutor extends TransformExecutor {
29+
constructor(options: HideExecutor.IOptions) {
30+
super();
31+
this._options = options;
32+
}
33+
34+
// input has data and schema
35+
public apply(input: TransformExecutor.IData): TransformExecutor.IData {
36+
const newSchema = { ...input.schema };
37+
38+
if (this._options.hideAll) {
39+
newSchema.fields = newSchema.fields.filter(
40+
(field) => field.name === 'key',
41+
);
42+
} else {
43+
newSchema.fields = newSchema.fields.filter(
44+
(field) => field.name !== this._options.field,
45+
);
46+
}
47+
48+
return new DataSource(input.data, input.fields, newSchema);
49+
}
50+
51+
protected _options: HideExecutor.IOptions;
52+
}
53+
54+
/**
55+
* The namespace for the `HideExecutor` class statics.
56+
*/
57+
export namespace HideExecutor {
58+
/**
59+
* An options object for initializing a Hide.
60+
*/
61+
export interface IOptions {
62+
/**
63+
* The name of the field to hide in the data source.
64+
*/
65+
field: string;
66+
67+
/**
68+
* Boolean indicating if all columns should be hidden
69+
*/
70+
hideAll: boolean;
71+
}
72+
}
73+
2874
/**
2975
* A transformation that filters a single field by the provided operator and
3076
* value.

js/core/transformStateManager.ts

+23-4
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,17 @@ import { Transform } from './transform';
33
import { View } from './view';
44

55
import {
6-
SortExecutor,
76
FilterExecutor,
7+
HideExecutor,
8+
SortExecutor,
89
TransformExecutor,
910
} from './transformExecutors';
1011

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

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

15-
import { Signal, ISignal } from '@lumino/signaling';
16+
import { ISignal, Signal } from '@lumino/signaling';
1617
import { DataSource } from '../datasource';
1718

1819
/**
@@ -25,6 +26,7 @@ export class TransformStateManager {
2526
this._state[transform.column] = {
2627
sort: undefined,
2728
filter: undefined,
29+
hide: undefined,
2830
};
2931
}
3032

@@ -41,6 +43,9 @@ export class TransformStateManager {
4143
case 'filter':
4244
this._state[transform.column]['filter'] = transform;
4345
break;
46+
case 'hide':
47+
this._state[transform.columnIndex]['hide'] = transform;
48+
break;
4449
default:
4550
throw 'unreachable';
4651
}
@@ -110,6 +115,7 @@ export class TransformStateManager {
110115
private _createExecutors(data: Readonly<DataSource>): TransformExecutor[] {
111116
const sortExecutors: SortExecutor[] = [];
112117
const filterExecutors: FilterExecutor[] = [];
118+
const hideExecutors: HideExecutor[] = [];
113119

114120
Object.keys(this._state).forEach((column) => {
115121
const transform: TransformStateManager.IColumn = this._state[column];
@@ -146,10 +152,17 @@ export class TransformStateManager {
146152
});
147153
filterExecutors.push(executor);
148154
}
155+
if (transform.hide) {
156+
const executor = new HideExecutor({
157+
field: data.schema.fields[transform.hide.columnIndex]['name'],
158+
hideAll: transform.hide.hideAll,
159+
});
160+
hideExecutors.push(executor);
161+
}
149162
});
150163

151164
// Always put filters first
152-
return [...filterExecutors, ...sortExecutors];
165+
return [...filterExecutors, ...sortExecutors, ...hideExecutors];
153166
}
154167

155168
/**
@@ -171,10 +184,12 @@ export class TransformStateManager {
171184
columnState.sort = undefined;
172185
} else if (transformType === 'filter') {
173186
columnState.filter = undefined;
187+
} else if (transformType === 'hide') {
188+
columnState.hide = undefined;
174189
} else {
175190
throw 'unreachable';
176191
}
177-
if (!columnState.sort && !columnState.filter) {
192+
if (!columnState.sort && !columnState.filter && !columnState.hide) {
178193
delete this._state[column];
179194
}
180195
this._changed.emit({
@@ -229,6 +244,9 @@ export class TransformStateManager {
229244
if (this._state[column].filter) {
230245
transforms.push(this._state[column].filter!);
231246
}
247+
if (this._state[column].hide) {
248+
transforms.push(this._state[column].hide!);
249+
}
232250
});
233251
return transforms;
234252
}
@@ -255,6 +273,7 @@ export namespace TransformStateManager {
255273
export interface IColumn {
256274
filter: Transform.Filter | undefined;
257275
sort: Transform.Sort | undefined;
276+
hide: Transform.Hide | undefined;
258277
}
259278
export interface IState {
260279
[key: string]: IColumn;

js/core/view.ts

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ export class View {
4242
if (region === 'body') {
4343
return this._data.length;
4444
} else {
45+
// If there are no body rows, return one for the header row
4546
return this._bodyFields[0]?.rows.length ?? 1;
4647
}
4748
}

js/core/viewbasedjsonmodel.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ import { View } from './view';
1010

1111
import { TransformStateManager } from './transformStateManager';
1212

13-
import { ArrayUtils } from '../utils';
1413
import { DataSource } from '../datasource';
14+
import { ArrayUtils } from '../utils';
1515

1616
/**
1717
* A view based data model implementation for in-memory JSON data.
@@ -76,6 +76,7 @@ export class ViewBasedJSONModel extends MutableDataModel {
7676
*/
7777
updateDataset(data: DataSource): void {
7878
this._dataset = data;
79+
// does not happen when selecting hide column
7980
this._updatePrimaryKeyMap();
8081
const view = new View(this._dataset);
8182
this.currentView = view;
@@ -566,6 +567,7 @@ export class ViewBasedJSONModel extends MutableDataModel {
566567
}
567568
// We need to rerun the transforms, as the changed cells may change the order
568569
// or visibility of other rows
570+
console.log('update row value');
569571
this.currentView = this._transformState.createView(this._dataset);
570572
}
571573

js/feathergrid.ts

+51
Original file line numberDiff line numberDiff line change
@@ -1070,6 +1070,57 @@ export class FeatherGrid extends Widget {
10701070
this.grid.selectionModel?.clear();
10711071
},
10721072
});
1073+
commands.addCommand(FeatherGridContextMenu.CommandID.HideColumn, {
1074+
label: 'Hide Column',
1075+
mnemonic: -1,
1076+
execute: (args) => {
1077+
const cellClick: FeatherGridContextMenu.CommandArgs =
1078+
args as FeatherGridContextMenu.CommandArgs;
1079+
const colIndex = this._dataModel.getSchemaIndex(
1080+
cellClick.region,
1081+
cellClick.columnIndex,
1082+
);
1083+
this._dataModel.addTransform({
1084+
type: 'hide',
1085+
columnIndex: colIndex,
1086+
hideAll: false,
1087+
});
1088+
},
1089+
});
1090+
commands.addCommand(FeatherGridContextMenu.CommandID.HideAllColumns, {
1091+
label: 'Hide All Columns',
1092+
mnemonic: -1,
1093+
execute: (args) => {
1094+
const cellClick: FeatherGridContextMenu.CommandArgs =
1095+
args as FeatherGridContextMenu.CommandArgs;
1096+
const colIndex = this._dataModel.getSchemaIndex(
1097+
cellClick.region,
1098+
cellClick.columnIndex,
1099+
);
1100+
this._dataModel.addTransform({
1101+
type: 'hide',
1102+
columnIndex: colIndex,
1103+
hideAll: true,
1104+
});
1105+
},
1106+
});
1107+
commands.addCommand(FeatherGridContextMenu.CommandID.ShowAllColumns, {
1108+
label: 'Show All Columns',
1109+
mnemonic: -1,
1110+
execute: () => {
1111+
const activeTransforms: Transform.TransformSpec[] =
1112+
this._dataModel.activeTransforms;
1113+
console.log(
1114+
'this._dataModel.activeTransforms',
1115+
this._dataModel.activeTransforms,
1116+
);
1117+
const newTransforms = activeTransforms.filter(
1118+
(val) => val.type !== 'hide',
1119+
);
1120+
console.log('newTransforms', newTransforms);
1121+
this._dataModel.replaceTransforms(newTransforms);
1122+
},
1123+
});
10731124

10741125
return commands;
10751126
}

0 commit comments

Comments
 (0)