From: Stas Vilchik Date: Wed, 30 May 2018 15:33:38 +0000 (+0200) Subject: SONAR-10833 Reduce loading waterfall X-Git-Tag: 7.5~1098 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=fa85337a62f36696f5a50e1a6a794b8909bb8d44;p=sonarqube.git SONAR-10833 Reduce loading waterfall --- diff --git a/server/sonar-server/src/main/java/org/sonar/server/ui/ws/GlobalAction.java b/server/sonar-server/src/main/java/org/sonar/server/ui/ws/GlobalAction.java index 19baa441108..b2b70701e6e 100644 --- a/server/sonar-server/src/main/java/org/sonar/server/ui/ws/GlobalAction.java +++ b/server/sonar-server/src/main/java/org/sonar/server/ui/ws/GlobalAction.java @@ -50,7 +50,6 @@ import static org.sonar.core.config.WebConstants.SONAR_LF_ENABLE_GRAVATAR; import static org.sonar.core.config.WebConstants.SONAR_LF_GRAVATAR_SERVER_URL; import static org.sonar.core.config.WebConstants.SONAR_LF_LOGO_URL; import static org.sonar.core.config.WebConstants.SONAR_LF_LOGO_WIDTH_PX; -import static org.sonar.process.ProcessProperties.Property.SONARCLOUD_ENABLED; import static org.sonar.process.ProcessProperties.Property.SONAR_UPDATECENTER_ACTIVATE; public class GlobalAction implements NavigationWsAction, Startable { @@ -94,7 +93,6 @@ public class GlobalAction implements NavigationWsAction, Startable { @Override public void start() { - this.systemSettingValuesByKey.put(SONARCLOUD_ENABLED.getKey(), config.get(SONARCLOUD_ENABLED.getKey()).orElse(null)); this.systemSettingValuesByKey.put(SONAR_UPDATECENTER_ACTIVATE.getKey(), config.get(SONAR_UPDATECENTER_ACTIVATE.getKey()).orElse(null)); } diff --git a/server/sonar-server/src/test/java/org/sonar/server/ui/ws/GlobalActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/ui/ws/GlobalActionTest.java index adc91a98de5..0daaf5c5a3a 100644 --- a/server/sonar-server/src/test/java/org/sonar/server/ui/ws/GlobalActionTest.java +++ b/server/sonar-server/src/test/java/org/sonar/server/ui/ws/GlobalActionTest.java @@ -104,7 +104,6 @@ public class GlobalActionTest { settings.setProperty("sonar.lf.logoWidthPx", 135); settings.setProperty("sonar.lf.gravatarServerUrl", "https://secure.gravatar.com/avatar/{EMAIL_MD5}.jpg?s={SIZE}&d=identicon"); settings.setProperty("sonar.lf.enableGravatar", true); - settings.setProperty("sonar.sonarcloud.enabled", true); settings.setProperty("sonar.updatecenter.activate", false); settings.setProperty("sonar.editions.jsonUrl", "https://foo.bar/editions.json"); settings.setProperty("sonar.technicalDebt.ratingGrid", "0.05,0.1,0.2,0.5"); @@ -118,7 +117,6 @@ public class GlobalActionTest { " \"sonar.lf.logoWidthPx\": \"135\"," + " \"sonar.lf.gravatarServerUrl\": \"https://secure.gravatar.com/avatar/{EMAIL_MD5}.jpg?s={SIZE}&d=identicon\"," + " \"sonar.lf.enableGravatar\": \"true\"," + - " \"sonar.sonarcloud.enabled\": \"true\"," + " \"sonar.editions.jsonUrl\": \"https://foo.bar/editions.json\"," + " \"sonar.updatecenter.activate\": \"false\"," + " \"sonar.technicalDebt.ratingGrid\": \"0.05,0.1,0.2,0.5\"" + diff --git a/server/sonar-web/config/webpack.config.js b/server/sonar-web/config/webpack.config.js index 5e89c7f0e2f..7289ad95544 100644 --- a/server/sonar-web/config/webpack.config.js +++ b/server/sonar-web/config/webpack.config.js @@ -137,7 +137,12 @@ module.exports = ({ production = true }) => ({ }), // keep `InterpolateHtmlPlugin` after `HtmlWebpackPlugin` - !production && new InterpolateHtmlPlugin({ WEB_CONTEXT: '' }), + !production && + new InterpolateHtmlPlugin({ + WEB_CONTEXT: process.env.WEB_CONTEXT || '', + SERVER_STATUS: process.env.SERVER_STATUS || 'UP', + INSTANCE: process.env.INSTANCE || 'SonarQube' + }), !production && new webpack.HotModuleReplacementPlugin() ].filter(Boolean), diff --git a/server/sonar-web/public/index.html b/server/sonar-web/public/index.html index 4da3597a841..812681b41f7 100644 --- a/server/sonar-web/public/index.html +++ b/server/sonar-web/public/index.html @@ -23,7 +23,7 @@ - Loading... + %INSTANCE% <% for (let css of htmlWebpackPlugin.files.css) { %> @@ -37,7 +37,11 @@ Loading... - + <% for (let chunk in htmlWebpackPlugin.files.chunks) { %> <% } %> diff --git a/server/sonar-web/src/main/js/app/components/App.tsx b/server/sonar-web/src/main/js/app/components/App.tsx index 7390182e2fd..3930b084f79 100644 --- a/server/sonar-web/src/main/js/app/components/App.tsx +++ b/server/sonar-web/src/main/js/app/components/App.tsx @@ -26,6 +26,7 @@ import { CurrentUser } from '../types'; import { fetchCurrentUser } from '../../store/users/actions'; import { fetchLanguages, fetchAppState } from '../../store/rootActions'; import { fetchMyOrganizations } from '../../apps/account/organizations/actions'; +import { getInstance } from '../../helpers/system'; interface Props { children: JSX.Element; @@ -39,7 +40,6 @@ interface State { branchesEnabled: boolean; canAdmin: boolean; loading: boolean; - onSonarCloud: boolean; organizationsEnabled: boolean; } @@ -49,7 +49,6 @@ class App extends React.PureComponent { static childContextTypes = { branchesEnabled: PropTypes.bool.isRequired, canAdmin: PropTypes.bool.isRequired, - onSonarCloud: PropTypes.bool, organizationsEnabled: PropTypes.bool }; @@ -59,7 +58,6 @@ class App extends React.PureComponent { branchesEnabled: false, canAdmin: false, loading: true, - onSonarCloud: false, organizationsEnabled: false }; } @@ -68,7 +66,6 @@ class App extends React.PureComponent { return { branchesEnabled: this.state.branchesEnabled, canAdmin: this.state.canAdmin, - onSonarCloud: this.state.onSonarCloud, organizationsEnabled: this.state.organizationsEnabled }; } @@ -104,9 +101,6 @@ class App extends React.PureComponent { this.setState({ branchesEnabled: appState.branchesEnabled, canAdmin: appState.canAdmin, - onSonarCloud: Boolean( - appState.settings && appState.settings['sonar.sonarcloud.enabled'] === 'true' - ), organizationsEnabled: appState.organizationsEnabled }); } @@ -120,7 +114,7 @@ class App extends React.PureComponent { } return ( <> - + {this.props.children} ); diff --git a/server/sonar-web/src/main/js/app/components/AppContextContainer.tsx b/server/sonar-web/src/main/js/app/components/AppContextContainer.tsx deleted file mode 100644 index 0ab3e78ccc4..00000000000 --- a/server/sonar-web/src/main/js/app/components/AppContextContainer.tsx +++ /dev/null @@ -1,76 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 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 * as React from 'react'; -import * as PropTypes from 'prop-types'; -import Helmet from 'react-helmet'; -import GlobalLoading from './GlobalLoading'; -import { tryGetGlobalNavigation } from '../../api/nav'; - -interface Props { - children?: React.ReactNode; -} - -interface State { - loading: boolean; - onSonarCloud: boolean; -} - -export default class AppContextContainer extends React.PureComponent { - mounted = false; - static childContextTypes = { onSonarCloud: PropTypes.bool }; - state: State = { loading: true, onSonarCloud: false }; - - getChildContext() { - return { onSonarCloud: this.state.onSonarCloud }; - } - - componentDidMount() { - this.mounted = true; - tryGetGlobalNavigation().then( - appState => { - if (this.mounted) { - this.setState({ - loading: false, - onSonarCloud: Boolean( - appState.settings && appState.settings['sonar.sonarcloud.enabled'] === 'true' - ) - }); - } - }, - () => {} - ); - } - - componentWillUnmount() { - this.mounted = false; - } - - render() { - if (this.state.loading) { - return ; - } - return ( - <> - - {this.props.children} - - ); - } -} diff --git a/server/sonar-web/src/main/js/app/components/GlobalFooter.tsx b/server/sonar-web/src/main/js/app/components/GlobalFooter.tsx index 5baa8f12be9..63e5ee4eab5 100644 --- a/server/sonar-web/src/main/js/app/components/GlobalFooter.tsx +++ b/server/sonar-web/src/main/js/app/components/GlobalFooter.tsx @@ -18,12 +18,12 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import * as PropTypes from 'prop-types'; import { Link } from 'react-router'; import GlobalFooterSonarCloud from './GlobalFooterSonarCloud'; import GlobalFooterBranding from './GlobalFooterBranding'; import InstanceMessage from '../../components/common/InstanceMessage'; import { translate, translateWithParameters } from '../../helpers/l10n'; +import { isSonarCloud } from '../../helpers/system'; interface Props { hideLoggedInInfo?: boolean; @@ -31,72 +31,69 @@ interface Props { sonarqubeVersion?: string; } -export default class GlobalFooter extends React.PureComponent { - static contextTypes = { - onSonarCloud: PropTypes.bool - }; - - render() { - const { hideLoggedInInfo, productionDatabase, sonarqubeVersion } = this.props; - if (this.context.onSonarCloud) { - return ; - } +export default function GlobalFooter({ + hideLoggedInInfo, + productionDatabase, + sonarqubeVersion +}: Props) { + if (isSonarCloud()) { + return ; + } - return ( - + ); } diff --git a/server/sonar-web/src/main/js/app/components/GlobalLoading.tsx b/server/sonar-web/src/main/js/app/components/GlobalLoading.tsx index ec873fb3a2e..8ae81282526 100644 --- a/server/sonar-web/src/main/js/app/components/GlobalLoading.tsx +++ b/server/sonar-web/src/main/js/app/components/GlobalLoading.tsx @@ -18,12 +18,10 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import Helmet from 'react-helmet'; export default function GlobalLoading() { return ( <> -
Loading... diff --git a/server/sonar-web/src/main/js/app/components/Landing.tsx b/server/sonar-web/src/main/js/app/components/Landing.tsx index d9f522035fa..55f14b6056d 100644 --- a/server/sonar-web/src/main/js/app/components/Landing.tsx +++ b/server/sonar-web/src/main/js/app/components/Landing.tsx @@ -21,12 +21,12 @@ import * as React from 'react'; import * as PropTypes from 'prop-types'; import { connect } from 'react-redux'; import { CurrentUser, isLoggedIn } from '../types'; -import { getCurrentUser, getGlobalSettingValue } from '../../store/rootReducer'; +import { getCurrentUser } from '../../store/rootReducer'; import { getHomePageUrl } from '../../helpers/urls'; +import { isSonarCloud } from '../../helpers/system'; interface Props { currentUser: CurrentUser | undefined; - onSonarCloud: boolean; } class Landing extends React.PureComponent { @@ -35,7 +35,7 @@ class Landing extends React.PureComponent { }; componentDidMount() { - const { currentUser, onSonarCloud } = this.props; + const { currentUser } = this.props; if (currentUser && isLoggedIn(currentUser)) { if (currentUser.homepage) { const homepage = getHomePageUrl(currentUser.homepage); @@ -43,7 +43,7 @@ class Landing extends React.PureComponent { } else { this.context.router.replace('/projects'); } - } else if (onSonarCloud) { + } else if (isSonarCloud()) { window.location.href = 'https://about.sonarcloud.io'; } else { this.context.router.replace('/about'); @@ -55,12 +55,8 @@ class Landing extends React.PureComponent { } } -const mapStateToProps = (state: any) => { - const onSonarCloudSetting = getGlobalSettingValue(state, 'sonar.sonarcloud.enabled'); - return { - currentUser: getCurrentUser(state), - onSonarCloud: Boolean(onSonarCloudSetting && onSonarCloudSetting.value === 'true') - }; -}; +const mapStateToProps = (state: any) => ({ + currentUser: getCurrentUser(state) +}); export default connect(mapStateToProps)(Landing); diff --git a/server/sonar-web/src/main/js/app/components/MigrationContainer.js b/server/sonar-web/src/main/js/app/components/MigrationContainer.js deleted file mode 100644 index 72a4a20ac95..00000000000 --- a/server/sonar-web/src/main/js/app/components/MigrationContainer.js +++ /dev/null @@ -1,60 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 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. - */ -// @flow -import React from 'react'; -import { withRouter } from 'react-router'; -import GlobalLoading from './GlobalLoading'; -import { getSystemStatus } from '../../api/system'; - -class MigrationContainer extends React.PureComponent { - /*:: - props: { - children?: React.Element<*>, - router: { push: ({ pathname: string, query?: { return_to: string } }) => void } - }; - */ - - state = { loading: true }; - - componentDidMount() { - getSystemStatus().then(r => { - if (r.status === 'UP') { - this.setState({ loading: false }); - } else { - this.props.router.push({ - pathname: '/maintenance', - query: { - return_to: window.location.pathname + window.location.search + window.location.hash - } - }); - } - }); - } - - render() { - if (this.state.loading) { - return ; - } - - return this.props.children; - } -} - -export default withRouter(MigrationContainer); diff --git a/server/sonar-web/src/main/js/app/components/MigrationContainer.tsx b/server/sonar-web/src/main/js/app/components/MigrationContainer.tsx new file mode 100644 index 00000000000..ab47d5f6402 --- /dev/null +++ b/server/sonar-web/src/main/js/app/components/MigrationContainer.tsx @@ -0,0 +1,43 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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 * as React from 'react'; +import { WithRouterProps } from 'react-router'; +import { getSystemStatus } from '../../helpers/system'; + +export default class MigrationContainer extends React.PureComponent { + componentDidMount() { + if (getSystemStatus() !== 'UP') { + this.props.router.push({ + pathname: '/maintenance', + query: { + // eslint-disable-next-line camelcase + return_to: window.location.pathname + window.location.search + window.location.hash + } + }); + } + } + + render() { + if (getSystemStatus() !== 'UP') { + return null; + } + return this.props.children; + } +} diff --git a/server/sonar-web/src/main/js/app/components/__tests__/GlobalFooter-test.tsx b/server/sonar-web/src/main/js/app/components/__tests__/GlobalFooter-test.tsx index 81bc6f95a7f..6eb9e440d3a 100644 --- a/server/sonar-web/src/main/js/app/components/__tests__/GlobalFooter-test.tsx +++ b/server/sonar-web/src/main/js/app/components/__tests__/GlobalFooter-test.tsx @@ -20,6 +20,9 @@ import * as React from 'react'; import { shallow } from 'enzyme'; import GlobalFooter from '../GlobalFooter'; +import { isSonarCloud } from '../../../helpers/system'; + +jest.mock('../../../helpers/system', () => ({ isSonarCloud: jest.fn() })); it('should render the only logged in information', () => { expect(getWrapper()).toMatchSnapshot(); @@ -44,7 +47,6 @@ it('should render SonarCloud footer', () => { }); function getWrapper(props = {}, onSonarCloud = false) { - return shallow(, { - context: { onSonarCloud } - }); + (isSonarCloud as jest.Mock).mockImplementation(() => onSonarCloud); + return shallow(); } diff --git a/server/sonar-web/src/main/js/app/components/embed-docs-modal/EmbedDocsPopup.tsx b/server/sonar-web/src/main/js/app/components/embed-docs-modal/EmbedDocsPopup.tsx index 5280e553a75..9beafb064fb 100644 --- a/server/sonar-web/src/main/js/app/components/embed-docs-modal/EmbedDocsPopup.tsx +++ b/server/sonar-web/src/main/js/app/components/embed-docs-modal/EmbedDocsPopup.tsx @@ -25,6 +25,7 @@ import { CurrentUser, isLoggedIn } from '../../types'; import { translate } from '../../../helpers/l10n'; import { getBaseUrl } from '../../../helpers/urls'; import { DropdownOverlay } from '../../../components/controls/Dropdown'; +import { isSonarCloud } from '../../../helpers/system'; interface Props { currentUser: CurrentUser; @@ -34,7 +35,6 @@ interface Props { export default class EmbedDocsPopup extends React.PureComponent { static contextTypes = { - onSonarCloud: PropTypes.bool, openOnboardingTutorial: PropTypes.func }; @@ -159,8 +159,7 @@ export default class EmbedDocsPopup extends React.PureComponent { {translate('api_documentation.page')} - {this.context.onSonarCloud && this.renderSonarCloudLinks()} - {!this.context.onSonarCloud && this.renderSonarQubeLinks()} + {isSonarCloud() ? this.renderSonarCloudLinks() : this.renderSonarQubeLinks()} ); diff --git a/server/sonar-web/src/main/js/app/components/embed-docs-modal/SuggestionsProvider.tsx b/server/sonar-web/src/main/js/app/components/embed-docs-modal/SuggestionsProvider.tsx index bf1efda4cbb..909c6a5d1d4 100644 --- a/server/sonar-web/src/main/js/app/components/embed-docs-modal/SuggestionsProvider.tsx +++ b/server/sonar-web/src/main/js/app/components/embed-docs-modal/SuggestionsProvider.tsx @@ -22,6 +22,7 @@ import * as PropTypes from 'prop-types'; // eslint-disable-next-line import/no-extraneous-dependencies import * as suggestionsJson from 'Docs/EmbedDocsSuggestions.json'; import { SuggestionsContext } from './SuggestionsContext'; +import { isSonarCloud } from '../../../helpers/system'; export interface SuggestionLink { link: string; @@ -48,10 +49,6 @@ export default class SuggestionsProvider extends React.Component { suggestions: PropTypes.object }; - static contextTypes = { - onSonarCloud: PropTypes.bool - }; - state: State = { suggestions: [] }; getChildContext = (): { suggestions: SuggestionsContext } => { @@ -85,7 +82,7 @@ export default class SuggestionsProvider extends React.Component { }; render() { - const suggestions = this.context.onSonarCloud + const suggestions = isSonarCloud() ? this.state.suggestions : this.state.suggestions.filter(suggestion => suggestion.scope !== 'sonarcloud'); diff --git a/server/sonar-web/src/main/js/app/components/embed-docs-modal/__tests__/SuggestionsProvider-test.tsx b/server/sonar-web/src/main/js/app/components/embed-docs-modal/__tests__/SuggestionsProvider-test.tsx index 32a957e9117..2092c80a14d 100644 --- a/server/sonar-web/src/main/js/app/components/embed-docs-modal/__tests__/SuggestionsProvider-test.tsx +++ b/server/sonar-web/src/main/js/app/components/embed-docs-modal/__tests__/SuggestionsProvider-test.tsx @@ -20,6 +20,7 @@ import * as React from 'react'; import { shallow } from 'enzyme'; import SuggestionsProvider from '../SuggestionsProvider'; +import { isSonarCloud } from '../../../../helpers/system'; jest.mock( 'Docs/EmbedDocsSuggestions.json', @@ -30,7 +31,10 @@ jest.mock( { virtual: true } ); +jest.mock('../../../../helpers/system', () => ({ isSonarCloud: jest.fn() })); + it('should add & remove suggestions', () => { + (isSonarCloud as jest.Mock).mockImplementation(() => false); const children = jest.fn(); const wrapper = shallow({children}); const instance = wrapper.instance() as SuggestionsProvider; @@ -49,10 +53,9 @@ it('should add & remove suggestions', () => { }); it('should show sonarcloud pages', () => { + (isSonarCloud as jest.Mock).mockImplementation(() => true); const children = jest.fn(); - const wrapper = shallow({children}, { - context: { onSonarCloud: true } - }); + const wrapper = shallow({children}); const instance = wrapper.instance() as SuggestionsProvider; expect(children).lastCalledWith({ suggestions: [] }); diff --git a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBranch.tsx b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBranch.tsx index fa0fd612b5b..6a390a20932 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBranch.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBranch.tsx @@ -37,6 +37,7 @@ import HelpTooltip from '../../../../components/controls/HelpTooltip'; import Toggler from '../../../../components/controls/Toggler'; import Tooltip from '../../../../components/controls/Tooltip'; import DropdownIcon from '../../../../components/icons-components/DropdownIcon'; +import { isSonarCloud } from '../../../../helpers/system'; interface Props { branchLikes: BranchLike[]; @@ -53,8 +54,7 @@ export default class ComponentNavBranch extends React.PureComponent ({ isSonarCloud: jest.fn() })); const mainBranch: MainBranch = { isMain: true, name: 'master' }; const fooBranch: LongLivingBranch = { isMain: false, name: 'foo', type: BranchType.LONG }; +beforeEach(() => { + (isSonarCloud as jest.Mock).mockImplementation(() => false); +}); + it('renders main branch', () => { const component = {} as Component; expect( @@ -131,6 +138,7 @@ it('renders no branch support popup', () => { }); it('renders nothing on SonarCloud without branch support', () => { + (isSonarCloud as jest.Mock).mockImplementation(() => true); const component = {} as Component; const wrapper = shallow( import('./GlobalNavPlus')); @@ -42,7 +43,6 @@ const GlobalNavPlus = lazyLoad(() => import('./GlobalNavPlus')); interface StateProps { appState: AppState; currentUser: CurrentUser; - onSonarCloud: boolean; } interface DispatchProps { @@ -100,16 +100,16 @@ class GlobalNav extends React.PureComponent {
    - + {isSonarCloud() && } {isLoggedIn(this.props.currentUser) && - this.props.onSonarCloud && ( + isSonarCloud() && ( @@ -127,15 +127,10 @@ class GlobalNav extends React.PureComponent { } } -const mapStateToProps = (state: any): StateProps => { - const sonarCloudSetting = getGlobalSettingValue(state, 'sonar.sonarcloud.enabled'); - - return { - currentUser: getCurrentUser(state), - appState: getAppState(state), - onSonarCloud: Boolean(sonarCloudSetting && sonarCloudSetting.value === 'true') - }; -}; +const mapStateToProps = (state: any): StateProps => ({ + currentUser: getCurrentUser(state), + appState: getAppState(state) +}); const mapDispatchToProps: DispatchProps = { skipOnboarding }; diff --git a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavExplore.tsx b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavExplore.tsx index c5028920cd6..aaf35d724e2 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavExplore.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavExplore.tsx @@ -23,19 +23,14 @@ import { translate } from '../../../../helpers/l10n'; interface Props { location: { pathname: string }; - onSonarCloud: boolean; } -export default function GlobalNavExplore({ location, onSonarCloud }: Props) { - if (!onSonarCloud) { - return null; - } - +export default function GlobalNavExplore({ location }: Props) { const active = location.pathname.startsWith('explore'); return (
  • - + {translate('explore')}
  • diff --git a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavMenu.tsx b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavMenu.tsx index 99e20aa58c5..25c7daaa489 100644 --- a/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavMenu.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/global/GlobalNavMenu.tsx @@ -26,12 +26,12 @@ import { getQualityGatesUrl, getBaseUrl } from '../../../../helpers/urls'; import { isMySet } from '../../../../apps/issues/utils'; import Dropdown from '../../../../components/controls/Dropdown'; import DropdownIcon from '../../../../components/icons-components/DropdownIcon'; +import { isSonarCloud } from '../../../../helpers/system'; interface Props { appState: AppState; currentUser: CurrentUser; location: { pathname: string }; - onSonarCloud?: boolean; } export default class GlobalNavMenu extends React.PureComponent { @@ -40,14 +40,14 @@ export default class GlobalNavMenu extends React.PureComponent { } renderProjects() { - if (this.props.onSonarCloud && !isLoggedIn(this.props.currentUser)) { + if (isSonarCloud() && !isLoggedIn(this.props.currentUser)) { return null; } return (
  • - - {this.props.onSonarCloud ? translate('my_projects') : translate('projects.page')} + + {isSonarCloud() ? translate('my_projects') : translate('projects.page')}
  • ); @@ -56,7 +56,7 @@ export default class GlobalNavMenu extends React.PureComponent { renderPortfolios() { return (
  • - + {translate('portfolios.page')}
  • @@ -64,18 +64,18 @@ export default class GlobalNavMenu extends React.PureComponent { } renderIssuesLink() { - if (this.props.onSonarCloud && !isLoggedIn(this.props.currentUser)) { + if (isSonarCloud() && !isLoggedIn(this.props.currentUser)) { return null; } const active = this.props.location.pathname === 'issues'; - if (this.props.onSonarCloud) { + if (isSonarCloud()) { return (
  • + className={active ? 'active' : undefined} + to={{ pathname: '/issues', query: { resolved: 'false' } }}> {translate('my_issues')}
  • @@ -88,7 +88,7 @@ export default class GlobalNavMenu extends React.PureComponent { : { resolved: 'false' }; return (
  • - + {translate('issues.page')}
  • @@ -98,7 +98,7 @@ export default class GlobalNavMenu extends React.PureComponent { renderRulesLink() { return (
  • - + {translate('coding_rules.page')}
  • @@ -108,7 +108,7 @@ export default class GlobalNavMenu extends React.PureComponent { renderProfilesLink() { return (
  • - + {translate('quality_profiles.page')}
  • @@ -118,7 +118,7 @@ export default class GlobalNavMenu extends React.PureComponent { renderQualityGatesLink() { return (
  • - + {translate('quality_gates.page')}
  • @@ -132,7 +132,7 @@ export default class GlobalNavMenu extends React.PureComponent { return (
  • - + {translate('layout.settings')}
  • diff --git a/server/sonar-web/src/main/js/app/utils/startReactApp.js b/server/sonar-web/src/main/js/app/utils/startReactApp.js index 6d143225d4a..611b8a238d1 100644 --- a/server/sonar-web/src/main/js/app/utils/startReactApp.js +++ b/server/sonar-web/src/main/js/app/utils/startReactApp.js @@ -147,10 +147,8 @@ const startReactApp = () => { - import('../components/AppContextContainer'))}> - import('../components/SimpleSessionsContainer'))}> - - + import('../components/SimpleSessionsContainer'))}> + diff --git a/server/sonar-web/src/main/js/apps/about/components/AboutApp.js b/server/sonar-web/src/main/js/apps/about/components/AboutApp.js index 3a82128c095..9074488497c 100644 --- a/server/sonar-web/src/main/js/apps/about/components/AboutApp.js +++ b/server/sonar-web/src/main/js/apps/about/components/AboutApp.js @@ -36,6 +36,7 @@ import { getFacet } from '../../../api/issues'; import { getAppState, getCurrentUser, getGlobalSettingValue } from '../../../store/rootReducer'; import { translate } from '../../../helpers/l10n'; import { fetchAboutPageSettings } from '../actions'; +import { isSonarCloud } from '../../../helpers/system'; import '../styles.css'; /*:: @@ -60,8 +61,7 @@ class AboutApp extends React.PureComponent { }, currentUser: { isLoggedIn: boolean }, customText?: string, - fetchAboutPageSettings: () => Promise<*>, - onSonarCloud?: { value: string } + fetchAboutPageSettings: () => Promise<*> }; */ @@ -72,7 +72,7 @@ class AboutApp extends React.PureComponent { componentDidMount() { this.mounted = true; - if (this.props.onSonarCloud && this.props.onSonarCloud.value === 'true') { + if (isSonarCloud()) { window.location = 'https://about.sonarcloud.io'; } else { this.loadData(); @@ -104,24 +104,31 @@ class AboutApp extends React.PureComponent { } loadData() { - Promise.all([this.loadProjects(), this.loadIssues(), this.loadCustomText()]).then(responses => { - if (this.mounted) { - const [projectsCount, issues] = responses; - const issueTypes = keyBy(issues.facet, 'val'); - this.setState({ - projectsCount, - issueTypes, - loading: false - }); + Promise.all([this.loadProjects(), this.loadIssues(), this.loadCustomText()]).then( + responses => { + if (this.mounted) { + const [projectsCount, issues] = responses; + const issueTypes = keyBy(issues.facet, 'val'); + this.setState({ + projectsCount, + issueTypes, + loading: false + }); + } + }, + () => { + if (this.mounted) { + this.setState({ loading: false }); + } } - }); + ); } render() { - const { customText, onSonarCloud } = this.props; + const { customText } = this.props; const { loading, issueTypes, projectsCount } = this.state; - if (onSonarCloud && onSonarCloud.value === 'true') { + if (isSonarCloud()) { return null; } @@ -135,18 +142,19 @@ class AboutApp extends React.PureComponent { } return ( -
    +

    {translate('layout.sonar.slogan')}

    {!this.props.currentUser.isLoggedIn && ( - + {translate('layout.login')} )} {translate('about_page.read_documentation')} @@ -202,8 +210,7 @@ class AboutApp extends React.PureComponent { const mapStateToProps = state => ({ appState: getAppState(state), currentUser: getCurrentUser(state), - customText: getGlobalSettingValue(state, 'sonar.lf.aboutText'), - onSonarCloud: getGlobalSettingValue(state, 'sonar.sonarcloud.enabled') + customText: getGlobalSettingValue(state, 'sonar.lf.aboutText') }); const mapDispatchToProps = { fetchAboutPageSettings }; diff --git a/server/sonar-web/src/main/js/apps/documentation/components/App.tsx b/server/sonar-web/src/main/js/apps/documentation/components/App.tsx index cec2a0e8251..84ed6c38d7c 100644 --- a/server/sonar-web/src/main/js/apps/documentation/components/App.tsx +++ b/server/sonar-web/src/main/js/apps/documentation/components/App.tsx @@ -20,7 +20,6 @@ import * as React from 'react'; import Helmet from 'react-helmet'; import { Link } from 'react-router'; -import * as PropTypes from 'prop-types'; import Menu from './Menu'; import NotFound from '../../../app/components/NotFound'; import ScreenPositionHelper from '../../../components/common/ScreenPositionHelper'; @@ -28,6 +27,7 @@ import DocMarkdownBlock from '../../../components/docs/DocMarkdownBlock'; import DeferredSpinner from '../../../components/common/DeferredSpinner'; import { translate } from '../../../helpers/l10n'; import { getFrontMatter } from '../../../helpers/markdown'; +import { isSonarCloud } from '../../../helpers/system'; import '../styles.css'; interface Props { @@ -43,10 +43,6 @@ interface State { export default class App extends React.PureComponent { mounted = false; - static contextTypes = { - onSonarCloud: PropTypes.bool - }; - state: State = { loading: false, notFound: false }; componentDidMount() { @@ -72,7 +68,7 @@ export default class App extends React.PureComponent { ({ default: content }) => { if (this.mounted) { const { scope } = getFrontMatter(content || ''); - if (scope === 'sonarcloud' && !this.context.onSonarCloud) { + if (scope === 'sonarcloud' && !isSonarCloud()) { this.setState({ loading: false, notFound: true }); } else { this.setState({ content, loading: false, notFound: false }); diff --git a/server/sonar-web/src/main/js/apps/documentation/components/Menu.tsx b/server/sonar-web/src/main/js/apps/documentation/components/Menu.tsx index dffe69579ba..fbd4ee1a753 100644 --- a/server/sonar-web/src/main/js/apps/documentation/components/Menu.tsx +++ b/server/sonar-web/src/main/js/apps/documentation/components/Menu.tsx @@ -20,7 +20,6 @@ import * as React from 'react'; import { Link } from 'react-router'; import * as classNames from 'classnames'; -import * as PropTypes from 'prop-types'; import OpenCloseIcon from '../../../components/icons-components/OpenCloseIcon'; import { activeOrChildrenActive, @@ -29,6 +28,7 @@ import { getEntryRoot } from '../utils'; import * as Docs from '../documentation.directory-loader'; +import { isSonarCloud } from '../../../helpers/system'; const pages = (Docs as any) as DocumentationEntry[]; @@ -37,12 +37,8 @@ interface Props { } export default class Menu extends React.PureComponent { - static contextTypes = { - onSonarCloud: PropTypes.bool - }; - getMenuEntriesHierarchy = (root?: string): Array => { - const instancePages = this.context.onSonarCloud + const instancePages = isSonarCloud() ? pages : pages.filter(page => page.scope !== 'sonarcloud'); const toplevelEntries = getEntryChildren(instancePages, root); diff --git a/server/sonar-web/src/main/js/apps/issues/IssuesPageSelector.tsx b/server/sonar-web/src/main/js/apps/issues/IssuesPageSelector.tsx index 70ba38db7a4..b5c65fd6ed5 100644 --- a/server/sonar-web/src/main/js/apps/issues/IssuesPageSelector.tsx +++ b/server/sonar-web/src/main/js/apps/issues/IssuesPageSelector.tsx @@ -22,28 +22,24 @@ import { connect } from 'react-redux'; import AppContainer from './components/AppContainer'; import { CurrentUser, isLoggedIn } from '../../app/types'; import { RawQuery } from '../../helpers/query'; -import { getCurrentUser, getGlobalSettingValue } from '../../store/rootReducer'; +import { getCurrentUser } from '../../store/rootReducer'; +import { isSonarCloud } from '../../helpers/system'; interface StateProps { currentUser: CurrentUser; - onSonarCloud: boolean; } interface Props extends StateProps { location: { pathname: string; query: RawQuery }; } -function IssuesPage({ currentUser, location, onSonarCloud }: Props) { - const myIssues = (isLoggedIn(currentUser) && onSonarCloud) || undefined; +function IssuesPage({ currentUser, location }: Props) { + const myIssues = (isLoggedIn(currentUser) && isSonarCloud()) || undefined; return ; } -const stateToProps = (state: any) => { - const onSonarCloudSetting = getGlobalSettingValue(state, 'sonar.sonarcloud.enabled'); - return { - currentUser: getCurrentUser(state), - onSonarCloud: Boolean(onSonarCloudSetting && onSonarCloudSetting.value === 'true') - }; -}; +const stateToProps = (state: any) => ({ + currentUser: getCurrentUser(state) +}); export default connect(stateToProps)(IssuesPage); diff --git a/server/sonar-web/src/main/js/apps/issues/components/App.tsx b/server/sonar-web/src/main/js/apps/issues/components/App.tsx index 708e786183e..2ae38d862de 100644 --- a/server/sonar-web/src/main/js/apps/issues/components/App.tsx +++ b/server/sonar-web/src/main/js/apps/issues/components/App.tsx @@ -70,6 +70,7 @@ import { scrollToElement } from '../../../helpers/scrolling'; import EmptySearch from '../../../components/common/EmptySearch'; import Checkbox from '../../../components/controls/Checkbox'; import DropdownIcon from '../../../components/icons-components/DropdownIcon'; +import { isSonarCloud } from '../../../helpers/system'; import '../../../components/search-navigator.css'; import '../styles.css'; @@ -91,7 +92,6 @@ interface Props { location: { pathname: string; query: RawQuery }; myIssues?: boolean; onBranchesChange: () => void; - onSonarCloud: boolean; organization?: { key: string }; } @@ -845,13 +845,13 @@ export default class App extends React.PureComponent { } renderFacets() { - const { component, currentUser, onSonarCloud } = this.props; + const { component, currentUser } = this.props; const { query } = this.state; return (
    {currentUser.isLoggedIn && - !onSonarCloud && ( + !isSonarCloud() && ( { canSetHome={Boolean( !this.props.organization && !this.props.component && - (!this.props.onSonarCloud || this.props.myIssues) + (!isSonarCloud() || this.props.myIssues) )} loading={this.state.loading} onReload={this.handleReload} - onSonarCloud={this.props.onSonarCloud} paging={paging} selectedIndex={selectedIndex} /> diff --git a/server/sonar-web/src/main/js/apps/issues/components/AppContainer.tsx b/server/sonar-web/src/main/js/apps/issues/components/AppContainer.tsx index 8ef80073218..7bc1a48e240 100644 --- a/server/sonar-web/src/main/js/apps/issues/components/AppContainer.tsx +++ b/server/sonar-web/src/main/js/apps/issues/components/AppContainer.tsx @@ -24,11 +24,7 @@ import { searchIssues } from '../../../api/issues'; import { getOrganizations } from '../../../api/organizations'; import { CurrentUser } from '../../../app/types'; import throwGlobalError from '../../../app/utils/throwGlobalError'; -import { - getCurrentUser, - areThereCustomOrganizations, - getGlobalSettingValue -} from '../../../store/rootReducer'; +import { getCurrentUser, areThereCustomOrganizations } from '../../../store/rootReducer'; import { lazyLoad } from '../../../components/lazyLoad'; import { parseIssueFromResponse } from '../../../helpers/issues'; import { RawQuery } from '../../../helpers/query'; @@ -36,16 +32,11 @@ import { receiveOrganizations } from '../../../store/organizations/duck'; interface StateProps { currentUser: CurrentUser; - onSonarCloud: boolean; } -const mapStateToProps = (state: any): StateProps => { - const onSonarCloudSetting = getGlobalSettingValue(state, 'sonar.sonarcloud.enabled'); - return { - currentUser: getCurrentUser(state), - onSonarCloud: Boolean(onSonarCloudSetting && onSonarCloudSetting.value === 'true') - }; -}; +const mapStateToProps = (state: any): StateProps => ({ + currentUser: getCurrentUser(state) +}); const fetchIssueOrganizations = (organizationKeys: string[]) => (dispatch: Dispatch) => { if (!organizationKeys.length) { diff --git a/server/sonar-web/src/main/js/apps/issues/components/PageActions.tsx b/server/sonar-web/src/main/js/apps/issues/components/PageActions.tsx index 30d4d3191ae..38e0821b0e9 100644 --- a/server/sonar-web/src/main/js/apps/issues/components/PageActions.tsx +++ b/server/sonar-web/src/main/js/apps/issues/components/PageActions.tsx @@ -24,12 +24,12 @@ import { HomePageType, Paging } from '../../../app/types'; import DeferredSpinner from '../../../components/common/DeferredSpinner'; import HomePageSelect from '../../../components/controls/HomePageSelect'; import { translate } from '../../../helpers/l10n'; +import { isSonarCloud } from '../../../helpers/system'; interface Props { canSetHome: boolean; loading: boolean; onReload: () => void; - onSonarCloud: boolean; paging: Paging | undefined; selectedIndex: number | undefined; } @@ -73,9 +73,7 @@ export default class PageActions extends React.PureComponent { )} diff --git a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationDelete.tsx b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationDelete.tsx index bdc610e13d3..ce7ebfdaad9 100644 --- a/server/sonar-web/src/main/js/apps/organizations/components/OrganizationDelete.tsx +++ b/server/sonar-web/src/main/js/apps/organizations/components/OrganizationDelete.tsx @@ -28,6 +28,7 @@ import { deleteOrganization } from '../actions'; import { Organization } from '../../../app/types'; import { Button } from '../../../components/ui/buttons'; import { getOrganizationBilling } from '../../../api/organizations'; +import { isSonarCloud } from '../../../helpers/system'; interface DispatchToProps { deleteOrganization: (key: string) => Promise; @@ -46,8 +47,7 @@ interface State { export class OrganizationDelete extends React.PureComponent { mounted = false; static contextTypes = { - router: PropTypes.object, - onSonarCloud: PropTypes.bool + router: PropTypes.object }; state: State = {}; @@ -62,7 +62,7 @@ export class OrganizationDelete extends React.PureComponent { } fetchOrganizationPlanInfo = () => { - if (this.context.onSonarCloud) { + if (isSonarCloud()) { getOrganizationBilling(this.props.organization.key).then( billingInfo => { if (this.mounted) { diff --git a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationDelete-test.tsx b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationDelete-test.tsx index fff071d494a..04cc3670168 100644 --- a/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationDelete-test.tsx +++ b/server/sonar-web/src/main/js/apps/organizations/components/__tests__/OrganizationDelete-test.tsx @@ -22,6 +22,7 @@ import { shallow } from 'enzyme'; import { OrganizationDelete } from '../OrganizationDelete'; import { getOrganizationBilling } from '../../../../api/organizations'; import { waitAndUpdate } from '../../../../helpers/testUtils'; +import { isSonarCloud } from '../../../../helpers/system'; jest.mock('../../../../api/organizations', () => ({ getOrganizationBilling: jest.fn(() => @@ -29,6 +30,8 @@ jest.mock('../../../../api/organizations', () => ({ ) })); +jest.mock('../../../../helpers/system', () => ({ isSonarCloud: jest.fn() })); + beforeEach(() => { (getOrganizationBilling as jest.Mock).mockClear(); }); @@ -38,6 +41,7 @@ it('smoke test', () => { }); it('should redirect the page', async () => { + (isSonarCloud as jest.Mock).mockImplementation(() => false); const deleteOrganization = jest.fn(() => Promise.resolve()); const replace = jest.fn(); const wrapper = getWrapper({ deleteOrganization }, { router: { replace } }); @@ -48,6 +52,7 @@ it('should redirect the page', async () => { }); it('should show a info message for paying organization', async () => { + (isSonarCloud as jest.Mock).mockImplementation(() => true); const wrapper = getWrapper({}, { onSonarCloud: true }); await waitAndUpdate(wrapper); expect(getOrganizationBilling).toHaveBeenCalledWith('foo'); diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationMeta.tsx b/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationMeta.tsx index ba47200eb0e..6815ae5dae9 100644 --- a/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationMeta.tsx +++ b/server/sonar-web/src/main/js/apps/organizations/navigation/OrganizationNavigationMeta.tsx @@ -18,21 +18,16 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import { connect } from 'react-redux'; import { Organization, HomePageType } from '../../../app/types'; import HomePageSelect from '../../../components/controls/HomePageSelect'; import { translate } from '../../../helpers/l10n'; -import { getGlobalSettingValue } from '../../../store/rootReducer'; +import { isSonarCloud } from '../../../helpers/system'; -interface StateProps { - onSonarCloud: boolean; -} - -interface Props extends StateProps { +interface Props { organization: Organization; } -export function OrganizationNavigationMeta({ onSonarCloud, organization }: Props) { +export default function OrganizationNavigationMeta({ organization }: Props) { return (
    {organization.url != null && ( @@ -47,7 +42,7 @@ export function OrganizationNavigationMeta({ onSonarCloud, organization }: Props
    {translate('organization.key')}: {organization.key}
    - {onSonarCloud && ( + {isSonarCloud() && (
    ); } - -const mapStateToProps = (state: any): StateProps => { - const sonarCloudSetting = getGlobalSettingValue(state, 'sonar.sonarcloud.enabled'); - - return { - onSonarCloud: Boolean(sonarCloudSetting && sonarCloudSetting.value === 'true') - }; -}; - -export default connect(mapStateToProps)(OrganizationNavigationMeta); diff --git a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigationMeta-test.tsx b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigationMeta-test.tsx index b9fd225d471..96d9f772c63 100644 --- a/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigationMeta-test.tsx +++ b/server/sonar-web/src/main/js/apps/organizations/navigation/__tests__/OrganizationNavigationMeta-test.tsx @@ -19,14 +19,15 @@ */ import * as React from 'react'; import { shallow } from 'enzyme'; -import { OrganizationNavigationMeta } from '../OrganizationNavigationMeta'; +import OrganizationNavigationMeta from '../OrganizationNavigationMeta'; import { Visibility } from '../../../../app/types'; +jest.mock('../../../../helpers/system', () => ({ isSonarCloud: () => true })); + it('renders', () => { expect( shallow( - { const { selectedType, badgeOptions } = this.state; const header = translate('overview.badges.title'); const fullBadgeOptions = { project, ...badgeOptions, ...getBranchLikeQuery(branchLike) }; - const badges = this.props.onSonarCloud + const badges = isSonarCloud() ? [BadgeType.measure, BadgeType.qualityGate, BadgeType.marketing] : [BadgeType.measure, BadgeType.qualityGate]; return ( diff --git a/server/sonar-web/src/main/js/apps/overview/badges/__tests__/BadgesModal-test.tsx b/server/sonar-web/src/main/js/apps/overview/badges/__tests__/BadgesModal-test.tsx index 5cff7462feb..23555a9a631 100644 --- a/server/sonar-web/src/main/js/apps/overview/badges/__tests__/BadgesModal-test.tsx +++ b/server/sonar-web/src/main/js/apps/overview/badges/__tests__/BadgesModal-test.tsx @@ -22,10 +22,10 @@ import { shallow } from 'enzyme'; import BadgesModal from '../BadgesModal'; import { click } from '../../../../helpers/testUtils'; import { ShortLivingBranch, BranchType } from '../../../../app/types'; +import { isSonarCloud } from '../../../../helpers/system'; -jest.mock('../../../../helpers/urls', () => ({ - getHostUrl: () => 'host' -})); +jest.mock('../../../../helpers/urls', () => ({ getHostUrl: () => 'host' })); +jest.mock('../../../../helpers/system', () => ({ isSonarCloud: jest.fn() })); const shortBranch: ShortLivingBranch = { isMain: false, @@ -35,14 +35,9 @@ const shortBranch: ShortLivingBranch = { }; it('should display the modal after click on sonar cloud', () => { + (isSonarCloud as jest.Mock).mockImplementation(() => true); const wrapper = shallow( - + ); expect(wrapper).toMatchSnapshot(); click(wrapper.find('Button')); @@ -50,14 +45,9 @@ it('should display the modal after click on sonar cloud', () => { }); it('should display the modal after click on sonar qube', () => { + (isSonarCloud as jest.Mock).mockImplementation(() => false); const wrapper = shallow( - + ); expect(wrapper).toMatchSnapshot(); click(wrapper.find('Button')); diff --git a/server/sonar-web/src/main/js/apps/overview/meta/Meta.tsx b/server/sonar-web/src/main/js/apps/overview/meta/Meta.tsx index 37d1618f37d..c2145d14c3b 100644 --- a/server/sonar-web/src/main/js/apps/overview/meta/Meta.tsx +++ b/server/sonar-web/src/main/js/apps/overview/meta/Meta.tsx @@ -44,12 +44,11 @@ interface Props { export default class Meta extends React.PureComponent { static contextTypes = { - onSonarCloud: PropTypes.bool, organizationsEnabled: PropTypes.bool }; render() { - const { onSonarCloud, organizationsEnabled } = this.context; + const { organizationsEnabled } = this.context; const { branchLike, component, metrics } = this.props; const { qualifier, description, qualityProfiles, qualityGate, visibility } = component; @@ -110,7 +109,6 @@ export default class Meta extends React.PureComponent { diff --git a/server/sonar-web/src/main/js/apps/projects/components/AllProjects.tsx b/server/sonar-web/src/main/js/apps/projects/components/AllProjects.tsx index 2da30f32e17..c015b983357 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/AllProjects.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/AllProjects.tsx @@ -36,6 +36,7 @@ import { RawQuery } from '../../../helpers/query'; import { Project, Facets } from '../types'; import { fetchProjects, parseSorting, SORTING_SWITCH } from '../utils'; import { parseUrlQuery, Query } from '../query'; +import { isSonarCloud } from '../../../helpers/system'; import '../../../components/search-navigator.css'; import '../styles.css'; @@ -43,7 +44,6 @@ export interface Props { currentUser: CurrentUser; isFavorite: boolean; location: { pathname: string; query: RawQuery }; - onSonarCloud: boolean; organization?: { key: string }; organizationsEnabled: boolean; storageOptionsSuffix?: string; @@ -245,7 +245,7 @@ export default class AllProjects extends React.PureComponent { onQueryChange={this.updateLocationQuery} organization={this.props.organization} query={this.state.query} - showFavoriteFilter={!this.props.onSonarCloud} + showFavoriteFilter={!isSonarCloud()} view={this.getView()} visualization={this.getVisualization()} /> @@ -266,7 +266,6 @@ export default class AllProjects extends React.PureComponent { loading={this.state.loading} onPerspectiveChange={this.handlePerspectiveChange} onQueryChange={this.updateLocationQuery} - onSonarCloud={this.props.onSonarCloud} onSortChange={this.handleSortChange} organization={this.props.organization} projects={this.state.projects} @@ -301,7 +300,6 @@ export default class AllProjects extends React.PureComponent { cardType={this.getView()} isFavorite={this.props.isFavorite} isFiltered={this.isFiltered()} - onSonarCloud={this.props.onSonarCloud} organization={this.props.organization} projects={this.state.projects} query={this.state.query} diff --git a/server/sonar-web/src/main/js/apps/projects/components/AllProjectsContainer.tsx b/server/sonar-web/src/main/js/apps/projects/components/AllProjectsContainer.tsx index cd24cb1cb1e..5de80726a26 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/AllProjectsContainer.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/AllProjectsContainer.tsx @@ -20,16 +20,11 @@ import { connect } from 'react-redux'; import { CurrentUser } from '../../../app/types'; import { lazyLoad } from '../../../components/lazyLoad'; -import { - getCurrentUser, - areThereCustomOrganizations, - getGlobalSettingValue -} from '../../../store/rootReducer'; +import { getCurrentUser, areThereCustomOrganizations } from '../../../store/rootReducer'; import { RawQuery } from '../../../helpers/query'; interface StateProps { currentUser: CurrentUser; - onSonarCloud: boolean; organizationsEnabled: boolean; } @@ -40,14 +35,10 @@ interface OwnProps { storageOptionsSuffix?: string; } -const stateToProps = (state: any) => { - const onSonarCloudSetting = getGlobalSettingValue(state, 'sonar.sonarcloud.enabled'); - return { - currentUser: getCurrentUser(state), - onSonarCloud: Boolean(onSonarCloudSetting && onSonarCloudSetting.value === 'true'), - organizationsEnabled: areThereCustomOrganizations(state) - }; -}; +const stateToProps = (state: any) => ({ + currentUser: getCurrentUser(state), + organizationsEnabled: areThereCustomOrganizations(state) +}); export default connect(stateToProps)( lazyLoad(() => import('./AllProjects')) diff --git a/server/sonar-web/src/main/js/apps/projects/components/DefaultPageSelector.tsx b/server/sonar-web/src/main/js/apps/projects/components/DefaultPageSelector.tsx index 07119e134ed..1fffa7f7d3e 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/DefaultPageSelector.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/DefaultPageSelector.tsx @@ -24,11 +24,11 @@ import { PROJECTS_DEFAULT_FILTER, PROJECTS_FAVORITE, PROJECTS_ALL } from '../uti import { get } from '../../../helpers/storage'; import { searchProjects } from '../../../api/components'; import { CurrentUser, isLoggedIn } from '../../../app/types'; +import { isSonarCloud } from '../../../helpers/system'; interface Props { currentUser: CurrentUser; location: { pathname: string; query: { [x: string]: string } }; - onSonarCloud: boolean; } interface State { @@ -47,17 +47,17 @@ export default class DefaultPageSelector extends React.PureComponent; } diff --git a/server/sonar-web/src/main/js/apps/projects/components/DefaultPageSelectorContainer.tsx b/server/sonar-web/src/main/js/apps/projects/components/DefaultPageSelectorContainer.tsx index 00f726ac4d1..f9cacdeec53 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/DefaultPageSelectorContainer.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/DefaultPageSelectorContainer.tsx @@ -20,19 +20,14 @@ import { connect } from 'react-redux'; import DefaultPageSelector from './DefaultPageSelector'; import { CurrentUser } from '../../../app/types'; -import { getCurrentUser, getGlobalSettingValue } from '../../../store/rootReducer'; +import { getCurrentUser } from '../../../store/rootReducer'; interface StateProps { currentUser: CurrentUser; - onSonarCloud: boolean; } -const stateToProps = (state: any) => { - const onSonarCloudSetting = getGlobalSettingValue(state, 'sonar.sonarcloud.enabled'); - return { - currentUser: getCurrentUser(state), - onSonarCloud: Boolean(onSonarCloudSetting && onSonarCloudSetting.value === 'true') - }; -}; +const stateToProps = (state: any) => ({ + currentUser: getCurrentUser(state) +}); export default connect(stateToProps)(DefaultPageSelector); diff --git a/server/sonar-web/src/main/js/apps/projects/components/NoFavoriteProjects.tsx b/server/sonar-web/src/main/js/apps/projects/components/NoFavoriteProjects.tsx index 935ff76d795..6c52d002bb1 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/NoFavoriteProjects.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/NoFavoriteProjects.tsx @@ -28,16 +28,13 @@ import Dropdown from '../../../components/controls/Dropdown'; import { getMyOrganizations } from '../../../store/rootReducer'; import OrganizationListItem from '../../../components/ui/OrganizationListItem'; import { translate } from '../../../helpers/l10n'; +import { isSonarCloud } from '../../../helpers/system'; interface StateProps { organizations: Organization[]; } -interface Props extends StateProps { - onSonarCloud: boolean; -} - -export class NoFavoriteProjects extends React.PureComponent { +export class NoFavoriteProjects extends React.PureComponent { static contextTypes = { openOnboardingTutorial: PropTypes.func }; @@ -49,11 +46,11 @@ export class NoFavoriteProjects extends React.PureComponent { }; render() { - const { onSonarCloud, organizations } = this.props; + const { organizations } = this.props; return (

    {translate('projects.no_favorite_projects')}

    - {onSonarCloud ? ( + {isSonarCloud() ? (

    {translate('projects.no_favorite_projects.how_to_add_projects')}

    diff --git a/server/sonar-web/src/main/js/apps/projects/components/PageHeader.tsx b/server/sonar-web/src/main/js/apps/projects/components/PageHeader.tsx index c0aeb6f835b..17c584fdc52 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/PageHeader.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/PageHeader.tsx @@ -28,6 +28,7 @@ import HomePageSelect from '../../../components/controls/HomePageSelect'; import { translate } from '../../../helpers/l10n'; import { RawQuery } from '../../../helpers/query'; import { Project } from '../types'; +import { isSonarCloud } from '../../../helpers/system'; interface Props { currentUser: CurrentUser; @@ -35,7 +36,6 @@ interface Props { loading: boolean; onPerspectiveChange: (x: { view: string; visualization?: string }) => void; onQueryChange: (change: RawQuery) => void; - onSonarCloud: boolean; onSortChange: (sort: string, desc: boolean) => void; organization?: { key: string }; projects?: Project[]; @@ -50,7 +50,7 @@ export default function PageHeader(props: Props) { const { loading, total, projects, currentUser, view } = props; const limitReached = projects != null && total != null && projects.length < total; const defaultOption = isLoggedIn(currentUser) ? 'name' : 'analysis_date'; - const showHomePageSelect = !props.onSonarCloud || props.isFavorite; + const showHomePageSelect = !isSonarCloud() || props.isFavorite; return (
    @@ -106,7 +106,7 @@ export default function PageHeader(props: Props) { )} diff --git a/server/sonar-web/src/main/js/apps/projects/components/ProjectsList.tsx b/server/sonar-web/src/main/js/apps/projects/components/ProjectsList.tsx index 045298cc38d..491da7f539b 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/ProjectsList.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/ProjectsList.tsx @@ -30,7 +30,6 @@ interface Props { cardType?: string; isFavorite: boolean; isFiltered: boolean; - onSonarCloud: boolean; organization?: { key: string }; projects: Project[]; query: Query; @@ -42,11 +41,7 @@ export default class ProjectsList extends React.PureComponent { if (isFiltered) { return isFavorite ? : ; } - return isFavorite ? ( - - ) : ( - - ); + return isFavorite ? : ; } render() { @@ -58,8 +53,8 @@ export default class ProjectsList extends React.PureComponent { ? projects.map(project => ( )) diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/AllProjects-test.tsx b/server/sonar-web/src/main/js/apps/projects/components/__tests__/AllProjects-test.tsx index b6339e6c3fb..7497a286fa9 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/__tests__/AllProjects-test.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/AllProjects-test.tsx @@ -171,7 +171,6 @@ function shallowRender( currentUser={{ isLoggedIn: true }} isFavorite={false} location={{ pathname: '/projects', query: {} }} - onSonarCloud={false} organizationsEnabled={false} {...props} />, diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/DefaultPageSelector-test.tsx b/server/sonar-web/src/main/js/apps/projects/components/__tests__/DefaultPageSelector-test.tsx index f840055a266..f5beee0d39c 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/__tests__/DefaultPageSelector-test.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/DefaultPageSelector-test.tsx @@ -88,11 +88,7 @@ function mountRender( replace: any = jest.fn() ) { return mount( - , + , { context: { router: { replace } } } ); } diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/NoFavoriteProjects-test.tsx b/server/sonar-web/src/main/js/apps/projects/components/__tests__/NoFavoriteProjects-test.tsx index 611e3e650e0..d49eaa62610 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/__tests__/NoFavoriteProjects-test.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/NoFavoriteProjects-test.tsx @@ -21,17 +21,20 @@ import * as React from 'react'; import { shallow } from 'enzyme'; import { NoFavoriteProjects } from '../NoFavoriteProjects'; import { Visibility } from '../../../../app/types'; +import { isSonarCloud } from '../../../../helpers/system'; + +jest.mock('../../../../helpers/system', () => ({ isSonarCloud: jest.fn() })); it('renders', () => { - expect(shallow()).toMatchSnapshot(); + (isSonarCloud as jest.Mock).mockImplementation(() => false); + expect(shallow()).toMatchSnapshot(); }); it('renders for SonarCloud', () => { + (isSonarCloud as jest.Mock).mockImplementation(() => true); const organizations = [ { isAdmin: true, key: 'org1', name: 'org1', projectVisibility: Visibility.Public }, { isAdmin: false, key: 'org2', name: 'org2', projectVisibility: Visibility.Public } ]; - expect( - shallow() - ).toMatchSnapshot(); + expect(shallow()).toMatchSnapshot(); }); diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/PageHeader-test.tsx b/server/sonar-web/src/main/js/apps/projects/components/__tests__/PageHeader-test.tsx index 30c4d346c4f..a8230cb27d5 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/__tests__/PageHeader-test.tsx +++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/PageHeader-test.tsx @@ -75,7 +75,6 @@ function shallowRender(props?: {}) { loading={false} onPerspectiveChange={jest.fn()} onQueryChange={jest.fn()} - onSonarCloud={false} onSortChange={jest.fn()} projects={[]} query={{ search: 'test' }} diff --git a/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/AllProjects-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/AllProjects-test.tsx.snap index ec7df22da87..88824ab0f4d 100644 --- a/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/AllProjects-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/projects/components/__tests__/__snapshots__/AllProjects-test.tsx.snap @@ -38,7 +38,6 @@ exports[`renders 1`] = ` loading={false} onPerspectiveChange={[Function]} onQueryChange={[Function]} - onSonarCloud={false} onSortChange={[Function]} projects={ Array [ @@ -87,7 +86,6 @@ exports[`renders 1`] = ` cardType="overall" isFavorite={false} isFiltered={false} - onSonarCloud={false} projects={ Array [ Object { @@ -170,7 +168,6 @@ exports[`renders 2`] = ` loading={false} onPerspectiveChange={[Function]} onQueryChange={[Function]} - onSonarCloud={false} onSortChange={[Function]} projects={ Array [ diff --git a/server/sonar-web/src/main/js/apps/sessions/components/LoginContainer.tsx b/server/sonar-web/src/main/js/apps/sessions/components/LoginContainer.tsx index 2750f8f083e..31e0eb9bc60 100644 --- a/server/sonar-web/src/main/js/apps/sessions/components/LoginContainer.tsx +++ b/server/sonar-web/src/main/js/apps/sessions/components/LoginContainer.tsx @@ -18,7 +18,6 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import * as PropTypes from 'prop-types'; import { connect } from 'react-redux'; import Login from './Login'; import LoginSonarCloud from './LoginSonarCloud'; @@ -26,6 +25,7 @@ import { doLogin } from '../../../store/rootActions'; import { getIdentityProviders } from '../../../api/users'; import { IdentityProvider } from '../../../app/types'; import { getBaseUrl } from '../../../helpers/urls'; +import { isSonarCloud } from '../../../helpers/system'; interface OwnProps { location: { @@ -51,10 +51,6 @@ interface State { class LoginContainer extends React.PureComponent { mounted = false; - static contextTypes = { - onSonarCloud: PropTypes.bool - }; - state: State = {}; componentDidMount() { @@ -96,7 +92,7 @@ class LoginContainer extends React.PureComponent { return null; } - if (this.context.onSonarCloud) { + if (isSonarCloud()) { return ( void, open: boolean, organization?: string, - sonarCloud: boolean, stepNumber: number, token: string |}; @@ -73,7 +72,6 @@ export default class AnalysisStep extends React.PureComponent { onDone={this.handleLanguageSelect} onReset={this.handleLanguageReset} organization={this.props.organization} - sonarCloud={this.props.sonarCloud} />
    {this.renderCommand()}
    diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/LanguageStep.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/LanguageStep.js index a2c44562cf1..c9bd1c15e5a 100644 --- a/server/sonar-web/src/main/js/apps/tutorials/onboarding/LanguageStep.js +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/LanguageStep.js @@ -22,13 +22,13 @@ import React from 'react'; import NewProjectForm from './NewProjectForm'; import RadioToggle from '../../../components/controls/RadioToggle'; import { translate } from '../../../helpers/l10n'; +import { isSonarCloud } from '../../../helpers/system'; /*:: type Props = {| onDone: (result: Result) => void, onReset: () => void, organization?: string, - sonarCloud: boolean |}; */ @@ -48,8 +48,6 @@ export type Result = State; */ export default class LanguageStep extends React.PureComponent { /*:: props: Props; */ - static defaultProps = { sonarCloud: false }; - state /*: State */ = {}; isConfigured = () => { @@ -157,7 +155,7 @@ export default class LanguageStep extends React.PureComponent { (this.state.cFamilyCompiler === 'clang-gcc' && this.state.os != null))) || (this.state.language === 'other' && this.state.os !== undefined); - const languages = this.props.sonarCloud + const languages = isSonarCloud() ? ['java', 'dotnet', 'c-family', 'other'] : ['java', 'dotnet', 'other']; diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/Onboarding.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/Onboarding.js index e7c31f647cc..cc04c85868c 100644 --- a/server/sonar-web/src/main/js/apps/tutorials/onboarding/Onboarding.js +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/Onboarding.js @@ -31,6 +31,7 @@ import { skipOnboarding } from '../../../api/users'; import { translate, translateWithParameters } from '../../../helpers/l10n'; import { getProjectUrl } from '../../../helpers/urls'; import './styles.css'; +import { isSonarCloud } from '../../../helpers/system'; /*:: type Props = {| @@ -58,7 +59,6 @@ export default class Onboarding extends React.PureComponent { /*:: state: State; */ static contextTypes = { - onSonarCloud: PropTypes.bool, router: PropTypes.object }; @@ -145,7 +145,6 @@ export default class Onboarding extends React.PureComponent { return null; } - const { onSonarCloud } = this.context; const { organizationsEnabled } = this.props; const { step, token } = this.state; let stepNumber = 1; @@ -171,7 +170,9 @@ export default class Onboarding extends React.PureComponent { )}

    {translate( - onSonarCloud ? 'tutorials.find_it_back_in_plus' : 'tutorials.find_it_back_in_help' + isSonarCloud() + ? 'tutorials.find_it_back_in_plus' + : 'tutorials.find_it_back_in_help' )}

    @@ -208,7 +209,6 @@ export default class Onboarding extends React.PureComponent { onReset={this.handleReset} open={step === 'analysis'} organization={this.state.organization} - sonarCloud={onSonarCloud} stepNumber={stepNumber} token={token} /> diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/LanguageStep-test.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/LanguageStep-test.js index 07b69ea16a4..2609b550dd5 100644 --- a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/LanguageStep-test.js +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/LanguageStep-test.js @@ -21,6 +21,13 @@ import React from 'react'; import { shallow } from 'enzyme'; import LanguageStep from '../LanguageStep'; +import { isSonarCloud } from '../../../../helpers/system'; + +jest.mock('../../../../helpers/system', () => ({ isSonarCloud: jest.fn() })); + +beforeEach(() => { + isSonarCloud.mockImplementation(() => false); +}); it('selects java', () => { const onDone = jest.fn(); @@ -60,8 +67,9 @@ it('selects c#', () => { }); it('selects c-family', () => { + isSonarCloud.mockImplementation(() => true); const onDone = jest.fn(); - const wrapper = shallow(); + const wrapper = shallow(); wrapper.find('RadioToggle').prop('onCheck')('c-family'); wrapper.update(); diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/Onboarding-test.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/Onboarding-test.js index 2d5019ae82d..e3acb2a83f6 100644 --- a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/Onboarding-test.js +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/Onboarding-test.js @@ -22,14 +22,22 @@ import React from 'react'; import { shallow, mount } from 'enzyme'; import Onboarding from '../Onboarding'; import { click, doAsync } from '../../../../helpers/testUtils'; +import { getInstance, isSonarCloud } from '../../../../helpers/system'; jest.mock('../../../../api/users', () => ({ skipOnboarding: () => Promise.resolve() })); +jest.mock('../../../../helpers/system', () => ({ + getInstance: jest.fn(), + isSonarCloud: jest.fn() +})); + const currentUser = { login: 'admin', isLoggedIn: true }; it('guides for on-premise', () => { + getInstance.mockImplementation(() => 'SonarQube'); + isSonarCloud.mockImplementation(() => false); const wrapper = shallow( { }); it('guides for sonarcloud', () => { + getInstance.mockImplementation(() => 'SonarCloud'); + isSonarCloud.mockImplementation(() => true); const wrapper = shallow( - , - { context: { onSonarCloud: true } } + ); expect(wrapper).toMatchSnapshot(); @@ -65,6 +74,8 @@ it('guides for sonarcloud', () => { }); it('finishes', () => { + getInstance.mockImplementation(() => 'SonarQube'); + isSonarCloud.mockImplementation(() => false); const onFinish = jest.fn(); const wrapper = mount( diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/Onboarding-test.js.snap b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/Onboarding-test.js.snap index 997502681fe..313284fb6a0 100644 --- a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/Onboarding-test.js.snap +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/Onboarding-test.js.snap @@ -201,7 +201,6 @@ exports[`guides for sonarcloud 1`] = ` onFinish={[Function]} onReset={[Function]} open={false} - sonarCloud={true} stepNumber={3} />
    @@ -279,7 +278,6 @@ exports[`guides for sonarcloud 2`] = ` onReset={[Function]} open={false} organization="my-org" - sonarCloud={true} stepNumber={3} />
    @@ -357,7 +355,6 @@ exports[`guides for sonarcloud 3`] = ` onReset={[Function]} open={true} organization="my-org" - sonarCloud={true} stepNumber={3} token="abcd1234" /> diff --git a/server/sonar-web/src/main/js/components/common/InstanceMessage.tsx b/server/sonar-web/src/main/js/components/common/InstanceMessage.tsx index 9c68882039d..451e7850dc5 100644 --- a/server/sonar-web/src/main/js/components/common/InstanceMessage.tsx +++ b/server/sonar-web/src/main/js/components/common/InstanceMessage.tsx @@ -18,31 +18,19 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import * as PropTypes from 'prop-types'; +import { getInstance } from '../../helpers/system'; interface Props { - children?: (transformedMessage: string) => React.ReactNode; + children?: (transformedMessage: string) => React.ReactChild; message: string; } -const InstanceMessage: React.SFC = ( - { children, message }: Props, - context: { onSonarCloud: boolean } -) => { - const transformedMessage = message.replace( - /\{instance\}/gim, - context.onSonarCloud ? 'SonarCloud' : 'SonarQube' - ); +export default function InstanceMessage({ children, message }: Props): any { + const transformedMessage = message.replace(/\{instance\}/gim, getInstance()); if (children) { return children(transformedMessage); } - return transformedMessage as any; -}; - -InstanceMessage.contextTypes = { - onSonarCloud: PropTypes.bool -}; - -export default InstanceMessage; + return transformedMessage; +} diff --git a/server/sonar-web/src/main/js/components/common/__tests__/InstanceMessage-test.tsx b/server/sonar-web/src/main/js/components/common/__tests__/InstanceMessage-test.tsx index 482d988b92e..b9d77e3b748 100644 --- a/server/sonar-web/src/main/js/components/common/__tests__/InstanceMessage-test.tsx +++ b/server/sonar-web/src/main/js/components/common/__tests__/InstanceMessage-test.tsx @@ -20,6 +20,9 @@ import * as React from 'react'; import { shallow } from 'enzyme'; import InstanceMessage from '../InstanceMessage'; +import { getInstance } from '../../../helpers/system'; + +jest.mock('../../../helpers/system', () => ({ getInstance: jest.fn() })); it('should replace {instance} with "SonarQube"', () => { const childFunc = jest.fn(); @@ -44,7 +47,6 @@ function getWrapper( message: string, onSonarCloud = false ) { - return shallow({children}, { - context: { onSonarCloud } - }); + (getInstance as jest.Mock).mockImplementation(() => (onSonarCloud ? 'SonarCloud' : 'SonarQube')); + return shallow({children}); } diff --git a/server/sonar-web/src/main/js/components/docs/DocMarkdownBlock.tsx b/server/sonar-web/src/main/js/components/docs/DocMarkdownBlock.tsx index 384f0339d78..4ec569cb432 100644 --- a/server/sonar-web/src/main/js/components/docs/DocMarkdownBlock.tsx +++ b/server/sonar-web/src/main/js/components/docs/DocMarkdownBlock.tsx @@ -21,11 +21,11 @@ import * as React from 'react'; import * as classNames from 'classnames'; import remark from 'remark'; import reactRenderer from 'remark-react'; -import * as PropTypes from 'prop-types'; import DocLink from './DocLink'; import DocParagraph from './DocParagraph'; import DocImg from './DocImg'; import { separateFrontMatter } from '../../helpers/markdown'; +import { isSonarCloud } from '../../helpers/system'; interface Props { className?: string; @@ -33,43 +33,36 @@ interface Props { displayH1?: boolean; } -export default class DocMarkdownBlock extends React.PureComponent { - static contextTypes = { - onSonarCloud: PropTypes.bool - }; - - render() { - const { className, content, displayH1 } = this.props; - const parsed = separateFrontMatter(content || ''); - return ( -
    - {displayH1 &&

    {parsed.frontmatter.title}

    } - { - remark() - // .use(remarkInclude) - .use(reactRenderer, { - remarkReactComponents: { - // do not render outer
    - div: React.Fragment, - // use custom link to render documentation anchors - a: DocLink, - // used to handle `@include` - p: DocParagraph, - // use custom img tag to render documentation images - img: DocImg - }, - toHast: {} - }) - .processSync(filterContent(parsed.content, this.context.onSonarCloud)).contents - } -
    - ); - } +export default function DocMarkdownBlock({ className, content, displayH1 }: Props) { + const parsed = separateFrontMatter(content || ''); + return ( +
    + {displayH1 &&

    {parsed.frontmatter.title}

    } + { + remark() + // .use(remarkInclude) + .use(reactRenderer, { + remarkReactComponents: { + // do not render outer
    + div: React.Fragment, + // use custom link to render documentation anchors + a: DocLink, + // used to handle `@include` + p: DocParagraph, + // use custom img tag to render documentation images + img: DocImg + }, + toHast: {} + }) + .processSync(filterContent(parsed.content)).contents + } +
    + ); } -function filterContent(content: string, onSonarCloud: boolean) { - const beginning = onSonarCloud ? '' : ''; - const ending = onSonarCloud ? '' : ''; +function filterContent(content: string) { + const beginning = isSonarCloud() ? '' : ''; + const ending = isSonarCloud() ? '' : ''; let newContent = content; let start = newContent.indexOf(beginning); diff --git a/server/sonar-web/src/main/js/components/docs/__tests__/DocMarkdownBlock-test.tsx b/server/sonar-web/src/main/js/components/docs/__tests__/DocMarkdownBlock-test.tsx index ebe70a27247..898ff22a5a3 100644 --- a/server/sonar-web/src/main/js/components/docs/__tests__/DocMarkdownBlock-test.tsx +++ b/server/sonar-web/src/main/js/components/docs/__tests__/DocMarkdownBlock-test.tsx @@ -20,6 +20,7 @@ import * as React from 'react'; import { shallow } from 'enzyme'; import DocMarkdownBlock from '../DocMarkdownBlock'; +import { isSonarCloud } from '../../../helpers/system'; // mock `remark` and `remark-react` to work around the issue with cjs imports jest.mock('remark', () => { @@ -32,6 +33,8 @@ jest.mock('remark-react', () => { return { default: remarkReact }; }); +jest.mock('../../../helpers/system', () => ({ isSonarCloud: jest.fn() })); + it('should render simple markdown', () => { expect(shallow()).toMatchSnapshot(); }); @@ -42,7 +45,7 @@ it('should render use custom component for links', () => { ).toMatchSnapshot(); }); -it.only('should cut sonarqube/sonarcloud content', () => { +it('should cut sonarqube/sonarcloud content', () => { const content = ` some @@ -62,11 +65,9 @@ sonarcloud text`; - expect( - shallow(, { context: { onSonarCloud: false } }) - ).toMatchSnapshot(); + (isSonarCloud as jest.Mock).mockImplementation(() => false); + expect(shallow()).toMatchSnapshot(); - expect( - shallow(, { context: { onSonarCloud: true } }) - ).toMatchSnapshot(); + (isSonarCloud as jest.Mock).mockImplementation(() => true); + expect(shallow()).toMatchSnapshot(); }); diff --git a/server/sonar-web/src/main/js/helpers/system.ts b/server/sonar-web/src/main/js/helpers/system.ts new file mode 100644 index 00000000000..6bc79a7d6b2 --- /dev/null +++ b/server/sonar-web/src/main/js/helpers/system.ts @@ -0,0 +1,30 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 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. + */ +export function getSystemStatus(): string { + return (window as any).serverStatus; +} + +export function getInstance(): 'SonarQube' | 'SonarCloud' { + return (window as any).instance; +} + +export function isSonarCloud() { + return getInstance() === 'SonarCloud'; +}