Skip to content

Commit

Permalink
feat(presets): add missing row selections preset option (#11)
Browse files Browse the repository at this point in the history
* feat(presets): add missing row selections preset option

* feat(formatters): add new percentCompleteBarWithText Formatter
same as percentCompleteBarFormatter but makes the progress bar thicker and also adds the % text inside the progress bar

* fix(filter): Grid Preset Filters should work with Tree Data View
- the Tree Data must execute pre-filtering with Tree Data when having Grid Preset Filters
  • Loading branch information
ghiscoding authored Jul 13, 2020
1 parent 41a36cc commit e0a729c
Show file tree
Hide file tree
Showing 17 changed files with 242 additions and 64 deletions.
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -119,9 +119,9 @@ npm run test:watch
- [x] Backend Services + Pagination
- [x] Local Pagination
- [x] Grid Presets
- [ ] Preset Row Selections
- [ ] Doesn't work in SF because of cacheable queries
- [ ] Preset Filters not working with Tree Data View
- [x] Preset Row Selections
- [x] Should work even after initializing the dataset later (SF)
- [x] Preset Filters not working with Tree Data View
- [ ] Dynamically Add Columns
- [ ] Translations Support
- [ ] Tree Data
Expand All @@ -146,7 +146,7 @@ npm run test:watch
- [x] Bundle Creation (vanilla bundle)
- [ ] Eventually add Unit Tests as a Pre-Bundle task
- [x] Remove any Deprecated code
- [ ] Create a [Migration Guide](https://github.com/ghiscoding/slickgrid-universal/wiki/Migration-for-Angular-Aurelia-Slickgrid) for Angular/Aurelia
- [ ] Create and Update the [Migration Guide](https://github.com/ghiscoding/slickgrid-universal/wiki/Migration-for-Angular-Aurelia-Slickgrid) for Angular/Aurelia
- [x] Add simple input bindings in the demo (e.g. pinned rows input)
- [x] Add possibility to use SVG instead of Font Family
- [x] Add Typings (interfaces) for Slick Grid & DataView objects
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,14 @@ describe('the Percent Complete Formatter', () => {
const input = 0;
const color = 'red';
const output = percentCompleteBarFormatter(1, 1, input, {} as Column, {});
expect(output).toBe(`<span class="percent-complete-bar" style="background:${color}; width:${input}%"></span>`);
expect(output).toBe(`<span class="percent-complete-bar" title="${input}%" style="background:${color}; width:${input}%"></span>`);
});

it('should display a red color bar when value is a negative number', () => {
const input = -15;
const color = 'red';
const output = percentCompleteBarFormatter(1, 1, input, {} as Column, {});
expect(output).toBe(`<span class="percent-complete-bar" style="background:${color}; width:${input}%"></span>`);
expect(output).toBe(`<span class="percent-complete-bar" title="${input}%" style="background:${color}; width:${input}%"></span>`);
});

it('should display a silver color bar when value is between 30 and 69', () => {
Expand All @@ -32,21 +32,21 @@ describe('the Percent Complete Formatter', () => {
const color = 'silver';
const output1 = percentCompleteBarFormatter(1, 1, input1, {} as Column, {});
const output2 = percentCompleteBarFormatter(1, 1, input2, {} as Column, {});
expect(output1).toBe(`<span class="percent-complete-bar" style="background:${color}; width:${input1}%"></span>`);
expect(output2).toBe(`<span class="percent-complete-bar" style="background:${color}; width:${input2}%"></span>`);
expect(output1).toBe(`<span class="percent-complete-bar" title="${input1}%" style="background:${color}; width:${input1}%"></span>`);
expect(output2).toBe(`<span class="percent-complete-bar" title="${input2}%" style="background:${color}; width:${input2}%"></span>`);
});

it('should display a green color bar when value greater or equal to 70 and is a type string', () => {
const input = '70';
const color = 'green';
const output = percentCompleteBarFormatter(1, 1, input, {} as Column, {});
expect(output).toBe(`<span class="percent-complete-bar" style="background:${color}; width:${input}%"></span>`);
expect(output).toBe(`<span class="percent-complete-bar" title="${input}%" style="background:${color}; width:${input}%"></span>`);
});

it('should display a green color bar with percentage of 100% when number is greater than 100 is provided', () => {
const input = 125;
const color = 'green';
const output = percentCompleteBarFormatter(1, 1, input, {} as Column, {});
expect(output).toBe(`<span class="percent-complete-bar" style="background:${color}; width:100%"></span>`);
expect(output).toBe(`<span class="percent-complete-bar" title="100%" style="background:${color}; width:100%"></span>`);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { Column } from '../../interfaces/index';
import { percentCompleteBarWithTextFormatter } from '../percentCompleteBarWithTextFormatter';

describe('the Percent Complete with Text Formatter', () => {
it('should return an empty string when no value is provided', () => {
const output = percentCompleteBarWithTextFormatter(1, 1, '', {} as Column, {});
expect(output).toBe('');
});

it('should return empty string when non-numeric value is provided', () => {
const output = percentCompleteBarWithTextFormatter(1, 1, 'hello', {} as Column, {});
expect(output).toBe('');
});

it('should display a red color bar formatter when number 0 is provided', () => {
const input = 0;
const color = 'red';
const output = percentCompleteBarWithTextFormatter(1, 1, input, {} as Column, {});
expect(output).toBe(`<div class="percent-complete-bar-with-text" title="${input}%" style="background:${color}; width:${input}%">${input}%</div>`);
});

it('should display a red color bar when value is a negative number', () => {
const input = -15;
const color = 'red';
const output = percentCompleteBarWithTextFormatter(1, 1, input, {} as Column, {});
expect(output).toBe(`<div class="percent-complete-bar-with-text" title="${input}%" style="background:${color}; width:${input}%">${input}%</div>`);
});

it('should display a silver color bar when value is between 30 and 69', () => {
const input1 = 30;
const input2 = 69;
const color = 'silver';
const output1 = percentCompleteBarWithTextFormatter(1, 1, input1, {} as Column, {});
const output2 = percentCompleteBarWithTextFormatter(1, 1, input2, {} as Column, {});
expect(output1).toBe(`<div class="percent-complete-bar-with-text" title="${input1}%" style="background:${color}; width:${input1}%">${input1}%</div>`);
expect(output2).toBe(`<div class="percent-complete-bar-with-text" title="${input2}%" style="background:${color}; width:${input2}%">${input2}%</div>`);
});

it('should display a green color bar when value greater or equal to 70 and is a type string', () => {
const input = '70';
const color = 'green';
const output = percentCompleteBarWithTextFormatter(1, 1, input, {} as Column, {});
expect(output).toBe(`<div class="percent-complete-bar-with-text" title="${input}%" style="background:${color}; width:${input}%">${input}%</div>`);
});

it('should display a green color bar with percentage of 100% when number is greater than 100 is provided', () => {
const input = 125;
const color = 'green';
const output = percentCompleteBarWithTextFormatter(1, 1, input, {} as Column, {});
expect(output).toBe(`<div class="percent-complete-bar-with-text" title="100%" style="background:${color}; width:100%">100%</div>`);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -19,56 +19,56 @@ describe('the Percent Complete Formatter', () => {
it('should display a red color percentage when number 0 is provided', () => {
const input = 0;
const output = percentCompleteFormatter(1, 1, input, {} as Column, {});
expect(output).toBe(`<span style='color:red'>0%</span>`);
expect(output).toBe(`<span style="color:red">0%</span>`);
});

it('should display a red color percentage when a negative number is provided', () => {
const input = -15;
const output = percentCompleteFormatter(1, 1, input, {} as Column, {});
expect(output).toBe(`<span style='color:red'>-15%</span>`);
expect(output).toBe(`<span style="color:red">-15%</span>`);
});

it('should display a green color percentage when a positive number greater or equal to 50 is provided', () => {
const input = 50;
const output = percentCompleteFormatter(1, 1, input, {} as Column, {});
expect(output).toBe(`<span style='color:green'>50%</span>`);
expect(output).toBe(`<span style="color:green">50%</span>`);
});

it('should display a green color percentage when a positive number greater than 50 and is a type string is provided', () => {
const input = '99';
const output = percentCompleteFormatter(1, 1, input, {} as Column, {});
expect(output).toBe(`<span style='color:green'>99%</span>`);
expect(output).toBe(`<span style="color:green">99%</span>`);
});

it('should display a green color percentage of 100% when number is greater than 100 is provided', () => {
const input = 125;
const output = percentCompleteFormatter(1, 1, input, {} as Column, {});
expect(output).toBe(`<span style='color:green'>100%</span>`);
expect(output).toBe(`<span style="color:green">100%</span>`);
});

it('should display a negative percentage with parentheses when "displayNegativeNumberWithParentheses" is enabled in the "params"', () => {
const input = -2.4;
const output = percentCompleteFormatter(1, 1, input, { params: { displayNegativeNumberWithParentheses: true } } as Column, {});
expect(output).toBe(`<span style='color:red'>(2.4%)</span>`);
expect(output).toBe(`<span style="color:red">(2.4%)</span>`);
});

it('should display a negative number with thousand separator and parentheses when "displayNegativeNumberWithParentheses" is enabled in the "params"', () => {
const input = -345678.024;
const output = percentCompleteFormatter(1, 1, input, { params: { displayNegativeNumberWithParentheses: true, thousandSeparator: ',' } } as Column, {});
expect(output).toBe(`<span style='color:red'>(345,678.024%)</span>`);
expect(output).toBe(`<span style="color:red">(345,678.024%)</span>`);
});

it('should display a negative percentage with parentheses when input is negative and "displayNegativeNumberWithParentheses" is enabled in the Formatter Options', () => {
gridStub.getOptions = () => ({ formatterOptions: { displayNegativeNumberWithParentheses: true, minDecimal: 2 } } as GridOption);
const input = -2.4;
const output = percentCompleteFormatter(1, 1, input, {} as Column, {}, gridStub);
expect(output).toBe(`<span style='color:red'>(2.40%)</span>`);
expect(output).toBe(`<span style="color:red">(2.40%)</span>`);
});

it('should display a negative average with thousand separator and parentheses when input is negative and "displayNegativeNumberWithParentheses" is enabled in the Formatter Options', () => {
gridStub.getOptions = () => ({ formatterOptions: { displayNegativeNumberWithParentheses: true, minDecimal: 2, decimalSeparator: ',', thousandSeparator: '_' } } as GridOption);
const input = -345678.024;
const output = percentCompleteFormatter(1, 1, input, {} as Column, {}, gridStub);
expect(output).toBe(`<span style='color:red'>(345_678,02%)</span>`);
expect(output).toBe(`<span style="color:red">(345_678,02%)</span>`);
});
});
6 changes: 5 additions & 1 deletion packages/common/src/formatters/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { maskFormatter } from './maskFormatter';
import { multipleFormatter } from './multipleFormatter';
import { percentFormatter } from './percentFormatter';
import { percentCompleteBarFormatter } from './percentCompleteBarFormatter';
import { percentCompleteBarWithTextFormatter } from './percentCompleteBarWithTextFormatter';
import { percentCompleteFormatter } from './percentCompleteFormatter';
import { percentSymbolFormatter } from './percentSymbolFormatter';
import { progressBarFormatter } from './progressBarFormatter';
Expand Down Expand Up @@ -198,9 +199,12 @@ export const Formatters = {
/** Takes a cell value number (between 0.0-100) and displays a red (<50) or green (>=50) bar */
percentComplete: percentCompleteFormatter,

/** Takes a cell value number (between 0-100) and displays Bootstrap "percent-complete-bar" a red (<30), silver (>30 & <70) or green (>=70) bar */
/** Takes a cell value number (between 0-100) and displays a SlickGrid custom "percent-complete-bar" a red (<30), silver (>30 & <70) or green (>=70) bar */
percentCompleteBar: percentCompleteBarFormatter,

/** Takes a cell value number (between 0-100) and displays SlickGrid custom "percent-complete-bar" with Text a red (<30), silver (>30 & <70) or green (>=70) bar */
percentCompleteBarWithText: percentCompleteBarWithTextFormatter,

/** Takes a cell value number (between 0-100) and add the "%" after the number */
percentSymbol: percentSymbolFormatter,

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,5 +20,5 @@ export const percentCompleteBarFormatter: Formatter = (row: number, cell: number
color = 'green';
}

return `<span class="percent-complete-bar" style="background:${color}; width:${inputNumber}%"></span>`;
return `<span class="percent-complete-bar" title="${inputNumber}%" style="background:${color}; width:${inputNumber}%"></span>`;
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { Column, Formatter } from './../interfaces/index';

export const percentCompleteBarWithTextFormatter: Formatter = (row: number, cell: number, value: any, columnDef: Column, dataContext: any): string => {
const isNumber = (value === null || value === undefined || value === '') ? false : !isNaN(+value);
if (!isNumber) {
return '';
}

let color = '';
let inputNumber = parseFloat(value);
if (inputNumber > 100) {
inputNumber = 100;
}

if (inputNumber < 30) {
color = 'red';
} else if (inputNumber < 70) {
color = 'silver';
} else {
color = 'green';
}

return `<div class="percent-complete-bar-with-text" title="${inputNumber}%" style="background:${color}; width:${inputNumber}%">${inputNumber}%</div>`;
};
2 changes: 1 addition & 1 deletion packages/common/src/formatters/percentCompleteFormatter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export const percentCompleteFormatter: Formatter = (row: number, cell: number, v
const colorStyle = (value < 50) ? 'red' : 'green';
const formattedNumber = formatNumber(value, minDecimal, maxDecimal, displayNegativeNumberWithParentheses, '', '%', decimalSeparator, thousandSeparator);
const outputFormattedValue = value > 100 ? '100%' : formattedNumber;
return `<span style='color:${colorStyle}'>${outputFormattedValue}</span>`;
return `<span style="color:${colorStyle}">${outputFormattedValue}</span>`;
}
return value;
};
27 changes: 27 additions & 0 deletions packages/common/src/services/__tests__/filter.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -940,6 +940,32 @@ describe('FilterService', () => {
{ id: 'gender', field: 'gender', filter: { operator: '', searchTerms: ['male'] } },
]);
});

it('should pre-filter the tree dataset when the grid is a Tree Data View', () => {
const spyRefresh = jest.spyOn(dataViewStub, 'refresh');
const spyPreFilter = jest.spyOn(service, 'preFilterTreeData');
const spyGetCols = jest.spyOn(gridStub, 'getColumns').mockReturnValue([
{ id: 'name', field: 'name', filter: { model: Filters.input, operator: 'EQ' } },
{ id: 'gender', field: 'gender' },
{ id: 'size', field: 'size', filter: { model: Filters.input, operator: '>=' } }
]);
gridOptionMock.enableTreeData = true;
gridOptionMock.treeDataOptions = { columnId: 'file', childrenPropName: 'files' };
gridOptionMock.presets = {
filters: [{ columnId: 'size', searchTerms: [20], operator: '>=' }]
};
service.init(gridStub);
const output = service.populateColumnFilterSearchTermPresets(gridOptionMock.presets.filters);

expect(spyGetCols).toHaveBeenCalled();
expect(spyRefresh).toHaveBeenCalled();
expect(spyPreFilter).toHaveBeenCalled();
expect(output).toEqual([
{ id: 'name', field: 'name', filter: { model: Filters.input, operator: 'EQ' } },
{ id: 'gender', field: 'gender', },
{ id: 'size', field: 'size', filter: { model: Filters.input, operator: '>=', searchTerms: [20] } },
]);
});
});

describe('updateFilters method', () => {
Expand Down Expand Up @@ -1084,6 +1110,7 @@ describe('FilterService', () => {
beforeEach(() => {
gridOptionMock.enableTreeData = true;
gridOptionMock.treeDataOptions = { columnId: 'file', childrenPropName: 'files' };
jest.clearAllMocks();
});

it('should expect "setSortColumns" to have been called after init', () => {
Expand Down
28 changes: 21 additions & 7 deletions packages/common/src/services/filter.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,6 @@ export class FilterService {
private _firstColumnIdRendered: string | number = '';
private _filtersMetadata: any[] = [];
private _columnFilters: ColumnFilters = {};
private _dataView: SlickDataView;
private _grid: SlickGrid;
private _onSearchChange: SlickEvent<OnSearchChangeEvent>;
private _tmpPreFilteredData: number[];
Expand Down Expand Up @@ -93,6 +92,11 @@ export class FilterService {
return (this._grid && this._grid.getColumns) ? this._grid.getColumns() : [];
}

/** Getter of SlickGrid DataView object */
private get _dataView(): SlickDataView {
return (this._grid?.getData && this._grid.getData()) as SlickDataView;
}

/**
* Initialize the Service
* @param grid
Expand Down Expand Up @@ -149,7 +153,6 @@ export class FilterService {
* @param grid SlickGrid Grid object
*/
bindBackendOnFilter(grid: SlickGrid) {
this._dataView = grid?.getData && grid.getData() as SlickDataView;
this._filtersMetadata = [];

// subscribe to SlickGrid onHeaderRowCellRendered event to create filter template
Expand Down Expand Up @@ -179,8 +182,6 @@ export class FilterService {
*/
bindLocalOnFilter(grid: SlickGrid) {
this._filtersMetadata = [];
this._dataView = grid?.getData && grid.getData() as SlickDataView;

this._dataView.setFilterArgs({ columnFilters: this._columnFilters, grid: this._grid, dataView: this._dataView });
this._dataView.setFilter(this.customLocalFilter.bind(this));

Expand Down Expand Up @@ -608,19 +609,32 @@ export class FilterService {
}

// from each presets, we will find the associated columnDef and apply the preset searchTerms & operator if there is
const columnPreset = filters.find((presetFilter: CurrentFilter) => {
return presetFilter.columnId === columnDef.id;
});
const columnPreset = filters.find((presetFilter: CurrentFilter) => presetFilter.columnId === columnDef.id);
if (columnPreset && columnPreset.searchTerms && Array.isArray(columnPreset.searchTerms)) {
columnDef.filter = columnDef.filter || {};
columnDef.filter.operator = columnPreset.operator || columnDef.filter.operator || '';
columnDef.filter.searchTerms = columnPreset.searchTerms;
}
});

// when we have a Filter Presets on a Tree Data View grid, we need to call the pre-filtering of tree data
this.refreshTreeDataFilters();
}
return this._columnDefinitions;
}

/**
* when we have a Filter Presets on a Tree Data View grid, we need to call the pre-filtering of tree data
* we need to do this because Tree Data is the only type of grid that requires a pre-filter (preFilterTreeData) to be executed before the final filtering
* @param filters
*/
refreshTreeDataFilters() {
if (this._dataView && this._gridOptions?.enableTreeData) {
this._tmpPreFilteredData = this.preFilterTreeData(this._dataView.getItems(), this._columnFilters);
this._dataView.refresh(); // and finally this refresh() is what triggers a DataView filtering check
}
}

/**
* Set the sort icons in the UI (ONLY the icons, it does not do any sorting)
* The column sort icons are not necessarily inter-connected to the sorting functionality itself,
Expand Down
14 changes: 14 additions & 0 deletions packages/common/src/styles/slickgrid-examples.scss
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,20 @@
background-color: transparent;
}

.percent-complete-bar-with-text {
display: inline-block;
height: 20px;
-moz-border-radius: 3px;
-webkit-border-radius: 3px;
border-radius: 3px;
background-color: transparent;
line-height: 20px;
min-width: 25px;
text-align: center;
top: 2px;
color: #ffffff;
}

/* Slick.Editors.Text, Slick.Editors.Date */
.ui-datepicker-trigger {
margin-top: 2px;
Expand Down
Binary file not shown.
Loading

0 comments on commit e0a729c

Please sign in to comment.