diff options
author | Wouter Admiraal <wouter.admiraal@sonarsource.com> | 2019-08-09 08:36:54 +0200 |
---|---|---|
committer | SonarTech <sonartech@sonarsource.com> | 2019-08-27 20:21:04 +0200 |
commit | 87714eac31a67db8d55af07b7e6411eb64bce2a8 (patch) | |
tree | a1ba2de9e90462981bae1ed5947f499195238a14 | |
parent | 6e6c533c1299ec31a1c0923e259e135912220c17 (diff) | |
download | sonarqube-87714eac31a67db8d55af07b7e6411eb64bce2a8.tar.gz sonarqube-87714eac31a67db8d55af07b7e6411eb64bce2a8.zip |
SONAR-12392 Fix Issue filtering using Directory facet
4 files changed, 149 insertions, 18 deletions
diff --git a/server/sonar-web/src/main/js/api/components.ts b/server/sonar-web/src/main/js/api/components.ts index ea2f2381150..8b26dacc1bb 100644 --- a/server/sonar-web/src/main/js/api/components.ts +++ b/server/sonar-web/src/main/js/api/components.ts @@ -160,6 +160,10 @@ export function getFiles(data: GetTreeParams) { return getTree<TreeComponentWithPath>({ ...data, qualifiers: 'FIL' }); } +export function getDirectories(data: GetTreeParams) { + return getTree<TreeComponentWithPath>({ ...data, qualifiers: 'DIR' }); +} + export function getComponentData(data: { component: string } & T.BranchParameters): Promise<any> { return getJSON('/api/components/show', data); } diff --git a/server/sonar-web/src/main/js/apps/issues/sidebar/DirectoryFacet.tsx b/server/sonar-web/src/main/js/apps/issues/sidebar/DirectoryFacet.tsx index 3eb7246ae1f..bc092c083ad 100644 --- a/server/sonar-web/src/main/js/apps/issues/sidebar/DirectoryFacet.tsx +++ b/server/sonar-web/src/main/js/apps/issues/sidebar/DirectoryFacet.tsx @@ -23,48 +23,50 @@ import QualifierIcon from 'sonar-ui-common/components/icons/QualifierIcon'; import { translate } from 'sonar-ui-common/helpers/l10n'; import { collapsePath } from 'sonar-ui-common/helpers/path'; import { highlightTerm } from 'sonar-ui-common/helpers/search'; -import { getTree, TreeComponent } from '../../../api/components'; +import { getDirectories, TreeComponentWithPath } from '../../../api/components'; import ListStyleFacet from '../../../components/facet/ListStyleFacet'; import { Facet, Query } from '../utils'; interface Props { componentKey: string; - fetching: boolean; directories: string[]; + fetching: boolean; loadSearchResultCount: (property: string, changes: Partial<Query>) => Promise<Facet>; onChange: (changes: Partial<Query>) => void; onToggle: (property: string) => void; open: boolean; query: Query; - stats: T.Dict<number> | undefined; + stats: Facet | undefined; } export default class DirectoryFacet extends React.PureComponent<Props> { - getFacetItemText = (directory: string) => { - return collapsePath(directory, 15); + getFacetItemText = (path: string) => { + return collapsePath(path, 15); }; - getSearchResultKey = (directory: TreeComponent) => { - return directory.name; + getSearchResultKey = (directory: TreeComponentWithPath) => { + return directory.path; }; - getSearchResultText = (directory: TreeComponent) => { + getSearchResultText = (directory: TreeComponentWithPath) => { return directory.name; }; handleSearch = (query: string, page: number) => { - return getTree({ + return getDirectories({ component: this.props.componentKey, q: query, - qualifiers: 'DIR', p: page, ps: 30 - }).then(({ components, paging }) => ({ paging, results: components })); + }).then(({ components, paging }) => ({ + paging, + results: components.filter(dir => dir.path !== undefined) + })); }; - loadSearchResultCount = (directories: TreeComponent[]) => { + loadSearchResultCount = (directories: TreeComponentWithPath[]) => { return this.props.loadSearchResultCount('directories', { - directories: directories.map(directory => directory.name) + directories: directories.map(directory => directory.path) }); }; @@ -75,17 +77,17 @@ export default class DirectoryFacet extends React.PureComponent<Props> { </> ); - renderFacetItem = (directory: string) => { - return this.renderDirectory(collapsePath(directory, 15)); + renderFacetItem = (path: string) => { + return this.renderDirectory(collapsePath(path, 15)); }; - renderSearchResult = (directory: TreeComponent, term: string) => { - return this.renderDirectory(highlightTerm(collapsePath(directory.name), term)); + renderSearchResult = (directory: TreeComponentWithPath, term: string) => { + return this.renderDirectory(highlightTerm(collapsePath(directory.path, 15), term)); }; render() { return ( - <ListStyleFacet<TreeComponent> + <ListStyleFacet<TreeComponentWithPath> facetHeader={translate('issues.facet.directories')} fetching={this.props.fetching} getFacetItemText={this.getFacetItemText} diff --git a/server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/DirectoryFacet-test.tsx b/server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/DirectoryFacet-test.tsx new file mode 100644 index 00000000000..0b9f9ba777f --- /dev/null +++ b/server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/DirectoryFacet-test.tsx @@ -0,0 +1,70 @@ +/* + * SonarQube + * Copyright (C) 2009-2019 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import { shallow } from 'enzyme'; +import * as React from 'react'; +import { TreeComponentWithPath } from '../../../../api/components'; +import { Query } from '../../utils'; +import DirectoryFacet from '../DirectoryFacet'; + +it('should render correctly', () => { + const wrapper = shallowRender(); + const instance = wrapper.instance(); + expect(wrapper).toMatchSnapshot(); + expect( + instance.renderSearchResult({ path: 'foo/bar' } as TreeComponentWithPath, 'foo') + ).toMatchSnapshot(); + expect(instance.renderFacetItem('foo/bar')).toMatchSnapshot(); +}); + +describe("ListStyleFacet's callback props", () => { + const wrapper = shallowRender(); + const instance = wrapper.instance(); + + test('#getSearchResultText()', () => { + expect(instance.getSearchResultText({ name: 'bar' } as TreeComponentWithPath)).toBe('bar'); + }); + + test('#getSearchResultKey()', () => { + expect(instance.getSearchResultKey({ path: 'foo/bar' } as TreeComponentWithPath)).toBe( + 'foo/bar' + ); + }); + + test('#getFacetItemText()', () => { + expect(instance.getFacetItemText('foo/bar')).toBe('foo/bar'); + }); +}); + +function shallowRender(props: Partial<DirectoryFacet['props']> = {}) { + return shallow<DirectoryFacet>( + <DirectoryFacet + componentKey="foo" + directories={['foo/', 'bar/baz/']} + fetching={false} + loadSearchResultCount={jest.fn()} + onChange={jest.fn()} + onToggle={jest.fn()} + open={false} + query={{} as Query} + stats={undefined} + {...props} + /> + ); +} diff --git a/server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/__snapshots__/DirectoryFacet-test.tsx.snap b/server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/__snapshots__/DirectoryFacet-test.tsx.snap new file mode 100644 index 00000000000..ce08e6ffa03 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/__snapshots__/DirectoryFacet-test.tsx.snap @@ -0,0 +1,55 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should render correctly 1`] = ` +<ListStyleFacet + facetHeader="issues.facet.directories" + fetching={false} + getFacetItemText={[Function]} + getSearchResultKey={[Function]} + getSearchResultText={[Function]} + loadSearchResultCount={[Function]} + maxInitialItems={15} + maxItems={100} + minSearchLength={3} + onChange={[MockFunction]} + onSearch={[Function]} + onToggle={[MockFunction]} + open={false} + property="directories" + query={Object {}} + renderFacetItem={[Function]} + renderSearchResult={[Function]} + searchPlaceholder="search.search_for_directories" + values={ + Array [ + "foo/", + "bar/baz/", + ] + } +/> +`; + +exports[`should render correctly 2`] = ` +<React.Fragment> + <QualifierIcon + className="little-spacer-right" + qualifier="DIR" + /> + <React.Fragment> + <mark> + foo + </mark> + /bar + </React.Fragment> +</React.Fragment> +`; + +exports[`should render correctly 3`] = ` +<React.Fragment> + <QualifierIcon + className="little-spacer-right" + qualifier="DIR" + /> + foo/bar +</React.Fragment> +`; |