diff options
24 files changed, 303 insertions, 117 deletions
diff --git a/server/sonar-web/src/main/js/apps/organizations/components/forms/AddMemberForm.js b/server/sonar-web/src/main/js/apps/organizations/components/forms/AddMemberForm.js index 4502597be29..e59f7137a8b 100644 --- a/server/sonar-web/src/main/js/apps/organizations/components/forms/AddMemberForm.js +++ b/server/sonar-web/src/main/js/apps/organizations/components/forms/AddMemberForm.js @@ -98,7 +98,9 @@ export default class AddMemberForm extends React.PureComponent { </div> <footer className="modal-foot"> <div> - <button type="submit">{translate('organization.members.add_to_members')}</button> + <button type="submit" disabled={!this.state.selectedMember}> + {translate('organization.members.add_to_members')} + </button> <button type="reset" className="button-link" onClick={this.closeForm}> {translate('cancel')} </button> diff --git a/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/__snapshots__/AddMemberForm-test.js.snap b/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/__snapshots__/AddMemberForm-test.js.snap index 9fa2ecff49d..8fbd79d33c3 100644 --- a/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/__snapshots__/AddMemberForm-test.js.snap +++ b/server/sonar-web/src/main/js/apps/organizations/components/forms/__tests__/__snapshots__/AddMemberForm-test.js.snap @@ -61,6 +61,7 @@ exports[`should render and open the modal 2`] = ` > <div> <button + disabled={true} type="submit" > organization.members.add_to_members diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/StaticGraphs.js b/server/sonar-web/src/main/js/apps/projectActivity/components/GraphsHistory.js index a303e66b9bc..36ac11b372e 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/StaticGraphs.js +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/GraphsHistory.js @@ -19,13 +19,13 @@ */ import React from 'react'; import moment from 'moment'; -import { some, sortBy } from 'lodash'; +import { sortBy } from 'lodash'; import { AutoSizer } from 'react-virtualized'; import AdvancedTimeline from '../../../components/charts/AdvancedTimeline'; import GraphsTooltips from './GraphsTooltips'; -import StaticGraphsLegend from './StaticGraphsLegend'; +import GraphsLegendStatic from './GraphsLegendStatic'; import { formatMeasure, getShortType } from '../../../helpers/measures'; -import { EVENT_TYPES, isCustomGraph } from '../utils'; +import { EVENT_TYPES, hasHistoryData, isCustomGraph } from '../utils'; import { translate } from '../../../helpers/l10n'; import type { Analysis, MeasureHistory } from '../types'; import type { Serie } from '../../../components/charts/AdvancedTimeline'; @@ -52,7 +52,7 @@ type State = { tooltipXPos: ?number }; -export default class StaticGraphs extends React.PureComponent { +export default class GraphsHistory extends React.PureComponent { props: Props; state: State = { tooltipIdx: null, @@ -99,13 +99,12 @@ export default class StaticGraphs extends React.PureComponent { return []; }; - hasSeriesData = () => some(this.props.series, serie => serie.data && serie.data.length > 2); - updateTooltip = (selectedDate: ?Date, tooltipXPos: ?number, tooltipIdx: ?number) => this.setState({ selectedDate, tooltipXPos, tooltipIdx }); render() { const { loading } = this.props; + const { graph, series } = this.props; if (loading) { return ( @@ -117,7 +116,7 @@ export default class StaticGraphs extends React.PureComponent { ); } - if (!this.hasSeriesData()) { + if (!hasHistoryData(series)) { return ( <div className="project-activity-graph-container"> <div className="note text-center"> @@ -132,10 +131,9 @@ export default class StaticGraphs extends React.PureComponent { } const { selectedDate, tooltipIdx, tooltipXPos } = this.state; - const { graph, series } = this.props; return ( <div className="project-activity-graph-container"> - <StaticGraphsLegend series={series} /> + <GraphsLegendStatic series={series} /> <div className="project-activity-graph"> <AutoSizer> {({ height, width }) => ( diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/StaticGraphsLegend.js b/server/sonar-web/src/main/js/apps/projectActivity/components/GraphsLegendStatic.js index a1ceab688f4..7dffdf75321 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/StaticGraphsLegend.js +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/GraphsLegendStatic.js @@ -25,7 +25,7 @@ type Props = { series: Array<{ name: string, translatedName: string, style: string }> }; -export default function StaticGraphsLegend({ series }: Props) { +export default function GraphsLegendStatic({ series }: Props) { return ( <div className="project-activity-graph-legends"> {series.map(serie => ( diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/GraphsZoom.js b/server/sonar-web/src/main/js/apps/projectActivity/components/GraphsZoom.js index 73e9411b862..f6e6bab8dc7 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/GraphsZoom.js +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/GraphsZoom.js @@ -19,9 +19,9 @@ */ // @flow import React from 'react'; -import { some } from 'lodash'; import { AutoSizer } from 'react-virtualized'; import ZoomTimeLine from '../../../components/charts/ZoomTimeLine'; +import { hasHistoryData } from '../utils'; import type { Serie } from '../../../components/charts/AdvancedTimeline'; type Props = { @@ -35,37 +35,31 @@ type Props = { updateGraphZoom: (from: ?Date, to: ?Date) => void }; -export default class GraphsZoom extends React.PureComponent { - props: Props; - - hasHistoryData = () => some(this.props.series, serie => serie.data && serie.data.length > 2); - - render() { - const { loading } = this.props; - if (loading || !this.hasHistoryData()) { - return null; - } - - return ( - <div className="project-activity-graph-zoom"> - <AutoSizer disableHeight={true}> - {({ width }) => ( - <ZoomTimeLine - endDate={this.props.graphEndDate} - height={64} - width={width} - interpolate="linear" - leakPeriodDate={this.props.leakPeriodDate} - metricType={this.props.metricsType} - padding={[0, 10, 18, 60]} - series={this.props.series} - showAreas={this.props.showAreas} - startDate={this.props.graphStartDate} - updateZoom={this.props.updateGraphZoom} - /> - )} - </AutoSizer> - </div> - ); +export default function GraphsZoom(props: Props) { + const { loading } = props; + if (loading || !hasHistoryData(props.series)) { + return null; } + + return ( + <div className="project-activity-graph-zoom"> + <AutoSizer disableHeight={true}> + {({ width }) => ( + <ZoomTimeLine + endDate={props.graphEndDate} + height={64} + width={width} + interpolate="linear" + leakPeriodDate={props.leakPeriodDate} + metricType={props.metricsType} + padding={[0, 10, 18, 60]} + series={props.series} + showAreas={props.showAreas} + startDate={props.graphStartDate} + updateZoom={props.updateGraphZoom} + /> + )} + </AutoSizer> + </div> + ); } diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityApp.js b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityApp.js index 954c6169f29..02a1f1b5eb3 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityApp.js +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityApp.js @@ -125,6 +125,7 @@ export default class ProjectActivityApp extends React.PureComponent { leakPeriodDate={moment(this.props.project.leakPeriodDate).toDate()} loading={this.props.graphLoading} measuresHistory={measuresHistory} + metrics={this.props.metrics} metricsType={this.getMetricType()} project={this.props.project.key} query={query} diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityGraphs.js b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityGraphs.js index 7fb3bb818f6..0b86b71bdc5 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityGraphs.js +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityGraphs.js @@ -22,7 +22,7 @@ import React from 'react'; import { debounce, findLast, maxBy, minBy, sortBy } from 'lodash'; import ProjectActivityGraphsHeader from './ProjectActivityGraphsHeader'; import GraphsZoom from './GraphsZoom'; -import StaticGraphs from './StaticGraphs'; +import GraphsHistory from './GraphsHistory'; import { datesQueryChanged, generateSeries, @@ -30,7 +30,7 @@ import { historyQueryChanged } from '../utils'; import type { RawQuery } from '../../../helpers/query'; -import type { Analysis, MeasureHistory, Query } from '../types'; +import type { Analysis, MeasureHistory, Metric, Query } from '../types'; import type { Serie } from '../../../components/charts/AdvancedTimeline'; type Props = { @@ -38,6 +38,7 @@ type Props = { leakPeriodDate: Date, loading: boolean, measuresHistory: Array<MeasureHistory>, + metrics: Array<Metric>, metricsType: string, project: string, query: Query, @@ -136,8 +137,13 @@ export default class ProjectActivityGraphs extends React.PureComponent { const { series } = this.state; return ( <div className="project-activity-layout-page-main-inner boxed-group boxed-group-inner"> - <ProjectActivityGraphsHeader graph={query.graph} updateQuery={this.props.updateQuery} /> - <StaticGraphs + <ProjectActivityGraphsHeader + graph={query.graph} + metrics={this.props.metrics} + selectedMetrics={this.props.query.customMetrics} + updateQuery={this.props.updateQuery} + /> + <GraphsHistory analyses={this.props.analyses} eventFilter={query.category} graph={query.graph} diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityGraphsHeader.js b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityGraphsHeader.js index 33ee4ffab72..194af091b69 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityGraphsHeader.js +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityGraphsHeader.js @@ -20,13 +20,17 @@ // @flow import React from 'react'; import Select from 'react-select'; -import { GRAPH_TYPES } from '../utils'; +import AddGraphMetric from './forms/AddGraphMetric'; +import { isCustomGraph, GRAPH_TYPES } from '../utils'; import { translate } from '../../../helpers/l10n'; +import type { Metric } from '../types'; import type { RawQuery } from '../../../helpers/query'; type Props = { - updateQuery: RawQuery => void, - graph: string + graph: string, + metrics: Array<Metric>, + selectedMetrics: Array<string>, + updateQuery: RawQuery => void }; export default class ProjectActivityGraphsHeader extends React.PureComponent { @@ -38,6 +42,11 @@ export default class ProjectActivityGraphsHeader extends React.PureComponent { } }; + handleAddMetric = (metric: string) => { + const selectedMetrics = [...this.props.selectedMetrics, metric]; + this.props.updateQuery({ customMetrics: selectedMetrics }); + }; + render() { const selectOptions = GRAPH_TYPES.map(graph => ({ label: translate('project_activity.graphs', graph), @@ -54,6 +63,13 @@ export default class ProjectActivityGraphsHeader extends React.PureComponent { options={selectOptions} onChange={this.handleGraphChange} /> + {isCustomGraph(this.props.graph) && + <AddGraphMetric + addMetric={this.handleAddMetric} + className="spacer-left" + metrics={this.props.metrics} + selectedMetrics={this.props.selectedMetrics} + />} </header> ); } diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/StaticGraphs-test.js b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/GraphsHistory-test.js index dacaff2025f..94d9d326340 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/StaticGraphs-test.js +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/GraphsHistory-test.js @@ -19,7 +19,7 @@ */ import React from 'react'; import { shallow } from 'enzyme'; -import StaticGraphs from '../StaticGraphs'; +import GraphsHistory from '../GraphsHistory'; const ANALYSES = [ { @@ -95,20 +95,20 @@ const DEFAULT_PROPS = { }; it('should show a loading view', () => { - expect(shallow(<StaticGraphs {...DEFAULT_PROPS} loading={true} />)).toMatchSnapshot(); + expect(shallow(<GraphsHistory {...DEFAULT_PROPS} loading={true} />)).toMatchSnapshot(); }); it('should show that there is no data', () => { - expect(shallow(<StaticGraphs {...DEFAULT_PROPS} series={EMPTY_SERIES} />)).toMatchSnapshot(); + expect(shallow(<GraphsHistory {...DEFAULT_PROPS} series={EMPTY_SERIES} />)).toMatchSnapshot(); }); it('should correctly render a graph', () => { - expect(shallow(<StaticGraphs {...DEFAULT_PROPS} />)).toMatchSnapshot(); + expect(shallow(<GraphsHistory {...DEFAULT_PROPS} />)).toMatchSnapshot(); }); it('should correctly filter events', () => { - expect(shallow(<StaticGraphs {...DEFAULT_PROPS} />).instance().getEvents()).toMatchSnapshot(); + expect(shallow(<GraphsHistory {...DEFAULT_PROPS} />).instance().getEvents()).toMatchSnapshot(); expect( - shallow(<StaticGraphs {...DEFAULT_PROPS} eventFilter="OTHER" />).instance().getEvents() + shallow(<GraphsHistory {...DEFAULT_PROPS} eventFilter="OTHER" />).instance().getEvents() ).toMatchSnapshot(); }); diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/StaticGraphsLegend-test.js b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/GraphsLegendStatic-test.js index 05d28fa8da9..2226ebb4208 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/StaticGraphsLegend-test.js +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/GraphsLegendStatic-test.js @@ -19,7 +19,7 @@ */ import React from 'react'; import { shallow } from 'enzyme'; -import StaticGraphsLegend from '../StaticGraphsLegend'; +import GraphsLegendStatic from '../GraphsLegendStatic'; const SERIES = [ { name: 'bugs', translatedName: 'Bugs', style: '2', data: [] }, @@ -27,5 +27,5 @@ const SERIES = [ ]; it('should render correctly the list of series', () => { - expect(shallow(<StaticGraphsLegend series={SERIES} />)).toMatchSnapshot(); + expect(shallow(<GraphsLegendStatic series={SERIES} />)).toMatchSnapshot(); }); diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/StaticGraphs-test.js.snap b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/GraphsHistory-test.js.snap index ba33441a2a6..06e5621c923 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/StaticGraphs-test.js.snap +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/GraphsHistory-test.js.snap @@ -29,7 +29,7 @@ exports[`should correctly render a graph 1`] = ` <div className="project-activity-graph-container" > - <StaticGraphsLegend + <GraphsLegendStatic series={ Array [ Object { diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/StaticGraphsLegend-test.js.snap b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/GraphsLegendStatic-test.js.snap index 1fd564f69ef..1fd564f69ef 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/StaticGraphsLegend-test.js.snap +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/GraphsLegendStatic-test.js.snap diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityApp-test.js.snap b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityApp-test.js.snap index 91f1dcdc0e4..1943a2f48ac 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityApp-test.js.snap +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityApp-test.js.snap @@ -179,6 +179,15 @@ exports[`should render correctly 1`] = ` }, ] } + metrics={ + Array [ + Object { + "key": "code_smells", + "name": "Code Smells", + "type": "INT", + }, + ] + } metricsType="INT" project="org.sonarsource.sonarqube:sonarqube" query={ diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityGraphs-test.js.snap b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityGraphs-test.js.snap index 6da3cc4d3bb..3c46221619f 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityGraphs-test.js.snap +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/__snapshots__/ProjectActivityGraphs-test.js.snap @@ -8,7 +8,7 @@ exports[`should render correctly the graph and legends 1`] = ` graph="overview" updateQuery={[Function]} /> - <StaticGraphs + <GraphsHistory analyses={ Array [ Object { diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/forms/AddGraphMetric.js b/server/sonar-web/src/main/js/apps/projectActivity/components/forms/AddGraphMetric.js new file mode 100644 index 00000000000..a7193b62093 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/forms/AddGraphMetric.js @@ -0,0 +1,147 @@ +/* + * 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 Modal from 'react-modal'; +import Select from 'react-select'; +import { translate } from '../../../../helpers/l10n'; +import type { Metric } from '../../types'; + +type Props = { + addMetric: (metric: string) => void, + className?: string, + metrics: Array<Metric>, + selectedMetrics: Array<string> +}; + +type State = { + open: boolean, + selectedMetric?: string +}; + +export default class AddGraphMetric extends React.PureComponent { + props: Props; + state: State = { + open: false + }; + + getMetricsType = () => { + if (this.props.selectedMetrics.length > 0) { + const metric = this.props.metrics.find( + metric => metric.key === this.props.selectedMetrics[0] + ); + return metric && metric.type; + } + }; + + getMetricsOptions = () => { + const selectedType = this.getMetricsType(); + return this.props.metrics + .filter(metric => { + if (metric.hidden) { + return false; + } + if (selectedType) { + return selectedType === metric.type && !this.props.selectedMetrics.includes(metric.key); + } + return true; + }) + .map((metric: Metric) => ({ + value: metric.key, + label: metric.custom ? metric.name : translate('metric', metric.key, 'name') + })); + }; + + openForm = () => { + this.setState({ + open: true + }); + }; + + closeForm = () => { + this.setState({ + open: false, + selectedMetric: undefined + }); + }; + + handleChange = (option: { value: string, label: string }) => + this.setState({ selectedMetric: option.value }); + + handleSubmit = (e: Object) => { + e.preventDefault(); + if (this.state.selectedMetric) { + this.props.addMetric(this.state.selectedMetric); + this.closeForm(); + } + }; + + renderModal() { + return ( + <Modal + isOpen={true} + contentLabel="graph metric add" + className="modal" + overlayClassName="modal-overlay" + onRequestClose={this.closeForm}> + <header className="modal-head"> + <h2>{translate('project_activity.graphs.custom.add_metric')}</h2> + </header> + <form onSubmit={this.handleSubmit}> + <div className="modal-body"> + <div className="modal-large-field"> + <label>{translate('project_activity.graphs.custom.search')}</label> + <Select + autofocus={true} + className="Select-big" + clearable={false} + noResultsText={translate('no_results')} + onChange={this.handleChange} + options={this.getMetricsOptions()} + placeholder="" + searchable={true} + value={this.state.selectedMetric} + /> + </div> + </div> + <footer className="modal-foot"> + <div> + <button type="submit" disabled={!this.state.selectedMetric}> + {translate('project_activity.graphs.custom.add')} + </button> + <button type="reset" className="button-link" onClick={this.closeForm}> + {translate('cancel')} + </button> + </div> + </footer> + </form> + </Modal> + ); + } + + render() { + return ( + <button className={this.props.className} onClick={this.openForm}> + {translate('project_activity.graphs.custom.add')} + {this.state.open && this.renderModal()} + </button> + ); + } +} diff --git a/server/sonar-web/src/main/js/apps/projectActivity/types.js b/server/sonar-web/src/main/js/apps/projectActivity/types.js index 9a9c96abf71..ab6c9fa78a3 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/types.js +++ b/server/sonar-web/src/main/js/apps/projectActivity/types.js @@ -37,6 +37,8 @@ export type HistoryItem = { date: Date, value: string }; export type MeasureHistory = { metric: string, history: Array<HistoryItem> }; export type Metric = { + custom?: boolean, + hidden?: boolean, key: string, name: string, type: string diff --git a/server/sonar-web/src/main/js/apps/projectActivity/utils.js b/server/sonar-web/src/main/js/apps/projectActivity/utils.js index 9ee44a3fc59..24c4f3fecc6 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/utils.js +++ b/server/sonar-web/src/main/js/apps/projectActivity/utils.js @@ -65,6 +65,11 @@ export const datesQueryChanged = (prevQuery: Query, nextQuery: Query): boolean = return previousFrom !== nextFrom || previousTo !== nextTo; }; +export const hasHistoryData = (series: Array<Serie>) => + series.some( + serie => serie.data && serie.data.length > 2 && serie.data.some(p => p.y || p.y === 0) + ); + export const historyQueryChanged = (prevQuery: Query, nextQuery: Query): boolean => prevQuery.graph !== nextQuery.graph; diff --git a/server/sonar-web/src/main/js/apps/users/components/UsersSelectSearch.css b/server/sonar-web/src/main/js/apps/users/components/UsersSelectSearch.css deleted file mode 100644 index c8780833809..00000000000 --- a/server/sonar-web/src/main/js/apps/users/components/UsersSelectSearch.css +++ /dev/null @@ -1,13 +0,0 @@ -.Select-big .Select-control { - padding-top: 4px; - padding-bottom: 4px; -} - -.Select-big .Select-placeholder { - margin-top: 4px; - margin-bottom: 4px; -} - -.Select-big .Select-value-label { - margin-top: 5px; -} diff --git a/server/sonar-web/src/main/js/apps/users/components/UsersSelectSearch.js b/server/sonar-web/src/main/js/apps/users/components/UsersSelectSearch.js index f6a9b1ad5ee..3e887b078c4 100644 --- a/server/sonar-web/src/main/js/apps/users/components/UsersSelectSearch.js +++ b/server/sonar-web/src/main/js/apps/users/components/UsersSelectSearch.js @@ -24,7 +24,6 @@ import { debounce } from 'lodash'; import { translate, translateWithParameters } from '../../../helpers/l10n'; import UsersSelectSearchOption from './UsersSelectSearchOption'; import UsersSelectSearchValue from './UsersSelectSearchValue'; -import './UsersSelectSearch.css'; export type Option = { login: string, diff --git a/server/sonar-web/src/main/js/apps/users/components/UsersSelectSearchOption.js b/server/sonar-web/src/main/js/apps/users/components/UsersSelectSearchOption.js index e7f4a5ab428..e1b8056fd0e 100644 --- a/server/sonar-web/src/main/js/apps/users/components/UsersSelectSearchOption.js +++ b/server/sonar-web/src/main/js/apps/users/components/UsersSelectSearchOption.js @@ -62,11 +62,9 @@ export default class UsersSelectSearchOption extends React.PureComponent { onMouseEnter={this.handleMouseEnter} onMouseMove={this.handleMouseMove} title={user.name}> - <div className="little-spacer-bottom little-spacer-top"> - <Avatar hash={user.avatar} email={user.email} name={user.name} size={AVATAR_SIZE} /> - <strong className="spacer-left">{this.props.children}</strong> - <span className="note little-spacer-left">{user.login}</span> - </div> + <Avatar hash={user.avatar} email={user.email} name={user.name} size={AVATAR_SIZE} /> + <strong className="spacer-left">{this.props.children}</strong> + <span className="note little-spacer-left">{user.login}</span> </div> ); } diff --git a/server/sonar-web/src/main/js/apps/users/components/__tests__/__snapshots__/UsersSelectSearchOption-test.js.snap b/server/sonar-web/src/main/js/apps/users/components/__tests__/__snapshots__/UsersSelectSearchOption-test.js.snap index 80c53be30fe..56c7a055882 100644 --- a/server/sonar-web/src/main/js/apps/users/components/__tests__/__snapshots__/UsersSelectSearchOption-test.js.snap +++ b/server/sonar-web/src/main/js/apps/users/components/__tests__/__snapshots__/UsersSelectSearchOption-test.js.snap @@ -7,25 +7,21 @@ exports[`should render correctly with email instead of hash 1`] = ` onMouseMove={[Function]} title="Administrator" > - <div - className="little-spacer-bottom little-spacer-top" + <Connect(Avatar) + email="admin@admin.ch" + name="Administrator" + size={20} + /> + <strong + className="spacer-left" > - <Connect(Avatar) - email="admin@admin.ch" - name="Administrator" - size={20} - /> - <strong - className="spacer-left" - > - Administrator - </strong> - <span - className="note little-spacer-left" - > - admin - </span> - </div> + Administrator + </strong> + <span + className="note little-spacer-left" + > + admin + </span> </div> `; @@ -36,24 +32,20 @@ exports[`should render correctly without all parameters 1`] = ` onMouseMove={[Function]} title="Administrator" > - <div - className="little-spacer-bottom little-spacer-top" + <Connect(Avatar) + hash="7daf6c79d4802916d83f6266e24850af" + name="Administrator" + size={20} + /> + <strong + className="spacer-left" + > + Administrator + </strong> + <span + className="note little-spacer-left" > - <Connect(Avatar) - hash="7daf6c79d4802916d83f6266e24850af" - name="Administrator" - size={20} - /> - <strong - className="spacer-left" - > - Administrator - </strong> - <span - className="note little-spacer-left" - > - admin - </span> - </div> + admin + </span> </div> `; diff --git a/server/sonar-web/src/main/js/components/charts/AdvancedTimeline.js b/server/sonar-web/src/main/js/components/charts/AdvancedTimeline.js index 413a53a78d3..78ff543351f 100644 --- a/server/sonar-web/src/main/js/components/charts/AdvancedTimeline.js +++ b/server/sonar-web/src/main/js/components/charts/AdvancedTimeline.js @@ -124,7 +124,10 @@ export default class AdvancedTimeline extends React.PureComponent { } else if (props.metricType === 'LEVEL') { return this.getLevelScale(availableHeight); } else { - return scaleLinear().range([availableHeight, 0]).domain([0, max(flatData, d => d.y)]).nice(); + return scaleLinear() + .range([availableHeight, 0]) + .domain([0, max(flatData, d => d.y) || 0]) + .nice(); } }; diff --git a/server/sonar-web/src/main/less/components/react-select.less b/server/sonar-web/src/main/less/components/react-select.less index a29d4113e52..e191986705f 100644 --- a/server/sonar-web/src/main/less/components/react-select.less +++ b/server/sonar-web/src/main/less/components/react-select.less @@ -346,6 +346,29 @@ opacity: 0.5; } +.Select-big .Select-control { + padding-top: 4px; + padding-bottom: 4px; +} + +.Select-big .Select-placeholder { + margin-top: 4px; + margin-bottom: 4px; +} + +.Select-big .Select-value-label { + display: inline-block; + margin-top: 5px; +} + +.Select-big .Select-option { + padding: 4px 8px; +} + +.Select-big img { + padding-top: 0; +} + .Select--multi .Select-value-icon, .Select--multi .Select-value-label { display: inline-block; diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties index b5a2d54c317..78886e2d67b 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -1288,7 +1288,10 @@ project_activity.graphs.overview=Overview project_activity.graphs.coverage=Coverage project_activity.graphs.duplications=Duplications project_activity.graphs.custom=Custom +project_activity.graphs.custom.add=Add metric +project_activity.graphs.custom.add_metric=Add a metric project_activity.graphs.custom.no_history=There is no historical data to show, please add more metrics to your graph. +project_activity.graphs.custom.search=Search for a metric by name project_activity.custom_metric.covered_lines=Covered Lines |