diff options
author | Stas Vilchik <vilchiks@gmail.com> | 2017-04-03 17:56:23 +0200 |
---|---|---|
committer | Stas Vilchik <stas-vilchik@users.noreply.github.com> | 2017-04-13 12:21:37 +0200 |
commit | 139261bbc13192621ef795d6d45298e1d8e1b7f3 (patch) | |
tree | 7aa153b4b3fec7e8fbf3b3b4f5ed0a1a5cc69113 /server/sonar-web/src/main/js/apps/issues/sidebar/AssigneeFacet.js | |
parent | d665528c8751ead9ca93e3d18dd8600fac92834b (diff) | |
download | sonarqube-139261bbc13192621ef795d6d45298e1d8e1b7f3.tar.gz sonarqube-139261bbc13192621ef795d6d45298e1d8e1b7f3.zip |
SONAR-9064 Rework facets sidebar on the issues page
Diffstat (limited to 'server/sonar-web/src/main/js/apps/issues/sidebar/AssigneeFacet.js')
-rw-r--r-- | server/sonar-web/src/main/js/apps/issues/sidebar/AssigneeFacet.js | 168 |
1 files changed, 168 insertions, 0 deletions
diff --git a/server/sonar-web/src/main/js/apps/issues/sidebar/AssigneeFacet.js b/server/sonar-web/src/main/js/apps/issues/sidebar/AssigneeFacet.js new file mode 100644 index 00000000000..cf7bb4be8f2 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/issues/sidebar/AssigneeFacet.js @@ -0,0 +1,168 @@ +/* + * 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 { sortBy, uniq, without } from 'lodash'; +import FacetBox from './components/FacetBox'; +import FacetHeader from './components/FacetHeader'; +import FacetItem from './components/FacetItem'; +import FacetItemsList from './components/FacetItemsList'; +import FacetFooter from './components/FacetFooter'; +import { searchAssignees } from '../utils'; +import type { ReferencedUser, Component } from '../utils'; +import Avatar from '../../../components/ui/Avatar'; +import { translate } from '../../../helpers/l10n'; + +type Props = {| + assigned: boolean, + assignees: Array<string>, + component?: Component, + facetMode: string, + onChange: (changes: {}) => void, + onToggle: (property: string) => void, + open: boolean, + stats?: { [string]: number }, + referencedUsers: { [string]: ReferencedUser } +|}; + +export default class AssigneeFacet extends React.PureComponent { + props: Props; + + static defaultProps = { + open: true + }; + + property = 'assignees'; + + handleItemClick = (itemValue: string) => { + if (itemValue === '') { + // unassigned + this.props.onChange({ assigned: !this.props.assigned, assignees: [] }); + } else { + // defined assignee + const { assignees } = this.props; + const newValue = sortBy( + assignees.includes(itemValue) ? without(assignees, itemValue) : [...assignees, itemValue] + ); + this.props.onChange({ assigned: true, assignees: newValue }); + } + }; + + handleHeaderClick = () => { + this.props.onToggle(this.property); + }; + + handleSearch = (query: string) => searchAssignees(query, this.props.component); + + handleSelect = (assignee: string) => { + const { assignees } = this.props; + this.props.onChange({ assigned: true, [this.property]: uniq([...assignees, assignee]) }); + }; + + isAssigneeActive(assignee: string) { + return assignee === '' ? !this.props.assigned : this.props.assignees.includes(assignee); + } + + getAssigneeName(assignee: string): React.Element<*> | string { + if (assignee === '') { + return translate('unassigned'); + } else { + const { referencedUsers } = this.props; + if (referencedUsers[assignee]) { + return ( + <span> + <Avatar + className="little-spacer-right" + hash={referencedUsers[assignee].avatar} + size={16} + /> + {referencedUsers[assignee].name} + </span> + ); + } else { + return assignee; + } + } + } + + getStat(assignee: string): ?number { + const { stats } = this.props; + return stats ? stats[assignee] : null; + } + + renderOption = (option: { avatar: string, label: string }) => { + return ( + <span> + {option.avatar != null && + <Avatar className="little-spacer-right" hash={option.avatar} size={16} />} + {option.label} + </span> + ); + }; + + render() { + const { stats } = this.props; + + if (!stats) { + return null; + } + + const assignees = sortBy( + Object.keys(stats), + // put unassigned first + key => key === '' ? 0 : 1, + // the sort by number + key => -stats[key] + ); + + return ( + <FacetBox property={this.property}> + <FacetHeader + hasValue={!this.props.assigned || this.props.assignees.length > 0} + name={translate('issues.facet', this.property)} + onClick={this.handleHeaderClick} + open={this.props.open} + /> + + {this.props.open && + <FacetItemsList> + {assignees.map(assignee => ( + <FacetItem + active={this.isAssigneeActive(assignee)} + facetMode={this.props.facetMode} + key={assignee} + name={this.getAssigneeName(assignee)} + onClick={this.handleItemClick} + stat={this.getStat(assignee)} + value={assignee} + /> + ))} + </FacetItemsList>} + + {this.props.open && + <FacetFooter + onSearch={this.handleSearch} + onSelect={this.handleSelect} + renderOption={this.renderOption} + />} + </FacetBox> + ); + } +} |