diff options
author | Stas Vilchik <stas.vilchik@sonarsource.com> | 2017-08-17 21:39:59 +0200 |
---|---|---|
committer | Janos Gyerik <janos.gyerik@sonarsource.com> | 2017-09-12 11:34:36 +0200 |
commit | cff416d7f9910c258bc8d7175c08afff96a9eb2a (patch) | |
tree | 78500908a2afde31b28ef938d4d61609d448f279 /server/sonar-web/src/main/js/apps/overview/meta | |
parent | 139467cf51932ba232190f363ad864e60eb3fd4d (diff) | |
download | sonarqube-cff416d7f9910c258bc8d7175c08afff96a9eb2a.tar.gz sonarqube-cff416d7f9910c258bc8d7175c08afff96a9eb2a.zip |
SONAR-9702 Build UI for short-lived branches (#2371)
Diffstat (limited to 'server/sonar-web/src/main/js/apps/overview/meta')
5 files changed, 174 insertions, 6 deletions
diff --git a/server/sonar-web/src/main/js/apps/overview/meta/Meta.js b/server/sonar-web/src/main/js/apps/overview/meta/Meta.js index fd849228480..a79b44dbd41 100644 --- a/server/sonar-web/src/main/js/apps/overview/meta/Meta.js +++ b/server/sonar-web/src/main/js/apps/overview/meta/Meta.js @@ -30,7 +30,14 @@ import MetaSize from './MetaSize'; import MetaTags from './MetaTags'; import { areThereCustomOrganizations } from '../../../store/rootReducer'; -const Meta = ({ component, history, measures, areThereCustomOrganizations, router }) => { +const Meta = ({ + component, + history, + measures, + areThereCustomOrganizations, + onComponentChange, + router +}) => { const { qualifier, description, qualityProfiles, qualityGate } = component; const isProject = qualifier === 'TRK'; @@ -53,7 +60,7 @@ const Meta = ({ component, history, measures, areThereCustomOrganizations, route <MetaSize component={component} measures={measures} /> - {isProject && <MetaTags component={component} />} + {isProject && <MetaTags component={component} onComponentChange={onComponentChange} />} {(isProject || isApplication) && <AnalysesList diff --git a/server/sonar-web/src/main/js/apps/overview/meta/MetaTags.js b/server/sonar-web/src/main/js/apps/overview/meta/MetaTags.js index b9d67b8e474..7254f0e2197 100644 --- a/server/sonar-web/src/main/js/apps/overview/meta/MetaTags.js +++ b/server/sonar-web/src/main/js/apps/overview/meta/MetaTags.js @@ -19,9 +19,10 @@ */ //@flow import React from 'react'; +import { setProjectTags } from '../../../api/components'; import { translate } from '../../../helpers/l10n'; import TagsList from '../../../components/tags/TagsList'; -import ProjectTagsSelectorContainer from '../../projects/components/ProjectTagsSelectorContainer'; +import MetaTagsSelector from './MetaTagsSelector'; /*:: type Props = { @@ -31,7 +32,8 @@ type Props = { configuration?: { showSettings?: boolean } - } + }, + onComponentChange: {} => void }; */ @@ -104,6 +106,13 @@ export default class MetaTags extends React.PureComponent { }; } + handleSetProjectTags = (tags /*: Array<string> */) => { + setProjectTags({ project: this.props.component.key, tags: tags.join(',') }).then( + () => this.props.onComponentChange({ tags }), + () => {} + ); + }; + render() { const { tags, key } = this.props.component; const { popupOpen, popupPosition } = this.state; @@ -119,10 +128,11 @@ export default class MetaTags extends React.PureComponent { </button> {popupOpen && <div ref={tagsSelector => (this.tagsSelector = tagsSelector)}> - <ProjectTagsSelectorContainer + <MetaTagsSelector position={popupPosition} project={key} selectedTags={tags} + setProjectTags={this.handleSetProjectTags} /> </div>} </div> diff --git a/server/sonar-web/src/main/js/apps/overview/meta/MetaTagsSelector.js b/server/sonar-web/src/main/js/apps/overview/meta/MetaTagsSelector.js new file mode 100644 index 00000000000..76e25c9c1f1 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/overview/meta/MetaTagsSelector.js @@ -0,0 +1,89 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +//@flow +import React from 'react'; +import { debounce, without } from 'lodash'; +import TagsSelector from '../../../components/tags/TagsSelector'; +import { searchProjectTags } from '../../../api/components'; + +/*:: +type Props = { + position: {}, + project: string, + selectedTags: Array<string>, + setProjectTags: (Array<string>) => void +}; +*/ + +/*:: +type State = { + searchResult: Array<string> +}; +*/ + +const LIST_SIZE = 10; + +export default class MetaTagsSelector extends React.PureComponent { + /*:: props: Props; */ + /*:: state: State; */ + + constructor(props /*: Props */) { + super(props); + this.state = { searchResult: [] }; + this.onSearch = debounce(this.onSearch, 250); + } + + componentDidMount() { + this.onSearch(''); + } + + onSearch = (query /*: string */) => { + searchProjectTags({ + q: query || '', + ps: Math.min(this.props.selectedTags.length - 1 + LIST_SIZE, 100) + }).then(result => { + this.setState({ + searchResult: result.tags + }); + }); + }; + + onSelect = (tag /*: string */) => { + this.props.setProjectTags([...this.props.selectedTags, tag]); + }; + + onUnselect = (tag /*: string */) => { + this.props.setProjectTags(without(this.props.selectedTags, tag)); + }; + + render() { + return ( + <TagsSelector + position={this.props.position} + tags={this.state.searchResult} + selectedTags={this.props.selectedTags} + listSize={LIST_SIZE} + onSearch={this.onSearch} + onSelect={this.onSelect} + onUnselect={this.onUnselect} + /> + ); + } +} diff --git a/server/sonar-web/src/main/js/apps/overview/meta/__tests__/MetaTagsSelector-test.js b/server/sonar-web/src/main/js/apps/overview/meta/__tests__/MetaTagsSelector-test.js new file mode 100644 index 00000000000..59744a204de --- /dev/null +++ b/server/sonar-web/src/main/js/apps/overview/meta/__tests__/MetaTagsSelector-test.js @@ -0,0 +1,61 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +/* eslint-disable import/order, import/first */ +import * as React from 'react'; +import { mount, shallow } from 'enzyme'; +import MetaTagsSelector from '../MetaTagsSelector'; + +jest.mock('../../../../api/components', () => ({ + searchProjectTags: jest.fn() +})); + +jest.useFakeTimers(); + +import { searchProjectTags } from '../../../../api/components'; + +it('searches tags on mount', () => { + searchProjectTags.mockImplementation(() => Promise.resolve({ tags: ['foo', 'bar'] })); + + mount( + <MetaTagsSelector position={{}} project="foo" selectedTags={[]} setProjectTags={jest.fn()} /> + ); + jest.runAllTimers(); + + expect(searchProjectTags).toBeCalledWith({ ps: 9, q: '' }); +}); + +it('selects and deselects tags', () => { + const setProjectTags = jest.fn(); + const wrapper = shallow( + <MetaTagsSelector + position={{}} + project="foo" + selectedTags={['foo', 'bar']} + setProjectTags={setProjectTags} + /> + ); + + wrapper.find('TagsSelector').prop('onSelect')('baz'); + expect(setProjectTags).toHaveBeenLastCalledWith(['foo', 'bar', 'baz']); + + // note that the `selectedTags` is a prop and so it wasn't changed + wrapper.find('TagsSelector').prop('onUnselect')('bar'); + expect(setProjectTags).toHaveBeenLastCalledWith(['foo']); +}); diff --git a/server/sonar-web/src/main/js/apps/overview/meta/__tests__/__snapshots__/MetaTags-test.js.snap b/server/sonar-web/src/main/js/apps/overview/meta/__tests__/__snapshots__/MetaTags-test.js.snap index 0eb1415ab03..875302462d5 100644 --- a/server/sonar-web/src/main/js/apps/overview/meta/__tests__/__snapshots__/MetaTags-test.js.snap +++ b/server/sonar-web/src/main/js/apps/overview/meta/__tests__/__snapshots__/MetaTags-test.js.snap @@ -40,7 +40,7 @@ exports[`should open the tag selector on click 2`] = ` /> </button> <div> - <Connect(ProjectTagsSelectorContainer) + <MetaTagsSelector position={ Object { "right": 0, @@ -54,6 +54,7 @@ exports[`should open the tag selector on click 2`] = ` "bar", ] } + setProjectTags={[Function]} /> </div> </div> |