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 {
@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));
}
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");
" \"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\"" +
}),
// 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),
<meta name="msapplication-TileColor" content="#FFFFFF" />
<meta name="msapplication-TileImage" content="%WEB_CONTEXT%/mstile-512x512.png" />
- <title>Loading...</title>
+ <title>%INSTANCE%</title>
<% for (let css of htmlWebpackPlugin.files.css) { %>
<style><%= compilation.assets[css].source() %></style>
<span class="global-loading-text">Loading...</span>
</div>
</div>
- <script>window.baseUrl = '%WEB_CONTEXT%';</script>
+ <script>
+ window.baseUrl = '%WEB_CONTEXT%';
+ window.serverStatus = '%SERVER_STATUS%';
+ window.instance = '%INSTANCE%';
+ </script>
<% for (let chunk in htmlWebpackPlugin.files.chunks) { %>
<script src="%WEB_CONTEXT%/<%= htmlWebpackPlugin.files.chunks[chunk].entry %>"></script>
<% } %>
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;
branchesEnabled: boolean;
canAdmin: boolean;
loading: boolean;
- onSonarCloud: boolean;
organizationsEnabled: boolean;
}
static childContextTypes = {
branchesEnabled: PropTypes.bool.isRequired,
canAdmin: PropTypes.bool.isRequired,
- onSonarCloud: PropTypes.bool,
organizationsEnabled: PropTypes.bool
};
branchesEnabled: false,
canAdmin: false,
loading: true,
- onSonarCloud: false,
organizationsEnabled: false
};
}
return {
branchesEnabled: this.state.branchesEnabled,
canAdmin: this.state.canAdmin,
- onSonarCloud: this.state.onSonarCloud,
organizationsEnabled: this.state.organizationsEnabled
};
}
this.setState({
branchesEnabled: appState.branchesEnabled,
canAdmin: appState.canAdmin,
- onSonarCloud: Boolean(
- appState.settings && appState.settings['sonar.sonarcloud.enabled'] === 'true'
- ),
organizationsEnabled: appState.organizationsEnabled
});
}
}
return (
<>
- <Helmet defaultTitle={this.state.onSonarCloud ? 'SonarCloud' : 'SonarQube'} />
+ <Helmet defaultTitle={getInstance()} />
{this.props.children}
</>
);
+++ /dev/null
-/*
- * 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<Props, State> {
- 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 <GlobalLoading />;
- }
- return (
- <>
- <Helmet defaultTitle={this.state.onSonarCloud ? 'SonarCloud' : 'SonarQube'} />
- {this.props.children}
- </>
- );
- }
-}
* 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;
sonarqubeVersion?: string;
}
-export default class GlobalFooter extends React.PureComponent<Props> {
- static contextTypes = {
- onSonarCloud: PropTypes.bool
- };
-
- render() {
- const { hideLoggedInInfo, productionDatabase, sonarqubeVersion } = this.props;
- if (this.context.onSonarCloud) {
- return <GlobalFooterSonarCloud />;
- }
+export default function GlobalFooter({
+ hideLoggedInInfo,
+ productionDatabase,
+ sonarqubeVersion
+}: Props) {
+ if (isSonarCloud()) {
+ return <GlobalFooterSonarCloud />;
+ }
- return (
- <div id="footer" className="page-footer page-container">
- {productionDatabase === false && (
- <div className="alert alert-danger">
- <p className="big" id="evaluation_warning">
- {translate('footer.production_database_warning')}
- </p>
- <p>
- <InstanceMessage message={translate('footer.production_database_explanation')} />
- </p>
- </div>
- )}
+ return (
+ <div className="page-footer page-container" id="footer">
+ {productionDatabase === false && (
+ <div className="alert alert-danger">
+ <p className="big" id="evaluation_warning">
+ {translate('footer.production_database_warning')}
+ </p>
+ <p>
+ <InstanceMessage message={translate('footer.production_database_explanation')} />
+ </p>
+ </div>
+ )}
- <GlobalFooterBranding />
+ <GlobalFooterBranding />
- <ul className="page-footer-menu">
- {!hideLoggedInInfo &&
- sonarqubeVersion && (
- <li className="page-footer-menu-item">
- {translateWithParameters('footer.version_x', sonarqubeVersion)}
- </li>
- )}
- <li className="page-footer-menu-item">
- <a href="http://www.gnu.org/licenses/lgpl-3.0.txt">{translate('footer.license')}</a>
- </li>
- <li className="page-footer-menu-item">
- <a href="http://www.sonarqube.org">{translate('footer.community')}</a>
- </li>
- <li className="page-footer-menu-item">
- <a href="https://redirect.sonarsource.com/doc/home.html">
- {translate('footer.documentation')}
- </a>
- </li>
+ <ul className="page-footer-menu">
+ {!hideLoggedInInfo &&
+ sonarqubeVersion && (
+ <li className="page-footer-menu-item">
+ {translateWithParameters('footer.version_x', sonarqubeVersion)}
+ </li>
+ )}
+ <li className="page-footer-menu-item">
+ <a href="http://www.gnu.org/licenses/lgpl-3.0.txt">{translate('footer.license')}</a>
+ </li>
+ <li className="page-footer-menu-item">
+ <a href="http://www.sonarqube.org">{translate('footer.community')}</a>
+ </li>
+ <li className="page-footer-menu-item">
+ <a href="https://redirect.sonarsource.com/doc/home.html">
+ {translate('footer.documentation')}
+ </a>
+ </li>
+ <li className="page-footer-menu-item">
+ <a href="https://redirect.sonarsource.com/doc/community.html">
+ {translate('footer.support')}
+ </a>
+ </li>
+ <li className="page-footer-menu-item">
+ <a href="https://redirect.sonarsource.com/doc/plugin-library.html">
+ {translate('footer.plugins')}
+ </a>
+ </li>
+ {!hideLoggedInInfo && (
<li className="page-footer-menu-item">
- <a href="https://redirect.sonarsource.com/doc/community.html">
- {translate('footer.support')}
- </a>
+ <Link to="/web_api">{translate('footer.web_api')}</Link>
</li>
+ )}
+ {!hideLoggedInInfo && (
<li className="page-footer-menu-item">
- <a href="https://redirect.sonarsource.com/doc/plugin-library.html">
- {translate('footer.plugins')}
- </a>
+ <Link to="/about">{translate('footer.about')}</Link>
</li>
- {!hideLoggedInInfo && (
- <li className="page-footer-menu-item">
- <Link to="/web_api">{translate('footer.web_api')}</Link>
- </li>
- )}
- {!hideLoggedInInfo && (
- <li className="page-footer-menu-item">
- <Link to="/about">{translate('footer.about')}</Link>
- </li>
- )}
- </ul>
- </div>
- );
- }
+ )}
+ </ul>
+ </div>
+ );
}
* 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 (
<>
- <Helmet defaultTitle={'Loading...'} />
<div className="global-loading">
<i className="spinner global-loading-spinner" />
<span className="global-loading-text">Loading...</span>
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<Props> {
};
componentDidMount() {
- const { currentUser, onSonarCloud } = this.props;
+ const { currentUser } = this.props;
if (currentUser && isLoggedIn(currentUser)) {
if (currentUser.homepage) {
const homepage = getHomePageUrl(currentUser.homepage);
} 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');
}
}
-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<Props>(mapStateToProps)(Landing);
+++ /dev/null
-/*
- * 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 <GlobalLoading />;
- }
-
- return this.props.children;
- }
-}
-
-export default withRouter(MigrationContainer);
--- /dev/null
+/*
+ * 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<WithRouterProps> {
+ 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;
+ }
+}
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();
});
function getWrapper(props = {}, onSonarCloud = false) {
- return shallow(<GlobalFooter productionDatabase={true} {...props} />, {
- context: { onSonarCloud }
- });
+ (isSonarCloud as jest.Mock).mockImplementation(() => onSonarCloud);
+ return shallow(<GlobalFooter productionDatabase={true} {...props} />);
}
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;
export default class EmbedDocsPopup extends React.PureComponent<Props> {
static contextTypes = {
- onSonarCloud: PropTypes.bool,
openOnboardingTutorial: PropTypes.func
};
{translate('api_documentation.page')}
</Link>
</li>
- {this.context.onSonarCloud && this.renderSonarCloudLinks()}
- {!this.context.onSonarCloud && this.renderSonarQubeLinks()}
+ {isSonarCloud() ? this.renderSonarCloudLinks() : this.renderSonarQubeLinks()}
</ul>
</DropdownOverlay>
);
// 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;
suggestions: PropTypes.object
};
- static contextTypes = {
- onSonarCloud: PropTypes.bool
- };
-
state: State = { suggestions: [] };
getChildContext = (): { suggestions: SuggestionsContext } => {
};
render() {
- const suggestions = this.context.onSonarCloud
+ const suggestions = isSonarCloud()
? this.state.suggestions
: this.state.suggestions.filter(suggestion => suggestion.scope !== 'sonarcloud');
import * as React from 'react';
import { shallow } from 'enzyme';
import SuggestionsProvider from '../SuggestionsProvider';
+import { isSonarCloud } from '../../../../helpers/system';
jest.mock(
'Docs/EmbedDocsSuggestions.json',
{ 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(<SuggestionsProvider>{children}</SuggestionsProvider>);
const instance = wrapper.instance() as SuggestionsProvider;
});
it('should show sonarcloud pages', () => {
+ (isSonarCloud as jest.Mock).mockImplementation(() => true);
const children = jest.fn();
- const wrapper = shallow(<SuggestionsProvider>{children}</SuggestionsProvider>, {
- context: { onSonarCloud: true }
- });
+ const wrapper = shallow(<SuggestionsProvider>{children}</SuggestionsProvider>);
const instance = wrapper.instance() as SuggestionsProvider;
expect(children).lastCalledWith({ suggestions: [] });
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[];
mounted = false;
static contextTypes = {
- branchesEnabled: PropTypes.bool.isRequired,
- onSonarCloud: PropTypes.bool
+ branchesEnabled: PropTypes.bool.isRequired
};
state: State = {
const { branchLikes, currentBranchLike } = this.props;
const { configuration } = this.props.component;
- if (this.context.onSonarCloud && !this.context.branchesEnabled) {
+ if (isSonarCloud() && !this.context.branchesEnabled) {
return null;
}
PullRequest
} from '../../../../types';
import { click } from '../../../../../helpers/testUtils';
+import { isSonarCloud } from '../../../../../helpers/system';
+
+jest.mock('../../../../../helpers/system', () => ({ 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(
});
it('renders nothing on SonarCloud without branch support', () => {
+ (isSonarCloud as jest.Mock).mockImplementation(() => true);
const component = {} as Component;
const wrapper = shallow(
<ComponentNavBranch
import Tooltip from '../../../../components/controls/Tooltip';
import { lazyLoad } from '../../../../components/lazyLoad';
import { translate } from '../../../../helpers/l10n';
-import { getCurrentUser, getAppState, getGlobalSettingValue } from '../../../../store/rootReducer';
+import { getCurrentUser, getAppState } from '../../../../store/rootReducer';
import { skipOnboarding } from '../../../../store/users/actions';
import { SuggestionLink } from '../../embed-docs-modal/SuggestionsProvider';
+import { isSonarCloud } from '../../../../helpers/system';
import './GlobalNav.css';
const GlobalNavPlus = lazyLoad(() => import('./GlobalNavPlus'));
interface StateProps {
appState: AppState;
currentUser: CurrentUser;
- onSonarCloud: boolean;
}
interface DispatchProps {
<GlobalNavMenu {...this.props} />
<ul className="global-navbar-menu pull-right">
- <GlobalNavExplore location={this.props.location} onSonarCloud={this.props.onSonarCloud} />
+ {isSonarCloud() && <GlobalNavExplore location={this.props.location} />}
<EmbedDocsPopupHelper
currentUser={this.props.currentUser}
showTooltip={this.state.onboardingTutorialTooltip}
suggestions={this.props.suggestions}
- tooltip={!this.props.onSonarCloud}
+ tooltip={!isSonarCloud()}
/>
<Search appState={this.props.appState} currentUser={this.props.currentUser} />
{isLoggedIn(this.props.currentUser) &&
- this.props.onSonarCloud && (
+ isSonarCloud() && (
<Tooltip
overlay={translate('tutorials.follow_later')}
visible={this.state.onboardingTutorialTooltip}>
}
}
-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 };
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 (
<li>
- <Link to="/explore/projects" className={active ? 'active' : undefined}>
+ <Link className={active ? 'active' : undefined} to="/explore/projects">
{translate('explore')}
</Link>
</li>
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<Props> {
}
renderProjects() {
- if (this.props.onSonarCloud && !isLoggedIn(this.props.currentUser)) {
+ if (isSonarCloud() && !isLoggedIn(this.props.currentUser)) {
return null;
}
return (
<li>
- <Link to="/projects" activeClassName="active">
- {this.props.onSonarCloud ? translate('my_projects') : translate('projects.page')}
+ <Link activeClassName="active" to="/projects">
+ {isSonarCloud() ? translate('my_projects') : translate('projects.page')}
</Link>
</li>
);
renderPortfolios() {
return (
<li>
- <Link to="/portfolios" activeClassName="active">
+ <Link activeClassName="active" to="/portfolios">
{translate('portfolios.page')}
</Link>
</li>
}
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 (
<li>
<Link
- to={{ pathname: '/issues', query: { resolved: 'false' } }}
- className={active ? 'active' : undefined}>
+ className={active ? 'active' : undefined}
+ to={{ pathname: '/issues', query: { resolved: 'false' } }}>
{translate('my_issues')}
</Link>
</li>
: { resolved: 'false' };
return (
<li>
- <Link to={{ pathname: '/issues', query }} className={active ? 'active' : undefined}>
+ <Link className={active ? 'active' : undefined} to={{ pathname: '/issues', query }}>
{translate('issues.page')}
</Link>
</li>
renderRulesLink() {
return (
<li>
- <Link to="/coding_rules" className={this.activeLink('/coding_rules')}>
+ <Link className={this.activeLink('/coding_rules')} to="/coding_rules">
{translate('coding_rules.page')}
</Link>
</li>
renderProfilesLink() {
return (
<li>
- <Link to="/profiles" activeClassName="active">
+ <Link activeClassName="active" to="/profiles">
{translate('quality_profiles.page')}
</Link>
</li>
renderQualityGatesLink() {
return (
<li>
- <Link to={getQualityGatesUrl()} activeClassName="active">
+ <Link activeClassName="active" to={getQualityGatesUrl()}>
{translate('quality_gates.page')}
</Link>
</li>
return (
<li>
- <Link to="/admin" activeClassName="active">
+ <Link activeClassName="active" to="/admin">
{translate('layout.settings')}
</Link>
</li>
</Route>
<Route component={MigrationContainer}>
- <Route component={lazyLoad(() => import('../components/AppContextContainer'))}>
- <Route component={lazyLoad(() => import('../components/SimpleSessionsContainer'))}>
- <Route path="/sessions" childRoutes={sessionsRoutes} />
- </Route>
+ <Route component={lazyLoad(() => import('../components/SimpleSessionsContainer'))}>
+ <Route path="/sessions" childRoutes={sessionsRoutes} />
</Route>
<Route path="/" component={App}>
import { getAppState, getCurrentUser, getGlobalSettingValue } from '../../../store/rootReducer';
import { translate } from '../../../helpers/l10n';
import { fetchAboutPageSettings } from '../actions';
+import { isSonarCloud } from '../../../helpers/system';
import '../styles.css';
/*::
},
currentUser: { isLoggedIn: boolean },
customText?: string,
- fetchAboutPageSettings: () => Promise<*>,
- onSonarCloud?: { value: string }
+ fetchAboutPageSettings: () => Promise<*>
};
*/
componentDidMount() {
this.mounted = true;
- if (this.props.onSonarCloud && this.props.onSonarCloud.value === 'true') {
+ if (isSonarCloud()) {
window.location = 'https://about.sonarcloud.io';
} else {
this.loadData();
}
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;
}
}
return (
- <div id="about-page" className="page page-limited about-page">
+ <div className="page page-limited about-page" id="about-page">
<div className="about-page-entry">
<div className="about-page-intro">
<h1 className="big-spacer-bottom">{translate('layout.sonar.slogan')}</h1>
{!this.props.currentUser.isLoggedIn && (
- <Link to="/sessions/new" className="button button-active big-spacer-right">
+ <Link className="button button-active big-spacer-right" to="/sessions/new">
{translate('layout.login')}
</Link>
)}
<a
className="button"
href="https://redirect.sonarsource.com/doc/home.html"
+ rel="noopener noreferrer"
target="_blank">
{translate('about_page.read_documentation')}
</a>
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 };
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';
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 {
export default class App extends React.PureComponent<Props, State> {
mounted = false;
- static contextTypes = {
- onSonarCloud: PropTypes.bool
- };
-
state: State = { loading: false, notFound: false };
componentDidMount() {
({ 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 });
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,
getEntryRoot
} from '../utils';
import * as Docs from '../documentation.directory-loader';
+import { isSonarCloud } from '../../../helpers/system';
const pages = (Docs as any) as DocumentationEntry[];
}
export default class Menu extends React.PureComponent<Props> {
- static contextTypes = {
- onSonarCloud: PropTypes.bool
- };
-
getMenuEntriesHierarchy = (root?: string): Array<DocumentationEntry> => {
- const instancePages = this.context.onSonarCloud
+ const instancePages = isSonarCloud()
? pages
: pages.filter(page => page.scope !== 'sonarcloud');
const toplevelEntries = getEntryChildren(instancePages, root);
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 <AppContainer location={location} myIssues={myIssues} />;
}
-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<StateProps>(stateToProps)(IssuesPage);
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';
location: { pathname: string; query: RawQuery };
myIssues?: boolean;
onBranchesChange: () => void;
- onSonarCloud: boolean;
organization?: { key: string };
}
}
renderFacets() {
- const { component, currentUser, onSonarCloud } = this.props;
+ const { component, currentUser } = this.props;
const { query } = this.state;
return (
<div className="layout-page-filters">
{currentUser.isLoggedIn &&
- !onSonarCloud && (
+ !isSonarCloud() && (
<MyIssuesFilter
myIssues={this.state.myIssues}
onMyIssuesChange={this.handleMyIssuesChange}
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}
/>
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';
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<any>) => {
if (!organizationKeys.length) {
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;
}
<HomePageSelect
className="huge-spacer-left"
currentPage={
- this.props.onSonarCloud
- ? { type: HomePageType.MyIssues }
- : { type: HomePageType.Issues }
+ isSonarCloud() ? { type: HomePageType.MyIssues } : { type: HomePageType.Issues }
}
/>
)}
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<void>;
export class OrganizationDelete extends React.PureComponent<Props, State> {
mounted = false;
static contextTypes = {
- router: PropTypes.object,
- onSonarCloud: PropTypes.bool
+ router: PropTypes.object
};
state: State = {};
}
fetchOrganizationPlanInfo = () => {
- if (this.context.onSonarCloud) {
+ if (isSonarCloud()) {
getOrganizationBilling(this.props.organization.key).then(
billingInfo => {
if (this.mounted) {
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(() =>
)
}));
+jest.mock('../../../../helpers/system', () => ({ isSonarCloud: jest.fn() }));
+
beforeEach(() => {
(getOrganizationBilling as jest.Mock<any>).mockClear();
});
});
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 } });
});
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');
* 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 (
<div className="navbar-context-meta">
{organization.url != null && (
<div className="text-muted">
<strong>{translate('organization.key')}:</strong> {organization.key}
</div>
- {onSonarCloud && (
+ {isSonarCloud() && (
<div className="navbar-context-meta-secondary">
<HomePageSelect
currentPage={{ type: HomePageType.Organization, organization: organization.key }}
</div>
);
}
-
-const mapStateToProps = (state: any): StateProps => {
- const sonarCloudSetting = getGlobalSettingValue(state, 'sonar.sonarcloud.enabled');
-
- return {
- onSonarCloud: Boolean(sonarCloudSetting && sonarCloudSetting.value === 'true')
- };
-};
-
-export default connect(mapStateToProps)(OrganizationNavigationMeta);
*/
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(
<OrganizationNavigationMeta
- onSonarCloud={true}
organization={{
key: 'foo',
name: 'Foo',
}
}
/>
- <Connect(OrganizationNavigationMeta)
+ <OrganizationNavigationMeta
organization={
Object {
"key": "foo",
import Modal from '../../../components/controls/Modal';
import { getBranchLikeQuery } from '../../../helpers/branches';
import { translate } from '../../../helpers/l10n';
-import './styles.css';
import { Button, ResetButtonLink } from '../../../components/ui/buttons';
+import { isSonarCloud } from '../../../helpers/system';
+import './styles.css';
interface Props {
branchLike?: BranchLike;
metrics: { [key: string]: Metric };
- onSonarCloud: boolean;
project: string;
qualifier: string;
}
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 (
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,
};
it('should display the modal after click on sonar cloud', () => {
+ (isSonarCloud as jest.Mock).mockImplementation(() => true);
const wrapper = shallow(
- <BadgesModal
- branchLike={shortBranch}
- metrics={{}}
- onSonarCloud={true}
- project="foo"
- qualifier="TRK"
- />
+ <BadgesModal branchLike={shortBranch} metrics={{}} project="foo" qualifier="TRK" />
);
expect(wrapper).toMatchSnapshot();
click(wrapper.find('Button'));
});
it('should display the modal after click on sonar qube', () => {
+ (isSonarCloud as jest.Mock).mockImplementation(() => false);
const wrapper = shallow(
- <BadgesModal
- branchLike={shortBranch}
- metrics={{}}
- onSonarCloud={false}
- project="foo"
- qualifier="TRK"
- />
+ <BadgesModal branchLike={shortBranch} metrics={{}} project="foo" qualifier="TRK" />
);
expect(wrapper).toMatchSnapshot();
click(wrapper.find('Button'));
export default class Meta extends React.PureComponent<Props> {
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;
<BadgesModal
branchLike={branchLike}
metrics={metrics}
- onSonarCloud={onSonarCloud}
project={component.key}
qualifier={component.qualifier}
/>
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';
currentUser: CurrentUser;
isFavorite: boolean;
location: { pathname: string; query: RawQuery };
- onSonarCloud: boolean;
organization?: { key: string };
organizationsEnabled: boolean;
storageOptionsSuffix?: string;
onQueryChange={this.updateLocationQuery}
organization={this.props.organization}
query={this.state.query}
- showFavoriteFilter={!this.props.onSonarCloud}
+ showFavoriteFilter={!isSonarCloud()}
view={this.getView()}
visualization={this.getVisualization()}
/>
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}
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}
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;
}
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<StateProps, {}, OwnProps>(stateToProps)(
lazyLoad(() => import('./AllProjects'))
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 {
}
componentDidMount() {
- if (this.props.onSonarCloud && !isLoggedIn(this.props.currentUser)) {
+ if (isSonarCloud() && !isLoggedIn(this.props.currentUser)) {
this.context.router.replace('/explore/projects');
}
- if (!this.props.onSonarCloud) {
+ if (!isSonarCloud()) {
this.defineIfShouldBeRedirected();
}
}
componentDidUpdate(prevProps: Props) {
- if (!this.props.onSonarCloud) {
+ if (!isSonarCloud()) {
if (prevProps.location !== this.props.location) {
this.defineIfShouldBeRedirected();
} else if (this.state.shouldBeRedirected === true) {
}
render() {
- if (this.props.onSonarCloud && isLoggedIn(this.props.currentUser)) {
+ if (isSonarCloud() && isLoggedIn(this.props.currentUser)) {
return <AllProjectsContainer isFavorite={true} location={this.props.location} />;
}
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<StateProps>(stateToProps)(DefaultPageSelector);
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<Props> {
+export class NoFavoriteProjects extends React.PureComponent<StateProps> {
static contextTypes = {
openOnboardingTutorial: PropTypes.func
};
};
render() {
- const { onSonarCloud, organizations } = this.props;
+ const { organizations } = this.props;
return (
<div className="projects-empty-list">
<h3>{translate('projects.no_favorite_projects')}</h3>
- {onSonarCloud ? (
+ {isSonarCloud() ? (
<div className="spacer-top">
<p>{translate('projects.no_favorite_projects.how_to_add_projects')}</p>
<div className="huge-spacer-top">
import { translate } from '../../../helpers/l10n';
import { RawQuery } from '../../../helpers/query';
import { Project } from '../types';
+import { isSonarCloud } from '../../../helpers/system';
interface Props {
currentUser: CurrentUser;
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[];
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 (
<header className="page-header projects-topbar-items">
<HomePageSelect
className="huge-spacer-left"
currentPage={
- props.onSonarCloud ? { type: HomePageType.MyProjects } : { type: HomePageType.Projects }
+ isSonarCloud() ? { type: HomePageType.MyProjects } : { type: HomePageType.Projects }
}
/>
)}
cardType?: string;
isFavorite: boolean;
isFiltered: boolean;
- onSonarCloud: boolean;
organization?: { key: string };
projects: Project[];
query: Query;
if (isFiltered) {
return isFavorite ? <EmptyFavoriteSearch query={query} /> : <EmptySearch />;
}
- return isFavorite ? (
- <NoFavoriteProjects onSonarCloud={this.props.onSonarCloud} />
- ) : (
- <EmptyInstance />
- );
+ return isFavorite ? <NoFavoriteProjects /> : <EmptyInstance />;
}
render() {
? projects.map(project => (
<ProjectCard
key={project.key}
- project={project}
organization={this.props.organization}
+ project={project}
type={this.props.cardType}
/>
))
currentUser={{ isLoggedIn: true }}
isFavorite={false}
location={{ pathname: '/projects', query: {} }}
- onSonarCloud={false}
organizationsEnabled={false}
{...props}
/>,
replace: any = jest.fn()
) {
return mount(
- <DefaultPageSelector
- currentUser={currentUser}
- location={{ pathname: '/projects', query }}
- onSonarCloud={false}
- />,
+ <DefaultPageSelector currentUser={currentUser} location={{ pathname: '/projects', query }} />,
{ context: { router: { replace } } }
);
}
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(<NoFavoriteProjects onSonarCloud={false} organizations={[]} />)).toMatchSnapshot();
+ (isSonarCloud as jest.Mock).mockImplementation(() => false);
+ expect(shallow(<NoFavoriteProjects organizations={[]} />)).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(<NoFavoriteProjects onSonarCloud={true} organizations={organizations} />)
- ).toMatchSnapshot();
+ expect(shallow(<NoFavoriteProjects organizations={organizations} />)).toMatchSnapshot();
});
loading={false}
onPerspectiveChange={jest.fn()}
onQueryChange={jest.fn()}
- onSonarCloud={false}
onSortChange={jest.fn()}
projects={[]}
query={{ search: 'test' }}
loading={false}
onPerspectiveChange={[Function]}
onQueryChange={[Function]}
- onSonarCloud={false}
onSortChange={[Function]}
projects={
Array [
cardType="overall"
isFavorite={false}
isFiltered={false}
- onSonarCloud={false}
projects={
Array [
Object {
loading={false}
onPerspectiveChange={[Function]}
onQueryChange={[Function]}
- onSonarCloud={false}
onSortChange={[Function]}
projects={
Array [
* 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';
import { getIdentityProviders } from '../../../api/users';
import { IdentityProvider } from '../../../app/types';
import { getBaseUrl } from '../../../helpers/urls';
+import { isSonarCloud } from '../../../helpers/system';
interface OwnProps {
location: {
class LoginContainer extends React.PureComponent<Props, State> {
mounted = false;
- static contextTypes = {
- onSonarCloud: PropTypes.bool
- };
-
state: State = {};
componentDidMount() {
return null;
}
- if (this.context.onSonarCloud) {
+ if (isSonarCloud()) {
return (
<LoginSonarCloud
identityProviders={identityProviders}
onReset: () => void,
open: boolean,
organization?: string,
- sonarCloud: boolean,
stepNumber: number,
token: string
|};
onDone={this.handleLanguageSelect}
onReset={this.handleLanguageReset}
organization={this.props.organization}
- sonarCloud={this.props.sonarCloud}
/>
</div>
<div className="flex-column flex-column-half">{this.renderCommand()}</div>
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
|};
*/
export default class LanguageStep extends React.PureComponent {
/*:: props: Props; */
- static defaultProps = { sonarCloud: false };
-
state /*: State */ = {};
isConfigured = () => {
(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'];
import { translate, translateWithParameters } from '../../../helpers/l10n';
import { getProjectUrl } from '../../../helpers/urls';
import './styles.css';
+import { isSonarCloud } from '../../../helpers/system';
/*::
type Props = {|
/*:: state: State; */
static contextTypes = {
- onSonarCloud: PropTypes.bool,
router: PropTypes.object
};
return null;
}
- const { onSonarCloud } = this.context;
const { organizationsEnabled } = this.props;
const { step, token } = this.state;
let stepNumber = 1;
)}
<p className="note">
{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'
)}
</p>
</div>
onReset={this.handleReset}
open={step === 'analysis'}
organization={this.state.organization}
- sonarCloud={onSonarCloud}
stepNumber={stepNumber}
token={token}
/>
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();
});
it('selects c-family', () => {
+ isSonarCloud.mockImplementation(() => true);
const onDone = jest.fn();
- const wrapper = shallow(<LanguageStep onDone={onDone} onReset={jest.fn()} sonarCloud={true} />);
+ const wrapper = shallow(<LanguageStep onDone={onDone} onReset={jest.fn()} />);
wrapper.find('RadioToggle').prop('onCheck')('c-family');
wrapper.update();
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(
<Onboarding
className="modal-container"
});
it('guides for sonarcloud', () => {
+ getInstance.mockImplementation(() => 'SonarCloud');
+ isSonarCloud.mockImplementation(() => true);
const wrapper = shallow(
- <Onboarding currentUser={currentUser} onFinish={jest.fn()} organizationsEnabled={true} />,
- { context: { onSonarCloud: true } }
+ <Onboarding currentUser={currentUser} onFinish={jest.fn()} organizationsEnabled={true} />
);
expect(wrapper).toMatchSnapshot();
});
it('finishes', () => {
+ getInstance.mockImplementation(() => 'SonarQube');
+ isSonarCloud.mockImplementation(() => false);
const onFinish = jest.fn();
const wrapper = mount(
<Onboarding currentUser={currentUser} onFinish={onFinish} organizationsEnabled={false} />
onFinish={[Function]}
onReset={[Function]}
open={false}
- sonarCloud={true}
stepNumber={3}
/>
</div>
onReset={[Function]}
open={false}
organization="my-org"
- sonarCloud={true}
stepNumber={3}
/>
</div>
onReset={[Function]}
open={true}
organization="my-org"
- sonarCloud={true}
stepNumber={3}
token="abcd1234"
/>
* 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<Props> = (
- { 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;
+}
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();
message: string,
onSonarCloud = false
) {
- return shallow(<InstanceMessage message={message}>{children}</InstanceMessage>, {
- context: { onSonarCloud }
- });
+ (getInstance as jest.Mock).mockImplementation(() => (onSonarCloud ? 'SonarCloud' : 'SonarQube'));
+ return shallow(<InstanceMessage message={message}>{children}</InstanceMessage>);
}
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;
displayH1?: boolean;
}
-export default class DocMarkdownBlock extends React.PureComponent<Props> {
- static contextTypes = {
- onSonarCloud: PropTypes.bool
- };
-
- render() {
- const { className, content, displayH1 } = this.props;
- const parsed = separateFrontMatter(content || '');
- return (
- <div className={classNames('markdown', className)}>
- {displayH1 && <h1>{parsed.frontmatter.title}</h1>}
- {
- remark()
- // .use(remarkInclude)
- .use(reactRenderer, {
- remarkReactComponents: {
- // do not render outer <div />
- 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
- }
- </div>
- );
- }
+export default function DocMarkdownBlock({ className, content, displayH1 }: Props) {
+ const parsed = separateFrontMatter(content || '');
+ return (
+ <div className={classNames('markdown', className)}>
+ {displayH1 && <h1>{parsed.frontmatter.title}</h1>}
+ {
+ remark()
+ // .use(remarkInclude)
+ .use(reactRenderer, {
+ remarkReactComponents: {
+ // do not render outer <div />
+ 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
+ }
+ </div>
+ );
}
-function filterContent(content: string, onSonarCloud: boolean) {
- const beginning = onSonarCloud ? '<!-- sonarqube -->' : '<!-- sonarcloud -->';
- const ending = onSonarCloud ? '<!-- /sonarqube -->' : '<!-- /sonarcloud -->';
+function filterContent(content: string) {
+ const beginning = isSonarCloud() ? '<!-- sonarqube -->' : '<!-- sonarcloud -->';
+ const ending = isSonarCloud() ? '<!-- /sonarqube -->' : '<!-- /sonarcloud -->';
let newContent = content;
let start = newContent.indexOf(beginning);
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', () => {
return { default: remarkReact };
});
+jest.mock('../../../helpers/system', () => ({ isSonarCloud: jest.fn() }));
+
it('should render simple markdown', () => {
expect(shallow(<DocMarkdownBlock content="this is *bold* text" />)).toMatchSnapshot();
});
).toMatchSnapshot();
});
-it.only('should cut sonarqube/sonarcloud content', () => {
+it('should cut sonarqube/sonarcloud content', () => {
const content = `
some
text`;
- expect(
- shallow(<DocMarkdownBlock content={content} />, { context: { onSonarCloud: false } })
- ).toMatchSnapshot();
+ (isSonarCloud as jest.Mock).mockImplementation(() => false);
+ expect(shallow(<DocMarkdownBlock content={content} />)).toMatchSnapshot();
- expect(
- shallow(<DocMarkdownBlock content={content} />, { context: { onSonarCloud: true } })
- ).toMatchSnapshot();
+ (isSonarCloud as jest.Mock).mockImplementation(() => true);
+ expect(shallow(<DocMarkdownBlock content={content} />)).toMatchSnapshot();
});
--- /dev/null
+/*
+ * 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';
+}