name: string;
textDescription: string;
homeUrl: string;
- requestUrl: string;
+ licenseRequestUrl: string;
downloadUrl: string;
}
() => {}
);
+ renderStatusMsg(edition?: Edition) {
+ const { editionStatus } = this.props;
+ return (
+ <NavBarNotif className="alert alert-info">
+ <i className="spinner spacer-right text-bottom" />
+ <span>
+ {edition ? (
+ translateWithParameters(
+ 'marketplace.status_x.' + editionStatus.installationStatus,
+ edition.name
+ )
+ ) : (
+ translate('marketplace.status', editionStatus.installationStatus)
+ )}
+ </span>
+ </NavBarNotif>
+ );
+ }
+
renderRestartMsg(edition?: Edition) {
const { editionStatus, preventRestart } = this.props;
return (
renderStatusAlert() {
const { editionStatus } = this.props;
- const { installationStatus, nextEditionKey } = editionStatus;
+ const { currentEditionKey, installationStatus, nextEditionKey } = editionStatus;
const nextEdition =
this.props.editions && this.props.editions.find(edition => edition.key === nextEditionKey);
+ const currentEdition =
+ this.props.editions &&
+ this.props.editions.find(
+ edition =>
+ edition.key === currentEditionKey || (!currentEditionKey && edition.key === 'community')
+ );
switch (installationStatus) {
case 'AUTOMATIC_IN_PROGRESS':
- return (
- <NavBarNotif className="alert alert-info">
- <i className="spinner spacer-right text-bottom" />
- <span>{translate('marketplace.status.AUTOMATIC_IN_PROGRESS')}</span>
- </NavBarNotif>
- );
+ return this.renderStatusMsg(nextEdition);
case 'AUTOMATIC_READY':
- case 'UNINSTALL_IN_PROGRESS':
return this.renderRestartMsg(nextEdition);
+ case 'UNINSTALL_IN_PROGRESS':
+ return this.renderRestartMsg(currentEdition);
case 'MANUAL_IN_PROGRESS':
return this.renderManualMsg(nextEdition);
}
textDescription: 'Foo desc',
downloadUrl: 'download_url',
homeUrl: 'more_url',
- requestUrl: 'license_url'
+ licenseRequestUrl: 'license_url'
}
]}
preventRestart={false}
}
render() {
- const { canInstall, canUninstall, editions, editionStatus, loading } = this.props;
+ const { canInstall, canUninstall, editions, loading } = this.props;
if (loading) {
return <i className="big-spacer-bottom spinner" />;
}
const sortedEditions = sortEditions(editions);
- const installedIdx =
- editionStatus &&
- sortedEditions.findIndex(edition => edition.key === editionStatus.currentEditionKey);
+ const status = this.props.editionStatus || { installationStatus: 'NONE' };
+ const inProgressStatus = [
+ 'AUTOMATIC_IN_PROGRESS',
+ 'AUTOMATIC_READY',
+ 'UNINSTALL_IN_PROGRESS'
+ ].includes(status.installationStatus);
+ const installedIdx = sortedEditions.findIndex(
+ edition => edition.key === status.currentEditionKey
+ );
+ const nextIdx = sortedEditions.findIndex(edition => edition.key === status.nextEditionKey);
+ const currentIdx = inProgressStatus ? nextIdx : installedIdx;
return (
<div className="spacer-bottom marketplace-editions">
- {sortedEditions.map((edition, idx) => (
- <EditionBox
- canInstall={canInstall}
- canUninstall={canUninstall}
- edition={edition}
- editionStatus={editionStatus}
- isDowngrade={installedIdx !== undefined && idx < installedIdx}
- key={edition.key}
- onInstall={this.handleOpenLicenseForm}
- onUninstall={this.handleOpenUninstallForm}
- />
- ))}
+ <EditionBox
+ actionLabel={translate('marketplace.downgrade')}
+ disableAction={inProgressStatus}
+ displayAction={canUninstall && currentIdx > 0}
+ edition={sortedEditions[0]}
+ editionStatus={status}
+ key={sortedEditions[0].key}
+ onAction={this.handleOpenUninstallForm}
+ />
+ {sortedEditions
+ .slice(1)
+ .map((edition, idx) => (
+ <EditionBox
+ actionLabel={
+ currentIdx > idx + 1 ? (
+ translate('marketplace.downgrade')
+ ) : (
+ translate('marketplace.upgrade')
+ )
+ }
+ disableAction={inProgressStatus}
+ displayAction={canInstall && currentIdx !== idx + 1}
+ edition={edition}
+ editionStatus={status}
+ key={edition.key}
+ onAction={this.handleOpenLicenseForm}
+ />
+ ))}
{this.renderForms(sortedEditions, installedIdx)}
</div>
textDescription: 'foo',
downloadUrl: 'download_url',
homeUrl: 'more_url',
- requestUrl: 'license_url'
+ licenseRequestUrl: 'license_url'
},
{
key: 'comunity',
textDescription: 'bar',
downloadUrl: 'download_url',
homeUrl: 'more_url',
- requestUrl: 'license_url'
+ licenseRequestUrl: 'license_url'
}
];
expect(wrapper).toMatchSnapshot();
});
+it('should display community without the downgrade button', () => {
+ const communityBox = getWrapper({
+ editions: DEFAULT_EDITIONS,
+ editionStatus: {
+ currentEditionKey: '',
+ installationStatus: 'NONE'
+ },
+ loading: false
+ })
+ .find('EditionBox')
+ .first();
+ expect(communityBox.prop('displayAction')).toBeFalsy();
+});
+
+it('should not display action buttons', () => {
+ const wrapper = getWrapper({
+ editions: DEFAULT_EDITIONS,
+ editionStatus: {
+ currentEditionKey: '',
+ installationStatus: 'NONE'
+ },
+ loading: false,
+ canInstall: false,
+ canUninstall: false
+ });
+ wrapper.find('EditionBox').forEach(box => expect(box.prop('displayAction')).toBeFalsy());
+});
+
+it('should display disabled action buttons', () => {
+ const wrapper = getWrapper({
+ editions: DEFAULT_EDITIONS,
+ editionStatus: { installationStatus: 'AUTOMATIC_IN_PROGRESS', nextEditionKey: 'developer' },
+ loading: false
+ });
+
+ wrapper.find('EditionBox').forEach(box => expect(box.prop('disableAction')).toBeTruthy());
+ expect(wrapper.find('EditionBox').map(box => box.prop('displayAction'))).toEqual([true, false]);
+
+ wrapper.setProps({
+ editionStatus: { currentEditionKey: 'developer', installationStatus: 'UNINSTALL_IN_PROGRESS' }
+ });
+ wrapper.find('EditionBox').forEach(box => expect(box.prop('disableAction')).toBeTruthy());
+ expect(wrapper.find('EditionBox').map(box => box.prop('displayAction'))).toEqual([false, true]);
+
+ wrapper.setProps({ editionStatus: { installationStatus: 'AUTOMATIC_READY' } });
+ wrapper.find('EditionBox').forEach(box => expect(box.prop('disableAction')).toBeTruthy());
+});
+
it('should open the license form', () => {
const wrapper = getWrapper({ editions: DEFAULT_EDITIONS });
(wrapper.instance() as EditionBoxes).handleOpenLicenseForm(DEFAULT_EDITIONS[0]);
className="spacer-bottom marketplace-editions"
>
<EditionBox
- canInstall={true}
- canUninstall={true}
+ actionLabel="marketplace.downgrade"
+ disableAction={false}
+ displayAction={true}
edition={
Object {
"downloadUrl": "download_url",
"homeUrl": "more_url",
"key": "comunity",
+ "licenseRequestUrl": "license_url",
"name": "Comunity Edition",
- "requestUrl": "license_url",
"textDescription": "bar",
}
}
"nextEditionKey": "",
}
}
- isDowngrade={true}
- onInstall={[Function]}
- onUninstall={[Function]}
+ onAction={[Function]}
/>
<EditionBox
- canInstall={true}
- canUninstall={true}
+ actionLabel="marketplace.upgrade"
+ disableAction={false}
+ displayAction={false}
edition={
Object {
"downloadUrl": "download_url",
"homeUrl": "more_url",
"key": "developer",
+ "licenseRequestUrl": "license_url",
"name": "Developer Edition",
- "requestUrl": "license_url",
"textDescription": "foo",
}
}
"nextEditionKey": "",
}
}
- isDowngrade={false}
- onInstall={[Function]}
- onUninstall={[Function]}
+ onAction={[Function]}
/>
</div>
`;
import { translate } from '../../../helpers/l10n';
interface Props {
- canInstall: boolean;
- canUninstall: boolean;
+ actionLabel: string;
+ disableAction: boolean;
+ displayAction: boolean;
edition: Edition;
editionStatus?: EditionStatus;
- isDowngrade?: boolean;
- onInstall: (edition: Edition) => void;
- onUninstall: () => void;
+ onAction: (edition: Edition) => void;
}
export default class EditionBox extends React.PureComponent<Props> {
- handleInstall = () => this.props.onInstall(this.props.edition);
-
- renderActions(isInstalled?: boolean, installInProgress?: boolean) {
- const { canInstall, canUninstall, editionStatus } = this.props;
- const uninstallInProgress =
- editionStatus && editionStatus.installationStatus === 'UNINSTALL_IN_PROGRESS';
-
- if (canInstall && !isInstalled) {
- return (
- <button disabled={installInProgress || uninstallInProgress} onClick={this.handleInstall}>
- {this.props.isDowngrade ? (
- translate('marketplace.downgrade')
- ) : (
- translate('marketplace.upgrade')
- )}
- </button>
- );
- }
- if (canUninstall && isInstalled) {
- return (
- <button
- className="button-red"
- disabled={installInProgress || uninstallInProgress}
- onClick={this.props.onUninstall}>
- {translate('marketplace.uninstall')}
- </button>
- );
- }
-
- return null;
- }
+ handleAction = () => this.props.onAction(this.props.edition);
render() {
- const { edition, editionStatus } = this.props;
- const isInstalled = editionStatus && editionStatus.currentEditionKey === edition.key;
- const installInProgress =
- editionStatus &&
- ['AUTOMATIC_IN_PROGRESS', 'AUTOMATIC_READY'].includes(editionStatus.installationStatus);
+ const { disableAction, displayAction, edition, editionStatus } = this.props;
return (
<div className="boxed-group boxed-group-inner marketplace-edition">
{editionStatus && <EditionBoxBadge editionKey={edition.key} status={editionStatus} />}
<a href={edition.homeUrl} target="_blank">
{translate('marketplace.learn_more')}
</a>
- {this.renderActions(isInstalled, installInProgress)}
+ {displayAction && (
+ <button disabled={disableAction} onClick={this.handleAction}>
+ {this.props.actionLabel}
+ </button>
+ )}
</div>
</div>
);
}
export default function EditionBoxBadge({ editionKey, status }: Props) {
- const inProgress = ['AUTOMATIC_IN_PROGRESS', 'AUTOMATIC_READY'].includes(
- status.installationStatus
- );
- const isInstalling = inProgress && status.nextEditionKey === editionKey;
+ const isInstalled =
+ status.currentEditionKey === editionKey ||
+ (!status.currentEditionKey && editionKey === 'community');
+ const isProgressing =
+ status.nextEditionKey === editionKey || (!status.nextEditionKey && editionKey === 'community');
+ const inProgressStatus = [
+ 'AUTOMATIC_READY',
+ 'AUTOMATIC_IN_PROGRESS',
+ 'UNINSTALL_IN_PROGRESS'
+ ].includes(status.installationStatus);
- if (isInstalling) {
- const installReady = status.installationStatus === 'AUTOMATIC_READY';
+ if (inProgressStatus) {
+ if (isProgressing) {
+ return (
+ <span className="marketplace-edition-badge badge badge-normal-size">
+ {status.installationStatus === 'AUTOMATIC_IN_PROGRESS' ? (
+ translate('marketplace.installing')
+ ) : (
+ translate('marketplace.pending')
+ )}
+ </span>
+ );
+ }
+ } else if (isInstalled) {
return (
- <span className="marketplace-edition-badge badge badge-normal-size">
- {installReady ? translate('marketplace.pending') : translate('marketplace.installing')}
- </span>
- );
- }
-
- const isInstalled = status.currentEditionKey === editionKey;
- if (isInstalled) {
- return (
- <span className="marketplace-edition-badge badge badge-normal-size">
- <CheckIcon size={14} className="little-spacer-right text-bottom" />
+ <span className="marketplace-edition-badge badge badge-normal-size display-flex-center">
+ <CheckIcon size={14} className="little-spacer-right" />
{translate('marketplace.installed')}
</span>
);
};
getLicenseFormUrl = (edition: Edition) => {
- let url = edition.requestUrl;
+ let url = edition.licenseRequestUrl;
if (this.state.formData) {
const query = stringify(omitNil(this.state.formData));
if (query) {
<PluginDescription plugin={plugin} updateQuery={updateQuery} />
<td className="text-top big-spacer-right">
<ul>
- <li className="diplay-flex-row little-spacer-bottom">
+ <li className="display-flex-row little-spacer-bottom">
<div className="pull-left spacer-right">
<span className="badge badge-success">{plugin.release.version}</span>
</div>
render() {
const { release, update } = this.props;
return (
- <li key={release.version} className="diplay-flex-row little-spacer-bottom">
+ <li key={release.version} className="display-flex-row little-spacer-bottom">
<div className="pull-left spacer-right">
{update.status === 'COMPATIBLE' ? (
<span className="js-update-version badge badge-success">{release.version}</span>
const { edition } = this.props;
const { loading } = this.state;
const currentEdition = edition ? edition.name : translate('marketplace.commercial_edition');
- const header = translateWithParameters('marketplace.uninstall_x', currentEdition);
+ const header = translateWithParameters('marketplace.downgrade_to_community_edition');
return (
<Modal
isOpen={true}
<footer className="modal-foot">
{loading && <i className="spinner spacer-right" />}
- <button className="button-red" disabled={loading} onClick={this.handleConfirmClick}>
- {translate('marketplace.uninstall')}
+ <button disabled={loading} onClick={this.handleConfirmClick}>
+ {translate('marketplace.downgrade')}
</button>
<a className="js-modal-close" href="#" onClick={this.handleCancelClick}>
{translate('cancel')}
textDescription: 'Foo desc',
downloadUrl: 'download_url',
homeUrl: 'more_url',
- requestUrl: 'license_url'
+ licenseRequestUrl: 'license_url'
};
it('should display the edition', () => {
expect(getWrapper()).toMatchSnapshot();
});
-it('should disable upgrade button', () => {
- expect(
- getWrapper({
- editionStatus: {
- currentEditionKey: '',
- nextEditionKey: 'foo',
- installationStatus: 'AUTOMATIC_IN_PROGRESS'
- }
- })
- ).toMatchSnapshot();
- expect(
- getWrapper({
- editionStatus: {
- currentEditionKey: '',
- nextEditionKey: 'foo',
- installationStatus: 'AUTOMATIC_READY'
- }
- })
- ).toMatchSnapshot();
+it('should disable action button', () => {
+ expect(getWrapper({ disableAction: true })).toMatchSnapshot();
});
-it('should disable uninstall button', () => {
- expect(
- getWrapper({
- editionStatus: {
- currentEditionKey: 'foo',
- nextEditionKey: 'foo',
- installationStatus: 'AUTOMATIC_IN_PROGRESS'
- }
- })
- ).toMatchSnapshot();
-});
-
-it('should correctly hide upgrade/uninstall buttons', () => {
- expect(getWrapper({ canInstall: false })).toMatchSnapshot();
- expect(
- getWrapper({
- canUninstall: false,
- editionStatus: {
- currentEditionKey: 'foo',
- nextEditionKey: '',
- installationStatus: 'NONE'
- }
- })
- ).toMatchSnapshot();
-});
-
-it('should display a downgrade button', () => {
- expect(getWrapper({ isDowngrade: true })).toMatchSnapshot();
+it('should correctly hide action buttons', () => {
+ expect(getWrapper({ displayAction: false })).toMatchSnapshot();
});
function getWrapper(props = {}) {
return shallow(
<EditionBox
- canInstall={true}
- canUninstall={true}
+ actionLabel="action"
+ disableAction={false}
+ displayAction={true}
edition={DEFAULT_EDITION}
editionStatus={DEFAULT_STATUS}
- onInstall={jest.fn()}
- onUninstall={jest.fn()}
+ onAction={jest.fn()}
{...props}
/>
);
textDescription: 'Foo desc',
downloadUrl: 'download_url',
homeUrl: 'more_url',
- requestUrl: 'license_url'
+ licenseRequestUrl: 'license_url'
};
beforeEach(() => {
textDescription: 'Foo desc',
downloadUrl: 'download_url',
homeUrl: 'more_url',
- requestUrl: 'license_url'
+ licenseRequestUrl: 'license_url'
};
beforeEach(() => {
textDescription: 'Foo desc',
downloadUrl: 'download_url',
homeUrl: 'more_url',
- requestUrl: 'license_url'
+ licenseRequestUrl: 'license_url'
};
beforeEach(() => {
// Jest Snapshot v1, https://goo.gl/fbAQLP
-exports[`should correctly hide upgrade/uninstall buttons 1`] = `
+exports[`should correctly hide action buttons 1`] = `
<div
className="boxed-group boxed-group-inner marketplace-edition"
>
</div>
`;
-exports[`should correctly hide upgrade/uninstall buttons 2`] = `
-<div
- className="boxed-group boxed-group-inner marketplace-edition"
->
- <EditionBoxBadge
- editionKey="foo"
- status={
- Object {
- "currentEditionKey": "foo",
- "installationStatus": "NONE",
- "nextEditionKey": "",
- }
- }
- />
- <div>
- <h3
- className="spacer-bottom"
- >
- Foo
- </h3>
- <p>
- Foo desc
- </p>
- </div>
- <div
- className="marketplace-edition-action spacer-top"
- >
- <a
- href="more_url"
- target="_blank"
- >
- marketplace.learn_more
- </a>
- </div>
-</div>
-`;
-
-exports[`should disable uninstall button 1`] = `
-<div
- className="boxed-group boxed-group-inner marketplace-edition"
->
- <EditionBoxBadge
- editionKey="foo"
- status={
- Object {
- "currentEditionKey": "foo",
- "installationStatus": "AUTOMATIC_IN_PROGRESS",
- "nextEditionKey": "foo",
- }
- }
- />
- <div>
- <h3
- className="spacer-bottom"
- >
- Foo
- </h3>
- <p>
- Foo desc
- </p>
- </div>
- <div
- className="marketplace-edition-action spacer-top"
- >
- <a
- href="more_url"
- target="_blank"
- >
- marketplace.learn_more
- </a>
- <button
- className="button-red"
- disabled={true}
- onClick={[Function]}
- >
- marketplace.uninstall
- </button>
- </div>
-</div>
-`;
-
-exports[`should disable upgrade button 1`] = `
-<div
- className="boxed-group boxed-group-inner marketplace-edition"
->
- <EditionBoxBadge
- editionKey="foo"
- status={
- Object {
- "currentEditionKey": "",
- "installationStatus": "AUTOMATIC_IN_PROGRESS",
- "nextEditionKey": "foo",
- }
- }
- />
- <div>
- <h3
- className="spacer-bottom"
- >
- Foo
- </h3>
- <p>
- Foo desc
- </p>
- </div>
- <div
- className="marketplace-edition-action spacer-top"
- >
- <a
- href="more_url"
- target="_blank"
- >
- marketplace.learn_more
- </a>
- <button
- disabled={true}
- onClick={[Function]}
- >
- marketplace.upgrade
- </button>
- </div>
-</div>
-`;
-
-exports[`should disable upgrade button 2`] = `
-<div
- className="boxed-group boxed-group-inner marketplace-edition"
->
- <EditionBoxBadge
- editionKey="foo"
- status={
- Object {
- "currentEditionKey": "",
- "installationStatus": "AUTOMATIC_READY",
- "nextEditionKey": "foo",
- }
- }
- />
- <div>
- <h3
- className="spacer-bottom"
- >
- Foo
- </h3>
- <p>
- Foo desc
- </p>
- </div>
- <div
- className="marketplace-edition-action spacer-top"
- >
- <a
- href="more_url"
- target="_blank"
- >
- marketplace.learn_more
- </a>
- <button
- disabled={true}
- onClick={[Function]}
- >
- marketplace.upgrade
- </button>
- </div>
-</div>
-`;
-
-exports[`should display a downgrade button 1`] = `
+exports[`should disable action button 1`] = `
<div
className="boxed-group boxed-group-inner marketplace-edition"
>
marketplace.learn_more
</a>
<button
- disabled={false}
+ disabled={true}
onClick={[Function]}
>
- marketplace.downgrade
+ action
</button>
</div>
</div>
disabled={false}
onClick={[Function]}
>
- marketplace.upgrade
+ action
</button>
</div>
</div>
"downloadUrl": "download_url",
"homeUrl": "more_url",
"key": "foo",
+ "licenseRequestUrl": "license_url",
"name": "Foo",
- "requestUrl": "license_url",
"textDescription": "Foo desc",
}
}
"downloadUrl": "download_url",
"homeUrl": "more_url",
"key": "foo",
+ "licenseRequestUrl": "license_url",
"name": "Foo",
- "requestUrl": "license_url",
"textDescription": "Foo desc",
},
]
bodyOpenClassName="ReactModal__Body--open"
className="modal"
closeTimeoutMS={0}
- contentLabel="marketplace.uninstall_x.Foo"
+ contentLabel="marketplace.downgrade_to_community_edition."
isOpen={true}
onRequestClose={[Function]}
overlayClassName="modal-overlay"
className="modal-head"
>
<h2>
- marketplace.uninstall_x.Foo
+ marketplace.downgrade_to_community_edition.
</h2>
</header>
<div
className="modal-foot"
>
<button
- className="button-red"
disabled={false}
onClick={[Function]}
>
- marketplace.uninstall
+ marketplace.downgrade
</button>
<a
className="js-modal-close"
display: inline-block !important;
}
-.diplay-flex-row {
+.display-flex-row {
display: flex !important;
flex-direction: row;
}
+.display-flex-center {
+ display: flex !important;
+ align-items: center;
+}
+
.rounded {
border-radius: 2px;
}
marketplace.installing=Installing...
marketplace.upgrade=Upgrade
marketplace.downgrade=Downgrade
-marketplace.uninstall_x=Uninstall {0}
+marketplace.downgrade_to_community_edition=Downgrade to Community Edition
marketplace.uninstall_x_confirmation=Are you sure you want to uninstall {0} and get back to the Community Edition?
marketplace.pending=Pending...
marketplace.checking_license=Checking your license...
marketplace.terms_and_conditions=Terms and Conditions
marketplace.editions_unavailable=Explore our Commercial Editions on {url}: advanced feature packs brought to you by SonarSource
marketplace.release_notes=Release Notes
-marketplace.status.AUTOMATIC_IN_PROGRESS=Updating your installation... Please wait...
-marketplace.status.AUTOMATIC_READY=Commercial Edition successfully installed. Please restart the server to activate your new features.
-marketplace.status.UNINSTALL_IN_PROGRESS=Commercial Edition successfully uninstalled. Please restart the server to remove the features.
+marketplace.status.AUTOMATIC_IN_PROGRESS=Installing your new Commercial Edition... Please wait...
+marketplace.status.AUTOMATIC_READY=Commercial Edition successfully installed. Please restart the server to activate your new edition.
+marketplace.status.UNINSTALL_IN_PROGRESS=Commercial Edition successfully downgraded. Please restart the server to remove the features.
marketplace.status.MANUAL_IN_PROGRESS=Commercial Edition can't automatically be installed because of internet access issues. Please manually install the package in your SonarQube's plugins folder.
-marketplace.status_x.AUTOMATIC_READY={0} successfully installed. Please restart the server to activate your new features.
-marketplace.status_X.UNINSTALL_IN_PROGRESS={0} successfully uninstalled. Please restart the server to remove the features.
+marketplace.status_x.AUTOMATIC_IN_PROGRESS=Installing your new {0}... Please wait...
+marketplace.status_x.AUTOMATIC_READY={0} successfully installed. Please restart the server to activate your new edition.
+marketplace.status_x.UNINSTALL_IN_PROGRESS=Successfully downgraded to {0}. Please restart the server to remove the features.
marketplace.status_x.MANUAL_IN_PROGRESS={0} can't automatically be installed because of internet access issues. Please manually install the package in your SonarQube's plugins folder.
marketplace.how_to_install=How to install it?
marketplace.enter_license_for_x=Enter your license key for {0}