aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web/src/main/js/apps/issues/sidebar
diff options
context:
space:
mode:
authorJay <jeremy.davis@sonarsource.com>2023-07-06 17:32:55 +0200
committersonartech <sonartech@sonarsource.com>2023-07-11 20:03:24 +0000
commit76c1f065c934a9abcba93dedb97fe7b4b8277ec4 (patch)
treef0e190f826d1736b02b0eba4a2488c0e649614f8 /server/sonar-web/src/main/js/apps/issues/sidebar
parentf062b56fd8656ee6239335a561474e25f73af5f5 (diff)
downloadsonarqube-76c1f065c934a9abcba93dedb97fe7b4b8277ec4.tar.gz
sonarqube-76c1f065c934a9abcba93dedb97fe7b4b8277ec4.zip
SONAR-19709 Migrate projects facets to the new UI
Diffstat (limited to 'server/sonar-web/src/main/js/apps/issues/sidebar')
-rw-r--r--server/sonar-web/src/main/js/apps/issues/sidebar/ListStyleFacet.tsx44
-rw-r--r--server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/__snapshots__/ListStyleFacet-test.tsx.snap22
2 files changed, 61 insertions, 5 deletions
diff --git a/server/sonar-web/src/main/js/apps/issues/sidebar/ListStyleFacet.tsx b/server/sonar-web/src/main/js/apps/issues/sidebar/ListStyleFacet.tsx
index dce39a06677..106ea557690 100644
--- a/server/sonar-web/src/main/js/apps/issues/sidebar/ListStyleFacet.tsx
+++ b/server/sonar-web/src/main/js/apps/issues/sidebar/ListStyleFacet.tsx
@@ -19,12 +19,13 @@
*/
import { FacetBox, FacetItem, FlagMessage, InputSearch } from 'design-system';
-import { sortBy, without } from 'lodash';
+import { max, sortBy, values, without } from 'lodash';
import * as React from 'react';
import ListFooter from '../../../components/controls/ListFooter';
import { translate, translateWithParameters } from '../../../helpers/l10n';
import { formatMeasure } from '../../../helpers/measures';
import { queriesEqual } from '../../../helpers/query';
+import { isDefined } from '../../../helpers/types';
import { MetricType } from '../../../types/metrics';
import { Dict, Paging, RawQuery } from '../../../types/types';
import { FacetItemsList } from './FacetItemsList';
@@ -39,6 +40,7 @@ interface SearchResponse<S> {
export interface Props<S> {
disabled?: boolean;
+ disableZero?: boolean;
facetHeader: string;
fetching: boolean;
getFacetItemText: (item: string) => string;
@@ -54,7 +56,7 @@ export interface Props<S> {
onClear?: () => void;
onItemClick?: (itemValue: string, multiple: boolean) => void;
onSearch: (query: string, page?: number) => Promise<SearchResponse<S>>;
- onToggle: (property: string) => void;
+ onToggle?: (property: string) => void;
open: boolean;
property: string;
query?: RawQuery;
@@ -63,6 +65,7 @@ export interface Props<S> {
searchPlaceholder: string;
showLessAriaLabel?: string;
showMoreAriaLabel?: string;
+ showStatBar?: boolean;
stats: Dict<number> | undefined;
values: string[];
}
@@ -155,7 +158,7 @@ export class ListStyleFacet<S> extends React.Component<Props<S>, State<S>> {
};
handleHeaderClick = () => {
- this.props.onToggle(this.props.property);
+ this.props.onToggle?.(this.props.property);
};
handleClear = () => {
@@ -241,6 +244,24 @@ export class ListStyleFacet<S> extends React.Component<Props<S>, State<S>> {
return stats?.[item];
}
+ getStatBarPercent = (item: string) => {
+ const { showStatBar, stats } = this.props;
+ const { searchResultsCounts } = this.state;
+
+ if (!showStatBar) {
+ return undefined;
+ }
+
+ const combined = { ...stats, ...searchResultsCounts };
+
+ const maxFacetValue = max(values(combined));
+ const facetValue = combined?.[item];
+
+ return isDefined(facetValue) && isDefined(maxFacetValue) && maxFacetValue > 0
+ ? facetValue / maxFacetValue
+ : undefined;
+ };
+
getFacetHeaderId = (property: string) => {
return `facet_${property}`;
};
@@ -255,6 +276,7 @@ export class ListStyleFacet<S> extends React.Component<Props<S>, State<S>> {
renderList() {
const {
+ disableZero,
maxInitialItems,
maxItems,
property,
@@ -293,11 +315,13 @@ export class ListStyleFacet<S> extends React.Component<Props<S>, State<S>> {
{limitedList.map((item) => (
<FacetItem
active={this.props.values.includes(item)}
+ disableZero={disableZero}
className="it__search-navigator-facet"
key={item}
name={this.props.renderFacetItem(item)}
onClick={this.handleItemClick}
stat={formatFacetStat(this.getStat(item)) ?? 0}
+ statBarPercent={this.getStatBarPercent(item)}
tooltip={this.props.getFacetItemText(item)}
value={item}
/>
@@ -313,10 +337,12 @@ export class ListStyleFacet<S> extends React.Component<Props<S>, State<S>> {
<FacetItem
active
className="it__search-navigator-facet"
+ disableZero={disableZero}
key={item}
name={this.props.renderFacetItem(item)}
onClick={this.handleItemClick}
stat={formatFacetStat(this.getStat(item)) ?? 0}
+ statBarPercent={this.getStatBarPercent(item)}
tooltip={this.props.getFacetItemText(item)}
value={item}
/>
@@ -344,6 +370,7 @@ export class ListStyleFacet<S> extends React.Component<Props<S>, State<S>> {
}
renderSearch() {
+ const { minSearchLength } = this.props;
return (
<InputSearch
className="it__search-box-input sw-mb-4 sw-w-full"
@@ -354,6 +381,8 @@ export class ListStyleFacet<S> extends React.Component<Props<S>, State<S>> {
value={this.state.query}
searchInputAriaLabel={translate('search_verb')}
clearIconAriaLabel={translate('clear')}
+ minLength={minSearchLength}
+ tooShortText={translateWithParameters('select2.tooShort', minSearchLength)}
/>
);
}
@@ -399,6 +428,7 @@ export class ListStyleFacet<S> extends React.Component<Props<S>, State<S>> {
}
renderSearchResult(result: S) {
+ const { disableZero } = this.props;
const key = this.props.getSearchResultKey(result);
const active = this.props.values.includes(key);
const stat = formatFacetStat(this.getStat(key) ?? this.state.searchResultsCounts[key]) ?? 0;
@@ -407,10 +437,12 @@ export class ListStyleFacet<S> extends React.Component<Props<S>, State<S>> {
<FacetItem
active={active}
className="it__search-navigator-facet"
+ disableZero={disableZero}
key={key}
name={this.props.renderSearchResult(result, this.state.query)}
onClick={this.handleItemClick}
stat={stat}
+ statBarPercent={this.getStatBarPercent(key)}
tooltip={this.props.getSearchResultText(result)}
value={key}
/>
@@ -423,6 +455,7 @@ export class ListStyleFacet<S> extends React.Component<Props<S>, State<S>> {
facetHeader,
fetching,
inner,
+ minSearchLength,
open,
property,
stats = {},
@@ -436,7 +469,7 @@ export class ListStyleFacet<S> extends React.Component<Props<S>, State<S>> {
const loadingResults =
query !== '' && searching && (searchResults === undefined || searchResults.length === 0);
- const showList = !query || loadingResults;
+ const showList = query.length < minSearchLength || loadingResults;
const nbSelectableItems = Object.keys(stats).length;
const nbSelectedItems = values.length;
@@ -447,13 +480,14 @@ export class ListStyleFacet<S> extends React.Component<Props<S>, State<S>> {
clearIconLabel={translate('clear')}
count={nbSelectedItems}
countLabel={translateWithParameters('x_selected', nbSelectedItems)}
+ data-property={property}
disabled={disabled}
id={this.getFacetHeaderId(property)}
inner={inner}
loading={fetching}
name={facetHeader}
onClear={this.handleClear}
- onClick={disabled ? undefined : this.handleHeaderClick}
+ onClick={disabled || !this.props.onToggle ? undefined : this.handleHeaderClick}
open={open && !disabled}
>
{!disabled && (
diff --git a/server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/__snapshots__/ListStyleFacet-test.tsx.snap b/server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/__snapshots__/ListStyleFacet-test.tsx.snap
index 1e996ba29e7..f3f1bf306ff 100644
--- a/server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/__snapshots__/ListStyleFacet-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/issues/sidebar/__tests__/__snapshots__/ListStyleFacet-test.tsx.snap
@@ -6,6 +6,7 @@ exports[`should be disabled 1`] = `
clearIconLabel="clear"
count={0}
countLabel="x_selected.0"
+ data-property="foo"
disabled={true}
id="facet_foo"
loading={false}
@@ -21,6 +22,7 @@ exports[`should display all selected items 1`] = `
clearIconLabel="clear"
count={3}
countLabel="x_selected.3"
+ data-property="foo"
id="facet_foo"
loading={false}
name="facet header"
@@ -35,10 +37,12 @@ exports[`should display all selected items 1`] = `
autoFocus={false}
className="it__search-box-input sw-mb-4 sw-w-full"
clearIconAriaLabel="clear"
+ minLength={2}
onChange={[Function]}
placeholder="search for foo..."
searchInputAriaLabel="search_verb"
size="auto"
+ tooShortText="select2.tooShort.2"
value=""
/>
<FacetItemsList
@@ -103,6 +107,7 @@ exports[`should render 1`] = `
clearIconLabel="clear"
count={0}
countLabel="x_selected.0"
+ data-property="foo"
id="facet_foo"
loading={false}
name="facet header"
@@ -117,10 +122,12 @@ exports[`should render 1`] = `
autoFocus={false}
className="it__search-box-input sw-mb-4 sw-w-full"
clearIconAriaLabel="clear"
+ minLength={2}
onChange={[Function]}
placeholder="search for foo..."
searchInputAriaLabel="search_verb"
size="auto"
+ tooShortText="select2.tooShort.2"
value=""
/>
<FacetItemsList
@@ -176,6 +183,7 @@ exports[`should search 1`] = `
clearIconLabel="clear"
count={0}
countLabel="x_selected.0"
+ data-property="foo"
id="facet_foo"
loading={false}
name="facet header"
@@ -190,10 +198,12 @@ exports[`should search 1`] = `
autoFocus={false}
className="it__search-box-input sw-mb-4 sw-w-full"
clearIconAriaLabel="clear"
+ minLength={2}
onChange={[Function]}
placeholder="search for foo..."
searchInputAriaLabel="search_verb"
size="auto"
+ tooShortText="select2.tooShort.2"
value="query"
/>
<FacetItemsList
@@ -242,6 +252,7 @@ exports[`should search 2`] = `
clearIconLabel="clear"
count={0}
countLabel="x_selected.0"
+ data-property="foo"
id="facet_foo"
loading={false}
name="facet header"
@@ -256,10 +267,12 @@ exports[`should search 2`] = `
autoFocus={false}
className="it__search-box-input sw-mb-4 sw-w-full"
clearIconAriaLabel="clear"
+ minLength={2}
onChange={[Function]}
placeholder="search for foo..."
searchInputAriaLabel="search_verb"
size="auto"
+ tooShortText="select2.tooShort.2"
value="query"
/>
<FacetItemsList
@@ -318,6 +331,7 @@ exports[`should search 3`] = `
clearIconLabel="clear"
count={0}
countLabel="x_selected.0"
+ data-property="foo"
id="facet_foo"
loading={false}
name="facet header"
@@ -332,10 +346,12 @@ exports[`should search 3`] = `
autoFocus={false}
className="it__search-box-input sw-mb-4 sw-w-full"
clearIconAriaLabel="clear"
+ minLength={2}
onChange={[Function]}
placeholder="search for foo..."
searchInputAriaLabel="search_verb"
size="auto"
+ tooShortText="select2.tooShort.2"
value=""
/>
<FacetItemsList
@@ -391,6 +407,7 @@ exports[`should search 4`] = `
clearIconLabel="clear"
count={0}
countLabel="x_selected.0"
+ data-property="foo"
id="facet_foo"
loading={false}
name="facet header"
@@ -405,10 +422,12 @@ exports[`should search 4`] = `
autoFocus={false}
className="it__search-box-input sw-mb-4 sw-w-full"
clearIconAriaLabel="clear"
+ minLength={2}
onChange={[Function]}
placeholder="search for foo..."
searchInputAriaLabel="search_verb"
size="auto"
+ tooShortText="select2.tooShort.2"
value="blabla"
/>
<div
@@ -430,6 +449,7 @@ exports[`should search 5`] = `
clearIconLabel="clear"
count={0}
countLabel="x_selected.0"
+ data-property="foo"
id="facet_foo"
loading={false}
name="facet header"
@@ -444,10 +464,12 @@ exports[`should search 5`] = `
autoFocus={false}
className="it__search-box-input sw-mb-4 sw-w-full"
clearIconAriaLabel="clear"
+ minLength={2}
onChange={[Function]}
placeholder="search for foo..."
searchInputAriaLabel="search_verb"
size="auto"
+ tooShortText="select2.tooShort.2"
value="blabla"
/>
<div