*/
// @flow
import React from 'react';
-import FacetBox from './FacetBox';
-import FacetHeader from './FacetHeader';
-import FacetItem from './FacetItem';
-import FacetItemsList from './FacetItemsList';
-import FacetItemMeasureValue from './FacetItemMeasureValue';
+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 FacetMeasureValue from './FacetMeasureValue';
import IssueTypeIcon from '../../../components/ui/IssueTypeIcon';
import Tooltip from '../../../components/controls/Tooltip';
import { filterMeasures, sortMeasures } from '../utils';
</Tooltip>
}
onClick={this.props.onChange}
- stat={<FacetItemMeasureValue measure={measure} />}
+ stat={<FacetMeasureValue measure={measure} />}
value={measure.metric.key}
/>
)}
+++ /dev/null
-/*
- * 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';
-
-type Props = {|
- children?: React.Element<*>
-|};
-
-export default function FacetBox(props: Props) {
- return (
- <div className="search-navigator-facet-box">
- {props.children}
- </div>
- );
-}
+++ /dev/null
-/*
- * 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
-/* eslint-disable max-len */
-import React from 'react';
-
-type Props = {|
- name: string,
- onClick?: () => void,
- open: boolean,
- values?: number
-|};
-
-export default class FacetHeader extends React.PureComponent {
- props: Props;
-
- static defaultProps = {
- open: true
- };
-
- handleClick = (event: Event & { currentTarget: HTMLElement }) => {
- event.preventDefault();
- event.currentTarget.blur();
- if (this.props.onClick) {
- this.props.onClick();
- }
- };
-
- renderCheckbox() {
- return (
- <svg viewBox="0 0 1792 1792" width="10" height="10" style={{ paddingTop: 3 }}>
- {this.props.open
- ? <path
- style={{ fill: 'currentColor ' }}
- d="M1683 808l-742 741q-19 19-45 19t-45-19l-742-741q-19-19-19-45.5t19-45.5l166-165q19-19 45-19t45 19l531 531 531-531q19-19 45-19t45 19l166 165q19 19 19 45.5t-19 45.5z"
- />
- : <path
- style={{ fill: 'currentColor ' }}
- d="M1363 877l-742 742q-19 19-45 19t-45-19l-166-166q-19-19-19-45t19-45l531-531-531-531q-19-19-19-45t19-45l166-166q19-19 45-19t45 19l742 742q19 19 19 45t-19 45z"
- />}
- </svg>
- );
- }
-
- renderValueIndicator() {
- if (this.props.open || !this.props.values) {
- return null;
- }
- return (
- <span className="spacer-left badge is-rounded">
- {this.props.values}
- </span>
- );
- }
-
- render() {
- return (
- <div>
- {this.props.onClick
- ? <a className="search-navigator-facet-header" href="#" onClick={this.handleClick}>
- {this.renderCheckbox()} {this.props.name} {this.renderValueIndicator()}
- </a>
- : <span className="search-navigator-facet-header">
- {this.props.name}
- </span>}
- </div>
- );
- }
-}
+++ /dev/null
-/*
- * 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 classNames from 'classnames';
-
-type Props = {|
- active: boolean,
- disabled: boolean,
- halfWidth: boolean,
- name: string | React.Element<*>,
- onClick: string => void,
- stat: string | React.Element<*>,
- value: string
-|};
-
-export default class FacetItem extends React.PureComponent {
- props: Props;
-
- static defaultProps = {
- disabled: false,
- halfWidth: false
- };
-
- handleClick = (event: Event & { currentTarget: HTMLElement }) => {
- event.preventDefault();
- this.props.onClick(this.props.value);
- };
-
- render() {
- const className = classNames('facet', 'search-navigator-facet', {
- active: this.props.active,
- 'search-navigator-facet-half': this.props.halfWidth
- });
-
- return this.props.disabled
- ? <span className={className}>
- <span className="facet-name">
- {this.props.name}
- </span>
- <span className="facet-stat">
- {this.props.stat}
- </span>
- </span>
- : <a className={className} href="#" onClick={this.handleClick}>
- <span className="facet-name">
- {this.props.name}
- </span>
- <span className="facet-stat">
- {this.props.stat}
- </span>
- </a>;
- }
-}
+++ /dev/null
-/*
- * 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 Measure from '../../../components/measure/Measure';
-import { isDiffMetric } from '../../../helpers/measures';
-import type { MeasureEnhanced } from '../../../components/measure/types';
-
-export default function FacetItemMeasureValue({ measure }: { measure: MeasureEnhanced }) {
- if (isDiffMetric(measure.metric.key)) {
- return (
- <div
- id={`measure-${measure.metric.key}-leak`}
- className="domain-measures-value domain-measures-leak">
- <Measure measure={measure} />
- </div>
- );
- }
-
- return (
- <div id={`measure-${measure.metric.key}-value`} className="domain-measures-value">
- <Measure measure={measure} />
- </div>
- );
-}
+++ /dev/null
-/*
- * 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';
-
-type Props = {|
- children?: Array<React.Element<*>>
-|};
-
-export default function FacetItemsList(props: Props) {
- return (
- <div className="search-navigator-facet-list">
- {props.children}
- </div>
- );
-}
--- /dev/null
+/*
+ * 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 Measure from '../../../components/measure/Measure';
+import { isDiffMetric } from '../../../helpers/measures';
+import type { MeasureEnhanced } from '../../../components/measure/types';
+
+export default function FacetMeasureValue({ measure }: { measure: MeasureEnhanced }) {
+ if (isDiffMetric(measure.metric.key)) {
+ return (
+ <div
+ id={`measure-${measure.metric.key}-leak`}
+ className="domain-measures-value domain-measures-leak">
+ <Measure measure={measure} />
+ </div>
+ );
+ }
+
+ return (
+ <div id={`measure-${measure.metric.key}-value`} className="domain-measures-value">
+ <Measure measure={measure} />
+ </div>
+ );
+}
|};
type State = {|
- closedFacets: { [string]: boolean },
- measuresByDomains: Array<{ name: string, measures: Array<MeasureEnhanced> }>
+ closedFacets: { [string]: boolean }
|};
export default class Sidebar extends React.PureComponent {
constructor(props: Props) {
super(props);
- this.state = {
- closedFacets: {},
- measuresByDomains: groupByDomains(props.measures)
- };
- }
-
- componentWillReceiveProps(nextProps: Props) {
- if (nextProps.measures !== this.props.measures) {
- this.setState({ measuresByDomains: groupByDomains(nextProps.measures) });
- }
+ this.state = { closedFacets: {} };
}
toggleFacet = (name: string) => {
changeMetric = (metric: string) => this.props.updateQuery({ metric });
render() {
- const { measuresByDomains } = this.state;
return (
<div className="search-navigator-facets-list">
- {measuresByDomains.map(domain =>
+ {groupByDomains(this.props.measures).map(domain =>
<DomainFacet
key={domain.name}
domain={domain}
+++ /dev/null
-/*
- * 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 { shallow } from 'enzyme';
-import { click } from '../../../../helpers/testUtils';
-import FacetHeader from '../FacetHeader';
-
-it('should render open facet with value', () => {
- expect(
- shallow(<FacetHeader name="foo" onClick={jest.fn()} open={true} values={1} />)
- ).toMatchSnapshot();
-});
-
-it('should render open facet without value', () => {
- expect(shallow(<FacetHeader name="foo" onClick={jest.fn()} open={true} />)).toMatchSnapshot();
-});
-
-it('should render closed facet with value', () => {
- expect(
- shallow(<FacetHeader name="foo" onClick={jest.fn()} open={false} values={1} />)
- ).toMatchSnapshot();
-});
-
-it('should render closed facet without value', () => {
- expect(shallow(<FacetHeader name="foo" onClick={jest.fn()} open={false} />)).toMatchSnapshot();
-});
-
-it('should render without link', () => {
- expect(shallow(<FacetHeader name="foo" open={false} />)).toMatchSnapshot();
-});
-
-it('should call onClick', () => {
- const onClick = jest.fn();
- const wrapper = shallow(<FacetHeader name="foo" onClick={onClick} open={false} />);
- click(wrapper.find('a'));
- expect(onClick).toHaveBeenCalled();
-});
+++ /dev/null
-/*
- * 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 { shallow } from 'enzyme';
-import { click } from '../../../../helpers/testUtils';
-import FacetItem from '../FacetItem';
-
-const renderFacetItem = (props: {}) =>
- shallow(
- <FacetItem active={false} name="foo" onClick={jest.fn()} stat={''} value="bar" {...props} />
- );
-
-it('should render active', () => {
- expect(renderFacetItem({ active: true })).toMatchSnapshot();
-});
-
-it('should render inactive', () => {
- expect(renderFacetItem({ active: false })).toMatchSnapshot();
-});
-
-it('should render stat', () => {
- expect(renderFacetItem({ stat: 13 })).toMatchSnapshot();
-});
-
-it('should render disabled', () => {
- expect(renderFacetItem({ disabled: true })).toMatchSnapshot();
-});
-
-it('should render half width', () => {
- expect(renderFacetItem({ halfWidth: true })).toMatchSnapshot();
-});
-
-it('should render effort stat', () => {
- expect(renderFacetItem({ facetMode: 'effort', stat: 1234 })).toMatchSnapshot();
-});
-
-it('should call onClick', () => {
- const onClick = jest.fn();
- const wrapper = renderFacetItem({ onClick });
- click(wrapper, { currentTarget: { dataset: { value: 'bar' } } });
- expect(onClick).toHaveBeenCalled();
-});
+++ /dev/null
-/*
- * 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 { shallow } from 'enzyme';
-import FacetItemMeasureValue from '../FacetItemMeasureValue';
-
-const MEASURE = {
- metric: {
- key: 'bugs',
- type: 'INT',
- name: 'Bugs',
- domain: 'Reliability'
- },
- value: '5',
- periods: [{ index: 1, value: '5' }],
- leak: '5'
-};
-const LEAK_MEASURE = {
- metric: {
- key: 'new_bugs',
- type: 'INT',
- name: 'New Bugs',
- domain: 'Reliability'
- },
- periods: [{ index: 1, value: '5' }],
- leak: '5'
-};
-
-it('should display measure value', () => {
- expect(shallow(<FacetItemMeasureValue measure={MEASURE} />)).toMatchSnapshot();
-});
-
-it('should display leak measure value', () => {
- expect(shallow(<FacetItemMeasureValue measure={LEAK_MEASURE} />)).toMatchSnapshot();
-});
--- /dev/null
+/*
+ * 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 { shallow } from 'enzyme';
+import FacetMeasureValue from '../FacetMeasureValue';
+
+const MEASURE = {
+ metric: {
+ key: 'bugs',
+ type: 'INT',
+ name: 'Bugs',
+ domain: 'Reliability'
+ },
+ value: '5',
+ periods: [{ index: 1, value: '5' }],
+ leak: '5'
+};
+const LEAK_MEASURE = {
+ metric: {
+ key: 'new_bugs',
+ type: 'INT',
+ name: 'New Bugs',
+ domain: 'Reliability'
+ },
+ periods: [{ index: 1, value: '5' }],
+ leak: '5'
+};
+
+it('should display measure value', () => {
+ expect(shallow(<FacetMeasureValue measure={MEASURE} />)).toMatchSnapshot();
+});
+
+it('should display leak measure value', () => {
+ expect(shallow(<FacetMeasureValue measure={LEAK_MEASURE} />)).toMatchSnapshot();
+});
}
onClick={[Function]}
stat={
- <FacetItemMeasureValue
+ <FacetMeasureValue
measure={
Object {
"leak": "5",
}
onClick={[Function]}
stat={
- <FacetItemMeasureValue
+ <FacetMeasureValue
measure={
Object {
"leak": "5",
}
onClick={[Function]}
stat={
- <FacetItemMeasureValue
+ <FacetMeasureValue
measure={
Object {
"leak": "5",
}
onClick={[Function]}
stat={
- <FacetItemMeasureValue
+ <FacetMeasureValue
measure={
Object {
"leak": "5",
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render closed facet with value 1`] = `
-<div>
- <a
- className="search-navigator-facet-header"
- href="#"
- onClick={[Function]}
- >
- <svg
- height="10"
- style={
- Object {
- "paddingTop": 3,
- }
- }
- viewBox="0 0 1792 1792"
- width="10"
- >
- <path
- d="M1363 877l-742 742q-19 19-45 19t-45-19l-166-166q-19-19-19-45t19-45l531-531-531-531q-19-19-19-45t19-45l166-166q19-19 45-19t45 19l742 742q19 19 19 45t-19 45z"
- style={
- Object {
- "fill": "currentColor ",
- }
- }
- />
- </svg>
-
- foo
-
- <span
- className="spacer-left badge is-rounded"
- >
- 1
- </span>
- </a>
-</div>
-`;
-
-exports[`should render closed facet without value 1`] = `
-<div>
- <a
- className="search-navigator-facet-header"
- href="#"
- onClick={[Function]}
- >
- <svg
- height="10"
- style={
- Object {
- "paddingTop": 3,
- }
- }
- viewBox="0 0 1792 1792"
- width="10"
- >
- <path
- d="M1363 877l-742 742q-19 19-45 19t-45-19l-166-166q-19-19-19-45t19-45l531-531-531-531q-19-19-19-45t19-45l166-166q19-19 45-19t45 19l742 742q19 19 19 45t-19 45z"
- style={
- Object {
- "fill": "currentColor ",
- }
- }
- />
- </svg>
-
- foo
-
- </a>
-</div>
-`;
-
-exports[`should render open facet with value 1`] = `
-<div>
- <a
- className="search-navigator-facet-header"
- href="#"
- onClick={[Function]}
- >
- <svg
- height="10"
- style={
- Object {
- "paddingTop": 3,
- }
- }
- viewBox="0 0 1792 1792"
- width="10"
- >
- <path
- d="M1683 808l-742 741q-19 19-45 19t-45-19l-742-741q-19-19-19-45.5t19-45.5l166-165q19-19 45-19t45 19l531 531 531-531q19-19 45-19t45 19l166 165q19 19 19 45.5t-19 45.5z"
- style={
- Object {
- "fill": "currentColor ",
- }
- }
- />
- </svg>
-
- foo
-
- </a>
-</div>
-`;
-
-exports[`should render open facet without value 1`] = `
-<div>
- <a
- className="search-navigator-facet-header"
- href="#"
- onClick={[Function]}
- >
- <svg
- height="10"
- style={
- Object {
- "paddingTop": 3,
- }
- }
- viewBox="0 0 1792 1792"
- width="10"
- >
- <path
- d="M1683 808l-742 741q-19 19-45 19t-45-19l-742-741q-19-19-19-45.5t19-45.5l166-165q19-19 45-19t45 19l531 531 531-531q19-19 45-19t45 19l166 165q19 19 19 45.5t-19 45.5z"
- style={
- Object {
- "fill": "currentColor ",
- }
- }
- />
- </svg>
-
- foo
-
- </a>
-</div>
-`;
-
-exports[`should render without link 1`] = `
-<div>
- <span
- className="search-navigator-facet-header"
- >
- foo
- </span>
-</div>
-`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render active 1`] = `
-<a
- className="facet search-navigator-facet active"
- href="#"
- onClick={[Function]}
->
- <span
- className="facet-name"
- >
- foo
- </span>
- <span
- className="facet-stat"
- />
-</a>
-`;
-
-exports[`should render disabled 1`] = `
-<span
- className="facet search-navigator-facet"
->
- <span
- className="facet-name"
- >
- foo
- </span>
- <span
- className="facet-stat"
- />
-</span>
-`;
-
-exports[`should render effort stat 1`] = `
-<a
- className="facet search-navigator-facet"
- href="#"
- onClick={[Function]}
->
- <span
- className="facet-name"
- >
- foo
- </span>
- <span
- className="facet-stat"
- >
- 1234
- </span>
-</a>
-`;
-
-exports[`should render half width 1`] = `
-<a
- className="facet search-navigator-facet search-navigator-facet-half"
- href="#"
- onClick={[Function]}
->
- <span
- className="facet-name"
- >
- foo
- </span>
- <span
- className="facet-stat"
- />
-</a>
-`;
-
-exports[`should render inactive 1`] = `
-<a
- className="facet search-navigator-facet"
- href="#"
- onClick={[Function]}
->
- <span
- className="facet-name"
- >
- foo
- </span>
- <span
- className="facet-stat"
- />
-</a>
-`;
-
-exports[`should render stat 1`] = `
-<a
- className="facet search-navigator-facet"
- href="#"
- onClick={[Function]}
->
- <span
- className="facet-name"
- >
- foo
- </span>
- <span
- className="facet-stat"
- >
- 13
- </span>
-</a>
-`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should display leak measure value 1`] = `
-<div
- className="domain-measures-value domain-measures-leak"
- id="measure-new_bugs-leak"
->
- <Measure
- measure={
- Object {
- "leak": "5",
- "metric": Object {
- "domain": "Reliability",
- "key": "new_bugs",
- "name": "New Bugs",
- "type": "INT",
- },
- "periods": Array [
- Object {
- "index": 1,
- "value": "5",
- },
- ],
- }
- }
- />
-</div>
-`;
-
-exports[`should display measure value 1`] = `
-<div
- className="domain-measures-value"
- id="measure-bugs-value"
->
- <Measure
- measure={
- Object {
- "leak": "5",
- "metric": Object {
- "domain": "Reliability",
- "key": "bugs",
- "name": "Bugs",
- "type": "INT",
- },
- "periods": Array [
- Object {
- "index": 1,
- "value": "5",
- },
- ],
- "value": "5",
- }
- }
- />
-</div>
-`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should display leak measure value 1`] = `
+<div
+ className="domain-measures-value domain-measures-leak"
+ id="measure-new_bugs-leak"
+>
+ <Measure
+ measure={
+ Object {
+ "leak": "5",
+ "metric": Object {
+ "domain": "Reliability",
+ "key": "new_bugs",
+ "name": "New Bugs",
+ "type": "INT",
+ },
+ "periods": Array [
+ Object {
+ "index": 1,
+ "value": "5",
+ },
+ ],
+ }
+ }
+ />
+</div>
+`;
+
+exports[`should display measure value 1`] = `
+<div
+ className="domain-measures-value"
+ id="measure-bugs-value"
+>
+ <Measure
+ measure={
+ Object {
+ "leak": "5",
+ "metric": Object {
+ "domain": "Reliability",
+ "key": "bugs",
+ "name": "Bugs",
+ "type": "INT",
+ },
+ "periods": Array [
+ Object {
+ "index": 1,
+ "value": "5",
+ },
+ ],
+ "value": "5",
+ }
+ }
+ />
+</div>
+`;
import Modal from 'react-modal';
import Select from 'react-select';
import { pickBy, sortBy } from 'lodash';
-import SearchSelect from './SearchSelect';
+import SearchSelect from '../../../components/controls/SearchSelect';
import Checkbox from '../../../components/controls/Checkbox';
import Tooltip from '../../../components/controls/Tooltip';
import MarkdownTips from '../../../components/common/MarkdownTips';
+++ /dev/null
-/*
- * 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 Select from 'react-select';
-import { debounce } from 'lodash';
-import { translate, translateWithParameters } from '../../../helpers/l10n';
-
-type Option = { label: string, value: string };
-
-type Props = {|
- autofocus: boolean,
- minimumQueryLength: number,
- onSearch: (query: string) => Promise<Array<Option>>,
- onSelect: (value: string) => void,
- renderOption?: (option: Object) => React.Element<*>,
- resetOnBlur: boolean,
- value?: string
-|};
-
-type State = {
- loading: boolean,
- options: Array<Option>,
- query: string
-};
-
-export default class SearchSelect extends React.PureComponent {
- mounted: boolean;
- props: Props;
- state: State;
-
- static defaultProps = {
- autofocus: true,
- minimumQueryLength: 2,
- resetOnBlur: true
- };
-
- constructor(props: Props) {
- super(props);
- this.state = { loading: false, options: [], query: '' };
- this.search = debounce(this.search, 250);
- }
-
- componentDidMount() {
- this.mounted = true;
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- search = (query: string) => {
- this.props.onSearch(query).then(options => {
- if (this.mounted) {
- this.setState({ loading: false, options });
- }
- });
- };
-
- handleBlur = () => {
- this.setState({ options: [], query: '' });
- };
-
- handleChange = (option: Option) => {
- this.props.onSelect(option.value);
- };
-
- handleInputChange = (query: string = '') => {
- if (query.length >= this.props.minimumQueryLength) {
- this.setState({ loading: true, query });
- this.search(query);
- } else {
- this.setState({ options: [], query });
- }
- };
-
- // disable internal filtering
- handleFilterOption = () => true;
-
- render() {
- return (
- <Select
- autofocus={this.props.autofocus}
- cache={false}
- className="input-super-large"
- clearable={false}
- filterOption={this.handleFilterOption}
- isLoading={this.state.loading}
- noResultsText={
- this.state.query.length < this.props.minimumQueryLength
- ? translateWithParameters('select2.tooShort', this.props.minimumQueryLength)
- : translate('select2.noMatches')
- }
- onBlur={this.props.resetOnBlur ? this.handleBlur : undefined}
- onChange={this.handleChange}
- onInputChange={this.handleInputChange}
- onOpen={this.props.minimumQueryLength === 0 ? this.handleInputChange : undefined}
- optionRenderer={this.props.renderOption}
- options={this.state.options}
- placeholder={translate('search_verb')}
- searchable={true}
- value={this.props.value}
- valueRenderer={this.props.renderOption}
- />
- );
- }
-}
+++ /dev/null
-/*
- * 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 { shallow } from 'enzyme';
-import SearchSelect from '../SearchSelect';
-
-jest.mock('lodash', () => ({
- debounce: fn => fn
-}));
-
-it('should render Select', () => {
- expect(shallow(<SearchSelect onSearch={jest.fn()} onSelect={jest.fn()} />)).toMatchSnapshot();
-});
-
-it('should call onSelect', () => {
- const onSelect = jest.fn();
- const wrapper = shallow(<SearchSelect onSearch={jest.fn()} onSelect={onSelect} />);
- wrapper.prop('onChange')({ value: 'foo' });
- expect(onSelect).lastCalledWith('foo');
-});
-
-it('should call onSearch', () => {
- const onSearch = jest.fn().mockReturnValue(Promise.resolve([]));
- const wrapper = shallow(
- <SearchSelect minimumQueryLength={2} onSearch={onSearch} onSelect={jest.fn()} />
- );
- wrapper.prop('onInputChange')('f');
- expect(onSearch).not.toHaveBeenCalled();
- wrapper.prop('onInputChange')('foo');
- expect(onSearch).lastCalledWith('foo');
-});
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render Select 1`] = `
-<Select
- addLabelText="Add \\"{label}\\"?"
- arrowRenderer={[Function]}
- autofocus={true}
- autosize={true}
- backspaceRemoves={true}
- backspaceToRemoveMessage="Press backspace to remove {label}"
- cache={false}
- className="input-super-large"
- clearAllText="Clear all"
- clearRenderer={[Function]}
- clearValueText="Clear value"
- clearable={false}
- deleteRemoves={true}
- delimiter=","
- disabled={false}
- escapeClearsValue={true}
- filterOption={[Function]}
- filterOptions={[Function]}
- ignoreAccents={true}
- ignoreCase={true}
- inputProps={Object {}}
- isLoading={false}
- joinValues={false}
- labelKey="label"
- matchPos="any"
- matchProp="any"
- menuBuffer={0}
- menuRenderer={[Function]}
- multi={false}
- noResultsText="select2.tooShort.2"
- onBlur={[Function]}
- onBlurResetsInput={true}
- onChange={[Function]}
- onCloseResetsInput={true}
- onInputChange={[Function]}
- optionComponent={[Function]}
- options={Array []}
- pageSize={5}
- placeholder="search_verb"
- required={false}
- scrollMenuIntoView={true}
- searchable={true}
- simpleValue={false}
- tabSelectsValue={true}
- valueComponent={[Function]}
- valueKey="value"
-/>
-`;
import React from 'react';
import { sortBy, uniq, without } from 'lodash';
import Avatar from '../../../components/ui/Avatar';
-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 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 { searchAssignees, formatFacetStat } from '../utils';
import { translate } from '../../../helpers/l10n';
import type { ReferencedUser, Component } from '../utils';
{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)}
+ stat={formatFacetStat(this.getStat(assignee), this.props.facetMode)}
value={assignee}
/>
)}
render() {
return (
- <FacetBox property={this.property}>
+ <FacetBox>
<FacetHeader
name={translate('issues.facet', this.property)}
onClear={this.handleClear}
// @flow
import React from 'react';
import { sortBy, without } from 'lodash';
-import FacetBox from './components/FacetBox';
-import FacetHeader from './components/FacetHeader';
-import FacetItem from './components/FacetItem';
-import FacetItemsList from './components/FacetItemsList';
+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 { formatFacetStat } from '../utils';
import { translate } from '../../../helpers/l10n';
type Props = {|
{authors.map(author =>
<FacetItem
active={this.props.authors.includes(author)}
- facetMode={this.props.facetMode}
key={author}
name={author}
onClick={this.handleItemClick}
- stat={this.getStat(author)}
+ stat={formatFacetStat(this.getStat(author), this.props.facetMode)}
value={author}
/>
)}
render() {
return (
- <FacetBox property={this.property}>
+ <FacetBox>
<FacetHeader
name={translate('issues.facet', this.property)}
onClear={this.handleClear}
import React from 'react';
import moment from 'moment';
import { max } from 'lodash';
-import FacetBox from './components/FacetBox';
-import FacetHeader from './components/FacetHeader';
-import FacetItem from './components/FacetItem';
+import FacetBox from '../../../components/facet/FacetBox';
+import FacetHeader from '../../../components/facet/FacetHeader';
+import FacetItem from '../../../components/facet/FacetItem';
import { BarChart } from '../../../components/charts/bar-chart';
import DateInput from '../../../components/controls/DateInput';
import { translate } from '../../../helpers/l10n';
<div className="spacer-top issues-predefined-periods">
<FacetItem
active={!this.hasValue()}
- facetMode=""
name={translate('issues.facet.createdAt.all')}
onClick={this.handlePeriodClick}
- stat={null}
value=""
/>
{component == null &&
<FacetItem
active={createdInLast === '1w'}
- facetMode=""
name={translate('issues.facet.createdAt.last_week')}
onClick={this.handlePeriodClick}
- stat={null}
value="1w"
/>}
{component == null &&
<FacetItem
active={createdInLast === '1m'}
- facetMode=""
name={translate('issues.facet.createdAt.last_month')}
onClick={this.handlePeriodClick}
- stat={null}
value="1m"
/>}
{component == null &&
<FacetItem
active={createdInLast === '1y'}
- facetMode=""
name={translate('issues.facet.createdAt.last_year')}
onClick={this.handlePeriodClick}
- stat={null}
value="1y"
/>}
{component != null &&
<FacetItem
active={sinceLeakPeriod}
- facetMode=""
name={translate('issues.leak_period')}
onClick={this.handleLeakPeriodClick}
- stat={null}
value=""
/>}
</div>
render() {
return (
- <FacetBox property={this.property}>
+ <FacetBox>
<FacetHeader
name={translate('issues.facet', this.property)}
onClear={this.handleClear}
// @flow
import React from 'react';
import { sortBy, without } from 'lodash';
-import FacetBox from './components/FacetBox';
-import FacetHeader from './components/FacetHeader';
-import FacetItem from './components/FacetItem';
-import FacetItemsList from './components/FacetItemsList';
-import type { ReferencedComponent } from '../utils';
+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 QualifierIcon from '../../../components/shared/QualifierIcon';
import { translate } from '../../../helpers/l10n';
+import { formatFacetStat } from '../utils';
+import type { ReferencedComponent } from '../utils';
type Props = {|
facetMode: string,
{directories.map(directory =>
<FacetItem
active={this.props.directories.includes(directory)}
- facetMode={this.props.facetMode}
key={directory}
name={this.renderName(directory)}
onClick={this.handleItemClick}
- stat={this.getStat(directory)}
+ stat={formatFacetStat(this.getStat(directory), this.props.facetMode)}
value={directory}
/>
)}
render() {
return (
- <FacetBox property={this.property}>
+ <FacetBox>
<FacetHeader
name={translate('issues.facet', this.property)}
onClear={this.handleClear}
*/
// @flow
import React from 'react';
-import FacetBox from './components/FacetBox';
-import FacetHeader from './components/FacetHeader';
-import FacetItem from './components/FacetItem';
-import FacetItemsList from './components/FacetItemsList';
+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 { translate } from '../../../helpers/l10n';
type Props = {|
const modes = ['count', 'effort'];
return (
- <FacetBox property={this.property}>
+ <FacetBox>
<FacetHeader name={translate('issues.facet.mode')} />
<FacetItemsList>
{modes.map(mode =>
<FacetItem
active={facetMode === mode}
- facetMode={this.props.facetMode}
halfWidth={true}
key={mode}
name={translate('issues.facet.mode', mode)}
onClick={this.handleItemClick}
- stat={null}
value={mode}
/>
)}
// @flow
import React from 'react';
import { sortBy, without } from 'lodash';
-import FacetBox from './components/FacetBox';
-import FacetHeader from './components/FacetHeader';
-import FacetItem from './components/FacetItem';
-import FacetItemsList from './components/FacetItemsList';
-import type { ReferencedComponent } from '../utils';
+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 QualifierIcon from '../../../components/shared/QualifierIcon';
import { translate } from '../../../helpers/l10n';
import { collapsePath } from '../../../helpers/path';
+import { formatFacetStat } from '../utils';
+import type { ReferencedComponent } from '../utils';
type Props = {|
facetMode: string,
{files.map(file =>
<FacetItem
active={this.props.files.includes(file)}
- facetMode={this.props.facetMode}
key={file}
name={this.renderName(file)}
onClick={this.handleItemClick}
- stat={this.getStat(file)}
+ stat={formatFacetStat(this.getStat(file), this.props.facetMode)}
value={file}
/>
)}
render() {
return (
- <FacetBox property={this.property}>
+ <FacetBox>
<FacetHeader
name={translate('issues.facet', this.property)}
onClear={this.handleClear}
// @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 FacetBox from '../../../components/facet/FacetBox';
+import FacetHeader from '../../../components/facet/FacetHeader';
+import FacetItem from '../../../components/facet/FacetItem';
+import FacetItemsList from '../../../components/facet/FacetItemsList';
import LanguageFacetFooter from './LanguageFacetFooter';
-import type { ReferencedLanguage } from '../utils';
import { translate } from '../../../helpers/l10n';
+import { formatFacetStat } from '../utils';
+import type { ReferencedLanguage } from '../utils';
type Props = {|
facetMode: string,
{languages.map(language =>
<FacetItem
active={this.props.languages.includes(language)}
- facetMode={this.props.facetMode}
key={language}
name={this.getLanguageName(language)}
onClick={this.handleItemClick}
- stat={this.getStat(language)}
+ stat={formatFacetStat(this.getStat(language), this.props.facetMode)}
value={language}
/>
)}
render() {
return (
- <FacetBox property={this.property}>
+ <FacetBox>
<FacetHeader
name={translate('issues.facet', this.property)}
onClear={this.handleClear}
// @flow
import React from 'react';
import { sortBy, without } from 'lodash';
-import FacetBox from './components/FacetBox';
-import FacetHeader from './components/FacetHeader';
-import FacetItem from './components/FacetItem';
-import FacetItemsList from './components/FacetItemsList';
-import type { ReferencedComponent } from '../utils';
+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 QualifierIcon from '../../../components/shared/QualifierIcon';
import { translate } from '../../../helpers/l10n';
+import { formatFacetStat } from '../utils';
+import type { ReferencedComponent } from '../utils';
type Props = {|
facetMode: string,
{modules.map(module =>
<FacetItem
active={this.props.modules.includes(module)}
- facetMode={this.props.facetMode}
key={module}
name={this.renderName(module)}
onClick={this.handleItemClick}
- stat={this.getStat(module)}
+ stat={formatFacetStat(this.getStat(module), this.props.facetMode)}
value={module}
/>
)}
render() {
return (
- <FacetBox property={this.property}>
+ <FacetBox>
<FacetHeader
name={translate('issues.facet', this.property)}
onClear={this.handleClear}
// @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 type { ReferencedComponent, Component } from '../utils';
+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 Organization from '../../../components/shared/Organization';
import QualifierIcon from '../../../components/shared/QualifierIcon';
import { searchProjects, getTree } from '../../../api/components';
import { translate } from '../../../helpers/l10n';
+import { formatFacetStat } from '../utils';
+import type { ReferencedComponent, Component } from '../utils';
type Props = {|
component?: Component,
{projects.map(project =>
<FacetItem
active={this.props.projects.includes(project)}
- facetMode={this.props.facetMode}
key={project}
name={this.renderName(project)}
onClick={this.handleItemClick}
- stat={this.getStat(project)}
+ stat={formatFacetStat(this.getStat(project), this.props.facetMode)}
value={project}
/>
)}
render() {
return (
- <FacetBox property={this.property}>
+ <FacetBox>
<FacetHeader
name={translate('issues.facet', this.property)}
onClear={this.handleClear}
// @flow
import React from 'react';
import { orderBy, without } from 'lodash';
-import FacetBox from './components/FacetBox';
-import FacetHeader from './components/FacetHeader';
-import FacetItem from './components/FacetItem';
-import FacetItemsList from './components/FacetItemsList';
+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 { translate } from '../../../helpers/l10n';
+import { formatFacetStat } from '../utils';
type Props = {|
facetMode: string,
<FacetItem
active={active}
disabled={stat === 0 && !active}
- facetMode={this.props.facetMode}
key={resolution}
halfWidth={true}
name={this.getFacetItemName(resolution)}
onClick={this.handleItemClick}
- stat={stat}
+ stat={formatFacetStat(stat, this.props.facetMode)}
value={resolution}
/>
);
const resolutions = ['', 'FIXED', 'FALSE-POSITIVE', 'WONTFIX', 'REMOVED'];
return (
- <FacetBox property={this.property}>
+ <FacetBox>
<FacetHeader
name={translate('issues.facet', this.property)}
onClear={this.handleClear}
// @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 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 { searchRules } from '../../../api/rules';
import { translate } from '../../../helpers/l10n';
+import { formatFacetStat } from '../utils';
type Props = {|
facetMode: string,
{rules.map(rule =>
<FacetItem
active={this.props.rules.includes(rule)}
- facetMode={this.props.facetMode}
key={rule}
name={this.getRuleName(rule)}
onClick={this.handleItemClick}
- stat={this.getStat(rule)}
+ stat={formatFacetStat(this.getStat(rule), this.props.facetMode)}
value={rule}
/>
)}
render() {
return (
- <FacetBox property={this.property}>
+ <FacetBox>
<FacetHeader
name={translate('issues.facet', this.property)}
onClear={this.handleClear}
// @flow
import React from 'react';
import { orderBy, without } from 'lodash';
-import FacetBox from './components/FacetBox';
-import FacetHeader from './components/FacetHeader';
-import FacetItem from './components/FacetItem';
-import FacetItemsList from './components/FacetItemsList';
+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 SeverityHelper from '../../../components/shared/SeverityHelper';
import { translate } from '../../../helpers/l10n';
+import { formatFacetStat } from '../utils';
type Props = {|
facetMode: string,
<FacetItem
active={active}
disabled={stat === 0 && !active}
- facetMode={this.props.facetMode}
halfWidth={true}
key={severity}
name={<SeverityHelper severity={severity} />}
onClick={this.handleItemClick}
- stat={stat}
+ stat={formatFacetStat(stat, this.props.facetMode)}
value={severity}
/>
);
const severities = ['BLOCKER', 'MINOR', 'CRITICAL', 'INFO', 'MAJOR'];
return (
- <FacetBox property={this.property}>
+ <FacetBox>
<FacetHeader
name={translate('issues.facet', this.property)}
onClear={this.handleClear}
// @flow
import React from 'react';
import { orderBy, without } from 'lodash';
-import FacetBox from './components/FacetBox';
-import FacetHeader from './components/FacetHeader';
-import FacetItem from './components/FacetItem';
-import FacetItemsList from './components/FacetItemsList';
+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 { translate } from '../../../helpers/l10n';
+import { formatFacetStat } from '../utils';
type Props = {|
facetMode: string,
<FacetItem
active={active}
disabled={stat === 0 && !active}
- facetMode={this.props.facetMode}
halfWidth={true}
key={status}
name={this.renderStatus(status)}
onClick={this.handleItemClick}
- stat={stat}
+ stat={formatFacetStat(stat, this.props.facetMode)}
value={status}
/>
);
const statuses = ['OPEN', 'RESOLVED', 'REOPENED', 'CLOSED', 'CONFIRMED'];
return (
- <FacetBox property={this.property}>
+ <FacetBox>
<FacetHeader
name={translate('issues.facet', this.property)}
onClear={this.handleClear}
// @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 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 { searchIssueTags } from '../../../api/issues';
import { translate } from '../../../helpers/l10n';
import type { Component } from '../utils';
+import { formatFacetStat } from '../utils';
type Props = {|
component?: Component,
{tags.map(tag =>
<FacetItem
active={this.props.tags.includes(tag)}
- facetMode={this.props.facetMode}
key={tag}
name={this.renderTag(tag)}
onClick={this.handleItemClick}
- stat={this.getStat(tag)}
+ stat={formatFacetStat(this.getStat(tag), this.props.facetMode)}
value={tag}
/>
)}
render() {
return (
- <FacetBox property={this.property}>
+ <FacetBox>
<FacetHeader
name={translate('issues.facet', this.property)}
onClear={this.handleClear}
// @flow
import React from 'react';
import { orderBy, without } from 'lodash';
-import FacetBox from './components/FacetBox';
-import FacetHeader from './components/FacetHeader';
-import FacetItem from './components/FacetItem';
-import FacetItemsList from './components/FacetItemsList';
+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 IssueTypeIcon from '../../../components/ui/IssueTypeIcon';
import { translate } from '../../../helpers/l10n';
+import { formatFacetStat } from '../utils';
type Props = {|
facetMode: string,
<FacetItem
active={active}
disabled={stat === 0 && !active}
- facetMode={this.props.facetMode}
key={type}
name={
<span>
</span>
}
onClick={this.handleItemClick}
- stat={stat}
+ stat={formatFacetStat(stat, this.props.facetMode)}
value={type}
/>
);
const types = ['BUG', 'VULNERABILITY', 'CODE_SMELL'];
return (
- <FacetBox property={this.property}>
+ <FacetBox>
<FacetHeader
name={translate('issues.facet', this.property)}
onClear={this.handleClear}
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`should render 1`] = `
-<FacetBox
- property="assignees"
->
+<FacetBox>
<FacetHeader
name="issues.facet.assignees"
onClear={[Function]}
<FacetItem
active={false}
disabled={false}
- facetMode="count"
halfWidth={false}
name="unassigned"
onClick={[Function]}
- stat={5}
+ stat="5"
value=""
/>
<FacetItem
active={false}
disabled={false}
- facetMode="count"
halfWidth={false}
name={
<span>
</span>
}
onClick={[Function]}
- stat={13}
+ stat="13"
value="foo"
/>
<FacetItem
active={false}
disabled={false}
- facetMode="count"
halfWidth={false}
name="bar"
onClick={[Function]}
- stat={7}
+ stat="7"
value="bar"
/>
</FacetItemsList>
`;
exports[`should render without stats 1`] = `
-<FacetBox
- property="assignees"
->
+<FacetBox>
<FacetHeader
name="issues.facet.assignees"
onClear={[Function]}
`;
exports[`should select unassigned 1`] = `
-<FacetBox
- property="assignees"
->
+<FacetBox>
<FacetHeader
name="issues.facet.assignees"
onClear={[Function]}
<FacetItem
active={true}
disabled={false}
- facetMode="count"
halfWidth={false}
name="unassigned"
onClick={[Function]}
- stat={5}
+ stat="5"
value=""
/>
<FacetItem
active={false}
disabled={false}
- facetMode="count"
halfWidth={false}
name={
<span>
</span>
}
onClick={[Function]}
- stat={13}
+ stat="13"
value="foo"
/>
<FacetItem
active={false}
disabled={false}
- facetMode="count"
halfWidth={false}
name="bar"
onClick={[Function]}
- stat={7}
+ stat="7"
value="bar"
/>
</FacetItemsList>
`;
exports[`should select user 1`] = `
-<FacetBox
- property="assignees"
->
+<FacetBox>
<FacetHeader
name="issues.facet.assignees"
onClear={[Function]}
<FacetItem
active={false}
disabled={false}
- facetMode="count"
halfWidth={false}
name="unassigned"
onClick={[Function]}
- stat={5}
+ stat="5"
value=""
/>
<FacetItem
active={true}
disabled={false}
- facetMode="count"
halfWidth={false}
name={
<span>
</span>
}
onClick={[Function]}
- stat={13}
+ stat="13"
value="foo"
/>
<FacetItem
active={false}
disabled={false}
- facetMode="count"
halfWidth={false}
name="bar"
onClick={[Function]}
- stat={7}
+ stat="7"
value="bar"
/>
</FacetItemsList>
+++ /dev/null
-/*
- * 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';
-
-type Props = {|
- children?: React.Element<*>,
- property: string
-|};
-
-export default function FacetBox(props: Props) {
- return (
- <div className="search-navigator-facet-box" data-property={props.property}>
- {props.children}
- </div>
- );
-}
+++ /dev/null
-/*
- * 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 SearchSelect from '../../components/SearchSelect';
-
-type Option = { label: string, value: string };
-
-type Props = {|
- minimumQueryLength?: number,
- onSearch: (query: string) => Promise<Array<Option>>,
- onSelect: (value: string) => void,
- renderOption?: (option: Object) => React.Element<*>
-|};
-
-export default class FacetFooter extends React.PureComponent {
- props: Props;
-
- render() {
- return (
- <div className="search-navigator-facet-footer">
- <SearchSelect autofocus={false} {...this.props} />
- </div>
- );
- }
-}
+++ /dev/null
-/*
- * 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
-/* eslint-disable max-len */
-import React from 'react';
-import { translate } from '../../../../helpers/l10n';
-
-type Props = {|
- name: string,
- onClear?: () => void,
- onClick?: () => void,
- open: boolean,
- values?: number
-|};
-
-export default class FacetHeader extends React.PureComponent {
- props: Props;
-
- static defaultProps = {
- open: true
- };
-
- handleClearClick = (event: Event & { currentTarget: HTMLElement }) => {
- event.preventDefault();
- event.currentTarget.blur();
- if (this.props.onClear) {
- this.props.onClear();
- }
- };
-
- handleClick = (event: Event & { currentTarget: HTMLElement }) => {
- event.preventDefault();
- event.currentTarget.blur();
- if (this.props.onClick) {
- this.props.onClick();
- }
- };
-
- renderCheckbox() {
- return (
- <svg viewBox="0 0 1792 1792" width="10" height="10" style={{ paddingTop: 3 }}>
- {this.props.open
- ? <path
- style={{ fill: 'currentColor ' }}
- d="M1683 808l-742 741q-19 19-45 19t-45-19l-742-741q-19-19-19-45.5t19-45.5l166-165q19-19 45-19t45 19l531 531 531-531q19-19 45-19t45 19l166 165q19 19 19 45.5t-19 45.5z"
- />
- : <path
- style={{ fill: 'currentColor ' }}
- d="M1363 877l-742 742q-19 19-45 19t-45-19l-166-166q-19-19-19-45t19-45l531-531-531-531q-19-19-19-45t19-45l166-166q19-19 45-19t45 19l742 742q19 19 19 45t-19 45z"
- />}
- </svg>
- );
- }
-
- renderValueIndicator() {
- if (this.props.open || !this.props.values) {
- return null;
- }
- return (
- <span className="spacer-left badge is-rounded">
- {this.props.values}
- </span>
- );
- }
-
- render() {
- const showClearButton: boolean = !!this.props.values && this.props.onClear != null;
-
- return (
- <div>
- {showClearButton &&
- <button
- className="search-navigator-facet-header-button button-small button-red"
- onClick={this.handleClearClick}>
- {translate('clear')}
- </button>}
-
- {this.props.onClick
- ? <a className="search-navigator-facet-header" href="#" onClick={this.handleClick}>
- {this.renderCheckbox()} {this.props.name} {this.renderValueIndicator()}
- </a>
- : <span className="search-navigator-facet-header">
- {this.props.name}
- </span>}
- </div>
- );
- }
-}
+++ /dev/null
-/*
- * 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 classNames from 'classnames';
-import { formatMeasure } from '../../../../helpers/measures';
-
-type Props = {|
- active: boolean,
- disabled: boolean,
- facetMode: string,
- halfWidth: boolean,
- name: string | React.Element<*>,
- onClick: string => void,
- stat: ?number,
- value: string
-|};
-
-export default class FacetItem extends React.PureComponent {
- props: Props;
-
- static defaultProps = {
- disabled: false,
- halfWidth: false
- };
-
- handleClick = (event: Event & { currentTarget: HTMLElement }) => {
- event.preventDefault();
- const value = event.currentTarget.dataset.value;
- this.props.onClick(value);
- };
-
- render() {
- const { stat } = this.props;
-
- const className = classNames('facet', 'search-navigator-facet', {
- active: this.props.active,
- 'search-navigator-facet-half': this.props.halfWidth
- });
-
- const formattedStat =
- stat &&
- formatMeasure(stat, this.props.facetMode === 'effort' ? 'SHORT_WORK_DUR' : 'SHORT_INT');
-
- return this.props.disabled
- ? <span className={className}>
- <span className="facet-name">
- {this.props.name}
- </span>
- {formattedStat != null &&
- <span className="facet-stat">
- {formattedStat}
- </span>}
- </span>
- : <a className={className} data-value={this.props.value} href="#" onClick={this.handleClick}>
- <span className="facet-name">
- {this.props.name}
- </span>
- {formattedStat != null &&
- <span className="facet-stat">
- {formattedStat}
- </span>}
- </a>;
- }
-}
+++ /dev/null
-/*
- * 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';
-
-type Props = {|
- children?: Array<React.Element<*>>
-|};
-
-export default function FacetItemsList(props: Props) {
- return (
- <div className="search-navigator-facet-list">
- {props.children}
- </div>
- );
-}
+++ /dev/null
-/*
- * 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 { shallow } from 'enzyme';
-import FacetBox from '../FacetBox';
-
-it('should render', () => {
- expect(
- shallow(
- <FacetBox property="foo">
- <div />
- </FacetBox>
- )
- ).toMatchSnapshot();
-});
+++ /dev/null
-/*
- * 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 { shallow } from 'enzyme';
-import FacetFooter from '../FacetFooter';
-
-it('should render', () => {
- expect(shallow(<FacetFooter onSearch={jest.fn()} onSelect={jest.fn()} />)).toMatchSnapshot();
-});
+++ /dev/null
-/*
- * 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 { shallow } from 'enzyme';
-import { click } from '../../../../../helpers/testUtils';
-import FacetHeader from '../FacetHeader';
-
-it('should render open facet with value', () => {
- expect(
- shallow(<FacetHeader name="foo" onClick={jest.fn()} open={true} values={1} />)
- ).toMatchSnapshot();
-});
-
-it('should render open facet without value', () => {
- expect(shallow(<FacetHeader name="foo" onClick={jest.fn()} open={true} />)).toMatchSnapshot();
-});
-
-it('should render closed facet with value', () => {
- expect(
- shallow(<FacetHeader name="foo" onClick={jest.fn()} open={false} values={1} />)
- ).toMatchSnapshot();
-});
-
-it('should render closed facet without value', () => {
- expect(shallow(<FacetHeader name="foo" onClick={jest.fn()} open={false} />)).toMatchSnapshot();
-});
-
-it('should render without link', () => {
- expect(shallow(<FacetHeader name="foo" open={false} />)).toMatchSnapshot();
-});
-
-it('should call onClick', () => {
- const onClick = jest.fn();
- const wrapper = shallow(<FacetHeader name="foo" onClick={onClick} open={false} />);
- click(wrapper.find('a'));
- expect(onClick).toHaveBeenCalled();
-});
-
-it('should clear', () => {
- const onClear = jest.fn();
- const wrapper = shallow(
- <FacetHeader name="foo" onClear={onClear} onClick={jest.fn()} open={false} values={3} />
- );
- expect(wrapper).toMatchSnapshot();
- click(wrapper.find('.button-red'));
- expect(onClear).toHaveBeenCalled();
-});
+++ /dev/null
-/*
- * 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 { shallow } from 'enzyme';
-import { click } from '../../../../../helpers/testUtils';
-import FacetItem from '../FacetItem';
-
-const renderFacetItem = (props: {}) =>
- shallow(
- <FacetItem
- active={false}
- facetMode="count"
- name="foo"
- onClick={jest.fn()}
- stat={null}
- value="bar"
- {...props}
- />
- );
-
-it('should render active', () => {
- expect(renderFacetItem({ active: true })).toMatchSnapshot();
-});
-
-it('should render inactive', () => {
- expect(renderFacetItem({ active: false })).toMatchSnapshot();
-});
-
-it('should render stat', () => {
- expect(renderFacetItem({ stat: 13 })).toMatchSnapshot();
-});
-
-it('should render disabled', () => {
- expect(renderFacetItem({ disabled: true })).toMatchSnapshot();
-});
-
-it('should render half width', () => {
- expect(renderFacetItem({ halfWidth: true })).toMatchSnapshot();
-});
-
-it('should render effort stat', () => {
- expect(renderFacetItem({ facetMode: 'effort', stat: 1234 })).toMatchSnapshot();
-});
-
-it('should call onClick', () => {
- const onClick = jest.fn();
- const wrapper = renderFacetItem({ onClick });
- click(wrapper, { currentTarget: { dataset: { value: 'bar' } } });
- expect(onClick).toHaveBeenCalled();
-});
+++ /dev/null
-/*
- * 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 { shallow } from 'enzyme';
-import FacetItemsList from '../FacetItemsList';
-
-it('should render', () => {
- expect(
- shallow(
- <FacetItemsList>
- <div />
- </FacetItemsList>
- )
- ).toMatchSnapshot();
-});
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render 1`] = `
-<div
- className="search-navigator-facet-box"
- data-property="foo"
->
- <div />
-</div>
-`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render 1`] = `
-<div
- className="search-navigator-facet-footer"
->
- <SearchSelect
- autofocus={false}
- minimumQueryLength={2}
- onSearch={[Function]}
- onSelect={[Function]}
- resetOnBlur={true}
- />
-</div>
-`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should clear 1`] = `
-<div>
- <button
- className="search-navigator-facet-header-button button-small button-red"
- onClick={[Function]}
- >
- clear
- </button>
- <a
- className="search-navigator-facet-header"
- href="#"
- onClick={[Function]}
- >
- <svg
- height="10"
- style={
- Object {
- "paddingTop": 3,
- }
- }
- viewBox="0 0 1792 1792"
- width="10"
- >
- <path
- d="M1363 877l-742 742q-19 19-45 19t-45-19l-166-166q-19-19-19-45t19-45l531-531-531-531q-19-19-19-45t19-45l166-166q19-19 45-19t45 19l742 742q19 19 19 45t-19 45z"
- style={
- Object {
- "fill": "currentColor ",
- }
- }
- />
- </svg>
-
- foo
-
- <span
- className="spacer-left badge is-rounded"
- >
- 3
- </span>
- </a>
-</div>
-`;
-
-exports[`should render closed facet with value 1`] = `
-<div>
- <a
- className="search-navigator-facet-header"
- href="#"
- onClick={[Function]}
- >
- <svg
- height="10"
- style={
- Object {
- "paddingTop": 3,
- }
- }
- viewBox="0 0 1792 1792"
- width="10"
- >
- <path
- d="M1363 877l-742 742q-19 19-45 19t-45-19l-166-166q-19-19-19-45t19-45l531-531-531-531q-19-19-19-45t19-45l166-166q19-19 45-19t45 19l742 742q19 19 19 45t-19 45z"
- style={
- Object {
- "fill": "currentColor ",
- }
- }
- />
- </svg>
-
- foo
-
- <span
- className="spacer-left badge is-rounded"
- >
- 1
- </span>
- </a>
-</div>
-`;
-
-exports[`should render closed facet without value 1`] = `
-<div>
- <a
- className="search-navigator-facet-header"
- href="#"
- onClick={[Function]}
- >
- <svg
- height="10"
- style={
- Object {
- "paddingTop": 3,
- }
- }
- viewBox="0 0 1792 1792"
- width="10"
- >
- <path
- d="M1363 877l-742 742q-19 19-45 19t-45-19l-166-166q-19-19-19-45t19-45l531-531-531-531q-19-19-19-45t19-45l166-166q19-19 45-19t45 19l742 742q19 19 19 45t-19 45z"
- style={
- Object {
- "fill": "currentColor ",
- }
- }
- />
- </svg>
-
- foo
-
- </a>
-</div>
-`;
-
-exports[`should render open facet with value 1`] = `
-<div>
- <a
- className="search-navigator-facet-header"
- href="#"
- onClick={[Function]}
- >
- <svg
- height="10"
- style={
- Object {
- "paddingTop": 3,
- }
- }
- viewBox="0 0 1792 1792"
- width="10"
- >
- <path
- d="M1683 808l-742 741q-19 19-45 19t-45-19l-742-741q-19-19-19-45.5t19-45.5l166-165q19-19 45-19t45 19l531 531 531-531q19-19 45-19t45 19l166 165q19 19 19 45.5t-19 45.5z"
- style={
- Object {
- "fill": "currentColor ",
- }
- }
- />
- </svg>
-
- foo
-
- </a>
-</div>
-`;
-
-exports[`should render open facet without value 1`] = `
-<div>
- <a
- className="search-navigator-facet-header"
- href="#"
- onClick={[Function]}
- >
- <svg
- height="10"
- style={
- Object {
- "paddingTop": 3,
- }
- }
- viewBox="0 0 1792 1792"
- width="10"
- >
- <path
- d="M1683 808l-742 741q-19 19-45 19t-45-19l-742-741q-19-19-19-45.5t19-45.5l166-165q19-19 45-19t45 19l531 531 531-531q19-19 45-19t45 19l166 165q19 19 19 45.5t-19 45.5z"
- style={
- Object {
- "fill": "currentColor ",
- }
- }
- />
- </svg>
-
- foo
-
- </a>
-</div>
-`;
-
-exports[`should render without link 1`] = `
-<div>
- <span
- className="search-navigator-facet-header"
- >
- foo
- </span>
-</div>
-`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render active 1`] = `
-<a
- className="facet search-navigator-facet active"
- data-value="bar"
- href="#"
- onClick={[Function]}
->
- <span
- className="facet-name"
- >
- foo
- </span>
-</a>
-`;
-
-exports[`should render disabled 1`] = `
-<span
- className="facet search-navigator-facet"
->
- <span
- className="facet-name"
- >
- foo
- </span>
-</span>
-`;
-
-exports[`should render effort stat 1`] = `
-<a
- className="facet search-navigator-facet"
- data-value="bar"
- href="#"
- onClick={[Function]}
->
- <span
- className="facet-name"
- >
- foo
- </span>
- <span
- className="facet-stat"
- >
- work_duration.x_days.3
- </span>
-</a>
-`;
-
-exports[`should render half width 1`] = `
-<a
- className="facet search-navigator-facet search-navigator-facet-half"
- data-value="bar"
- href="#"
- onClick={[Function]}
->
- <span
- className="facet-name"
- >
- foo
- </span>
-</a>
-`;
-
-exports[`should render inactive 1`] = `
-<a
- className="facet search-navigator-facet"
- data-value="bar"
- href="#"
- onClick={[Function]}
->
- <span
- className="facet-name"
- >
- foo
- </span>
-</a>
-`;
-
-exports[`should render stat 1`] = `
-<a
- className="facet search-navigator-facet"
- data-value="bar"
- href="#"
- onClick={[Function]}
->
- <span
- className="facet-name"
- >
- foo
- </span>
- <span
- className="facet-stat"
- >
- 13
- </span>
-</a>
-`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render 1`] = `
-<div
- className="search-navigator-facet-list"
->
- <div />
-</div>
-`;
// @flow
import { searchMembers } from '../../api/organizations';
import { searchUsers } from '../../api/users';
+import { formatMeasure } from '../../helpers/measures';
import {
queriesEqual,
cleanQuery,
return result;
};
+export const formatFacetStat = (stat: ?number, mode: string): ?string => {
+ if (stat != null) {
+ return formatMeasure(stat, mode === 'effort' ? 'SHORT_WORK_DUR' : 'SHORT_INT');
+ }
+};
+
export type ReferencedComponent = {
key: string,
name: string,
--- /dev/null
+/*
+ * 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 Select from 'react-select';
+import { debounce } from 'lodash';
+import { translate, translateWithParameters } from '../../helpers/l10n';
+
+type Option = { label: string, value: string };
+
+type Props = {|
+ autofocus: boolean,
+ minimumQueryLength: number,
+ onSearch: (query: string) => Promise<Array<Option>>,
+ onSelect: (value: string) => void,
+ renderOption?: (option: Object) => React.Element<*>,
+ resetOnBlur: boolean,
+ value?: string
+|};
+
+type State = {
+ loading: boolean,
+ options: Array<Option>,
+ query: string
+};
+
+export default class SearchSelect extends React.PureComponent {
+ mounted: boolean;
+ props: Props;
+ state: State;
+
+ static defaultProps = {
+ autofocus: true,
+ minimumQueryLength: 2,
+ resetOnBlur: true
+ };
+
+ constructor(props: Props) {
+ super(props);
+ this.state = { loading: false, options: [], query: '' };
+ this.search = debounce(this.search, 250);
+ }
+
+ componentDidMount() {
+ this.mounted = true;
+ }
+
+ componentWillUnmount() {
+ this.mounted = false;
+ }
+
+ search = (query: string) => {
+ this.props.onSearch(query).then(options => {
+ if (this.mounted) {
+ this.setState({ loading: false, options });
+ }
+ });
+ };
+
+ handleBlur = () => {
+ this.setState({ options: [], query: '' });
+ };
+
+ handleChange = (option: Option) => {
+ this.props.onSelect(option.value);
+ };
+
+ handleInputChange = (query: string = '') => {
+ if (query.length >= this.props.minimumQueryLength) {
+ this.setState({ loading: true, query });
+ this.search(query);
+ } else {
+ this.setState({ options: [], query });
+ }
+ };
+
+ // disable internal filtering
+ handleFilterOption = () => true;
+
+ render() {
+ return (
+ <Select
+ autofocus={this.props.autofocus}
+ cache={false}
+ className="input-super-large"
+ clearable={false}
+ filterOption={this.handleFilterOption}
+ isLoading={this.state.loading}
+ noResultsText={
+ this.state.query.length < this.props.minimumQueryLength
+ ? translateWithParameters('select2.tooShort', this.props.minimumQueryLength)
+ : translate('select2.noMatches')
+ }
+ onBlur={this.props.resetOnBlur ? this.handleBlur : undefined}
+ onChange={this.handleChange}
+ onInputChange={this.handleInputChange}
+ onOpen={this.props.minimumQueryLength === 0 ? this.handleInputChange : undefined}
+ optionRenderer={this.props.renderOption}
+ options={this.state.options}
+ placeholder={translate('search_verb')}
+ searchable={true}
+ value={this.props.value}
+ valueRenderer={this.props.renderOption}
+ />
+ );
+ }
+}
--- /dev/null
+/*
+ * 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 { shallow } from 'enzyme';
+import SearchSelect from '../SearchSelect';
+
+jest.mock('lodash', () => ({
+ debounce: fn => fn
+}));
+
+it('should render Select', () => {
+ expect(shallow(<SearchSelect onSearch={jest.fn()} onSelect={jest.fn()} />)).toMatchSnapshot();
+});
+
+it('should call onSelect', () => {
+ const onSelect = jest.fn();
+ const wrapper = shallow(<SearchSelect onSearch={jest.fn()} onSelect={onSelect} />);
+ wrapper.prop('onChange')({ value: 'foo' });
+ expect(onSelect).lastCalledWith('foo');
+});
+
+it('should call onSearch', () => {
+ const onSearch = jest.fn().mockReturnValue(Promise.resolve([]));
+ const wrapper = shallow(
+ <SearchSelect minimumQueryLength={2} onSearch={onSearch} onSelect={jest.fn()} />
+ );
+ wrapper.prop('onInputChange')('f');
+ expect(onSearch).not.toHaveBeenCalled();
+ wrapper.prop('onInputChange')('foo');
+ expect(onSearch).lastCalledWith('foo');
+});
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render Select 1`] = `
+<Select
+ addLabelText="Add \\"{label}\\"?"
+ arrowRenderer={[Function]}
+ autofocus={true}
+ autosize={true}
+ backspaceRemoves={true}
+ backspaceToRemoveMessage="Press backspace to remove {label}"
+ cache={false}
+ className="input-super-large"
+ clearAllText="Clear all"
+ clearRenderer={[Function]}
+ clearValueText="Clear value"
+ clearable={false}
+ deleteRemoves={true}
+ delimiter=","
+ disabled={false}
+ escapeClearsValue={true}
+ filterOption={[Function]}
+ filterOptions={[Function]}
+ ignoreAccents={true}
+ ignoreCase={true}
+ inputProps={Object {}}
+ isLoading={false}
+ joinValues={false}
+ labelKey="label"
+ matchPos="any"
+ matchProp="any"
+ menuBuffer={0}
+ menuRenderer={[Function]}
+ multi={false}
+ noResultsText="select2.tooShort.2"
+ onBlur={[Function]}
+ onBlurResetsInput={true}
+ onChange={[Function]}
+ onCloseResetsInput={true}
+ onInputChange={[Function]}
+ optionComponent={[Function]}
+ options={Array []}
+ pageSize={5}
+ placeholder="search_verb"
+ required={false}
+ scrollMenuIntoView={true}
+ searchable={true}
+ simpleValue={false}
+ tabSelectsValue={true}
+ valueComponent={[Function]}
+ valueKey="value"
+/>
+`;
--- /dev/null
+/*
+ * 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';
+
+type Props = {|
+ children?: React.Element<*>
+|};
+
+export default function FacetBox(props: Props) {
+ return (
+ <div className="search-navigator-facet-box">
+ {props.children}
+ </div>
+ );
+}
--- /dev/null
+/*
+ * 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 SearchSelect from '../controls/SearchSelect';
+
+type Option = { label: string, value: string };
+
+type Props = {|
+ minimumQueryLength?: number,
+ onSearch: (query: string) => Promise<Array<Option>>,
+ onSelect: (value: string) => void,
+ renderOption?: (option: Object) => React.Element<*>
+|};
+
+export default class FacetFooter extends React.PureComponent {
+ props: Props;
+
+ render() {
+ return (
+ <div className="search-navigator-facet-footer">
+ <SearchSelect autofocus={false} {...this.props} />
+ </div>
+ );
+ }
+}
--- /dev/null
+/*
+ * 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
+/* eslint-disable max-len */
+import React from 'react';
+import { translate } from '../../helpers/l10n';
+
+type Props = {|
+ name: string,
+ onClear?: () => void,
+ onClick?: () => void,
+ open: boolean,
+ values?: number
+|};
+
+export default class FacetHeader extends React.PureComponent {
+ props: Props;
+
+ static defaultProps = {
+ open: true
+ };
+
+ handleClearClick = (event: Event & { currentTarget: HTMLElement }) => {
+ event.preventDefault();
+ event.currentTarget.blur();
+ if (this.props.onClear) {
+ this.props.onClear();
+ }
+ };
+
+ handleClick = (event: Event & { currentTarget: HTMLElement }) => {
+ event.preventDefault();
+ event.currentTarget.blur();
+ if (this.props.onClick) {
+ this.props.onClick();
+ }
+ };
+
+ renderCheckbox() {
+ return (
+ <svg viewBox="0 0 1792 1792" width="10" height="10" style={{ paddingTop: 3 }}>
+ {this.props.open
+ ? <path
+ style={{ fill: 'currentColor ' }}
+ d="M1683 808l-742 741q-19 19-45 19t-45-19l-742-741q-19-19-19-45.5t19-45.5l166-165q19-19 45-19t45 19l531 531 531-531q19-19 45-19t45 19l166 165q19 19 19 45.5t-19 45.5z"
+ />
+ : <path
+ style={{ fill: 'currentColor ' }}
+ d="M1363 877l-742 742q-19 19-45 19t-45-19l-166-166q-19-19-19-45t19-45l531-531-531-531q-19-19-19-45t19-45l166-166q19-19 45-19t45 19l742 742q19 19 19 45t-19 45z"
+ />}
+ </svg>
+ );
+ }
+
+ renderValueIndicator() {
+ if (this.props.open || !this.props.values) {
+ return null;
+ }
+ return (
+ <span className="spacer-left badge is-rounded">
+ {this.props.values}
+ </span>
+ );
+ }
+
+ render() {
+ const showClearButton: boolean = !!this.props.values && this.props.onClear != null;
+
+ return (
+ <div>
+ {showClearButton &&
+ <button
+ className="search-navigator-facet-header-button button-small button-red"
+ onClick={this.handleClearClick}>
+ {translate('clear')}
+ </button>}
+
+ {this.props.onClick
+ ? <a className="search-navigator-facet-header" href="#" onClick={this.handleClick}>
+ {this.renderCheckbox()} {this.props.name} {this.renderValueIndicator()}
+ </a>
+ : <span className="search-navigator-facet-header">
+ {this.props.name}
+ </span>}
+ </div>
+ );
+ }
+}
--- /dev/null
+/*
+ * 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 classNames from 'classnames';
+
+type Props = {|
+ active: boolean,
+ disabled: boolean,
+ halfWidth: boolean,
+ name: string | React.Element<*>,
+ onClick: string => void,
+ stat?: ?(string | React.Element<*>),
+ value: string
+|};
+
+export default class FacetItem extends React.PureComponent {
+ props: Props;
+
+ static defaultProps = {
+ disabled: false,
+ halfWidth: false
+ };
+
+ handleClick = (event: Event & { currentTarget: HTMLElement }) => {
+ event.preventDefault();
+ this.props.onClick(this.props.value);
+ };
+
+ render() {
+ const className = classNames('facet', 'search-navigator-facet', {
+ active: this.props.active,
+ 'search-navigator-facet-half': this.props.halfWidth
+ });
+
+ return this.props.disabled
+ ? <span className={className}>
+ <span className="facet-name">
+ {this.props.name}
+ </span>
+ {this.props.stat != null &&
+ <span className="facet-stat">
+ {this.props.stat}
+ </span>}
+ </span>
+ : <a className={className} href="#" onClick={this.handleClick}>
+ <span className="facet-name">
+ {this.props.name}
+ </span>
+ {this.props.stat != null &&
+ <span className="facet-stat">
+ {this.props.stat}
+ </span>}
+ </a>;
+ }
+}
--- /dev/null
+/*
+ * 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';
+
+type Props = {|
+ children?: Array<React.Element<*>>
+|};
+
+export default function FacetItemsList(props: Props) {
+ return (
+ <div className="search-navigator-facet-list">
+ {props.children}
+ </div>
+ );
+}
--- /dev/null
+/*
+ * 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 { shallow } from 'enzyme';
+import FacetBox from '../FacetBox';
+
+it('should render', () => {
+ expect(
+ shallow(
+ <FacetBox>
+ <div />
+ </FacetBox>
+ )
+ ).toMatchSnapshot();
+});
--- /dev/null
+/*
+ * 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 { shallow } from 'enzyme';
+import FacetFooter from '../FacetFooter';
+
+it('should render', () => {
+ expect(shallow(<FacetFooter onSearch={jest.fn()} onSelect={jest.fn()} />)).toMatchSnapshot();
+});
--- /dev/null
+/*
+ * 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 { shallow } from 'enzyme';
+import { click } from '../../../helpers/testUtils';
+import FacetHeader from '../FacetHeader';
+
+it('should render open facet with value', () => {
+ expect(
+ shallow(<FacetHeader name="foo" onClick={jest.fn()} open={true} values={1} />)
+ ).toMatchSnapshot();
+});
+
+it('should render open facet without value', () => {
+ expect(shallow(<FacetHeader name="foo" onClick={jest.fn()} open={true} />)).toMatchSnapshot();
+});
+
+it('should render closed facet with value', () => {
+ expect(
+ shallow(<FacetHeader name="foo" onClick={jest.fn()} open={false} values={1} />)
+ ).toMatchSnapshot();
+});
+
+it('should render closed facet without value', () => {
+ expect(shallow(<FacetHeader name="foo" onClick={jest.fn()} open={false} />)).toMatchSnapshot();
+});
+
+it('should render without link', () => {
+ expect(shallow(<FacetHeader name="foo" open={false} />)).toMatchSnapshot();
+});
+
+it('should call onClick', () => {
+ const onClick = jest.fn();
+ const wrapper = shallow(<FacetHeader name="foo" onClick={onClick} open={false} />);
+ click(wrapper.find('a'));
+ expect(onClick).toHaveBeenCalled();
+});
+
+it('should clear', () => {
+ const onClear = jest.fn();
+ const wrapper = shallow(
+ <FacetHeader name="foo" onClear={onClear} onClick={jest.fn()} open={false} values={3} />
+ );
+ expect(wrapper).toMatchSnapshot();
+ click(wrapper.find('.button-red'));
+ expect(onClear).toHaveBeenCalled();
+});
--- /dev/null
+/*
+ * 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 { shallow } from 'enzyme';
+import { click } from '../../../helpers/testUtils';
+import FacetItem from '../FacetItem';
+
+const renderFacetItem = (props: {}) =>
+ shallow(
+ <FacetItem active={false} name="foo" onClick={jest.fn()} stat={null} value="bar" {...props} />
+ );
+
+it('should render active', () => {
+ expect(renderFacetItem({ active: true })).toMatchSnapshot();
+});
+
+it('should render inactive', () => {
+ expect(renderFacetItem({ active: false })).toMatchSnapshot();
+});
+
+it('should render stat', () => {
+ expect(renderFacetItem({ stat: '13' })).toMatchSnapshot();
+});
+
+it('should render disabled', () => {
+ expect(renderFacetItem({ disabled: true })).toMatchSnapshot();
+});
+
+it('should render half width', () => {
+ expect(renderFacetItem({ halfWidth: true })).toMatchSnapshot();
+});
+
+it('should render effort stat', () => {
+ expect(renderFacetItem({ facetMode: 'effort', stat: '1234' })).toMatchSnapshot();
+});
+
+it('should call onClick', () => {
+ const onClick = jest.fn();
+ const wrapper = renderFacetItem({ onClick });
+ click(wrapper, { currentTarget: { dataset: { value: 'bar' } } });
+ expect(onClick).toHaveBeenCalled();
+});
--- /dev/null
+/*
+ * 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 { shallow } from 'enzyme';
+import FacetItemsList from '../FacetItemsList';
+
+it('should render', () => {
+ expect(
+ shallow(
+ <FacetItemsList>
+ <div />
+ </FacetItemsList>
+ )
+ ).toMatchSnapshot();
+});
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render 1`] = `
+<div
+ className="search-navigator-facet-box"
+>
+ <div />
+</div>
+`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render 1`] = `
+<div
+ className="search-navigator-facet-footer"
+>
+ <SearchSelect
+ autofocus={false}
+ minimumQueryLength={2}
+ onSearch={[Function]}
+ onSelect={[Function]}
+ resetOnBlur={true}
+ />
+</div>
+`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should clear 1`] = `
+<div>
+ <button
+ className="search-navigator-facet-header-button button-small button-red"
+ onClick={[Function]}
+ >
+ clear
+ </button>
+ <a
+ className="search-navigator-facet-header"
+ href="#"
+ onClick={[Function]}
+ >
+ <svg
+ height="10"
+ style={
+ Object {
+ "paddingTop": 3,
+ }
+ }
+ viewBox="0 0 1792 1792"
+ width="10"
+ >
+ <path
+ d="M1363 877l-742 742q-19 19-45 19t-45-19l-166-166q-19-19-19-45t19-45l531-531-531-531q-19-19-19-45t19-45l166-166q19-19 45-19t45 19l742 742q19 19 19 45t-19 45z"
+ style={
+ Object {
+ "fill": "currentColor ",
+ }
+ }
+ />
+ </svg>
+
+ foo
+
+ <span
+ className="spacer-left badge is-rounded"
+ >
+ 3
+ </span>
+ </a>
+</div>
+`;
+
+exports[`should render closed facet with value 1`] = `
+<div>
+ <a
+ className="search-navigator-facet-header"
+ href="#"
+ onClick={[Function]}
+ >
+ <svg
+ height="10"
+ style={
+ Object {
+ "paddingTop": 3,
+ }
+ }
+ viewBox="0 0 1792 1792"
+ width="10"
+ >
+ <path
+ d="M1363 877l-742 742q-19 19-45 19t-45-19l-166-166q-19-19-19-45t19-45l531-531-531-531q-19-19-19-45t19-45l166-166q19-19 45-19t45 19l742 742q19 19 19 45t-19 45z"
+ style={
+ Object {
+ "fill": "currentColor ",
+ }
+ }
+ />
+ </svg>
+
+ foo
+
+ <span
+ className="spacer-left badge is-rounded"
+ >
+ 1
+ </span>
+ </a>
+</div>
+`;
+
+exports[`should render closed facet without value 1`] = `
+<div>
+ <a
+ className="search-navigator-facet-header"
+ href="#"
+ onClick={[Function]}
+ >
+ <svg
+ height="10"
+ style={
+ Object {
+ "paddingTop": 3,
+ }
+ }
+ viewBox="0 0 1792 1792"
+ width="10"
+ >
+ <path
+ d="M1363 877l-742 742q-19 19-45 19t-45-19l-166-166q-19-19-19-45t19-45l531-531-531-531q-19-19-19-45t19-45l166-166q19-19 45-19t45 19l742 742q19 19 19 45t-19 45z"
+ style={
+ Object {
+ "fill": "currentColor ",
+ }
+ }
+ />
+ </svg>
+
+ foo
+
+ </a>
+</div>
+`;
+
+exports[`should render open facet with value 1`] = `
+<div>
+ <a
+ className="search-navigator-facet-header"
+ href="#"
+ onClick={[Function]}
+ >
+ <svg
+ height="10"
+ style={
+ Object {
+ "paddingTop": 3,
+ }
+ }
+ viewBox="0 0 1792 1792"
+ width="10"
+ >
+ <path
+ d="M1683 808l-742 741q-19 19-45 19t-45-19l-742-741q-19-19-19-45.5t19-45.5l166-165q19-19 45-19t45 19l531 531 531-531q19-19 45-19t45 19l166 165q19 19 19 45.5t-19 45.5z"
+ style={
+ Object {
+ "fill": "currentColor ",
+ }
+ }
+ />
+ </svg>
+
+ foo
+
+ </a>
+</div>
+`;
+
+exports[`should render open facet without value 1`] = `
+<div>
+ <a
+ className="search-navigator-facet-header"
+ href="#"
+ onClick={[Function]}
+ >
+ <svg
+ height="10"
+ style={
+ Object {
+ "paddingTop": 3,
+ }
+ }
+ viewBox="0 0 1792 1792"
+ width="10"
+ >
+ <path
+ d="M1683 808l-742 741q-19 19-45 19t-45-19l-742-741q-19-19-19-45.5t19-45.5l166-165q19-19 45-19t45 19l531 531 531-531q19-19 45-19t45 19l166 165q19 19 19 45.5t-19 45.5z"
+ style={
+ Object {
+ "fill": "currentColor ",
+ }
+ }
+ />
+ </svg>
+
+ foo
+
+ </a>
+</div>
+`;
+
+exports[`should render without link 1`] = `
+<div>
+ <span
+ className="search-navigator-facet-header"
+ >
+ foo
+ </span>
+</div>
+`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render active 1`] = `
+<a
+ className="facet search-navigator-facet active"
+ href="#"
+ onClick={[Function]}
+>
+ <span
+ className="facet-name"
+ >
+ foo
+ </span>
+</a>
+`;
+
+exports[`should render disabled 1`] = `
+<span
+ className="facet search-navigator-facet"
+>
+ <span
+ className="facet-name"
+ >
+ foo
+ </span>
+</span>
+`;
+
+exports[`should render effort stat 1`] = `
+<a
+ className="facet search-navigator-facet"
+ href="#"
+ onClick={[Function]}
+>
+ <span
+ className="facet-name"
+ >
+ foo
+ </span>
+ <span
+ className="facet-stat"
+ >
+ 1234
+ </span>
+</a>
+`;
+
+exports[`should render half width 1`] = `
+<a
+ className="facet search-navigator-facet search-navigator-facet-half"
+ href="#"
+ onClick={[Function]}
+>
+ <span
+ className="facet-name"
+ >
+ foo
+ </span>
+</a>
+`;
+
+exports[`should render inactive 1`] = `
+<a
+ className="facet search-navigator-facet"
+ href="#"
+ onClick={[Function]}
+>
+ <span
+ className="facet-name"
+ >
+ foo
+ </span>
+</a>
+`;
+
+exports[`should render stat 1`] = `
+<a
+ className="facet search-navigator-facet"
+ href="#"
+ onClick={[Function]}
+>
+ <span
+ className="facet-name"
+ >
+ foo
+ </span>
+ <span
+ className="facet-stat"
+ >
+ 13
+ </span>
+</a>
+`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render 1`] = `
+<div
+ className="search-navigator-facet-list"
+>
+ <div />
+</div>
+`;