SONAR_UPDATECENTER_ACTIVATE("sonar.updatecenter.activate", "true"),
SONARCLOUD_ENABLED("sonar.sonarcloud.enabled", "false"),
-
SONAR_PRISMIC_ACCESS_TOKEN("sonar.prismic.accessToken", ""),
+ SONAR_ANALYTICS_TRACKING_ID("sonar.analytics.trackingId", ""),
BITBUCKETCLOUD_APP_KEY("sonar.bitbucketcloud.appKey", "sonarcloud"),
BITBUCKETCLOUD_ENDPOINT("sonar.bitbucketcloud.endpoint", "https://api.bitbucket.org"),
// whether the blue/green deployment of server is enabled
BLUE_GREEN_ENABLED("sonar.blueGreenEnabled", "false");
-
-
private final String key;
private final String defaultValue;
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_ANALYTICS_TRACKING_ID;
import static org.sonar.process.ProcessProperties.Property.SONAR_PRISMIC_ACCESS_TOKEN;
import static org.sonar.process.ProcessProperties.Property.SONAR_UPDATECENTER_ACTIVATE;
boolean isOnSonarCloud = config.getBoolean(SONARCLOUD_ENABLED.getKey()).orElse(false);
if (isOnSonarCloud) {
this.systemSettingValuesByKey.put(SONAR_PRISMIC_ACCESS_TOKEN.getKey(), config.get(SONAR_PRISMIC_ACCESS_TOKEN.getKey()).orElse(null));
+ this.systemSettingValuesByKey.put(SONAR_ANALYTICS_TRACKING_ID.getKey(), config.get(SONAR_ANALYTICS_TRACKING_ID.getKey()).orElse(null));
}
}
public void return_prismic_setting_on_sonarcloud_only() {
settings.setProperty("sonar.sonarcloud.enabled", true);
settings.setProperty("sonar.prismic.accessToken", "secret");
+ settings.setProperty("sonar.analytics.trackingId", "ga_id");
init();
assertJson(call()).isSimilarTo("{" +
" \"settings\": {" +
" \"sonar.prismic.accessToken\": \"secret\"" +
+ " \"sonar.analytics.trackingId\": \"ga_id\"" +
" }" +
"}");
}
userSession.logIn().setRoot();
when(webServer.isStandalone()).thenReturn(true);
-
assertJson(call()).isSimilarTo("{\"standalone\":true}");
}
userSession.logIn().setRoot();
when(webServer.isStandalone()).thenReturn(false);
-
assertJson(call()).isSimilarTo("{\"standalone\":false}");
}
"react-day-picker": "7.1.8",
"react-dom": "16.2.0",
"react-draggable": "3.0.5",
+ "react-ga": "2.5.3",
"react-helmet": "5.2.0",
"react-intl": "2.4.0",
"react-modal": "3.4.4",
import { fetchCurrentUser } from '../../store/users/actions';
import { fetchLanguages, fetchAppState } from '../../store/rootActions';
import { fetchMyOrganizations } from '../../apps/account/organizations/actions';
-import { getInstance } from '../../helpers/system';
+import { getInstance, isSonarCloud } from '../../helpers/system';
+import { lazyLoad } from '../../components/lazyLoad';
+
+const PageTracker = lazyLoad(() => import('./PageTracker'));
interface Props {
children: JSX.Element;
return (
<>
<Helmet defaultTitle={getInstance()} />
+ {isSonarCloud() && <PageTracker />}
{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 GoogleAnalytics from 'react-ga';
+import { withRouter, WithRouterProps } from 'react-router';
+import { connect } from 'react-redux';
+import { getGlobalSettingValue } from '../../store/rootReducer';
+
+interface StateProps {
+ trackingId?: string;
+}
+
+type Props = WithRouterProps & StateProps;
+
+export class PageTracker extends React.PureComponent<Props> {
+ componentDidMount() {
+ if (this.props.trackingId) {
+ GoogleAnalytics.initialize(this.props.trackingId);
+ this.trackPage();
+ }
+ }
+
+ componentDidUpdate(prevProps: Props) {
+ const currentPage = this.props.location.pathname;
+ const prevPage = prevProps.location.pathname;
+
+ if (currentPage !== prevPage) {
+ this.trackPage();
+ }
+ }
+
+ trackPage = () => {
+ const { location, trackingId } = this.props;
+ if (trackingId) {
+ GoogleAnalytics.pageview(location.pathname);
+ }
+ };
+
+ render() {
+ return null;
+ }
+}
+
+const mapStateToProps = (state: any): StateProps => ({
+ trackingId: (getGlobalSettingValue(state, 'sonar.analytics.trackingId') || {}).value
+});
+
+export default withRouter<{}>(connect<StateProps>(mapStateToProps)(PageTracker));
version "4.0.0"
resolved "https://registry.yarnpkg.com/react-error-overlay/-/react-error-overlay-4.0.0.tgz#d198408a85b4070937a98667f500c832f86bd5d4"
+react-ga@2.5.3:
+ version "2.5.3"
+ resolved "https://registry.yarnpkg.com/react-ga/-/react-ga-2.5.3.tgz#0f447c73664c069a5fc341f6f431262e3d4c23c4"
+ optionalDependencies:
+ prop-types "^15.6.0"
+ react "^15.6.2 || ^16.0"
+
react-helmet@5.2.0:
version "5.2.0"
resolved "https://registry.yarnpkg.com/react-helmet/-/react-helmet-5.2.0.tgz#a81811df21313a6d55c5f058c4aeba5d6f3d97a7"
object-assign "^4.1.1"
prop-types "^15.6.0"
+"react@^15.6.2 || ^16.0":
+ version "16.4.1"
+ resolved "https://registry.yarnpkg.com/react/-/react-16.4.1.tgz#de51ba5764b5dbcd1f9079037b862bd26b82fe32"
+ dependencies:
+ fbjs "^0.8.16"
+ loose-envify "^1.1.0"
+ object-assign "^4.1.1"
+ prop-types "^15.6.0"
+
read-pkg-up@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02"