aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web/src/main/js/apps/issues/sidebar/RuleFacet.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'server/sonar-web/src/main/js/apps/issues/sidebar/RuleFacet.tsx')
-rw-r--r--server/sonar-web/src/main/js/apps/issues/sidebar/RuleFacet.tsx153
1 files changed, 44 insertions, 109 deletions
diff --git a/server/sonar-web/src/main/js/apps/issues/sidebar/RuleFacet.tsx b/server/sonar-web/src/main/js/apps/issues/sidebar/RuleFacet.tsx
index e2ec1cdc721..be0c32bc774 100644
--- a/server/sonar-web/src/main/js/apps/issues/sidebar/RuleFacet.tsx
+++ b/server/sonar-web/src/main/js/apps/issues/sidebar/RuleFacet.tsx
@@ -18,17 +18,11 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
-import { sortBy, uniq, without } from 'lodash';
-import { formatFacetStat, Query } from '../utils';
+import ListStyleFacet from '../../../components/facet/ListStyleFacet';
+import { Query, ReferencedRule } from '../utils';
import { searchRules } from '../../../api/rules';
-import FacetBox from '../../../components/facet/FacetBox';
-import FacetHeader from '../../../components/facet/FacetHeader';
-import FacetItem from '../../../components/facet/FacetItem';
-import FacetItemsList from '../../../components/facet/FacetItemsList';
-import FacetFooter from '../../../components/facet/FacetFooter';
+import { Rule, Paging } from '../../../app/types';
import { translate } from '../../../helpers/l10n';
-import DeferredSpinner from '../../../components/common/DeferredSpinner';
-import MultipleSelectionHint from '../../../components/facet/MultipleSelectionHint';
interface Props {
fetching: boolean;
@@ -38,126 +32,67 @@ interface Props {
onToggle: (property: string) => void;
open: boolean;
organization: string | undefined;
- referencedRules: { [ruleKey: string]: { name: string } };
+ referencedRules: { [ruleKey: string]: ReferencedRule };
rules: string[];
stats: { [x: string]: number } | undefined;
}
-export default class RuleFacet extends React.PureComponent<Props> {
- property = 'rules';
-
- static defaultProps = {
- open: true
- };
-
- handleItemClick = (itemValue: string, multiple: boolean) => {
- const { rules } = this.props;
- if (multiple) {
- const newValue = sortBy(
- rules.includes(itemValue) ? without(rules, itemValue) : [...rules, itemValue]
- );
- this.props.onChange({ [this.property]: newValue });
- } else {
- this.props.onChange({
- [this.property]: rules.includes(itemValue) && rules.length < 2 ? [] : [itemValue]
- });
- }
- };
-
- handleHeaderClick = () => {
- this.props.onToggle(this.property);
- };
-
- handleClear = () => {
- this.props.onChange({ [this.property]: [] });
- };
+interface State {
+ query: string;
+ searching: boolean;
+ searchResults?: Rule[];
+ searchPaging?: Paging;
+}
- handleSearch = (query: string) => {
+export default class RuleFacet extends React.PureComponent<Props, State> {
+ handleSearch = (query: string, page = 1) => {
const { languages, organization } = this.props;
return searchRules({
f: 'name,langName',
languages: languages.length ? languages.join() : undefined,
organization,
q: query,
+ p: page,
+ ps: 30,
+ s: 'name',
// eslint-disable-next-line camelcase
include_external: true
- }).then(response =>
- response.rules.map(rule => ({ label: `(${rule.langName}) ${rule.name}`, value: rule.key }))
- );
+ }).then(response => ({
+ paging: { pageIndex: response.p, pageSize: response.ps, total: response.total },
+ results: response.rules
+ }));
};
- handleSelect = (option: { value: string }) => {
- const { rules } = this.props;
- this.props.onChange({ [this.property]: uniq([...rules, option.value]) });
- };
-
- getRuleName(rule: string): string {
+ getRuleName = (rule: string) => {
const { referencedRules } = this.props;
- return referencedRules[rule] ? referencedRules[rule].name : rule;
- }
-
- getStat(rule: string) {
- const { stats } = this.props;
- return stats ? stats[rule] : undefined;
- }
-
- renderList() {
- const { stats } = this.props;
-
- if (!stats) {
- return null;
- }
-
- const rules = sortBy(Object.keys(stats), key => -stats[key], key => this.getRuleName(key));
-
- return (
- <FacetItemsList>
- {rules.map(rule => (
- <FacetItem
- active={this.props.rules.includes(rule)}
- key={rule}
- loading={this.props.loading}
- name={this.getRuleName(rule)}
- onClick={this.handleItemClick}
- stat={formatFacetStat(this.getStat(rule))}
- tooltip={this.getRuleName(rule)}
- value={rule}
- />
- ))}
- </FacetItemsList>
- );
- }
-
- renderFooter() {
- if (!this.props.stats) {
- return null;
- }
+ return referencedRules[rule]
+ ? `(${referencedRules[rule].langName}) ${referencedRules[rule].name}`
+ : rule;
+ };
- return <FacetFooter onSearch={this.handleSearch} onSelect={this.handleSelect} />;
- }
+ renderSearchResult = (rule: Rule) => {
+ return `(${rule.langName}) ${rule.name}`;
+ };
render() {
- const { rules, stats = {} } = this.props;
- const values = rules.map(rule => this.getRuleName(rule));
return (
- <FacetBox property={this.property}>
- <FacetHeader
- name={translate('issues.facet', this.property)}
- onClear={this.handleClear}
- onClick={this.handleHeaderClick}
- open={this.props.open}
- values={values}
- />
-
- <DeferredSpinner loading={this.props.fetching} />
- {this.props.open && (
- <>
- {this.renderList()}
- {this.renderFooter()}
- <MultipleSelectionHint options={Object.keys(stats).length} values={rules.length} />
- </>
- )}
- </FacetBox>
+ <ListStyleFacet
+ facetHeader={translate('issues.facet.rules')}
+ fetching={this.props.fetching}
+ getFacetItemText={this.getRuleName}
+ getSearchResultKey={result => result.key}
+ getSearchResultText={result => result.name}
+ onChange={this.props.onChange}
+ onSearch={this.handleSearch}
+ onToggle={this.props.onToggle}
+ open={this.props.open}
+ property="rules"
+ renderFacetItem={this.getRuleName}
+ renderSearchResult={this.renderSearchResult}
+ searchPlaceholder={translate('search.search_for_rules')}
+ stats={this.props.stats}
+ values={this.props.rules}
+ />
);
}
}