aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web/src/main/js/apps/projectBaseline
diff options
context:
space:
mode:
authorJeremy Davis <jeremy.davis@sonarsource.com>2019-08-30 17:31:15 +0200
committerSonarTech <sonartech@sonarsource.com>2019-09-24 20:21:17 +0200
commit3079907d1f13a509709c72a5dade87d129a4eb5c (patch)
treed3a79825cbf8ae25a3f473f5cfc07ffbfd36eba2 /server/sonar-web/src/main/js/apps/projectBaseline
parent45f8d835abdaf01287e2cf4a149b87ab2abfd156 (diff)
downloadsonarqube-3079907d1f13a509709c72a5dade87d129a4eb5c.tar.gz
sonarqube-3079907d1f13a509709c72a5dade87d129a4eb5c.zip
SONAR-12430 Handle project baseline for Community Edition
Diffstat (limited to 'server/sonar-web/src/main/js/apps/projectBaseline')
-rw-r--r--server/sonar-web/src/main/js/apps/projectBaseline/__tests__/App-test.tsx8
-rw-r--r--server/sonar-web/src/main/js/apps/projectBaseline/__tests__/BranchBaselineSettingModal-test.tsx20
-rw-r--r--server/sonar-web/src/main/js/apps/projectBaseline/__tests__/ProjectBaselineSelector-test.tsx11
-rw-r--r--server/sonar-web/src/main/js/apps/projectBaseline/__tests__/__snapshots__/BranchBaselineSettingModal-test.tsx.snap2
-rw-r--r--server/sonar-web/src/main/js/apps/projectBaseline/__tests__/__snapshots__/ProjectBaselineSelector-test.tsx.snap99
-rw-r--r--server/sonar-web/src/main/js/apps/projectBaseline/__tests__/utils-test.ts40
-rw-r--r--server/sonar-web/src/main/js/apps/projectBaseline/components/App.tsx81
-rw-r--r--server/sonar-web/src/main/js/apps/projectBaseline/components/AppContainer.ts1
-rw-r--r--server/sonar-web/src/main/js/apps/projectBaseline/components/BranchAnalysisList.tsx8
-rw-r--r--server/sonar-web/src/main/js/apps/projectBaseline/components/BranchBaselineSettingModal.tsx42
-rw-r--r--server/sonar-web/src/main/js/apps/projectBaseline/components/ProjectBaselineSelector.tsx88
-rw-r--r--server/sonar-web/src/main/js/apps/projectBaseline/styles.css16
-rw-r--r--server/sonar-web/src/main/js/apps/projectBaseline/utils.ts41
13 files changed, 326 insertions, 131 deletions
diff --git a/server/sonar-web/src/main/js/apps/projectBaseline/__tests__/App-test.tsx b/server/sonar-web/src/main/js/apps/projectBaseline/__tests__/App-test.tsx
index 32b7edf81da..84c2a008476 100644
--- a/server/sonar-web/src/main/js/apps/projectBaseline/__tests__/App-test.tsx
+++ b/server/sonar-web/src/main/js/apps/projectBaseline/__tests__/App-test.tsx
@@ -93,6 +93,12 @@ it('should handle errors gracefully', async () => {
function shallowRender(props: Partial<App['props']> = {}) {
return shallow<App>(
- <App branchLikes={[]} canAdmin={true} component={mockComponent()} {...props} />
+ <App
+ branchLikes={[]}
+ branchesEnabled={true}
+ canAdmin={true}
+ component={mockComponent()}
+ {...props}
+ />
);
}
diff --git a/server/sonar-web/src/main/js/apps/projectBaseline/__tests__/BranchBaselineSettingModal-test.tsx b/server/sonar-web/src/main/js/apps/projectBaseline/__tests__/BranchBaselineSettingModal-test.tsx
index 230a2ec74c9..abe14e18235 100644
--- a/server/sonar-web/src/main/js/apps/projectBaseline/__tests__/BranchBaselineSettingModal-test.tsx
+++ b/server/sonar-web/src/main/js/apps/projectBaseline/__tests__/BranchBaselineSettingModal-test.tsx
@@ -88,26 +88,6 @@ it('should disable the save button when date is invalid', () => {
).toBe(true);
});
-describe('getSettingValue', () => {
- const wrapper = shallowRender();
- wrapper.setState({ analysis: 'analysis1', days: '35' });
-
- it('should work for Days', () => {
- wrapper.setState({ selected: 'NUMBER_OF_DAYS' });
- expect(wrapper.instance().getSettingValue()).toBe('35');
- });
-
- it('should work for Analysis', () => {
- wrapper.setState({ selected: 'SPECIFIC_ANALYSIS' });
- expect(wrapper.instance().getSettingValue()).toBe('analysis1');
- });
-
- it('should work for Previous version', () => {
- wrapper.setState({ selected: 'PREVIOUS_VERSION' });
- expect(wrapper.instance().getSettingValue()).toBeUndefined();
- });
-});
-
function shallowRender(props: Partial<BranchBaselineSettingModal['props']> = {}) {
return shallow<BranchBaselineSettingModal>(
<BranchBaselineSettingModal
diff --git a/server/sonar-web/src/main/js/apps/projectBaseline/__tests__/ProjectBaselineSelector-test.tsx b/server/sonar-web/src/main/js/apps/projectBaseline/__tests__/ProjectBaselineSelector-test.tsx
index 87608358874..74384231bf2 100644
--- a/server/sonar-web/src/main/js/apps/projectBaseline/__tests__/ProjectBaselineSelector-test.tsx
+++ b/server/sonar-web/src/main/js/apps/projectBaseline/__tests__/ProjectBaselineSelector-test.tsx
@@ -25,6 +25,7 @@ import ProjectBaselineSelector, {
it('should render correctly', () => {
expect(shallowRender()).toMatchSnapshot();
+ expect(shallowRender({ branchesEnabled: false })).toMatchSnapshot();
});
it('should not show save button when unchanged', () => {
@@ -32,7 +33,12 @@ it('should not show save button when unchanged', () => {
currentSetting: 'PREVIOUS_VERSION',
selected: 'PREVIOUS_VERSION'
});
- expect(wrapper.find('SubmitButton')).toHaveLength(0);
+ expect(
+ wrapper
+ .find('SubmitButton')
+ .parent()
+ .hasClass('invisible')
+ ).toBe(true);
});
it('should show save button when changed', () => {
@@ -84,7 +90,10 @@ it('should disable the save button when date is invalid', () => {
function shallowRender(props: Partial<ProjectBaselineSelectorProps> = {}) {
return shallow(
<ProjectBaselineSelector
+ branchesEnabled={true}
+ component=""
days="12"
+ onSelectAnalysis={jest.fn()}
onSelectDays={jest.fn()}
onSelectSetting={jest.fn()}
onSubmit={jest.fn()}
diff --git a/server/sonar-web/src/main/js/apps/projectBaseline/__tests__/__snapshots__/BranchBaselineSettingModal-test.tsx.snap b/server/sonar-web/src/main/js/apps/projectBaseline/__tests__/__snapshots__/BranchBaselineSettingModal-test.tsx.snap
index a9710d794a4..e9ffc30753c 100644
--- a/server/sonar-web/src/main/js/apps/projectBaseline/__tests__/__snapshots__/BranchBaselineSettingModal-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projectBaseline/__tests__/__snapshots__/BranchBaselineSettingModal-test.tsx.snap
@@ -17,7 +17,7 @@ exports[`should render correctly 1`] = `
onSubmit={[Function]}
>
<div
- className="modal-body branch-baseline-setting-modal"
+ className="modal-body modal-container branch-baseline-setting-modal"
>
<div
className="display-flex-row huge-spacer-bottom"
diff --git a/server/sonar-web/src/main/js/apps/projectBaseline/__tests__/__snapshots__/ProjectBaselineSelector-test.tsx.snap b/server/sonar-web/src/main/js/apps/projectBaseline/__tests__/__snapshots__/ProjectBaselineSelector-test.tsx.snap
index c8fe6992237..d938d19be84 100644
--- a/server/sonar-web/src/main/js/apps/projectBaseline/__tests__/__snapshots__/ProjectBaselineSelector-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projectBaseline/__tests__/__snapshots__/ProjectBaselineSelector-test.tsx.snap
@@ -6,21 +6,96 @@ exports[`should render correctly 1`] = `
onSubmit={[MockFunction]}
>
<div
- className="display-flex-row big-spacer-bottom"
- role="radiogroup"
+ className="branch-baseline-setting-modal"
>
- <BaselineSettingPreviousVersion
- onSelect={[MockFunction]}
- selected={false}
+ <div
+ className="display-flex-row big-spacer-bottom"
+ role="radiogroup"
+ >
+ <BaselineSettingPreviousVersion
+ onSelect={[MockFunction]}
+ selected={false}
+ />
+ <BaselineSettingDays
+ days="12"
+ isChanged={false}
+ isValid={false}
+ onChangeDays={[MockFunction]}
+ onSelect={[MockFunction]}
+ selected={false}
+ />
+ </div>
+ </div>
+ <div
+ className="big-spacer-top invisible"
+ >
+ <p
+ className="spacer-bottom"
+ >
+ baseline.next_analysis_notice
+ </p>
+ <DeferredSpinner
+ className="spacer-right"
+ loading={false}
+ timeout={100}
/>
- <BaselineSettingDays
- days="12"
- isChanged={false}
- isValid={true}
- onChangeDays={[MockFunction]}
- onSelect={[MockFunction]}
- selected={false}
+ <SubmitButton
+ disabled={true}
+ >
+ save
+ </SubmitButton>
+ </div>
+</form>
+`;
+
+exports[`should render correctly 2`] = `
+<form
+ className="project-baseline-selector"
+ onSubmit={[MockFunction]}
+>
+ <div
+ className="branch-baseline-setting-modal"
+ >
+ <div
+ className="display-flex-row big-spacer-bottom"
+ role="radiogroup"
+ >
+ <BaselineSettingPreviousVersion
+ onSelect={[MockFunction]}
+ selected={false}
+ />
+ <BaselineSettingDays
+ days="12"
+ isChanged={false}
+ isValid={false}
+ onChangeDays={[MockFunction]}
+ onSelect={[MockFunction]}
+ selected={false}
+ />
+ <BaselineSettingAnalysis
+ onSelect={[MockFunction]}
+ selected={false}
+ />
+ </div>
+ </div>
+ <div
+ className="big-spacer-top invisible"
+ >
+ <p
+ className="spacer-bottom"
+ >
+ baseline.next_analysis_notice
+ </p>
+ <DeferredSpinner
+ className="spacer-right"
+ loading={false}
+ timeout={100}
/>
+ <SubmitButton
+ disabled={true}
+ >
+ save
+ </SubmitButton>
</div>
</form>
`;
diff --git a/server/sonar-web/src/main/js/apps/projectBaseline/__tests__/utils-test.ts b/server/sonar-web/src/main/js/apps/projectBaseline/__tests__/utils-test.ts
new file mode 100644
index 00000000000..c77f816b373
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/projectBaseline/__tests__/utils-test.ts
@@ -0,0 +1,40 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2019 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.
+ */
+import { getSettingValue } from '../utils';
+
+describe('getSettingValue', () => {
+ it('should work for Days', () => {
+ expect(getSettingValue({ analysis: 'analysis', days: '35', type: 'NUMBER_OF_DAYS' })).toBe(
+ '35'
+ );
+ });
+
+ it('should work for Analysis', () => {
+ expect(getSettingValue({ analysis: 'analysis1', days: '35', type: 'SPECIFIC_ANALYSIS' })).toBe(
+ 'analysis1'
+ );
+ });
+
+ it('should work for Previous version', () => {
+ expect(
+ getSettingValue({ analysis: 'analysis1', days: '35', type: 'PREVIOUS_VERSION' })
+ ).toBeUndefined();
+ });
+});
diff --git a/server/sonar-web/src/main/js/apps/projectBaseline/components/App.tsx b/server/sonar-web/src/main/js/apps/projectBaseline/components/App.tsx
index c88e2fc9e64..816c0805985 100644
--- a/server/sonar-web/src/main/js/apps/projectBaseline/components/App.tsx
+++ b/server/sonar-web/src/main/js/apps/projectBaseline/components/App.tsx
@@ -25,16 +25,19 @@ import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n';
import { getNewCodePeriod, resetNewCodePeriod, setNewCodePeriod } from '../../../api/newCodePeriod';
import '../styles.css';
+import { getSettingValue } from '../utils';
import BranchList from './BranchList';
import ProjectBaselineSelector from './ProjectBaselineSelector';
interface Props {
branchLikes: T.BranchLike[];
+ branchesEnabled?: boolean;
canAdmin?: boolean;
component: T.Component;
}
interface State {
+ analysis?: string;
currentSetting?: T.NewCodePeriodSettingType;
currentSettingValue?: string;
days: string;
@@ -65,9 +68,34 @@ export default class App extends React.PureComponent<Props, State> {
this.mounted = false;
}
+ getUpdatedState(params: {
+ currentSetting?: T.NewCodePeriodSettingType;
+ currentSettingValue?: string;
+ generalSetting: T.NewCodePeriod;
+ }) {
+ const { currentSetting, currentSettingValue, generalSetting } = params;
+
+ return {
+ loading: false,
+ currentSetting,
+ currentSettingValue,
+ generalSetting,
+ selected: currentSetting,
+ days: currentSetting === 'NUMBER_OF_DAYS' ? currentSettingValue || '30' : '',
+ analysis: (currentSetting === 'SPECIFIC_ANALYSIS' && currentSettingValue) || ''
+ };
+ }
+
fetchLeakPeriodSetting() {
this.setState({ loading: true });
- Promise.all([getNewCodePeriod(), getNewCodePeriod({ project: this.props.component.key })]).then(
+
+ Promise.all([
+ getNewCodePeriod(),
+ getNewCodePeriod({
+ branch: this.props.branchesEnabled ? 'master' : undefined,
+ project: this.props.component.key
+ })
+ ]).then(
([generalSetting, setting]) => {
if (this.mounted) {
if (!generalSetting.type) {
@@ -75,22 +103,10 @@ export default class App extends React.PureComponent<Props, State> {
}
const currentSettingValue = setting.value;
const currentSetting = setting.inherited ? undefined : setting.type || 'PREVIOUS_VERSION';
- const newState = {
- loading: false,
- currentSetting,
- currentSettingValue,
- generalSetting,
- selected: currentSetting
- };
- if (currentSetting === 'NUMBER_OF_DAYS') {
- this.setState({
- days: currentSettingValue || '30',
- ...newState
- });
- } else {
- this.setState(newState);
- }
+ this.setState(
+ this.getUpdatedState({ generalSetting, currentSetting, currentSettingValue })
+ );
}
},
() => {
@@ -115,6 +131,8 @@ export default class App extends React.PureComponent<Props, State> {
);
};
+ handleSelectAnalysis = (analysis: T.ParsedAnalysis) => this.setState({ analysis: analysis.key });
+
handleSelectDays = (days: string) => this.setState({ days });
handleSelectSetting = (selected?: T.NewCodePeriodSettingType) => this.setState({ selected });
@@ -123,10 +141,9 @@ export default class App extends React.PureComponent<Props, State> {
e.preventDefault();
const { component } = this.props;
- const { days, selected } = this.state;
+ const { analysis, days, selected: type } = this.state;
- const type = selected;
- const value = type === 'NUMBER_OF_DAYS' ? days : undefined;
+ const value = getSettingValue({ type, analysis, days });
if (type) {
this.setState({ saving: true });
@@ -196,7 +213,9 @@ export default class App extends React.PureComponent<Props, State> {
}
render() {
+ const { branchLikes, branchesEnabled, component } = this.props;
const {
+ analysis,
currentSetting,
days,
generalSetting,
@@ -213,21 +232,23 @@ export default class App extends React.PureComponent<Props, State> {
<DeferredSpinner />
) : (
<div className="panel panel-white">
- <h2>{translate('project_baseline.default_setting')}</h2>
- <p>{translate('project_baseline.default_setting.description')}</p>
+ {branchesEnabled && (
+ <>
+ <h2>{translate('project_baseline.default_setting')}</h2>
+ <p>{translate('project_baseline.default_setting.description')}</p>
+ </>
+ )}
{generalSetting && (
<div className="text-right spacer-bottom">
{currentSetting && (
<>
- <Button
- className="spacer-right little-spacer-bottom"
- onClick={this.resetSetting}>
+ <Button className="little-spacer-bottom" onClick={this.resetSetting}>
{translate('project_baseline.reset_to_general')}
</Button>
</>
)}
- <div className="spacer-top spacer-right medium">
+ <div className="spacer-top medium">
<strong>{translate('project_baseline.general_setting')}: </strong>
{this.renderGeneralSetting(generalSetting)}
</div>
@@ -235,19 +256,23 @@ export default class App extends React.PureComponent<Props, State> {
)}
<ProjectBaselineSelector
+ analysis={analysis}
+ branchesEnabled={branchesEnabled}
+ component={component.key}
currentSetting={currentSetting}
currentSettingValue={currentSettingValue}
days={days}
+ onSelectAnalysis={this.handleSelectAnalysis}
onSelectDays={this.handleSelectDays}
onSelectSetting={this.handleSelectSetting}
onSubmit={this.handleSubmit}
saving={saving}
selected={selected}
/>
- {generalSetting && (
+ {generalSetting && branchesEnabled && (
<BranchList
- branchLikes={this.props.branchLikes}
- component={this.props.component}
+ branchLikes={branchLikes}
+ component={component}
inheritedSetting={
currentSetting
? {
diff --git a/server/sonar-web/src/main/js/apps/projectBaseline/components/AppContainer.ts b/server/sonar-web/src/main/js/apps/projectBaseline/components/AppContainer.ts
index 10205a7f932..1a38ec7f7f8 100644
--- a/server/sonar-web/src/main/js/apps/projectBaseline/components/AppContainer.ts
+++ b/server/sonar-web/src/main/js/apps/projectBaseline/components/AppContainer.ts
@@ -22,6 +22,7 @@ import { getAppState, Store } from '../../../store/rootReducer';
import App from './App';
const mapStateToProps = (state: Store) => ({
+ branchesEnabled: getAppState(state).branchesEnabled,
canAdmin: getAppState(state).canAdmin
});
diff --git a/server/sonar-web/src/main/js/apps/projectBaseline/components/BranchAnalysisList.tsx b/server/sonar-web/src/main/js/apps/projectBaseline/components/BranchAnalysisList.tsx
index 4791f62ba6e..b2ed30fd434 100644
--- a/server/sonar-web/src/main/js/apps/projectBaseline/components/BranchAnalysisList.tsx
+++ b/server/sonar-web/src/main/js/apps/projectBaseline/components/BranchAnalysisList.tsx
@@ -30,17 +30,17 @@ import { getProjectActivity } from '../../../api/projectActivity';
import DateFormatter from '../../../components/intl/DateFormatter';
import TimeFormatter from '../../../components/intl/TimeFormatter';
import Events from '../../projectActivity/components/Events';
-import { getAnalysesByVersionByDay, ParsedAnalysis } from '../../projectActivity/utils';
+import { getAnalysesByVersionByDay } from '../../projectActivity/utils';
interface Props {
analysis: string;
branch: string;
component: string;
- onSelectAnalysis: (analysis: ParsedAnalysis) => void;
+ onSelectAnalysis: (analysis: T.ParsedAnalysis) => void;
}
interface State {
- analyses: ParsedAnalysis[];
+ analyses: T.ParsedAnalysis[];
loading: boolean;
range: number;
scroll: number;
@@ -90,7 +90,7 @@ export default class BranchAnalysisList extends React.PureComponent<Props, State
analyses: result.analyses.map(analysis => ({
...analysis,
date: parseDate(analysis.date)
- })) as ParsedAnalysis[],
+ })) as T.ParsedAnalysis[],
loading: false
});
});
diff --git a/server/sonar-web/src/main/js/apps/projectBaseline/components/BranchBaselineSettingModal.tsx b/server/sonar-web/src/main/js/apps/projectBaseline/components/BranchBaselineSettingModal.tsx
index b8dd08c6b66..0a180907f92 100644
--- a/server/sonar-web/src/main/js/apps/projectBaseline/components/BranchBaselineSettingModal.tsx
+++ b/server/sonar-web/src/main/js/apps/projectBaseline/components/BranchBaselineSettingModal.tsx
@@ -24,8 +24,7 @@ import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
import { toNotSoISOString } from 'sonar-ui-common/helpers/dates';
import { translate, translateWithParameters } from 'sonar-ui-common/helpers/l10n';
import { setNewCodePeriod } from '../../../api/newCodePeriod';
-import { ParsedAnalysis } from '../../projectActivity/utils';
-import { validateDays } from '../utils';
+import { getSettingValue, validateSetting } from '../utils';
import BaselineSettingAnalysis from './BaselineSettingAnalysis';
import BaselineSettingDays from './BaselineSettingDays';
import BaselineSettingPreviousVersion from './BaselineSettingPreviousVersion';
@@ -73,24 +72,13 @@ export default class BranchBaselineSettingModal extends React.PureComponent<Prop
: null;
}
- getSettingValue() {
- switch (this.state.selected) {
- case 'NUMBER_OF_DAYS':
- return this.state.days;
- case 'SPECIFIC_ANALYSIS':
- return this.state.analysis;
- default:
- return undefined;
- }
- }
-
handleSubmit = (e: React.SyntheticEvent<HTMLFormElement>) => {
e.preventDefault();
const { branch, component } = this.props;
- const { analysisDate, selected: type } = this.state;
+ const { analysis, analysisDate, days, selected: type } = this.state;
- const value = this.getSettingValue();
+ const value = getSettingValue({ type, analysis, days });
if (type) {
this.setState({ saving: true });
@@ -121,7 +109,7 @@ export default class BranchBaselineSettingModal extends React.PureComponent<Prop
requestClose = () => this.props.onClose();
- handleSelectAnalysis = (analysis: ParsedAnalysis) =>
+ handleSelectAnalysis = (analysis: T.ParsedAnalysis) =>
this.setState({ analysis: analysis.key, analysisDate: analysis.date });
handleSelectDays = (days: string) => this.setState({ days });
@@ -132,20 +120,18 @@ export default class BranchBaselineSettingModal extends React.PureComponent<Prop
const { branch } = this.props;
const { analysis, days, saving, selected } = this.state;
- const currentSetting = branch.newCodePeriod && branch.newCodePeriod.type;
- const currentSettingValue = branch.newCodePeriod && branch.newCodePeriod.value;
-
const header = translateWithParameters('baseline.new_code_period_for_branch_x', branch.name);
- const isChanged =
- selected !== currentSetting ||
- (selected === 'NUMBER_OF_DAYS' && String(days) !== currentSettingValue) ||
- (selected === 'SPECIFIC_ANALYSIS' && analysis !== currentSettingValue);
+ const currentSetting = branch.newCodePeriod && branch.newCodePeriod.type;
+ const currentSettingValue = branch.newCodePeriod && branch.newCodePeriod.value;
- const isValid =
- selected === 'PREVIOUS_VERSION' ||
- (selected === 'SPECIFIC_ANALYSIS' && analysis.length > 0) ||
- (selected === 'NUMBER_OF_DAYS' && validateDays(days));
+ const { isChanged, isValid } = validateSetting({
+ analysis,
+ currentSetting,
+ currentSettingValue,
+ days,
+ selected
+ });
return (
<Modal contentLabel={header} onRequestClose={this.requestClose} size="large">
@@ -153,7 +139,7 @@ export default class BranchBaselineSettingModal extends React.PureComponent<Prop
<h2>{header}</h2>
</header>
<form onSubmit={this.handleSubmit}>
- <div className="modal-body branch-baseline-setting-modal">
+ <div className="modal-body modal-container branch-baseline-setting-modal">
<div className="display-flex-row huge-spacer-bottom" role="radiogroup">
<BaselineSettingPreviousVersion
isDefault={false}
diff --git a/server/sonar-web/src/main/js/apps/projectBaseline/components/ProjectBaselineSelector.tsx b/server/sonar-web/src/main/js/apps/projectBaseline/components/ProjectBaselineSelector.tsx
index a29dfb03eba..5aabd1ad5ac 100644
--- a/server/sonar-web/src/main/js/apps/projectBaseline/components/ProjectBaselineSelector.tsx
+++ b/server/sonar-web/src/main/js/apps/projectBaseline/components/ProjectBaselineSelector.tsx
@@ -17,18 +17,25 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import * as classNames from 'classnames';
import * as React from 'react';
import { SubmitButton } from 'sonar-ui-common/components/controls/buttons';
import DeferredSpinner from 'sonar-ui-common/components/ui/DeferredSpinner';
import { translate } from 'sonar-ui-common/helpers/l10n';
-import { validateDays } from '../utils';
+import { validateSetting } from '../utils';
+import BaselineSettingAnalysis from './BaselineSettingAnalysis';
import BaselineSettingDays from './BaselineSettingDays';
import BaselineSettingPreviousVersion from './BaselineSettingPreviousVersion';
+import BranchAnalysisList from './BranchAnalysisList';
export interface ProjectBaselineSelectorProps {
+ analysis?: string;
+ branchesEnabled?: boolean;
+ component: string;
currentSetting?: T.NewCodePeriodSettingType;
- currentSettingValue?: string | number;
+ currentSettingValue?: string;
days: string;
+ onSelectAnalysis: (analysis: T.ParsedAnalysis) => void;
onSelectDays: (value: string) => void;
onSelectSetting: (value: T.NewCodePeriodSettingType) => void;
onSubmit: (e: React.SyntheticEvent<HTMLFormElement>) => void;
@@ -37,37 +44,62 @@ export interface ProjectBaselineSelectorProps {
}
export default function ProjectBaselineSelector(props: ProjectBaselineSelectorProps) {
- const { currentSetting, days, currentSettingValue, saving, selected } = props;
+ const {
+ analysis,
+ branchesEnabled,
+ component,
+ currentSetting,
+ days,
+ currentSettingValue,
+ saving,
+ selected
+ } = props;
- const isChanged =
- selected !== currentSetting ||
- (selected === 'NUMBER_OF_DAYS' && String(days) !== currentSettingValue);
-
- const isValid = selected !== 'NUMBER_OF_DAYS' || validateDays(days);
+ const { isChanged, isValid } = validateSetting({
+ analysis,
+ currentSetting,
+ currentSettingValue,
+ days,
+ selected
+ });
return (
<form className="project-baseline-selector" onSubmit={props.onSubmit}>
- <div className="display-flex-row big-spacer-bottom" role="radiogroup">
- <BaselineSettingPreviousVersion
- onSelect={props.onSelectSetting}
- selected={selected === 'PREVIOUS_VERSION'}
- />
- <BaselineSettingDays
- days={days}
- isChanged={isChanged}
- isValid={isValid}
- onChangeDays={props.onSelectDays}
- onSelect={props.onSelectSetting}
- selected={selected === 'NUMBER_OF_DAYS'}
- />
- </div>
- {isChanged && (
- <div>
- <p className="spacer-bottom">{translate('baseline.next_analysis_notice')}</p>
- <DeferredSpinner className="spacer-right" loading={saving} />
- <SubmitButton disabled={saving || !isValid}>{translate('save')}</SubmitButton>
+ <div className="branch-baseline-setting-modal">
+ <div className="display-flex-row big-spacer-bottom" role="radiogroup">
+ <BaselineSettingPreviousVersion
+ onSelect={props.onSelectSetting}
+ selected={selected === 'PREVIOUS_VERSION'}
+ />
+ <BaselineSettingDays
+ days={days}
+ isChanged={isChanged}
+ isValid={isValid}
+ onChangeDays={props.onSelectDays}
+ onSelect={props.onSelectSetting}
+ selected={selected === 'NUMBER_OF_DAYS'}
+ />
+ {!branchesEnabled && (
+ <BaselineSettingAnalysis
+ onSelect={props.onSelectSetting}
+ selected={selected === 'SPECIFIC_ANALYSIS'}
+ />
+ )}
</div>
- )}
+ {selected === 'SPECIFIC_ANALYSIS' && (
+ <BranchAnalysisList
+ analysis={analysis || ''}
+ branch="master"
+ component={component}
+ onSelectAnalysis={props.onSelectAnalysis}
+ />
+ )}
+ </div>
+ <div className={classNames('big-spacer-top', { invisible: !isChanged })}>
+ <p className="spacer-bottom">{translate('baseline.next_analysis_notice')}</p>
+ <DeferredSpinner className="spacer-right" loading={saving} />
+ <SubmitButton disabled={saving || !isValid || !isChanged}>{translate('save')}</SubmitButton>
+ </div>
</form>
);
}
diff --git a/server/sonar-web/src/main/js/apps/projectBaseline/styles.css b/server/sonar-web/src/main/js/apps/projectBaseline/styles.css
index 06b52b4a9bc..9bffdfa35cc 100644
--- a/server/sonar-web/src/main/js/apps/projectBaseline/styles.css
+++ b/server/sonar-web/src/main/js/apps/projectBaseline/styles.css
@@ -18,13 +18,12 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-.project-baseline-selector {
- height: 300px;
+.project-baseline-selector > .branch-baseline-setting-modal {
+ max-height: 60vh;
+ padding-top: 2px;
}
.branch-baseline-setting-modal {
- height: 60vh;
- overflow: hidden;
display: flex;
flex-direction: column;
}
@@ -34,6 +33,7 @@
flex-direction: column;
overflow: hidden;
position: relative;
+ min-height: 200px;
}
.branch-analysis-list {
@@ -100,10 +100,6 @@
z-index: var(--belowNormalZIndex);
}
-.branch-analysis-version-badge.sticky + .branch-analysis-days-list {
- padding-top: 36px;
-}
-
.branch-analysis-version-badge .badge {
max-width: 385px;
border-radius: 0 2px 2px 0;
@@ -133,3 +129,7 @@
.project-activity-event-icon.OTHER {
color: #442d1b;
}
+
+.invisible {
+ visibility: hidden;
+}
diff --git a/server/sonar-web/src/main/js/apps/projectBaseline/utils.ts b/server/sonar-web/src/main/js/apps/projectBaseline/utils.ts
index afaa962b3dc..69b7cfabda0 100644
--- a/server/sonar-web/src/main/js/apps/projectBaseline/utils.ts
+++ b/server/sonar-web/src/main/js/apps/projectBaseline/utils.ts
@@ -22,3 +22,44 @@ export function validateDays(days: string) {
return !(days.length < 1 || isNaN(parsed) || parsed < 1 || String(parsed) !== days);
}
+
+export function getSettingValue({
+ analysis,
+ days,
+ type
+}: {
+ analysis?: string;
+ days?: string;
+ type?: T.NewCodePeriodSettingType;
+}) {
+ switch (type) {
+ case 'NUMBER_OF_DAYS':
+ return days;
+ case 'SPECIFIC_ANALYSIS':
+ return analysis;
+ default:
+ return undefined;
+ }
+}
+
+export function validateSetting(state: {
+ analysis?: string;
+ currentSetting?: T.NewCodePeriodSettingType;
+ currentSettingValue?: string;
+ days: string;
+ selected?: T.NewCodePeriodSettingType;
+}) {
+ const { analysis = '', currentSetting, currentSettingValue, days, selected } = state;
+
+ const isChanged =
+ selected !== currentSetting ||
+ (selected === 'NUMBER_OF_DAYS' && days !== currentSettingValue) ||
+ (selected === 'SPECIFIC_ANALYSIS' && analysis !== currentSettingValue);
+
+ const isValid =
+ selected === 'PREVIOUS_VERSION' ||
+ (selected === 'SPECIFIC_ANALYSIS' && analysis.length > 0) ||
+ (selected === 'NUMBER_OF_DAYS' && validateDays(days));
+
+ return { isChanged, isValid };
+}