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)
<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')
) : (
* 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';
}
interface State {
+ acceptTerms: boolean;
license: string;
licenseEdition?: Edition;
loading: boolean;
constructor(props: Props) {
super(props);
- this.state = { license: '', loading: false };
+ this.state = { acceptTerms: false, license: '', loading: false };
this.fetchLicensePreview = debounce(this.fetchLicensePreview, 100);
}
}
};
+ 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>
);
}
/>
<DeferredSpinner
- className="spacer-top"
loading={loading}
customSpinner={
<p className="spacer-top">
}>
{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>
);
}
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 () => {
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;
});
});
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 = {}) {
);
}
-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;
}
// 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}
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>
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>
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>
value=""
/>
<DeferredSpinner
- className="spacer-top"
customSpinner={
<p
className="spacer-top"
}
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>
`;