isExpired: boolean;
isOfficialDistribution: boolean;
isSupported: boolean;
+ isValidEdition: boolean;
isValidServerId: boolean;
loc: number;
maxLoc: number;
import GlobalFooterSonarCloud from './GlobalFooterSonarCloud';
import GlobalFooterBranding from './GlobalFooterBranding';
import InstanceMessage from '../../components/common/InstanceMessage';
-import { EDITIONS } from '../../apps/marketplace/utils';
+import { EDITIONS, EditionKey } from '../../apps/marketplace/utils';
import { translate, translateWithParameters } from '../../helpers/l10n';
import { isSonarCloud } from '../../helpers/system';
interface Props {
hideLoggedInInfo?: boolean;
productionDatabase: boolean;
- sonarqubeEdition: string;
+ sonarqubeEdition?: EditionKey;
sonarqubeVersion?: string;
}
export default function GlobalFooter({
hideLoggedInInfo,
productionDatabase,
+ sonarqubeEdition,
sonarqubeVersion
}: Props) {
if (isSonarCloud()) {
import { connect } from 'react-redux';
import GlobalFooter from './GlobalFooter';
import { getAppState } from '../../store/rootReducer';
+import { EditionKey } from '../../apps/marketplace/utils';
interface StateProps {
productionDatabase: boolean;
- sonarqubeEdition: string;
+ sonarqubeEdition?: EditionKey;
sonarqubeVersion?: string;
}
import { connect } from 'react-redux';
import OnboardingModal from '../../apps/tutorials/onboarding/OnboardingModal';
import LicensePromptModal from '../../apps/marketplace/components/LicensePromptModal';
-import { showLicense } from '../../api/marketplace';
+import { CurrentUser, isLoggedIn } from '../types';
import { differenceInDays, parseDate, toShortNotSoISOString } from '../../helpers/dates';
-import { hasMessage } from '../../helpers/l10n';
-import { save, get } from '../../helpers/storage';
+import { EditionKey } from '../../apps/marketplace/utils';
import { getCurrentUser, getAppState } from '../../store/rootReducer';
import { skipOnboarding } from '../../store/users/actions';
-import { CurrentUser, isLoggedIn } from '../types';
+import { showLicense } from '../../api/marketplace';
+import { hasMessage } from '../../helpers/l10n';
+import { save, get } from '../../helpers/storage';
interface StateProps {
canAdmin: boolean;
- currentEdition: string;
+ currentEdition?: EditionKey;
currentUser: CurrentUser;
}
}
closeOnboarding = () => {
- this.setState(state => ({
- modal: state.modal === ModalKey.onboarding ? undefined : state.modal
- }));
- this.props.skipOnboarding();
+ this.setState(state => {
+ if (state.modal === ModalKey.onboarding) {
+ this.props.skipOnboarding();
+ return { modal: undefined };
+ }
+ return undefined;
+ });
};
closeLicense = () => {
- this.setState(state => ({
- modal: state.modal === ModalKey.license ? undefined : state.modal
- }));
+ this.setState(state => {
+ if (state.modal === ModalKey.license) {
+ return { modal: undefined };
+ }
+ return undefined;
+ });
};
openOnboarding = () => {
tryAutoOpenLicense = () => {
const { canAdmin, currentEdition, currentUser } = this.props;
const hasLicenseManager = hasMessage('license.prompt.title');
- if (
- currentEdition !== 'community' &&
- isLoggedIn(currentUser) &&
- canAdmin &&
- hasLicenseManager
- ) {
+ const hasLicensedEdition = currentEdition && currentEdition !== EditionKey.community;
+
+ if (canAdmin && hasLicensedEdition && isLoggedIn(currentUser) && hasLicenseManager) {
const lastPrompt = get(LICENSE_PROMPT, currentUser.login);
+
if (!lastPrompt || differenceInDays(new Date(), parseDate(lastPrompt)) >= 1) {
return showLicense().then(license => {
- if (!license || license.edition !== currentEdition) {
+ if (!license || !license.isValidEdition) {
save(LICENSE_PROMPT, toShortNotSoISOString(new Date()), currentUser.login);
this.setState({ modal: ModalKey.license });
return Promise.resolve();
import * as React from 'react';
import { shallow } from 'enzyme';
import GlobalFooter from '../GlobalFooter';
+import { EditionKey } from '../../../apps/marketplace/utils';
import { isSonarCloud } from '../../../helpers/system';
jest.mock('../../../helpers/system', () => ({ isSonarCloud: jest.fn() }));
it('should display the sq version', () => {
expect(
- getWrapper({ sonarqubeEdition: 'enterprise', sonarqubeVersion: '6.4-SNAPSHOT' })
+ getWrapper({ sonarqubeEdition: EditionKey.enterprise, sonarqubeVersion: '6.4-SNAPSHOT' })
).toMatchSnapshot();
});
function getWrapper(props = {}, onSonarCloud = false) {
(isSonarCloud as jest.Mock).mockImplementation(() => onSonarCloud);
- return shallow(<GlobalFooter productionDatabase={true} sonarqubeEdition="community" {...props} />);
+ return shallow(<GlobalFooter productionDatabase={true} sonarqubeEdition={EditionKey.community} {...props} />);
}
import { waitAndUpdate } from '../../../helpers/testUtils';
import { differenceInDays, toShortNotSoISOString } from '../../../helpers/dates';
import { LoggedInUser } from '../../types';
+import { EditionKey } from '../../../apps/marketplace/utils';
jest.mock('../../../api/marketplace', () => ({
showLicense: jest.fn().mockResolvedValue(undefined)
});
it('should render only the children', async () => {
- const wrapper = getWrapper({ currentEdition: 'community' });
+ const wrapper = getWrapper({ currentEdition: EditionKey.community });
await shouldNotHaveModals(wrapper);
expect(showLicense).toHaveBeenCalledTimes(0);
expect(wrapper.find('div').exists()).toBeTruthy();
(hasMessage as jest.Mock<any>).mockReturnValueOnce(false);
await shouldNotHaveModals(getWrapper());
- (showLicense as jest.Mock<any>).mockResolvedValueOnce({ edition: 'enterprise' });
+ (showLicense as jest.Mock<any>).mockResolvedValueOnce({ isValidEdition: true });
await shouldNotHaveModals(getWrapper());
(get as jest.Mock<any>).mockReturnValueOnce('date');
(differenceInDays as jest.Mock<any>).mockReturnValueOnce(1);
await shouldDisplayLicense(getWrapper());
- (showLicense as jest.Mock<any>).mockResolvedValueOnce({ edition: 'developer' });
+ (showLicense as jest.Mock<any>).mockResolvedValueOnce({ isValidEdition: false });
await shouldDisplayLicense(getWrapper());
});
})
);
- (showLicense as jest.Mock<any>).mockResolvedValueOnce({ edition: 'enterprise' });
+ (showLicense as jest.Mock<any>).mockResolvedValueOnce({ isValidEdition: true });
await shouldDisplayOnboarding(
getWrapper({ currentUser: { ...LOGGED_IN_USER, showOnboardingTutorial: true } })
);
return shallow(
<StartupModal
canAdmin={true}
- currentEdition="enterprise"
+ currentEdition={EditionKey.enterprise}
currentUser={LOGGED_IN_USER}
skipOnboarding={jest.fn()}
{...props}>
import Footer from './Footer';
import PluginsList from './PluginsList';
import Search from './Search';
-import { filterPlugins, parseQuery, Query, serializeQuery } from './utils';
+import { filterPlugins, parseQuery, Query, serializeQuery, EditionKey } from './utils';
import Suggestions from '../../app/components/embed-docs-modal/Suggestions';
import {
getAvailablePlugins,
import './style.css';
export interface Props {
- currentEdition?: string;
+ currentEdition?: EditionKey;
fetchPendingPlugins: () => void;
location: { pathname: string; query: RawQuery };
pendingPlugins: PluginPendingResult;
};
render() {
- const { currentEdition = 'community', standaloneMode, pendingPlugins } = this.props;
+ const { currentEdition, standaloneMode, pendingPlugins } = this.props;
const { loadingPlugins, plugins } = this.state;
const query = parseQuery(this.props.location.query);
const filteredPlugins = query.search ? filterPlugins(plugins, query.search) : plugins;
*/
import { connect } from 'react-redux';
import App from './App';
+import { EditionKey } from './utils';
import {
getAppState,
getGlobalSettingValue,
}
interface StateToProps {
- currentEdition?: string;
+ currentEdition?: EditionKey;
pendingPlugins: PluginPendingResult;
standaloneMode: boolean;
updateCenterActive: boolean;
import * as React from 'react';
import EditionBox from './components/EditionBox';
-import { EDITIONS } from './utils';
+import { EDITIONS, EditionKey } from './utils';
import { getFormData } from '../../api/marketplace';
export interface Props {
- currentEdition: string;
+ currentEdition?: EditionKey;
}
interface State {
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
+import { EditionKey } from './utils';
import { translate } from '../../helpers/l10n';
interface Props {
- currentEdition: string;
+ currentEdition?: EditionKey;
}
export default function Header({ currentEdition }: Props) {
return (
<header className="page-header" id="marketplace-header">
<h1 className="page-title">{translate('marketplace.page')}</h1>
- <h3 className="page-description">
- {translate('marketplace.page.you_are_running', currentEdition)}
- </h3>
+ {currentEdition && (
+ <h3 className="page-description">
+ {translate('marketplace.page.you_are_running', currentEdition)}
+ </h3>
+ )}
<p className="page-description">
- {currentEdition === 'datacenter'
+ {currentEdition === EditionKey.datacenter
? translate('marketplace.page.description_best_edition')
: translate('marketplace.page.description')}
</p>
import * as React from 'react';
import { shallow } from 'enzyme';
import EditionBoxes from '../EditionBoxes';
-
-jest.mock('../utils', () => ({
- EDITIONS: [
- { key: 'community', name: 'Community Edition', homeUrl: 'more_url' },
- {
- key: 'developer',
- name: 'Developer Edition',
- homeUrl: 'more_url'
- },
- {
- key: 'enterprise',
- name: 'Enterprise Edition',
- homeUrl: 'more_url'
- },
- {
- key: 'datacenter',
- name: 'Data Center Edition',
- homeUrl: 'more_url'
- }
- ]
-}));
+import { EditionKey } from '../utils';
it('should display the available edition boxes correctly', () => {
expect(getWrapper()).toMatchSnapshot();
});
it('should display the enterprise and datacenter edition boxes', () => {
- expect(getWrapper({ currentEdition: 'developer' })).toMatchSnapshot();
+ expect(getWrapper({ currentEdition: EditionKey.developer })).toMatchSnapshot();
});
it('should display the datacenter edition box only', () => {
- expect(getWrapper({ currentEdition: 'enterprise' })).toMatchSnapshot();
+ expect(getWrapper({ currentEdition: EditionKey.enterprise })).toMatchSnapshot();
});
it('should not display any edition box', () => {
- expect(getWrapper({ currentEdition: 'datacenter' }).type()).toBeNull();
+ expect(getWrapper({ currentEdition: EditionKey.datacenter }).type()).toBeNull();
});
function getWrapper(props = {}) {
- return shallow(<EditionBoxes currentEdition={'community'} {...props} />);
+ return shallow(<EditionBoxes currentEdition={EditionKey.community} {...props} />);
}
import * as React from 'react';
import { shallow } from 'enzyme';
import Header from '../Header';
+import { EditionKey } from '../utils';
it('should render with installed editions', () => {
- expect(shallow(<Header currentEdition="community" />)).toMatchSnapshot();
- expect(shallow(<Header currentEdition="datacenter" />)).toMatchSnapshot();
+ expect(shallow(<Header currentEdition={EditionKey.community} />)).toMatchSnapshot();
+ expect(shallow(<Header currentEdition={EditionKey.datacenter} />)).toMatchSnapshot();
});
currentEdition="community"
edition={
Object {
- "homeUrl": "more_url",
+ "downloadUrl": "https://sonarsource.bintray.com/CommercialDistribution/editions/developer-edition-7.0.0.717.zip",
+ "homeUrl": "https://redirect.sonarsource.com/editions/developer.html",
"key": "developer",
"name": "Developer Edition",
}
currentEdition="community"
edition={
Object {
- "homeUrl": "more_url",
+ "downloadUrl": "https://sonarsource.bintray.com/CommercialDistribution/editions/enterprise-edition-7.0.0.717.zip",
+ "homeUrl": "https://redirect.sonarsource.com/editions/enterprise.html",
"key": "enterprise",
"name": "Enterprise Edition",
}
currentEdition="community"
edition={
Object {
- "homeUrl": "more_url",
+ "downloadUrl": "https://sonarsource.bintray.com/CommercialDistribution/editions/datacenter-edition-7.0.0.717.zip",
+ "homeUrl": "https://redirect.sonarsource.com/editions/datacenter.html",
"key": "datacenter",
"name": "Data Center Edition",
}
currentEdition="enterprise"
edition={
Object {
- "homeUrl": "more_url",
+ "downloadUrl": "https://sonarsource.bintray.com/CommercialDistribution/editions/datacenter-edition-7.0.0.717.zip",
+ "homeUrl": "https://redirect.sonarsource.com/editions/datacenter.html",
"key": "datacenter",
"name": "Data Center Edition",
}
currentEdition="developer"
edition={
Object {
- "homeUrl": "more_url",
+ "downloadUrl": "https://sonarsource.bintray.com/CommercialDistribution/editions/enterprise-edition-7.0.0.717.zip",
+ "homeUrl": "https://redirect.sonarsource.com/editions/enterprise.html",
"key": "enterprise",
"name": "Enterprise Edition",
}
currentEdition="developer"
edition={
Object {
- "homeUrl": "more_url",
+ "downloadUrl": "https://sonarsource.bintray.com/CommercialDistribution/editions/datacenter-edition-7.0.0.717.zip",
+ "homeUrl": "https://redirect.sonarsource.com/editions/datacenter.html",
"key": "datacenter",
"name": "Data Center Edition",
}
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import * as React from 'react';
-import { Edition, getEditionUrl } from '../utils';
+import { Edition, getEditionUrl, EditionKey } from '../utils';
import DocInclude from '../../../components/docs/DocInclude';
import { translate } from '../../../helpers/l10n';
interface Props {
- currentEdition: string;
+ currentEdition?: EditionKey;
edition: Edition;
ncloc?: number;
serverId?: string;
import * as React from 'react';
import { shallow } from 'enzyme';
import EditionBox from '../EditionBox';
+import { EditionKey } from '../../utils';
const DEFAULT_EDITION = {
- key: 'foo',
- name: 'Foo',
+ key: EditionKey.developer,
+ name: 'Developer',
downloadUrl: 'download_url',
homeUrl: 'more_url'
};
expect(
shallow(
<EditionBox
- currentEdition="community"
+ currentEdition={EditionKey.community}
edition={DEFAULT_EDITION}
ncloc={1000}
serverId="serverId"
className="boxed-group boxed-group-inner marketplace-edition"
>
<DocInclude
- path="/tooltips/editions/foo"
+ path="/tooltips/editions/developer"
/>
<div
className="marketplace-edition-action spacer-top"
import { cleanQuery, parseAsString, RawQuery, serializeString } from '../../helpers/query';
import { omitNil } from '../../helpers/request';
+export enum EditionKey {
+ community = 'community',
+ developer = 'developer',
+ enterprise = 'enterprise',
+ datacenter = 'datacenter'
+}
+
export interface Edition {
downloadUrl?: string;
homeUrl: string;
- key: string;
+ key: EditionKey;
name: string;
}
export const EDITIONS: Edition[] = [
{
- key: 'community',
+ key: EditionKey.community,
name: 'Community Edition',
homeUrl: 'https://redirect.sonarsource.com/editions/community.html'
},
{
- key: 'developer',
+ key: EditionKey.developer,
name: 'Developer Edition',
homeUrl: 'https://redirect.sonarsource.com/editions/developer.html',
downloadUrl:
'https://sonarsource.bintray.com/CommercialDistribution/editions/developer-edition-7.0.0.717.zip'
},
{
- key: 'enterprise',
+ key: EditionKey.enterprise,
name: 'Enterprise Edition',
homeUrl: 'https://redirect.sonarsource.com/editions/enterprise.html',
downloadUrl:
'https://sonarsource.bintray.com/CommercialDistribution/editions/enterprise-edition-7.0.0.717.zip'
},
{
- key: 'datacenter',
+ key: EditionKey.datacenter,
name: 'Data Center Edition',
homeUrl: 'https://redirect.sonarsource.com/editions/datacenter.html',
downloadUrl:
#
#------------------------------------------------------------------------------
marketplace.page=Marketplace
-marketplace.page.description=Discover more features with the SonarSource Editions:
-marketplace.page.description_best_edition=This Edition gives you access to all features of the SonarQube-SonarLint ecosystem, including all SonarSource code analyzers !
+marketplace.page.description=Discover more features with SonarSource Editions:
+marketplace.page.description_best_edition=This Edition gives you access to all features of the SonarQube-SonarLint ecosystem, including all SonarSource code analyzers!
marketplace.page.you_are_running.community=You are currently running a Community Edition.
marketplace.page.you_are_running.developer=You are currently running a Developer Edition.
marketplace.page.you_are_running.enterprise=You are currently running an Enterprise Edition.
marketplace.page.you_are_running.datacenter=You are currently running a Data Center Edition.
-marketplace.page.open_source_plugins=Community plugins
+marketplace.page.open_source_plugins=Plugins
marketplace.instance_needs_to_be_restarted_to={instance} needs to be restarted in order to
marketplace.install_x_plugins=install {nb} plugins
marketplace.update_x_plugins=update {nb} plugins