From: Stephan Müller Date: Fri, 16 Mar 2018 10:55:44 +0000 (+0100) Subject: mgr/dashboard: Search with spaces X-Git-Tag: v13.1.0~365^2 X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=ac88559c97eb9348a1a9eaed701d2d3cf895f307;p=ceph.git mgr/dashboard: Search with spaces Removed the usage of using comma to indicated a new search term and introduced the possibility to use quoted strings in order to search for spaces too. Also improved the column search handling in order to not get no search results found while typing a column name. Signed-off-by: Stephan Müller --- diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/table/table.component.spec.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/table/table.component.spec.ts index 8340dc6adf1f..92f6ec905c37 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/table/table.component.spec.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/table/table.component.spec.ts @@ -83,6 +83,23 @@ describe('TableComponent', () => { expect(component.rows[8].a).toBe(87); }); + it('should test search manipulation', () => { + let searchTerms = []; + spyOn(component, 'subSearch').and.callFake((d, search, c) => { + expect(search).toEqual(searchTerms); + }); + const searchTest = (s: string, st: string[]) => { + component.search = s; + searchTerms = st; + component.updateFilter(true); + }; + searchTest('a b c', [ 'a', 'b', 'c' ]); + searchTest('a+b c', [ 'a+b', 'c' ]); + searchTest('a,,,, b,,, c', [ 'a', 'b', 'c' ]); + searchTest('a,,,+++b,,, c', [ 'a+++b', 'c' ]); + searchTest('"a b c" "d e f", "g, h i"', [ 'a+b+c', 'd+e++f', 'g+h+i' ]); + }); + it('should search for multiple values', () => { doSearch('7 5 3', 5, {a: 57, b: 3249, c: [ -7, 'score15']}); }); @@ -96,6 +113,18 @@ describe('TableComponent', () => { doSearch('array:score21', 6, {a: 15, b: 225, c: [-5, 'score21']}); }); + it('should search with spaces', () => { + doSearch('\'poker array\':score21', 6, {a: 15, b: 225, c: [-5, 'score21']}); + doSearch('"poker array":score21', 6, {a: 15, b: 225, c: [-5, 'score21']}); + doSearch('poker+array:score21', 6, {a: 15, b: 225, c: [-5, 'score21']}); + }); + + it('should not search if column name is incomplete', () => { + doSearch('\'poker array\'', 100, {a: 0, b: 0, c: [-0, 'score6']}); + doSearch('pok', 100, {a: 0, b: 0, c: [-0, 'score6']}); + doSearch('pok:', 100, {a: 0, b: 0, c: [-0, 'score6']}); + }); + it('should restore full table after search', () => { expect(component.rows.length).toBe(100); component.search = '13'; diff --git a/src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/table/table.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/table/table.component.ts index efda07a91807..a528946737ab 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/table/table.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/shared/datatable/table/table.component.ts @@ -255,44 +255,61 @@ export class TableComponent implements AfterContentChecked, OnInit, OnChanges, O if (!event) { this.search = ''; } + let search = this.search.toLowerCase().replace(/,/g, ''); const columns = this.columns.filter(c => c.cellTransformation !== CellTemplate.sparkline); + if (search.match(/['"][^'"]+['"]/)) { + search = search.replace(/['"][^'"]+['"]/g, (match: string) => { + return match.replace(/(['"])([^'"]+)(['"])/g, '$2').replace(/ /g, '+'); + }); + } // update the rows - this.rows = this.subSearch(this.data, this.search.toLowerCase().split(/[, ]/), columns); + this.rows = this.subSearch(this.data, search.split(' ').filter(s => s.length > 0), columns); // Whenever the filter changes, always go back to the first page this.table.offset = 0; } subSearch (data: any[], currentSearch: string[], columns: CdTableColumn[]) { - let tempColumns: CdTableColumn[]; if (currentSearch.length === 0 || data.length === 0) { return data; } - const searchWords: string[] = currentSearch.pop().split(':'); - if (searchWords.length === 2) { - tempColumns = [...columns]; - columns = columns.filter((c) => c.name.toLowerCase().indexOf(searchWords[0]) !== -1); + const searchTerms: string[] = currentSearch.pop().replace('+', ' ').split(':'); + const columnsClone = [...columns]; + const dataClone = [...data]; + const filterColumns = (columnName: string) => + columnsClone.filter((c) => c.name.toLowerCase().indexOf(columnName) !== -1); + if (searchTerms.length === 2) { + columns = filterColumns(searchTerms[0]); } - const searchWord: string = _.last(searchWords); - if (searchWord.length > 0) { - data = data.filter(d => { - return columns.filter(c => { - let cellValue: any = _.get(d, c.prop); - if (_.isUndefined(cellValue)) { - return; - } - if (_.isArray(cellValue)) { - cellValue = cellValue.join(''); - } else if (_.isNumber(cellValue)) { - cellValue = cellValue.toString(); - } - return cellValue.toLowerCase().indexOf(searchWord) !== -1; - }).length > 0; - }); + const searchTerm: string = _.last(searchTerms); + data = this.basicDataSearch(searchTerm, data, columns); + // Checks if user searches for column but he is still typing + if (data.length === 0 && searchTerms.length === 1 && filterColumns(searchTerm).length > 0) { + data = dataClone; } - if (_.isArray(tempColumns)) { - columns = tempColumns; + return this.subSearch(data, currentSearch, columnsClone); + } + + basicDataSearch(searchTerm: string, data: any[], columns: CdTableColumn[]) { + if (searchTerm.length === 0) { + return data; } - return this.subSearch(data, currentSearch, columns); + return data.filter(d => { + return columns.filter(c => { + let cellValue: any = _.get(d, c.prop); + if (!_.isUndefined(c.pipe)) { + cellValue = c.pipe.transform(cellValue); + } + if (_.isUndefined(cellValue)) { + return; + } + if (_.isArray(cellValue)) { + cellValue = cellValue.join(' '); + } else if (_.isNumber(cellValue)) { + cellValue = cellValue.toString(); + } + return cellValue.toLowerCase().indexOf(searchTerm) !== -1; + }).length > 0; + }); } getRowClass() {