]> source.dussan.org Git - sonarqube.git/commitdiff
SONARCLOUD-62 Move /sq/* pages and terms.pdf (#382)
authorStas Vilchik <stas.vilchik@sonarsource.com>
Fri, 15 Jun 2018 09:25:03 +0000 (11:25 +0200)
committerSonarTech <sonartech@sonarsource.com>
Thu, 21 Jun 2018 18:21:28 +0000 (20:21 +0200)
* extract SonarCloudPage
* add "As a Service" page
* add "Branch analysis & PR decoration" page
* add "SonarLint integration" page
* add VSTS page
* Move terms.pdf

32 files changed:
server/sonar-web/public/images/sonarcloud/branch-01.png [new file with mode: 0644]
server/sonar-web/public/images/sonarcloud/branch-01@2x.png [new file with mode: 0644]
server/sonar-web/public/images/sonarcloud/branch-02.png [new file with mode: 0644]
server/sonar-web/public/images/sonarcloud/branch-02@2x.png [new file with mode: 0644]
server/sonar-web/public/images/sonarcloud/branch-03.png [new file with mode: 0644]
server/sonar-web/public/images/sonarcloud/branch-03@2x.png [new file with mode: 0644]
server/sonar-web/public/images/sonarcloud/gears.png [new file with mode: 0644]
server/sonar-web/public/images/sonarcloud/gears@2x.png [new file with mode: 0644]
server/sonar-web/public/images/sonarcloud/sl-notif.png [new file with mode: 0644]
server/sonar-web/public/images/sonarcloud/sl-notif@2x.png [new file with mode: 0644]
server/sonar-web/public/images/sonarcloud/windows.svg [new file with mode: 0644]
server/sonar-web/public/sonarcloud-terms.pdf [new file with mode: 0644]
server/sonar-web/src/main/js/app/components/GlobalFooterSonarCloud.tsx
server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/GlobalFooterSonarCloud-test.tsx.snap
server/sonar-web/src/main/js/apps/about/routes.ts
server/sonar-web/src/main/js/apps/about/sonarcloud/AsAService.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/about/sonarcloud/BranchAnalysis.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/about/sonarcloud/Footer.tsx
server/sonar-web/src/main/js/apps/about/sonarcloud/Home.tsx
server/sonar-web/src/main/js/apps/about/sonarcloud/HomeContainer.tsx [deleted file]
server/sonar-web/src/main/js/apps/about/sonarcloud/SQHome.tsx
server/sonar-web/src/main/js/apps/about/sonarcloud/SQHomeContainer.tsx [deleted file]
server/sonar-web/src/main/js/apps/about/sonarcloud/SQStartUsing.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/about/sonarcloud/SQTopNav.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/about/sonarcloud/SonarCloudPage.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/about/sonarcloud/SonarLintIntegration.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/about/sonarcloud/StartUsing.tsx
server/sonar-web/src/main/js/apps/about/sonarcloud/VSTS.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/apps/about/sonarcloud/__tests__/Home-test.tsx
server/sonar-web/src/main/js/apps/about/sonarcloud/style.css
sonar-plugin-api/src/main/java/org/sonar/api/web/ServletFilter.java
sonar-plugin-api/src/test/java/org/sonar/api/web/ServletFilterTest.java

diff --git a/server/sonar-web/public/images/sonarcloud/branch-01.png b/server/sonar-web/public/images/sonarcloud/branch-01.png
new file mode 100644 (file)
index 0000000..43de145
Binary files /dev/null and b/server/sonar-web/public/images/sonarcloud/branch-01.png differ
diff --git a/server/sonar-web/public/images/sonarcloud/branch-01@2x.png b/server/sonar-web/public/images/sonarcloud/branch-01@2x.png
new file mode 100644 (file)
index 0000000..263b094
Binary files /dev/null and b/server/sonar-web/public/images/sonarcloud/branch-01@2x.png differ
diff --git a/server/sonar-web/public/images/sonarcloud/branch-02.png b/server/sonar-web/public/images/sonarcloud/branch-02.png
new file mode 100644 (file)
index 0000000..f772222
Binary files /dev/null and b/server/sonar-web/public/images/sonarcloud/branch-02.png differ
diff --git a/server/sonar-web/public/images/sonarcloud/branch-02@2x.png b/server/sonar-web/public/images/sonarcloud/branch-02@2x.png
new file mode 100644 (file)
index 0000000..556232b
Binary files /dev/null and b/server/sonar-web/public/images/sonarcloud/branch-02@2x.png differ
diff --git a/server/sonar-web/public/images/sonarcloud/branch-03.png b/server/sonar-web/public/images/sonarcloud/branch-03.png
new file mode 100644 (file)
index 0000000..effbe56
Binary files /dev/null and b/server/sonar-web/public/images/sonarcloud/branch-03.png differ
diff --git a/server/sonar-web/public/images/sonarcloud/branch-03@2x.png b/server/sonar-web/public/images/sonarcloud/branch-03@2x.png
new file mode 100644 (file)
index 0000000..ed85c2b
Binary files /dev/null and b/server/sonar-web/public/images/sonarcloud/branch-03@2x.png differ
diff --git a/server/sonar-web/public/images/sonarcloud/gears.png b/server/sonar-web/public/images/sonarcloud/gears.png
new file mode 100644 (file)
index 0000000..231685e
Binary files /dev/null and b/server/sonar-web/public/images/sonarcloud/gears.png differ
diff --git a/server/sonar-web/public/images/sonarcloud/gears@2x.png b/server/sonar-web/public/images/sonarcloud/gears@2x.png
new file mode 100644 (file)
index 0000000..95f79dd
Binary files /dev/null and b/server/sonar-web/public/images/sonarcloud/gears@2x.png differ
diff --git a/server/sonar-web/public/images/sonarcloud/sl-notif.png b/server/sonar-web/public/images/sonarcloud/sl-notif.png
new file mode 100644 (file)
index 0000000..fdb0daf
Binary files /dev/null and b/server/sonar-web/public/images/sonarcloud/sl-notif.png differ
diff --git a/server/sonar-web/public/images/sonarcloud/sl-notif@2x.png b/server/sonar-web/public/images/sonarcloud/sl-notif@2x.png
new file mode 100644 (file)
index 0000000..ae07309
Binary files /dev/null and b/server/sonar-web/public/images/sonarcloud/sl-notif@2x.png differ
diff --git a/server/sonar-web/public/images/sonarcloud/windows.svg b/server/sonar-web/public/images/sonarcloud/windows.svg
new file mode 100644 (file)
index 0000000..b0155ea
--- /dev/null
@@ -0,0 +1 @@
+<svg viewBox="0 0 38 38" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.414"><path fill="#ff3d00" d="M0 0h17.5v17.5H0z"/><path fill="#00a6f6" d="M0 20.5h17.5V38H0z"/><path fill="#69bd00" d="M20.5 0H38v17.5H20.5z"/><path fill="#ffb600" d="M20.5 20.5H38V38H20.5z"/></svg>
\ No newline at end of file
diff --git a/server/sonar-web/public/sonarcloud-terms.pdf b/server/sonar-web/public/sonarcloud-terms.pdf
new file mode 100644 (file)
index 0000000..75fd88a
Binary files /dev/null and b/server/sonar-web/public/sonarcloud-terms.pdf differ
index 44dd558676a137ea18c875d5539c7658af3baa0f..d1ffc010768e93bf802c2132929f89d83445e960 100644 (file)
@@ -41,7 +41,9 @@ export default function GlobalFooterSonarCloud() {
           <a href="https://twitter.com/sonarcloud">{translate('footer.twitter')}</a>
         </li>
         <li className="page-footer-menu-item">
-          <Link to="/terms.pdf">{translate('footer.terms')}</Link>
+          <Link rel="noopener noreferrer" target="_blank" to="/sonarcloud-terms.pdf">
+            {translate('footer.terms')}
+          </Link>
         </li>
         <li className="page-footer-menu-item">
           <Link to="/privacy">{translate('footer.privacy')}</Link>
index 4593fe94ca24eb0fc72611efeeb7a0aabc51b14e..89bb14e6625ed198b73c7570a0ea13ec960f3dc4 100644 (file)
@@ -41,8 +41,10 @@ exports[`should render correctly 1`] = `
     >
       <Link
         onlyActiveOnIndex={false}
+        rel="noopener noreferrer"
         style={Object {}}
-        to="/terms.pdf"
+        target="_blank"
+        to="/sonarcloud-terms.pdf"
       >
         footer.terms
       </Link>
index 7758ecaa78eb2766b60fa0bc508c98090e902549..a042681c66cc45f7909138939dbf5017a1bae3aa 100644 (file)
@@ -24,12 +24,34 @@ const routes = [
   {
     indexRoute: {
       component: lazyLoad(
-        () =>
-          isSonarCloud() ? import('./sonarcloud/HomeContainer') : import('./components/AboutApp')
+        () => (isSonarCloud() ? import('./sonarcloud/Home') : import('./components/AboutApp'))
       )
     },
     childRoutes: isSonarCloud
-      ? [{ path: 'sq', component: lazyLoad(() => import('./sonarcloud/SQHomeContainer')) }]
+      ? [
+          {
+            path: 'sq',
+            childRoutes: [
+              { indexRoute: { component: lazyLoad(() => import('./sonarcloud/SQHome')) } },
+              {
+                path: 'as-a-service',
+                component: lazyLoad(() => import('./sonarcloud/AsAService'))
+              },
+              {
+                path: 'branch-analysis-and-pr-decoration',
+                component: lazyLoad(() => import('./sonarcloud/BranchAnalysis'))
+              },
+              {
+                path: 'sonarlint-integration',
+                component: lazyLoad(() => import('./sonarcloud/SonarLintIntegration'))
+              },
+              {
+                path: 'vsts',
+                component: lazyLoad(() => import('./sonarcloud/VSTS'))
+              }
+            ]
+          }
+        ]
       : []
   }
 ];
diff --git a/server/sonar-web/src/main/js/apps/about/sonarcloud/AsAService.tsx b/server/sonar-web/src/main/js/apps/about/sonarcloud/AsAService.tsx
new file mode 100644 (file)
index 0000000..8c49385
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ * 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 SonarCloudPage from './SonarCloudPage';
+import SQStartUsing from './SQStartUsing';
+import SQTopNav from './SQTopNav';
+import { isLoggedIn } from '../../../app/types';
+import { getBaseUrl } from '../../../helpers/urls';
+import './style.css';
+
+export default function AsAService() {
+  return (
+    <SonarCloudPage>
+      {({ currentUser }) => (
+        <div className="page page-limited sc-page">
+          <SQTopNav />
+
+          <div className="sc-child-header">
+            <img alt="" height="34" src={`${getBaseUrl()}/images/sonarcloud/as-a-service.svg`} />
+            <h1 className="sc-child-title">As a Service</h1>
+            <p className="sc-child-lead">
+              We fully operate the SonarQube base service, <br />which is hosted in Frankfurt,
+              Germany.
+            </p>
+            <img
+              alt=""
+              height="137"
+              src={`${getBaseUrl()}/images/sonarcloud/gears.png`}
+              srcSet={`${getBaseUrl()}/images/sonarcloud/gears.png 1x, ${getBaseUrl()}/images/sonarcloud/gears@2x.png 2x`}
+              width="270"
+            />
+          </div>
+
+          <ul className="sc-features-list">
+            <li className="sc-feature sc-child-feature">
+              <h3 className="sc-feature-title">Ready to use</h3>
+              <p className="sc-feature-description">
+                You need to worry about nothing but enjoying the service, everything else such as
+                hardware, provisioning, installation, configuration, monitoring is being taken care
+                of by us.
+              </p>
+            </li>
+            <li className="sc-feature sc-child-feature">
+              <h3 className="sc-feature-title">Always the latest and greatest</h3>
+              <p className="sc-feature-description">
+                SonarCloud always provides the latest and greatest features of SonarQube and our
+                selection of plugins. As soon as a new feature is fit for production, it will ship
+                to SonarCloud and wait that you use it.
+              </p>
+            </li>
+            <li className="sc-feature sc-child-feature">
+              <h3 className="sc-feature-title">Get started in minutes</h3>
+              <p className="sc-feature-description">
+                Simply sign up, create an oganization for your team, and you are ready to run your
+                builds to get your projects analyzed in minutes.
+              </p>
+            </li>
+            <li className="sc-feature sc-child-feature">
+              <h3 className="sc-feature-title">Designed to scale</h3>
+              <p className="sc-feature-description">
+                You do not need to care about sizing or planning your future needs, we take care of
+                this and will make sure that the service can handle the analysis of your code at the
+                pace you decide. When you are getting close to your subscription limit, you decide
+                whether you want to go to the next level.
+              </p>
+            </li>
+          </ul>
+          {!isLoggedIn(currentUser) && <SQStartUsing />}
+        </div>
+      )}
+    </SonarCloudPage>
+  );
+}
diff --git a/server/sonar-web/src/main/js/apps/about/sonarcloud/BranchAnalysis.tsx b/server/sonar-web/src/main/js/apps/about/sonarcloud/BranchAnalysis.tsx
new file mode 100644 (file)
index 0000000..49b8f30
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * 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 SonarCloudPage from './SonarCloudPage';
+import SQStartUsing from './SQStartUsing';
+import SQTopNav from './SQTopNav';
+import { isLoggedIn } from '../../../app/types';
+import { getBaseUrl } from '../../../helpers/urls';
+import './style.css';
+
+export default function BranchAnalysis() {
+  return (
+    <SonarCloudPage>
+      {({ currentUser }) => (
+        <div className="page page-limited sc-page">
+          <SQTopNav />
+
+          <div className="sc-child-header">
+            <img alt="" height="34" src={`${getBaseUrl()}/images/sonarcloud/branch-analysis.svg`} />
+            <h1 className="sc-child-title">
+              Branch analysis & <br />pull request decoration
+            </h1>
+            <p className="sc-child-lead">
+              SonarCloud comes with a built-in feature to automatically analyze <br />project
+              branches and pull requests as soon as they get created.
+            </p>
+          </div>
+
+          <ul className="sc-features-list sc-branch-features-list">
+            <li className="sc-feature sc-branch-feature">
+              <img
+                alt=""
+                className="sc-branch-feature-right"
+                height="270"
+                src={`${getBaseUrl()}/images/sonarcloud/branch-01.png`}
+                srcSet={`${getBaseUrl()}/images/sonarcloud/branch-01.png 1x, ${getBaseUrl()}/images/sonarcloud/branch-01@2x.png 2x`}
+                width="463"
+              />
+              <div>
+                <h3 className="sc-feature-title">Analyze branches and pull requests</h3>
+                <p className="sc-feature-description">
+                  For all project branches (main, maintenance, version, feature, etc.), you get the
+                  full experience in the project space, with a specific focus on that branch.
+                </p>
+                <p className="sc-feature-description">
+                  When analyzing pull requests (PRs), a Quality Gate will be generated along with
+                  the list of issues created in the PR.
+                </p>
+                <p className="sc-feature-description">
+                  To save time and insure consistency, the analysis configuration is reused across
+                  all branches of a project.
+                </p>
+              </div>
+            </li>
+            <li className="sc-feature sc-branch-feature">
+              <div>
+                <h3 className="sc-feature-title">Decorate PRs on VSTS and GitHub</h3>
+                <p className="sc-feature-description">
+                  Pull requests get decorated directly on VSTS and GitHub. The result of the PR
+                  analysis is available directly in the pull request itself, complementing nicely
+                  manual reviews made by peers and enabling to make a more educated decision for
+                  merging.
+                </p>
+              </div>
+              <img
+                alt=""
+                className="sc-branch-feature-left"
+                height="390"
+                src={`${getBaseUrl()}/images/sonarcloud/branch-02.png`}
+                srcSet={`${getBaseUrl()}/images/sonarcloud/branch-02.png 1x, ${getBaseUrl()}/images/sonarcloud/branch-02@2x.png 2x`}
+                width="471"
+              />
+            </li>
+            <li className="sc-feature sc-branch-feature">
+              <img
+                alt=""
+                className="sc-branch-feature-right"
+                height="169"
+                src={`${getBaseUrl()}/images/sonarcloud/branch-03.png`}
+                srcSet={`${getBaseUrl()}/images/sonarcloud/branch-03.png 1x, ${getBaseUrl()}/images/sonarcloud/branch-03@2x.png 2x`}
+                width="460"
+              />
+              <div>
+                <h3 className="sc-feature-title">Add a check in GitHub</h3>
+                <p className="sc-feature-description">
+                  Finally, a check can be added to the PR to provide the Quality Gate status of the
+                  PR, check that can optionally block the merge.
+                </p>
+              </div>
+            </li>
+          </ul>
+
+          <div className="sc-branch-bottom">
+            There is no longer an excuse for pushing issues to the master.
+          </div>
+
+          {!isLoggedIn(currentUser) && <SQStartUsing />}
+        </div>
+      )}
+    </SonarCloudPage>
+  );
+}
index 48cd48d5cc89ba0a5aa28f3963c4a3c26c119cec..f7634e2479f4331244c16b66175feed9c21094c7 100644 (file)
@@ -96,10 +96,9 @@ export default function Footer() {
               <li className="spacer-top">
                 <Link
                   className="sc-footer-link"
-                  download="terms.pdf"
                   rel="noopener noreferrer"
                   target="_blank"
-                  to="/terms.pdf">
+                  to="/sonarcloud-terms.pdf">
                   Terms
                 </Link>
               </li>
index e5d99cc504f6f2f0a23a884b63241a0b209401bf..629a1730dba51db8b5035f37b5dd2901f1f6d19a 100644 (file)
  */
 import * as React from 'react';
 import { Link } from 'react-router';
-import Footer from './Footer';
+import SonarCloudPage from './SonarCloudPage';
 import Pricing from './Pricing';
 import StartUsing from './StartUsing';
-import GlobalContainer from '../../../app/components/GlobalContainer';
-import { CurrentUser, isLoggedIn } from '../../../app/types';
+import { isLoggedIn } from '../../../app/types';
 import ChevronRightIcon from '../../../components/icons-components/ChevronRightcon';
 import './style.css';
 
-interface Props {
-  currentUser: CurrentUser;
-  location: { pathname: string };
-}
-
-export default class Home extends React.PureComponent<Props> {
-  componentDidMount() {
-    document.documentElement.classList.add('white-page');
-    document.body.classList.add('white-page');
-  }
-
-  componentWillUnmount() {
-    document.documentElement.classList.remove('white-page');
-    document.body.classList.remove('white-page');
-  }
-
-  render() {
-    return (
-      <GlobalContainer footer={<Footer />} location={this.props.location}>
+export default function Home() {
+  return (
+    <SonarCloudPage>
+      {({ currentUser }) => (
         <div className="page page-limited sc-page">
           <h1 className="sc-page-title">Continuous Code Quality Online</h1>
           <p className="sc-page-subtitle">
@@ -102,7 +86,7 @@ export default class Home extends React.PureComponent<Props> {
 
           <Pricing />
 
-          {!isLoggedIn(this.props.currentUser) && <StartUsing />}
+          {!isLoggedIn(currentUser) && <StartUsing />}
 
           <div className="sc-narrow-container text-center">
             <h2 className="sc-feature-title">Explore open source projects on SonarCloud</h2>
@@ -121,20 +105,6 @@ export default class Home extends React.PureComponent<Props> {
           <div className="sc-narrow-container sc-news">
             <h2 className="sc-news-title">News</h2>
             <ChevronRightIcon className="big-spacer-left" fill="#cfd3d7" />
-            <a
-              className="sc-news-link big-spacer-left"
-              href="http://feedburner.google.com/fb/a/mailverify?uri=NewsSonarCloud&loc=en_US"
-              rel="noopener noreferrer"
-              target="_blank">
-              Subscribe by email
-            </a>
-            <a
-              className="sc-news-link big-spacer-left"
-              href="http://feeds.feedburner.com/NewsSonarCloud"
-              rel="noopener noreferrer"
-              target="_blank">
-              Subscribe by feed
-            </a>
             <a
               className="sc-news-link big-spacer-left"
               href="https://blog.sonarsource.com/product/SonarCloud"
@@ -144,7 +114,7 @@ export default class Home extends React.PureComponent<Props> {
             </a>
           </div>
         </div>
-      </GlobalContainer>
-    );
-  }
+      )}
+    </SonarCloudPage>
+  );
 }
diff --git a/server/sonar-web/src/main/js/apps/about/sonarcloud/HomeContainer.tsx b/server/sonar-web/src/main/js/apps/about/sonarcloud/HomeContainer.tsx
deleted file mode 100644 (file)
index 3fc2153..0000000
+++ /dev/null
@@ -1,28 +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 { connect } from 'react-redux';
-import Home from './Home';
-import { getCurrentUser } from '../../../store/rootReducer';
-
-const mapStateToProps = (state: any) => ({
-  currentUser: getCurrentUser(state)
-});
-
-export default connect(mapStateToProps)(Home);
index 80fce78956969ec9dea9a898c2b08b7f8f3f5f4f..f495891978dca5315d8fccdbd270a3e4cbe1d224 100644 (file)
  */
 import * as React from 'react';
 import { Link } from 'react-router';
-import Footer from './Footer';
+import SonarCloudPage from './SonarCloudPage';
 import Pricing from './Pricing';
 import StartUsing from './StartUsing';
-import GlobalContainer from '../../../app/components/GlobalContainer';
+import { isLoggedIn } from '../../../app/types';
 import { getBaseUrl } from '../../../helpers/urls';
 import './style.css';
-import { CurrentUser, isLoggedIn } from '../../../app/types';
 
-interface Props {
-  currentUser: CurrentUser;
-  location: { pathname: string };
-}
-
-export default class SQHome extends React.PureComponent<Props> {
-  componentDidMount() {
-    document.documentElement.classList.add('white-page');
-    document.body.classList.add('white-page');
-  }
-
-  componentWillUnmount() {
-    document.documentElement.classList.remove('white-page');
-    document.body.classList.remove('white-page');
-  }
-
-  render() {
-    return (
-      <GlobalContainer footer={<Footer />} location={this.props.location}>
+export default function SQHome() {
+  return (
+    <SonarCloudPage>
+      {({ currentUser }) => (
         <div className="page sc-page sc-sq-page">
           <Jumbotron />
 
           <h2 className="sc-sq-header2">You use the service, we take care of the rest</h2>
           <Pricing />
-          {!isLoggedIn(this.props.currentUser) && <StartUsing />}
+          {!isLoggedIn(currentUser) && <StartUsing />}
 
           <Features />
           <Languages />
           <Integrations />
           <BottomNote />
         </div>
-      </GlobalContainer>
-    );
-  }
+      )}
+    </SonarCloudPage>
+  );
 }
 
 function Jumbotron() {
@@ -76,15 +60,15 @@ function Jumbotron() {
           <br />Log in or sign up with
         </div>
         <div>
-          <Link className="sc-sq-login-button" to="/sessions/init/github">
+          <Link className="sc-black-button sc-sq-login-button" to="/sessions/init/github">
             <img alt="" height="25" src={`${getBaseUrl()}/images/sonarcloud/github-white.svg`} />
             GitHub
           </Link>
-          <Link className="sc-sq-login-button" to="/sessions/init/bitbucket">
+          <Link className="sc-black-button sc-sq-login-button" to="/sessions/init/bitbucket">
             <img alt="" height="25" src={`${getBaseUrl()}/images/sonarcloud/bitbucket-white.svg`} />
             Bitbucket
           </Link>
-          <Link className="sc-sq-login-button" to="/sessions/init/microsoft">
+          <Link className="sc-black-button sc-sq-login-button" to="/sessions/init/microsoft">
             <img alt="" height="25" src={`${getBaseUrl()}/images/sonarcloud/windows-white.svg`} />
             VSTS
           </Link>
diff --git a/server/sonar-web/src/main/js/apps/about/sonarcloud/SQHomeContainer.tsx b/server/sonar-web/src/main/js/apps/about/sonarcloud/SQHomeContainer.tsx
deleted file mode 100644 (file)
index 33be1be..0000000
+++ /dev/null
@@ -1,28 +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 { connect } from 'react-redux';
-import SQHome from './SQHome';
-import { getCurrentUser } from '../../../store/rootReducer';
-
-const mapStateToProps = (state: any) => ({
-  currentUser: getCurrentUser(state)
-});
-
-export default connect(mapStateToProps)(SQHome);
diff --git a/server/sonar-web/src/main/js/apps/about/sonarcloud/SQStartUsing.tsx b/server/sonar-web/src/main/js/apps/about/sonarcloud/SQStartUsing.tsx
new file mode 100644 (file)
index 0000000..f7d6693
--- /dev/null
@@ -0,0 +1,32 @@
+/*
+ * 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 { Link } from 'react-router';
+
+export default function SQStartUsing() {
+  return (
+    <div className="sc-child-start-using">
+      <div className="sc-child-start-using-text">Start using SonarCloud</div>
+      <Link className="sc-orange-button sc-child-start-using-link" to="/sessions/new">
+        Sign up now
+      </Link>
+    </div>
+  );
+}
diff --git a/server/sonar-web/src/main/js/apps/about/sonarcloud/SQTopNav.tsx b/server/sonar-web/src/main/js/apps/about/sonarcloud/SQTopNav.tsx
new file mode 100644 (file)
index 0000000..0a60558
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+ * 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 { Link } from 'react-router';
+
+export default function SQTopNav() {
+  return (
+    <ul className="sc-top-nav">
+      <li className="sc-top-nav-item">
+        <Link className="sc-top-nav-link" to="/about/sq">
+          Home
+        </Link>
+      </li>
+      <li className="sc-top-nav-item">
+        <Link
+          activeClassName="sc-top-nav-active"
+          className="sc-top-nav-link"
+          to="/about/sq/as-a-service">
+          As a Service
+        </Link>
+      </li>
+      <li className="sc-top-nav-item">
+        <Link
+          activeClassName="sc-top-nav-active"
+          className="sc-top-nav-link"
+          to="/about/sq/branch-analysis-and-pr-decoration">
+          Branch analysis & PR decoration
+        </Link>
+      </li>
+      <li className="sc-top-nav-item">
+        <Link
+          activeClassName="sc-top-nav-active"
+          className="sc-top-nav-link"
+          to="/about/sq/sonarlint-integration">
+          SonarLint integration
+        </Link>
+      </li>
+    </ul>
+  );
+}
diff --git a/server/sonar-web/src/main/js/apps/about/sonarcloud/SonarCloudPage.tsx b/server/sonar-web/src/main/js/apps/about/sonarcloud/SonarCloudPage.tsx
new file mode 100644 (file)
index 0000000..84b4a99
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ * 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 { connect } from 'react-redux';
+import { withRouter, WithRouterProps } from 'react-router';
+import Footer from './Footer';
+import { getCurrentUser, getMyOrganizations } from '../../../store/rootReducer';
+import { CurrentUser, Organization } from '../../../app/types';
+import GlobalContainer from '../../../app/components/GlobalContainer';
+
+interface StateProps {
+  currentUser: CurrentUser;
+  userOrganizations?: Organization[];
+}
+
+interface OwnProps {
+  children: (props: StateProps) => React.ReactNode;
+}
+
+type Props = StateProps & WithRouterProps & OwnProps;
+
+class SonarCloudPage extends React.Component<Props> {
+  componentDidMount() {
+    document.documentElement.classList.add('white-page');
+    document.body.classList.add('white-page');
+  }
+
+  componentWillUnmount() {
+    document.documentElement.classList.remove('white-page');
+    document.body.classList.remove('white-page');
+  }
+
+  render() {
+    const { children, currentUser, userOrganizations } = this.props;
+    return (
+      <GlobalContainer footer={<Footer />} location={this.props.location}>
+        {children({ currentUser, userOrganizations })}
+      </GlobalContainer>
+    );
+  }
+}
+
+const mapStateToProps = (state: any) => ({
+  currentUser: getCurrentUser(state),
+  userOrganizations: getMyOrganizations(state)
+});
+
+export default withRouter<OwnProps>(
+  connect<StateProps, {}, OwnProps>(mapStateToProps)(SonarCloudPage)
+);
diff --git a/server/sonar-web/src/main/js/apps/about/sonarcloud/SonarLintIntegration.tsx b/server/sonar-web/src/main/js/apps/about/sonarcloud/SonarLintIntegration.tsx
new file mode 100644 (file)
index 0000000..17fe58e
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+ * 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 SonarCloudPage from './SonarCloudPage';
+import SQStartUsing from './SQStartUsing';
+import SQTopNav from './SQTopNav';
+import { isLoggedIn } from '../../../app/types';
+import { getBaseUrl } from '../../../helpers/urls';
+import './style.css';
+
+export default function SonarLintIntegration() {
+  return (
+    <SonarCloudPage>
+      {({ currentUser }) => (
+        <div className="page page-limited sc-page">
+          <SQTopNav />
+
+          <div className="sc-child-header">
+            <img
+              alt=""
+              height="34"
+              src={`${getBaseUrl()}/images/sonarcloud/sonarlint-integration.svg`}
+            />
+            <h1 className="sc-child-title">SonarLint integration</h1>
+            <p className="sc-child-lead">
+              SonarCloud can be extended with{' '}
+              <a className="sc-child-lead-link" href="https://www.sonarlint.org/">
+                SonarLint
+              </a>{' '}
+              to provide developers maximum insight <br />in their IDEs on code quality and make
+              sure they do not introduce new issues.
+            </p>
+            <img
+              alt=""
+              height="147"
+              src={`${getBaseUrl()}/images/sonarcloud/sl-notif.png`}
+              srcSet={`${getBaseUrl()}/images/sonarcloud/sl-notif.png 1x, ${getBaseUrl()}/images/sonarcloud/sl-notif@2x.png 2x`}
+              width="450"
+            />
+          </div>
+
+          <ul className="sc-features-list">
+            <li className="sc-feature sc-child-feature">
+              <h3 className="sc-feature-title">Get instant feedback</h3>
+              <p className="sc-feature-description">
+                SonarLint will provide developers with instant feedback in their IDEs as they are
+                writing code, like with a spell checker. SonarLint also shows already existing
+                issues in the code and enables developers to differentiate what issues they
+                introduced.
+              </p>
+            </li>
+            <li className="sc-feature sc-child-feature">
+              <h3 className="sc-feature-title">Share quality profiles</h3>
+              <p className="sc-feature-description">
+                Teams will share the ruleset used to check quality on the project. This means that
+                not only everyone in the team uses the same rules but it also means that if you
+                update this ruleset, everybody will use immediately the updated one.
+              </p>
+            </li>
+            <li className="sc-feature sc-child-feature">
+              <h3 className="sc-feature-title">Share configuration</h3>
+              <p className="sc-feature-description">
+                Project configuration such as exclutions, parameters and false positives get
+                conveyed to the IDE as they get defined, enabling the team get exactly the same view
+                on the project they are working on.
+              </p>
+            </li>
+            <li className="sc-feature sc-child-feature">
+              <h3 className="sc-feature-title">Event notification</h3>
+              <p className="sc-feature-description">
+                Developers will get notified directly in their IDEs when the Quality Gate of their
+                project fails or when they have introduced an issue that has been picked by
+                SonarCloud.
+              </p>
+            </li>
+          </ul>
+
+          {!isLoggedIn(currentUser) && <SQStartUsing />}
+        </div>
+      )}
+    </SonarCloudPage>
+  );
+}
index cade5100554929c89dcb5c00d2e09f1e9a5606c9..c640474aa7652fa14059ea00ffae6b9325dbeeb3 100644 (file)
@@ -24,7 +24,7 @@ import ChevronRightIcon from '../../../components/icons-components/ChevronRightc
 export default function StartUsing() {
   return (
     <div className="sc-narrow-container text-center">
-      <Link className="sc-start" to="/sessions/new">
+      <Link className="sc-orange-button sc-start" to="/sessions/new">
         Start using SonarCloud <ChevronRightIcon className="spacer-left" />
       </Link>
       <div className="big-spacer-top">
diff --git a/server/sonar-web/src/main/js/apps/about/sonarcloud/VSTS.tsx b/server/sonar-web/src/main/js/apps/about/sonarcloud/VSTS.tsx
new file mode 100644 (file)
index 0000000..f641ea8
--- /dev/null
@@ -0,0 +1,135 @@
+/*
+ * 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 { Link } from 'react-router';
+import SonarCloudPage from './SonarCloudPage';
+import { isLoggedIn } from '../../../app/types';
+import { getBaseUrl } from '../../../helpers/urls';
+import './style.css';
+
+export default function VSTS() {
+  return (
+    <SonarCloudPage>
+      {({ currentUser }) => (
+        <div className="page page-limited sc-page">
+          <ul className="sc-top-nav">
+            <li className="sc-top-nav-item">
+              <Link className="sc-top-nav-link" to="/about/sq">
+                Home
+              </Link>
+            </li>
+          </ul>
+          <div className="sc-child-header">
+            <h1 className="sc-child-title">Get the full experience in VSTS</h1>
+          </div>
+
+          <ul className="sc-features-list">
+            <li className="sc-feature sc-child-feature">
+              <h3 className="sc-feature-title">Native extension</h3>
+              <p className="sc-feature-description">
+                Using your existing VSTS account and the SonarCloud VSTS build tasks, adding and
+                configuring SonarCloud analysis to an existing build is a matter of minutes.
+              </p>
+            </li>
+            <li className="sc-feature sc-child-feature">
+              <h3 className="sc-feature-title">Branches and PR analysis</h3>
+              <p className="sc-feature-description">
+                SonarCloud comes with a built-in feature to automatically analyze project branches
+                and pull requests as soon as they get created.
+              </p>
+            </li>
+            <li className="sc-feature sc-child-feature">
+              <h3 className="sc-feature-title">Built-in Quality Gate</h3>
+              <p className="sc-feature-description">
+                A quality gate is available out of the box in order to verify code quality criteria
+                at any time, enabling to fail build pipelines but also enabling to notify, through a
+                webhook, any system that code quality criteria are not met.
+              </p>
+            </li>
+            <li className="sc-feature sc-child-feature">
+              <h3 className="sc-feature-title">Dedicated widget</h3>
+              <p className="sc-feature-description">
+                Once a project is in SonarCloud, a configurable widget can be added to the VSTS
+                dashboard in order to add code quality to KPIs already used on the project.
+              </p>
+            </li>
+          </ul>
+
+          <div className="sc-vsts-start-wrapper">
+            <div className="sc-vsts-start">
+              {!isLoggedIn(currentUser) && (
+                <div className="sc-vsts-start-box">
+                  <img
+                    alt="SonarCloud"
+                    height="38"
+                    src={`${getBaseUrl()}/images/sonarcloud-square-logo.svg`}
+                  />
+                  <h3 className="sc-vsts-start-title">Log in or Sign up</h3>
+                  <a className="sc-orange-button" href="/sessions/init/microsoft">
+                    SonarCloud
+                  </a>
+                </div>
+              )}
+              <div className="sc-vsts-start-box">
+                <img
+                  alt="VSTS Extension"
+                  height="38"
+                  src={`${getBaseUrl()}/images/sonarcloud/windows.svg`}
+                />
+                <h3 className="sc-vsts-start-title">Install VSTS Extension</h3>
+                <a
+                  className="sc-black-button"
+                  href="https://marketplace.visualstudio.com/items?itemName=SonarSource.sonarcloud"
+                  rel="noopener noreferrer"
+                  target="_blank">
+                  Marketplace
+                </a>
+              </div>
+            </div>
+          </div>
+
+          <div className="sc-integrations">
+            <h2 className="sc-sq-header2 sc-integrations-title">Analyze .NET languages and more</h2>
+            <ul className="sc-languages-list">
+              <li>
+                <img alt="C#" height="60" src={`${getBaseUrl()}/images/languages/c-sharp.svg`} />
+              </li>
+              <li>
+                <img alt="VB" height="60" src={`${getBaseUrl()}/images/languages/vb.svg`} />
+              </li>
+              <li>
+                <img alt="JavaScript" height="60" src={`${getBaseUrl()}/images/languages/js.svg`} />
+              </li>
+              <li>
+                <img alt="TypeScript" height="60" src={`${getBaseUrl()}/images/languages/ts.svg`} />
+              </li>
+              <li>
+                <img alt="T-SQL" height="60" src={`${getBaseUrl()}/images/languages/tsql.svg`} />
+              </li>
+              <li>
+                <img alt="C++" height="60" src={`${getBaseUrl()}/images/languages/c-plus.svg`} />
+              </li>
+            </ul>
+          </div>
+        </div>
+      )}
+    </SonarCloudPage>
+  );
+}
index 9c5caa9619c96af3cc28dea9e2de7b2434c8d95c..a4368fec7a705137c371ce0a0bd141b71d15bbfb 100644 (file)
@@ -24,15 +24,5 @@ import Home from '../Home';
 jest.mock('Docs/EmbedDocsSuggestions.json', () => ({}), { virtual: true });
 
 it('should render', () => {
-  expect(
-    shallow(<Home currentUser={{ isLoggedIn: false }} location={{ pathname: '/' }} />)
-  ).toBeDefined();
-});
-
-it('should not render "Start using SonarCloud" button', () => {
-  expect(
-    shallow(<Home currentUser={{ isLoggedIn: true }} location={{ pathname: '/' }} />)
-      .find('.sc-start')
-      .exists()
-  ).toBe(false);
+  expect(shallow(<Home />)).toBeDefined();
 });
index 1c3d8ada395423fe996c356fa18c832833098e2e..f05b2e23fcb89eb7b72920ba5474ba4934a8cd54 100644 (file)
   box-shadow: 0 0 0 3px rgba(230, 92, 0, 0.25);
 }
 
+.sc-black-button,
+.sc-orange-button {
+  display: inline-flex;
+  align-items: center;
+  height: 44px;
+  padding: 0 15px;
+  line-height: 44px;
+  border: none;
+  border-radius: 4px;
+
+  color: #fff;
+  font-size: 18px;
+  font-weight: 500;
+}
+
+.sc-black-button {
+  background-color: var(--sonarcloudBlack800);
+}
+
+.sc-black-button:hover,
+.sc-black-button:focus {
+  color: #fff;
+  background-color: var(--sonarcloudBlack900);
+}
+
+.sc-orange-button {
+  background-color: var(--sonarcloudOrange);
+}
+
+.sc-orange-button:hover,
+.sc-orange-button:focus {
+  background-color: var(--sonarcloudOrangeDark);
+  color: #fff;
+}
+
 .sc-page-title {
   line-height: 56px;
   margin-top: 40px;
   font-weight: 300;
 }
 
+.sc-feature-description + .sc-feature-description {
+  margin-top: 16px;
+}
+
 .sc-feature-link {
   margin-top: 16px;
   color: var(--sonarcloudOrange) !important;
 .sc-start {
   display: inline-flex;
   align-items: center;
-  height: 44px;
-  line-height: 44px;
-  padding: 0 16px;
-  border-radius: 5px;
-  border: none;
-  color: #fff;
   font-size: 16px;
   font-weight: 700;
-  background-color: var(--sonarcloudOrange);
 }
 
 .sc-start:hover,
 }
 
 .sc-sq-login-button {
-  display: inline-flex;
-  align-items: center;
-  height: 44px;
   margin-top: 16px;
   margin-right: 16px;
-  padding: 0 15px;
-  line-height: 44px;
-  border: none;
-  border-radius: 4px;
-  background-color: var(--sonarcloudBlack800);
-  color: #fff;
-  font-size: 18px;
-  font-weight: 500;
-}
-
-.sc-sq-login-button:hover,
-.sc-sq-login-button:focus {
-  color: #fff;
-  background-color: var(--sonarcloudBlack900);
 }
 
 .sc-sq-login-button > img {
 .sc-integrations {
   position: relative;
   background-color: var(--sonarcloudBlack200);
+  margin-left: -20px;
+  margin-right: -20px;
+  margin-bottom: -10px;
   padding: 44px 0px;
   text-align: center;
 }
 }
 
 .sc-bottom-note {
-  margin: 16px 0;
+  margin: 26px 0 16px;
   font-size: 16px;
   font-weight: 300;
   text-align: center;
   background: url(/images/sonarcloud/sq-background.svg) no-repeat top center;
   background-size: auto 200vh;
 }
+
+.sc-top-nav {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  margin-bottom: 30px;
+}
+
+.sc-top-nav-item + .sc-top-nav-item {
+  margin-left: 13px;
+  border-left: 1px solid var(--sonarcloudBlack300);
+  padding-left: 13px;
+}
+
+.sc-top-nav-link {
+  border-bottom-color: var(--sonarcloudBlack300);
+  color: var(--baseFontColor);
+  font-weight: 300;
+}
+
+a.sc-top-nav-link:hover,
+a.sc-top-nav-link:focus {
+  border-bottom-color: var(--sonarcloudOrange);
+  color: var(--sonarcloudOrange);
+}
+
+.sc-top-nav-active {
+  border: none;
+  font-weight: 500;
+}
+
+.sc-child-header {
+  margin-bottom: 50px;
+  text-align: center;
+}
+
+.sc-child-title {
+  margin: 20px 0;
+  line-height: 45px;
+  font-size: 44px;
+  font-weight: 700;
+}
+
+.sc-child-lead {
+  margin: 20px 0 35px;
+  line-height: 30px;
+  font-size: 21px;
+  font-weight: 300;
+}
+
+.sc-child-lead-link {
+  border-bottom-color: rgba(255, 102, 0, 0.2);
+  color: var(--sonarcloudOrange);
+}
+
+.sc-child-lead-link:hover,
+.sc-child-lead-link:focus {
+  border-bottom-color: var(--sonarcloudOrangeDark);
+  color: var(--sonarcloudOrangeDark);
+}
+
+.sc-child-feature {
+  width: calc(50% - 60px);
+}
+
+.sc-child-start-using {
+  display: flex;
+  align-items: center;
+  justify-content: space-between;
+  width: 600px;
+  margin: 20px auto;
+  padding: 30px;
+  border: 1px solid rgba(207, 211, 215, 0.5);
+  border-radius: 5px;
+  box-shadow: 0 3px 3px 0 rgba(7, 7, 6, 0.05);
+}
+
+.sc-child-start-using-text {
+  font-size: 21px;
+  font-weight: 500;
+}
+
+.sc-child-start-using-link {
+  padding-right: 0;
+}
+
+.sc-child-start-using-link::after {
+  content: '→';
+  padding: 0 16px;
+  font-size: 16px;
+  font-weight: 300;
+  transition: padding 0.1s ease;
+}
+
+.sc-child-start-using-link:hover::after,
+.sc-child-start-using-link:focus::after {
+  padding-left: 22px;
+  padding-right: 10px;
+}
+
+.sc-branch-features-list {
+  flex-direction: column;
+}
+
+.sc-branch-feature {
+  width: auto;
+  margin: 0;
+  padding: 20px 0 40px;
+  flex-direction: row;
+  align-items: center;
+  justify-content: space-between;
+}
+
+.sc-branch-feature + .sc-branch-feature {
+  border-top: 1px solid rgba(207, 211, 215, 0.5);
+}
+
+.sc-branch-feature-left {
+  margin-left: 60px;
+}
+
+.sc-branch-feature-right {
+  margin-right: 60px;
+}
+
+.sc-branch-bottom {
+  padding: 20px 0;
+  font-size: 21px;
+  font-weight: 500;
+  text-align: center;
+}
+
+.sc-vsts-start-wrapper {
+  margin-top: 20px;
+  margin-bottom: 50px;
+  text-align: center;
+}
+
+.sc-vsts-start {
+  display: inline-flex;
+  border: 1px solid rgba(207, 211, 215, 0.5);
+  border-radius: 5px;
+  box-shadow: 0 3px 3px 0 rgba(7, 7, 6, 0.05);
+}
+
+.sc-vsts-start-box {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  width: 210px;
+  padding: 30px;
+}
+
+.sc-vsts-start-box + .sc-vsts-start-box {
+  border-left: 1px solid rgba(207, 211, 215, 0.5);
+}
+
+.sc-vsts-start-title {
+  margin: 16px 0 24px;
+  font-size: 21px;
+  font-weight: 300;
+}
index 502d17cab79c2ef624e53cdf34e8c5cedd4e1517..5f255961196a09b4b923dd1aee424e37f90f380d 100644 (file)
@@ -142,9 +142,8 @@ public abstract class ServletFilter implements Filter {
     public static class Builder {
       private static final String WILDCARD_CHAR = "*";
       private static final Collection<String> STATIC_RESOURCES = unmodifiableList(asList(
-        "*.css", "*.css.map", "*.ico", "*.png", "*.jpg", "*.jpeg", "*.gif", "*.svg", "*.js", "*.js.map",
-        "/static/*", "/robots.txt","/favicon.ico", "/apple-touch-icon*", "/mstile*"
-      ));
+        "*.css", "*.css.map", "*.ico", "*.png", "*.jpg", "*.jpeg", "*.gif", "*.svg", "*.js", "*.js.map", "*.pdf",
+        "/static/*", "/robots.txt", "/favicon.ico", "/apple-touch-icon*", "/mstile*"));
 
       private final Set<String> inclusions = new LinkedHashSet<>();
       private final Set<String> exclusions = new LinkedHashSet<>();
index 84e800559cee05865f57c53a0873e1fda826ba34..a9caba6f8749155382b46c2c76b2ddd9cffbf1bc 100644 (file)
@@ -161,9 +161,9 @@ public class ServletFilterTest {
   @Test
   public void use_include_and_exclude_prefix() {
     ServletFilter.UrlPattern pattern = ServletFilter.UrlPattern.builder()
-        .includes("/foo_2")
-        .excludes("/foo")
-        .build();
+      .includes("/foo_2")
+      .excludes("/foo")
+      .build();
     assertThat(pattern.matches("/")).isFalse();
     assertThat(pattern.matches("/foo_2")).isTrue();
     assertThat(pattern.matches("/foo")).isFalse();
@@ -238,6 +238,7 @@ public class ServletFilterTest {
       "*.svg",
       "*.js",
       "*.js.map",
+      "*.pdf",
       "/static/*",
       "/robots.txt",
       "/favicon.ico",