aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGrégoire Aubert <gregoire.aubert@sonarsource.com>2017-11-06 12:09:19 +0100
committerGrégoire Aubert <gregoire.aubert@sonarsource.com>2017-11-06 16:18:50 +0100
commit76accff06136fe38497ab843476134bb00855f34 (patch)
tree8d6260d0314308eba8068fee2a729ba0ba1690f9
parent703c0bcc517272f73fc4a597b2cd190a1d78fef4 (diff)
downloadsonarqube-76accff06136fe38497ab843476134bb00855f34.tar.gz
sonarqube-76accff06136fe38497ab843476134bb00855f34.zip
SONAR-9937 Add TOS checkbox when installing an edition in the marketplace
-rw-r--r--server/sonar-web/src/main/js/apps/marketplace/components/LicenseEditionForm.tsx7
-rw-r--r--server/sonar-web/src/main/js/apps/marketplace/components/LicenseEditionSet.tsx124
-rw-r--r--server/sonar-web/src/main/js/apps/marketplace/components/__tests__/LicenseEditionForm-test.tsx25
-rw-r--r--server/sonar-web/src/main/js/apps/marketplace/components/__tests__/LicenseEditionSet-test.tsx36
-rw-r--r--server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/LicenseEditionForm-test.tsx.snap30
-rw-r--r--server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/LicenseEditionSet-test.tsx.snap25
6 files changed, 143 insertions, 104 deletions
diff --git a/server/sonar-web/src/main/js/apps/marketplace/components/LicenseEditionForm.tsx b/server/sonar-web/src/main/js/apps/marketplace/components/LicenseEditionForm.tsx
index abab7c84ed4..778c63fb457 100644
--- a/server/sonar-web/src/main/js/apps/marketplace/components/LicenseEditionForm.tsx
+++ b/server/sonar-web/src/main/js/apps/marketplace/components/LicenseEditionForm.tsx
@@ -81,7 +81,7 @@ export default class LicenseEditionForm extends React.PureComponent<Props, State
render() {
const { edition, isDowngrade } = this.props;
- const { submitting, status } = this.state;
+ const { license, submitting, status } = this.state;
const header = isDowngrade
? translateWithParameters('marketplace.downgrade_to_x', edition.name)
@@ -107,7 +107,10 @@ export default class LicenseEditionForm extends React.PureComponent<Props, State
<footer className="modal-foot">
{submitting && <i className="spinner spacer-right" />}
{status && (
- <button className="js-confirm" onClick={this.handleConfirmClick} disabled={submitting}>
+ <button
+ className="js-confirm"
+ onClick={this.handleConfirmClick}
+ disabled={!license || submitting}>
{status === 'AUTOMATIC_INSTALL' ? (
translate('marketplace.install')
) : (
diff --git a/server/sonar-web/src/main/js/apps/marketplace/components/LicenseEditionSet.tsx b/server/sonar-web/src/main/js/apps/marketplace/components/LicenseEditionSet.tsx
index edcd13a3d03..2053ea87e50 100644
--- a/server/sonar-web/src/main/js/apps/marketplace/components/LicenseEditionSet.tsx
+++ b/server/sonar-web/src/main/js/apps/marketplace/components/LicenseEditionSet.tsx
@@ -17,10 +17,11 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import { stringify } from 'querystring';
import * as React from 'react';
import * as classNames from 'classnames';
+import Checkbox from '../../../components/controls/Checkbox';
import { FormattedMessage } from 'react-intl';
-import { stringify } from 'querystring';
import { debounce } from 'lodash';
import DeferredSpinner from '../../../components/common/DeferredSpinner';
import { omitNil } from '../../../helpers/request';
@@ -35,6 +36,7 @@ export interface Props {
}
interface State {
+ acceptTerms: boolean;
license: string;
licenseEdition?: Edition;
loading: boolean;
@@ -50,7 +52,7 @@ export default class LicenseEditionSet extends React.PureComponent<Props, State>
constructor(props: Props) {
super(props);
- this.state = { license: '', loading: false };
+ this.state = { acceptTerms: false, license: '', loading: false };
this.fetchLicensePreview = debounce(this.fetchLicensePreview, 100);
}
@@ -116,57 +118,93 @@ export default class LicenseEditionSet extends React.PureComponent<Props, State>
}
};
+ handleTermsCheck = (checked: boolean) =>
+ this.setState({ acceptTerms: checked }, () =>
+ this.updateLicense(this.state.license, this.state.licenseEdition, this.state.previewStatus)
+ );
+
updateLicense = (license: string, licenseEdition?: Edition, previewStatus?: string) => {
this.setState({ license, licenseEdition, loading: false, previewStatus });
- this.props.updateLicense(license, previewStatus);
+ this.props.updateLicense(
+ previewStatus !== 'NO_INSTALL' && !this.state.acceptTerms ? undefined : license,
+ previewStatus
+ );
};
renderAlert() {
const { licenseEdition, previewStatus } = this.state;
if (!previewStatus) {
const { edition } = this.props;
- if (edition && licenseEdition && edition.key !== licenseEdition.key) {
- return (
- <p className="alert alert-danger spacer-top">
- {translateWithParameters('marketplace.wrong_license_type_x', edition.name)}
- </p>
- );
+ if (!edition) {
+ return undefined;
}
- return undefined;
+ return (
+ <div className="spacer-top">
+ {licenseEdition !== undefined &&
+ edition.key !== licenseEdition.key && (
+ <p className="alert alert-danger">
+ {translateWithParameters('marketplace.wrong_license_type_x', edition.name)}
+ </p>
+ )}
+ <a href={this.getLicenseFormUrl(edition)} target="_blank">
+ {translate('marketplace.i_need_a_license')}
+ </a>
+ </div>
+ );
}
return (
- <p
- className={classNames('alert spacer-top', {
- 'alert-warning': previewStatus === 'AUTOMATIC_INSTALL',
- 'alert-success': previewStatus === 'NO_INSTALL',
- 'alert-danger': previewStatus === 'MANUAL_INSTALL'
- })}>
- {translateWithParameters(
- 'marketplace.license_preview_status.' + previewStatus,
- licenseEdition ? licenseEdition.name : translate('marketplace.commercial_edition')
- )}
- {licenseEdition &&
- licenseEdition.key === 'datacenter' &&
- previewStatus !== 'NO_INSTALL' && (
- <span className="little-spacer-left">
- <FormattedMessage
- defaultMessage={translate('marketplace.how_to_setup_cluster_url')}
- id="marketplace.how_to_setup_cluster_url"
- values={{
- url: (
- <a
- href="https://redirect.sonarsource.com/doc/data-center-edition.html"
- target="_blank">
- {licenseEdition.name}
- </a>
- )
- }}
- />
+ <div className="spacer-top">
+ <p
+ className={classNames('alert', {
+ 'alert-warning': previewStatus === 'AUTOMATIC_INSTALL',
+ 'alert-success': previewStatus === 'NO_INSTALL',
+ 'alert-danger': previewStatus === 'MANUAL_INSTALL'
+ })}>
+ {translateWithParameters(
+ 'marketplace.license_preview_status.' + previewStatus,
+ licenseEdition ? licenseEdition.name : translate('marketplace.commercial_edition')
+ )}
+ {licenseEdition &&
+ licenseEdition.key === 'datacenter' &&
+ previewStatus !== 'NO_INSTALL' && (
+ <span className="little-spacer-left">
+ <FormattedMessage
+ defaultMessage={translate('marketplace.how_to_setup_cluster_url')}
+ id="marketplace.how_to_setup_cluster_url"
+ values={{
+ url: (
+ <a
+ href="https://redirect.sonarsource.com/doc/data-center-edition.html"
+ target="_blank">
+ {licenseEdition.name}
+ </a>
+ )
+ }}
+ />
+ </span>
+ )}
+ </p>
+ {previewStatus !== 'NO_INSTALL' && (
+ <span className="js-edition-tos">
+ <Checkbox
+ checked={this.state.acceptTerms}
+ id="edition-terms"
+ onCheck={this.handleTermsCheck}>
+ <label className="little-spacer-left" htmlFor="edition-terms">
+ {translate('marketplace.i_accept_the')}
+ </label>
+ </Checkbox>
+ <a
+ className="nowrap little-spacer-left"
+ href="http://dist.sonarsource.com/SonarSource_Terms_And_Conditions.pdf"
+ target="_blank">
+ {translate('marketplace.terms_and_conditions')}
+ </a>
</span>
)}
- </p>
+ </div>
);
}
@@ -194,7 +232,6 @@ export default class LicenseEditionSet extends React.PureComponent<Props, State>
/>
<DeferredSpinner
- className="spacer-top"
loading={loading}
customSpinner={
<p className="spacer-top">
@@ -204,15 +241,6 @@ export default class LicenseEditionSet extends React.PureComponent<Props, State>
}>
{this.renderAlert()}
</DeferredSpinner>
-
- {edition && (
- <a
- className="display-inline-block spacer-top"
- href={this.getLicenseFormUrl(edition)}
- target="_blank">
- {translate('marketplace.i_need_a_license')}
- </a>
- )}
</div>
);
}
diff --git a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/LicenseEditionForm-test.tsx b/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/LicenseEditionForm-test.tsx
index 745c8308a9b..7db7c0c0b5d 100644
--- a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/LicenseEditionForm-test.tsx
+++ b/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/LicenseEditionForm-test.tsx
@@ -47,15 +47,28 @@ it('should display correctly', () => {
expect(getWrapper()).toMatchSnapshot();
});
-it('should correctly change the button based on the status', () => {
+it('should correctly change the button based on the status and license', () => {
const wrapper = getWrapper();
+ let button;
(wrapper.instance() as LicenseEditionForm).mounted = true;
- wrapper.setState({ status: 'NO_INSTALL' });
- expect(wrapper.find('button')).toMatchSnapshot();
+
+ wrapper.setState({ license: 'mylicense', status: 'NO_INSTALL' });
+ button = wrapper.find('button');
+ expect(button.text()).toBe('save');
+ expect(button.prop('disabled')).toBeFalsy();
+
+ wrapper.setState({ license: undefined, status: 'MANUAL_INSTALL' });
+ button = wrapper.find('button');
+ expect(button.text()).toBe('save');
+ expect(button.prop('disabled')).toBeTruthy();
+
wrapper.setState({ status: 'AUTOMATIC_INSTALL' });
- expect(wrapper.find('button')).toMatchSnapshot();
- wrapper.setState({ status: 'MANUAL_INSTALL' });
- expect(wrapper.find('button')).toMatchSnapshot();
+ button = wrapper.find('button');
+ expect(button.text()).toContain('install');
+ expect(button.prop('disabled')).toBeTruthy();
+
+ wrapper.setState({ license: 'mylicense' });
+ expect(wrapper.find('button').prop('disabled')).toBeFalsy();
});
it('should update the edition status after install', async () => {
diff --git a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/LicenseEditionSet-test.tsx b/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/LicenseEditionSet-test.tsx
index ce68f4c2d3e..b0be56873fd 100644
--- a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/LicenseEditionSet-test.tsx
+++ b/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/LicenseEditionSet-test.tsx
@@ -30,7 +30,7 @@ jest.mock('../../../../api/marketplace', () => ({
jest.mock('lodash', () => {
const lodash = require.requireActual('lodash');
- lodash.debounce = (fn: Function) => (...args: any[]) => fn(args);
+ lodash.debounce = (fn: Function) => (...args: any[]) => fn(...args);
return lodash;
});
@@ -56,9 +56,32 @@ it('should display correctly', () => {
});
it('should correctly display status message after checking license', async () => {
- await testLicenseStatus('NO_INSTALL');
- await testLicenseStatus('AUTOMATIC_INSTALL');
- await testLicenseStatus('MANUAL_INSTALL');
+ let wrapper = await testLicenseStatus('NO_INSTALL', jest.fn());
+ expect(wrapper.find('p.alert')).toMatchSnapshot();
+ wrapper = await testLicenseStatus('AUTOMATIC_INSTALL', jest.fn());
+ expect(wrapper.find('p.alert')).toMatchSnapshot();
+ wrapper = await testLicenseStatus('MANUAL_INSTALL', jest.fn());
+ expect(wrapper.find('p.alert')).toMatchSnapshot();
+});
+
+it('should display terms of license checkbox', async () => {
+ let updateLicense = jest.fn();
+ let wrapper = await testLicenseStatus('NO_INSTALL', updateLicense);
+ expect(wrapper.find('.js-edition-tos').exists()).toBeFalsy();
+ expect(updateLicense).toHaveBeenCalledWith('mylicense', 'NO_INSTALL');
+
+ updateLicense = jest.fn();
+ wrapper = await testLicenseStatus('AUTOMATIC_INSTALL', updateLicense);
+ let tosCheckbox = wrapper.find('.js-edition-tos');
+ expect(tosCheckbox.find('a').exists()).toBeTruthy();
+ expect(updateLicense).toHaveBeenLastCalledWith(undefined, 'AUTOMATIC_INSTALL');
+ (tosCheckbox.find('Checkbox').prop('onCheck') as Function)(true);
+ expect(updateLicense).toHaveBeenLastCalledWith('mylicense', 'AUTOMATIC_INSTALL');
+
+ updateLicense = jest.fn();
+ wrapper = await testLicenseStatus('MANUAL_INSTALL', updateLicense);
+ expect(wrapper.find('.js-edition-tos').exists()).toBeTruthy();
+ expect(updateLicense).toHaveBeenLastCalledWith(undefined, 'MANUAL_INSTALL');
});
function getWrapper(props = {}) {
@@ -72,16 +95,15 @@ function getWrapper(props = {}) {
);
}
-async function testLicenseStatus(status: string) {
+async function testLicenseStatus(status: string, updateLicense: jest.Mock<any>) {
getLicensePreview.mockImplementation(() =>
Promise.resolve({ nextEditionKey: 'foo', previewStatus: status })
);
- const updateLicense = jest.fn();
const wrapper = getWrapper({ updateLicense });
(wrapper.instance() as LicenseEditionSet).mounted = true;
change(wrapper.find('textarea'), 'mylicense');
expect(getLicensePreview).toHaveBeenCalled();
await new Promise(setImmediate);
expect(updateLicense).toHaveBeenCalled();
- expect(wrapper.find('p.alert')).toMatchSnapshot();
+ return wrapper;
}
diff --git a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/LicenseEditionForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/LicenseEditionForm-test.tsx.snap
index d178e5134f4..49d105b88f5 100644
--- a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/LicenseEditionForm-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/LicenseEditionForm-test.tsx.snap
@@ -1,35 +1,5 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`should correctly change the button based on the status 1`] = `
-<button
- className="js-confirm"
- disabled={false}
- onClick={[Function]}
->
- save
-</button>
-`;
-
-exports[`should correctly change the button based on the status 2`] = `
-<button
- className="js-confirm"
- disabled={false}
- onClick={[Function]}
->
- marketplace.install
-</button>
-`;
-
-exports[`should correctly change the button based on the status 3`] = `
-<button
- className="js-confirm"
- disabled={false}
- onClick={[Function]}
->
- save
-</button>
-`;
-
exports[`should display correctly 1`] = `
<Modal
ariaHideApp={true}
diff --git a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/LicenseEditionSet-test.tsx.snap b/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/LicenseEditionSet-test.tsx.snap
index b990a23a26c..19750aefb8b 100644
--- a/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/LicenseEditionSet-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/marketplace/components/__tests__/__snapshots__/LicenseEditionSet-test.tsx.snap
@@ -2,7 +2,7 @@
exports[`should correctly display status message after checking license 1`] = `
<p
- className="alert spacer-top alert-success"
+ className="alert alert-success"
>
marketplace.license_preview_status.NO_INSTALL.Foo
</p>
@@ -10,7 +10,7 @@ exports[`should correctly display status message after checking license 1`] = `
exports[`should correctly display status message after checking license 2`] = `
<p
- className="alert spacer-top alert-warning"
+ className="alert alert-warning"
>
marketplace.license_preview_status.AUTOMATIC_INSTALL.Foo
</p>
@@ -18,7 +18,7 @@ exports[`should correctly display status message after checking license 2`] = `
exports[`should correctly display status message after checking license 3`] = `
<p
- className="alert spacer-top alert-danger"
+ className="alert alert-danger"
>
marketplace.license_preview_status.MANUAL_INSTALL.Foo
</p>
@@ -52,7 +52,6 @@ exports[`should display correctly 1`] = `
value=""
/>
<DeferredSpinner
- className="spacer-top"
customSpinner={
<p
className="spacer-top"
@@ -65,13 +64,17 @@ exports[`should display correctly 1`] = `
}
loading={false}
timeout={100}
- />
- <a
- className="display-inline-block spacer-top"
- href="license_url"
- target="_blank"
>
- marketplace.i_need_a_license
- </a>
+ <div
+ className="spacer-top"
+ >
+ <a
+ href="license_url"
+ target="_blank"
+ >
+ marketplace.i_need_a_license
+ </a>
+ </div>
+ </DeferredSpinner>
</div>
`;