Skip to content

Commit

Permalink
feat(state): add Pinning (frozen) to Grid State & Presets (#292)
Browse files Browse the repository at this point in the history
* feat(state): add pinning(frozen) to Grid State & Presets
  • Loading branch information
ghiscoding authored Mar 24, 2021
1 parent a07ebdf commit ba703d8
Show file tree
Hide file tree
Showing 26 changed files with 470 additions and 85 deletions.
2 changes: 1 addition & 1 deletion examples/webpack-demo-vanilla-bundle/assets/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"CLEAR_ALL_FILTERS": "Clear all Filters",
"CLEAR_ALL_GROUPING": "Clear all Grouping",
"CLEAR_ALL_SORTING": "Clear all Sorting",
"CLEAR_FROZEN_COLUMNS": "Clear Frozen Columns",
"CLEAR_PINNING": "Unfreeze Columns/Rows",
"CLONE": "Clone",
"COLLAPSE_ALL_GROUPS": "Collapse all Groups",
"COLUMNS": "Columns",
Expand Down
2 changes: 1 addition & 1 deletion examples/webpack-demo-vanilla-bundle/assets/i18n/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"CLEAR_ALL_FILTERS": "Supprimer tous les filtres",
"CLEAR_ALL_GROUPING": "Supprimer tous les groupes",
"CLEAR_ALL_SORTING": "Supprimer tous les tris",
"CLEAR_FROZEN_COLUMNS": "Libérer les colonnes gelées",
"CLEAR_PINNING": "Dégeler les colonnes/rangées",
"CLONE": "Cloner",
"COLLAPSE_ALL_GROUPS": "Réduire tous les groupes",
"COLUMNS": "Colonnes",
Expand Down
18 changes: 16 additions & 2 deletions examples/webpack-demo-vanilla-bundle/src/examples/example11.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
Column,
CurrentColumn,
CurrentFilter,
CurrentPinning,
CurrentSorter,
Editors,
FieldType,
Expand Down Expand Up @@ -58,6 +59,7 @@ export interface ViewDefinition {
columns?: CurrentColumn[];
filters: CurrentFilter[];
sorters?: CurrentSorter[];
pinning?: CurrentPinning;
}

export class Example11 {
Expand Down Expand Up @@ -326,7 +328,11 @@ export class Example11 {
],
onCommand: (e, args) => this.executeCommand(e, args)
},
headerMenu: {
hideFreezeColumnsCommand: false,
},
gridMenu: {
hideClearFrozenColumnsCommand: false,
customItems: [
{
command: 'modal',
Expand Down Expand Up @@ -357,6 +363,9 @@ export class Example11 {
if (presetSelection.sorters) {
this.gridOptions.presets.sorters = presetSelection.sorters;
}
if (presetSelection.pinning) {
this.gridOptions.presets.pinning = presetSelection.pinning;
}
}
}
}
Expand Down Expand Up @@ -618,7 +627,7 @@ export class Example11 {

this.predefinedViews.forEach(viewSelect => viewSelect.isSelected = false); // reset selection
const currentGridState = this.sgb.gridStateService.getCurrentGridState();
const { columns, filters, sorters } = currentGridState;
const { columns, filters, sorters, pinning } = currentGridState;

const viewName = await prompt('Please provide a name for the new View.');
if (viewName) {
Expand All @@ -632,6 +641,7 @@ export class Example11 {
columns: deepCopy(columns),
filters: deepCopy(filters),
sorters: deepCopy(sorters),
pinning: deepCopy(pinning),
};

this.dropdownDeleteViewClass = 'dropdown-item';
Expand Down Expand Up @@ -671,7 +681,7 @@ export class Example11 {
return;
}
const currentGridState = this.sgb.gridStateService.getCurrentGridState();
const { columns, filters, sorters } = currentGridState;
const { columns, filters, sorters, pinning } = currentGridState;

if (this.currentSelectedViewPreset && filters) {
const filterName = await prompt(`Update View name or click on OK to continue.`, this.currentSelectedViewPreset.label);
Expand All @@ -680,6 +690,7 @@ export class Example11 {
this.currentSelectedViewPreset.columns = columns || [];
this.currentSelectedViewPreset.filters = filters || [];
this.currentSelectedViewPreset.sorters = sorters || [];
this.currentSelectedViewPreset.pinning = pinning || {};
this.recreatePredefinedViews();
localStorage.setItem('gridViewPreset', JSON.stringify(this.predefinedViews));
}
Expand All @@ -696,10 +707,13 @@ export class Example11 {
const columns = selectedView?.columns ?? [];
const filters = selectedView?.filters ?? [];
const sorters = selectedView?.sorters ?? [];
const pinning = selectedView?.pinning ?? { frozenBottom: false, frozenColumn: -1, frozenRow: -1 };
this.sgb.filterService.updateFilters(filters as CurrentFilter[]);
this.sgb.sortService.updateSorting(sorters as CurrentSorter[]);
this.sgb.gridService.setPinning(pinning);
this.sgb.gridStateService.changeColumnsArrangement(columns);
} else {
this.sgb.gridService.clearPinning();
this.sgb.filterService.clearFilters();
this.sgb.sortService.clearSorting();
this.sgb.gridStateService.changeColumnsArrangement([...this.columnDefinitions].map(col => ({ columnId: `${col.id}` })));
Expand Down
3 changes: 3 additions & 0 deletions examples/webpack-demo-vanilla-bundle/src/examples/icons.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,16 +68,19 @@ export class Icons {
'.mdi.mdi-check-all',
'.mdi.mdi-check-bold',
'.mdi.mdi-checkbox-blank-outline',
'.mdi.mdi-checkbox-marked-circle-outline',
'.mdi.mdi-check-box-outline',
'.mdi.mdi-checkbox-marked',
'.mdi.mdi-check-circle',
'.mdi.mdi-check-circle-outline',
'.mdi.mdi-check-outline',
'.mdi.mdi-check-underline',
'.mdi.mdi-chevron-down',
'.mdi.mdi-chevron-down-box',
'.mdi.mdi-chevron-down-box-outline',
'.mdi.mdi-chevron-down-circle',
'.mdi.mdi-chevron-down-circle-outline',
'.mdi.mdi-clipboard-check',
'.mdi.mdi-clipboard-check-outline',
'.mdi.mdi-clipboard-edit',
'.mdi.mdi-clipboard-edit-outline',
Expand Down
2 changes: 1 addition & 1 deletion packages/common/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export class Constants {
TEXT_CLEAR_ALL_FILTERS: 'Clear all Filters',
TEXT_CLEAR_ALL_GROUPING: 'Clear all Grouping',
TEXT_CLEAR_ALL_SORTING: 'Clear all Sorting',
TEXT_CLEAR_FROZEN_COLUMNS: 'Clear Frozen Columns',
TEXT_CLEAR_PINNING: 'Unfreeze Columns/Rows',
TEXT_CLONE: 'Clone',
TEXT_COLLAPSE_ALL_GROUPS: 'Collapse all Groups',
TEXT_CONTAINS: 'Contains',
Expand Down
1 change: 1 addition & 0 deletions packages/common/src/enums/gridStateType.enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export enum GridStateType {
columns = 'columns',
filter = 'filter',
pagination = 'pagination',
pinning = 'pinning',
rowSelection = 'rowSelection',
sorter = 'sorter',
}
34 changes: 17 additions & 17 deletions packages/common/src/extensions/__tests__/gridMenuExtension.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -356,13 +356,13 @@ describe('gridMenuExtension', () => {
expect(SharedService.prototype.gridOptions.gridMenu!.customItems).toEqual([]);
});

it('should expect menu related to "Clear Frozen Columns"', () => {
it('should expect menu related to "Unfreeze Columns/Rows"', () => {
const copyGridOptionsMock = { ...gridOptionsMock, gridMenu: { hideClearFrozenColumnsCommand: false, } } as unknown as GridOption;
jest.spyOn(SharedService.prototype, 'gridOptions', 'get').mockReturnValue(copyGridOptionsMock);
extension.register();
extension.register(); // calling 2x register to make sure it doesn't duplicate commands
expect(SharedService.prototype.gridOptions.gridMenu!.customItems).toEqual([
{ iconCssClass: 'fa fa-times', title: 'Libérer les colonnes gelées', disabled: false, command: 'clear-frozen-columns', positionOrder: 49 },
{ iconCssClass: 'fa fa-times', title: 'Dégeler les colonnes/rangées', disabled: false, command: 'clear-pinning', positionOrder: 52 },
]);
});

Expand All @@ -373,8 +373,8 @@ describe('gridMenuExtension', () => {
extension.register(); // calling 2x register to make sure it doesn't duplicate commands
expect(SharedService.prototype.gridOptions.gridMenu!.customItems).toEqual([
{ iconCssClass: 'fa fa-filter text-danger', title: 'Supprimer tous les filtres', disabled: false, command: 'clear-filter', positionOrder: 50 },
{ iconCssClass: 'fa fa-random', title: 'Basculer la ligne des filtres', disabled: false, command: 'toggle-filter', positionOrder: 52 },
{ iconCssClass: 'fa fa-refresh', title: 'Rafraîchir les données', disabled: false, command: 'refresh-dataset', positionOrder: 56 }
{ iconCssClass: 'fa fa-random', title: 'Basculer la ligne des filtres', disabled: false, command: 'toggle-filter', positionOrder: 53 },
{ iconCssClass: 'fa fa-refresh', title: 'Rafraîchir les données', disabled: false, command: 'refresh-dataset', positionOrder: 57 }
]);
});

Expand All @@ -394,7 +394,7 @@ describe('gridMenuExtension', () => {
extension.register();
extension.register(); // calling 2x register to make sure it doesn't duplicate commands
expect(SharedService.prototype.gridOptions.gridMenu!.customItems).toEqual([
{ iconCssClass: 'fa fa-random', title: 'Basculer la ligne des filtres', disabled: false, command: 'toggle-filter', positionOrder: 52 },
{ iconCssClass: 'fa fa-random', title: 'Basculer la ligne des filtres', disabled: false, command: 'toggle-filter', positionOrder: 53 },
]);
});

Expand All @@ -404,7 +404,7 @@ describe('gridMenuExtension', () => {
extension.register();
extension.register(); // calling 2x register to make sure it doesn't duplicate commands
expect(SharedService.prototype.gridOptions.gridMenu!.customItems).toEqual([
{ iconCssClass: 'fa fa-refresh', title: 'Rafraîchir les données', disabled: false, command: 'refresh-dataset', positionOrder: 56 }
{ iconCssClass: 'fa fa-refresh', title: 'Rafraîchir les données', disabled: false, command: 'refresh-dataset', positionOrder: 57 }
]);
});

Expand All @@ -414,7 +414,7 @@ describe('gridMenuExtension', () => {
extension.register();
extension.register(); // calling 2x register to make sure it doesn't duplicate commands
expect(SharedService.prototype.gridOptions.gridMenu!.customItems).toEqual([
{ iconCssClass: 'fa fa-random', title: 'Basculer la ligne de pré-en-tête', disabled: false, command: 'toggle-preheader', positionOrder: 52 }
{ iconCssClass: 'fa fa-random', title: 'Basculer la ligne de pré-en-tête', disabled: false, command: 'toggle-preheader', positionOrder: 53 }
]);
});

Expand Down Expand Up @@ -448,7 +448,7 @@ describe('gridMenuExtension', () => {
extension.register();
extension.register(); // calling 2x register to make sure it doesn't duplicate commands
expect(SharedService.prototype.gridOptions.gridMenu!.customItems).toEqual([
{ iconCssClass: 'fa fa-download', title: 'Exporter en format CSV', disabled: false, command: 'export-csv', positionOrder: 53 }
{ iconCssClass: 'fa fa-download', title: 'Exporter en format CSV', disabled: false, command: 'export-csv', positionOrder: 54 }
]);
});

Expand All @@ -465,7 +465,7 @@ describe('gridMenuExtension', () => {
extension.register();
extension.register(); // calling 2x register to make sure it doesn't duplicate commands
expect(SharedService.prototype.gridOptions.gridMenu!.customItems).toEqual([
{ iconCssClass: 'fa fa-file-excel-o text-success', title: 'Exporter vers Excel', disabled: false, command: 'export-excel', positionOrder: 54 }
{ iconCssClass: 'fa fa-file-excel-o text-success', title: 'Exporter vers Excel', disabled: false, command: 'export-excel', positionOrder: 55 }
]);
});

Expand All @@ -475,7 +475,7 @@ describe('gridMenuExtension', () => {
extension.register();
extension.register(); // calling 2x register to make sure it doesn't duplicate commands
expect(SharedService.prototype.gridOptions.gridMenu!.customItems).toEqual([
{ iconCssClass: 'fa fa-download', title: 'Exporter en format texte (délimité par tabulation)', disabled: false, command: 'export-text-delimited', positionOrder: 55 }
{ iconCssClass: 'fa fa-download', title: 'Exporter en format texte (délimité par tabulation)', disabled: false, command: 'export-text-delimited', positionOrder: 56 }
]);
});

Expand Down Expand Up @@ -529,8 +529,8 @@ describe('gridMenuExtension', () => {
it('should have user grid menu custom items', () => {
extension.register();
expect(SharedService.prototype.gridOptions.gridMenu!.customItems).toEqual([
{ command: 'export-csv', disabled: false, iconCssClass: 'fa fa-download', positionOrder: 53, title: 'Exporter en format CSV' },
// { command: 'export-excel', disabled: false, iconCssClass: 'fa fa-file-excel-o text-success', positionOrder: 53, title: 'Exporter vers Excel' },
{ command: 'export-csv', disabled: false, iconCssClass: 'fa fa-download', positionOrder: 54, title: 'Exporter en format CSV' },
// { command: 'export-excel', disabled: false, iconCssClass: 'fa fa-file-excel-o text-success', positionOrder: 54, title: 'Exporter vers Excel' },
{ command: 'help', disabled: false, iconCssClass: 'fa fa-question-circle', positionOrder: 99, title: 'Aide', titleKey: 'HELP' },
]);
});
Expand All @@ -539,8 +539,8 @@ describe('gridMenuExtension', () => {
extension.register();
extension.register();
expect(SharedService.prototype.gridOptions.gridMenu!.customItems).toEqual([
{ command: 'export-csv', disabled: false, iconCssClass: 'fa fa-download', positionOrder: 53, title: 'Exporter en format CSV' },
// { command: 'export-excel', disabled: false, iconCssClass: 'fa fa-file-excel-o text-success', positionOrder: 53, title: 'Exporter vers Excel' },
{ command: 'export-csv', disabled: false, iconCssClass: 'fa fa-download', positionOrder: 54, title: 'Exporter en format CSV' },
// { command: 'export-excel', disabled: false, iconCssClass: 'fa fa-file-excel-o text-success', positionOrder: 54, title: 'Exporter vers Excel' },
{ command: 'help', disabled: false, iconCssClass: 'fa fa-question-circle', positionOrder: 99, title: 'Aide', titleKey: 'HELP' },
]);
});
Expand Down Expand Up @@ -588,19 +588,19 @@ describe('gridMenuExtension', () => {
mockGridMenuAddon.onCommand = new Slick.Event();
});

it('should call "clearFrozenColumns" when the command triggered is "clear-frozen-columns"', () => {
it('should call "clearFrozenColumns" when the command triggered is "clear-pinning"', () => {
const setOptionsSpy = jest.spyOn(gridStub, 'setOptions');
const setColumnsSpy = jest.spyOn(gridStub, 'setColumns');
const onCommandSpy = jest.spyOn(SharedService.prototype.gridOptions.gridMenu as GridMenu, 'onCommand');
jest.spyOn(SharedService.prototype, 'allColumns', 'get').mockReturnValue(columnsMock);
jest.spyOn(SharedService.prototype, 'visibleColumns', 'get').mockReturnValue(columnsMock.slice(0, 1));

const instance = extension.register() as SlickGridMenu;
instance.onCommand!.notify({ item: { command: 'clear-frozen-columns' }, column: {} as Column, grid: gridStub, command: 'clear-frozen-columns' }, new Slick.EventData(), gridStub);
instance.onCommand!.notify({ item: { command: 'clear-pinning' }, column: {} as Column, grid: gridStub, command: 'clear-pinning' }, new Slick.EventData(), gridStub);

expect(onCommandSpy).toHaveBeenCalled();
expect(setColumnsSpy).toHaveBeenCalled();
expect(setOptionsSpy).toHaveBeenCalledWith({ frozenColumn: -1, enableMouseWheelScrollHandler: false });
expect(setOptionsSpy).toHaveBeenCalledWith({ frozenColumn: -1, frozenRow: -1, frozenBottom: false, enableMouseWheelScrollHandler: false });
});

it('should call "clearFilters" and dataview refresh when the command triggered is "clear-filter"', () => {
Expand Down
34 changes: 22 additions & 12 deletions packages/common/src/extensions/gridMenuExtension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,17 +225,17 @@ export class GridMenuExtension implements Extension {
const gridOptions = this.sharedService.gridOptions;
const translationPrefix = getTranslationPrefix(gridOptions);

// show grid menu: Clear Frozen Columns
// show grid menu: Unfreeze Columns/Rows
if (this.sharedService.gridOptions && this._gridMenuOptions && !this._gridMenuOptions.hideClearFrozenColumnsCommand) {
const commandName = 'clear-frozen-columns';
const commandName = 'clear-pinning';
if (!originalCustomItems.some(item => item !== 'divider' && item.hasOwnProperty('command') && item.command === commandName)) {
gridMenuCustomItems.push(
{
iconCssClass: this._gridMenuOptions.iconClearFrozenColumnsCommand || 'fa fa-times',
title: this.extensionUtility.translateWhenEnabledAndServiceExist(`${translationPrefix}CLEAR_FROZEN_COLUMNS`, 'TEXT_CLEAR_FROZEN_COLUMNS'),
title: this.extensionUtility.translateWhenEnabledAndServiceExist(`${translationPrefix}CLEAR_PINNING`, 'TEXT_CLEAR_PINNING'),
disabled: false,
command: commandName,
positionOrder: 49
positionOrder: 52
}
);
}
Expand Down Expand Up @@ -268,7 +268,7 @@ export class GridMenuExtension implements Extension {
title: this.extensionUtility.translateWhenEnabledAndServiceExist(`${translationPrefix}TOGGLE_FILTER_ROW`, 'TEXT_TOGGLE_FILTER_ROW'),
disabled: false,
command: commandName,
positionOrder: 52
positionOrder: 53
}
);
}
Expand All @@ -284,7 +284,7 @@ export class GridMenuExtension implements Extension {
title: this.extensionUtility.translateWhenEnabledAndServiceExist(`${translationPrefix}REFRESH_DATASET`, 'TEXT_REFRESH_DATASET'),
disabled: false,
command: commandName,
positionOrder: 56
positionOrder: 57
}
);
}
Expand All @@ -302,7 +302,7 @@ export class GridMenuExtension implements Extension {
title: this.extensionUtility.translateWhenEnabledAndServiceExist(`${translationPrefix}TOGGLE_PRE_HEADER_ROW`, 'TEXT_TOGGLE_PRE_HEADER_ROW'),
disabled: false,
command: commandName,
positionOrder: 52
positionOrder: 53
}
);
}
Expand Down Expand Up @@ -337,7 +337,7 @@ export class GridMenuExtension implements Extension {
title: this.extensionUtility.translateWhenEnabledAndServiceExist(`${translationPrefix}EXPORT_TO_CSV`, 'TEXT_EXPORT_TO_CSV'),
disabled: false,
command: commandName,
positionOrder: 53
positionOrder: 54
}
);
}
Expand All @@ -353,7 +353,7 @@ export class GridMenuExtension implements Extension {
title: this.extensionUtility.translateWhenEnabledAndServiceExist(`${translationPrefix}EXPORT_TO_EXCEL`, 'TEXT_EXPORT_TO_EXCEL'),
disabled: false,
command: commandName,
positionOrder: 54
positionOrder: 55
}
);
}
Expand All @@ -369,7 +369,7 @@ export class GridMenuExtension implements Extension {
title: this.extensionUtility.translateWhenEnabledAndServiceExist(`${translationPrefix}EXPORT_TO_TAB_DELIMITED`, 'TEXT_EXPORT_TO_TAB_DELIMITED'),
disabled: false,
command: commandName,
positionOrder: 55
positionOrder: 56
}
);
}
Expand All @@ -394,15 +394,25 @@ export class GridMenuExtension implements Extension {

if (args && args.command) {
switch (args.command) {
case 'clear-frozen-columns':
case 'clear-pinning':
const visibleColumns = [...this.sharedService.visibleColumns];
this.sharedService.slickGrid.setOptions({ frozenColumn: -1, enableMouseWheelScrollHandler: false });
const newGridOptions = { frozenColumn: -1, frozenRow: -1, frozenBottom: false, enableMouseWheelScrollHandler: false };
this.sharedService.slickGrid.setOptions(newGridOptions);
this.sharedService.gridOptions.frozenColumn = newGridOptions.frozenColumn;
this.sharedService.gridOptions.frozenRow = newGridOptions.frozenRow;
this.sharedService.gridOptions.frozenBottom = newGridOptions.frozenBottom;
this.sharedService.gridOptions.enableMouseWheelScrollHandler = newGridOptions.enableMouseWheelScrollHandler;

// SlickGrid seems to be somehow resetting the columns to their original positions,
// so let's re-fix them to the position we kept as reference
if (Array.isArray(visibleColumns)) {
this.sharedService.slickGrid.setColumns(visibleColumns);
}

// we also need to autosize columns if the option is enabled
if (this.sharedService.gridOptions.enableAutoSizeColumns) {
this.sharedService.slickGrid.autosizeColumns();
}
break;
case 'clear-filter':
this.filterService.clearFilters();
Expand Down
Loading

0 comments on commit ba703d8

Please sign in to comment.