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

feat(state): add Pinning (frozen) to Grid State & Presets #292

Merged
merged 7 commits into from
Mar 24, 2021
Merged
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