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(presets): add missing row selections preset option #11

Merged
merged 3 commits into from
Jul 13, 2020
Merged
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
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