Browse Source

SONARCLOUD-62 Move /sq/* pages and terms.pdf (#382)

* extract SonarCloudPage
* add "As a Service" page
* add "Branch analysis & PR decoration" page
* add "SonarLint integration" page
* add VSTS page
* Move terms.pdf
tags/7.5
Stas Vilchik 6 years ago
parent
commit
7a8b69cb8e
31 changed files with 849 additions and 155 deletions
  1. BIN
      server/sonar-web/public/images/sonarcloud/branch-01.png
  2. BIN
      server/sonar-web/public/images/sonarcloud/branch-01@2x.png
  3. BIN
      server/sonar-web/public/images/sonarcloud/branch-02.png
  4. BIN
      server/sonar-web/public/images/sonarcloud/branch-02@2x.png
  5. BIN
      server/sonar-web/public/images/sonarcloud/branch-03.png
  6. BIN
      server/sonar-web/public/images/sonarcloud/branch-03@2x.png
  7. BIN
      server/sonar-web/public/images/sonarcloud/gears.png
  8. BIN
      server/sonar-web/public/images/sonarcloud/gears@2x.png
  9. BIN
      server/sonar-web/public/images/sonarcloud/sl-notif.png
  10. BIN
      server/sonar-web/public/images/sonarcloud/sl-notif@2x.png
  11. 1
    0
      server/sonar-web/public/images/sonarcloud/windows.svg
  12. BIN
      server/sonar-web/public/sonarcloud-terms.pdf
  13. 3
    1
      server/sonar-web/src/main/js/app/components/GlobalFooterSonarCloud.tsx
  14. 3
    1
      server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/GlobalFooterSonarCloud-test.tsx.snap
  15. 25
    3
      server/sonar-web/src/main/js/apps/about/routes.ts
  16. 90
    0
      server/sonar-web/src/main/js/apps/about/sonarcloud/AsAService.tsx
  17. 119
    0
      server/sonar-web/src/main/js/apps/about/sonarcloud/BranchAnalysis.tsx
  18. 1
    2
      server/sonar-web/src/main/js/apps/about/sonarcloud/Footer.tsx
  19. 10
    40
      server/sonar-web/src/main/js/apps/about/sonarcloud/Home.tsx
  20. 13
    29
      server/sonar-web/src/main/js/apps/about/sonarcloud/SQHome.tsx
  21. 0
    28
      server/sonar-web/src/main/js/apps/about/sonarcloud/SQHomeContainer.tsx
  22. 12
    8
      server/sonar-web/src/main/js/apps/about/sonarcloud/SQStartUsing.tsx
  23. 57
    0
      server/sonar-web/src/main/js/apps/about/sonarcloud/SQTopNav.tsx
  24. 67
    0
      server/sonar-web/src/main/js/apps/about/sonarcloud/SonarCloudPage.tsx
  25. 100
    0
      server/sonar-web/src/main/js/apps/about/sonarcloud/SonarLintIntegration.tsx
  26. 1
    1
      server/sonar-web/src/main/js/apps/about/sonarcloud/StartUsing.tsx
  27. 135
    0
      server/sonar-web/src/main/js/apps/about/sonarcloud/VSTS.tsx
  28. 1
    11
      server/sonar-web/src/main/js/apps/about/sonarcloud/__tests__/Home-test.tsx
  29. 205
    25
      server/sonar-web/src/main/js/apps/about/sonarcloud/style.css
  30. 2
    3
      sonar-plugin-api/src/main/java/org/sonar/api/web/ServletFilter.java
  31. 4
    3
      sonar-plugin-api/src/test/java/org/sonar/api/web/ServletFilterTest.java

BIN
server/sonar-web/public/images/sonarcloud/branch-01.png View File


BIN
server/sonar-web/public/images/sonarcloud/branch-01@2x.png View File


BIN
server/sonar-web/public/images/sonarcloud/branch-02.png View File


BIN
server/sonar-web/public/images/sonarcloud/branch-02@2x.png View File


BIN
server/sonar-web/public/images/sonarcloud/branch-03.png View File


BIN
server/sonar-web/public/images/sonarcloud/branch-03@2x.png View File


BIN
server/sonar-web/public/images/sonarcloud/gears.png View File


BIN
server/sonar-web/public/images/sonarcloud/gears@2x.png View File


BIN
server/sonar-web/public/images/sonarcloud/sl-notif.png View File


BIN
server/sonar-web/public/images/sonarcloud/sl-notif@2x.png View File


+ 1
- 0
server/sonar-web/public/images/sonarcloud/windows.svg View File

@@ -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>

BIN
server/sonar-web/public/sonarcloud-terms.pdf View File


+ 3
- 1
server/sonar-web/src/main/js/app/components/GlobalFooterSonarCloud.tsx View 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>

+ 3
- 1
server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/GlobalFooterSonarCloud-test.tsx.snap View 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>

+ 25
- 3
server/sonar-web/src/main/js/apps/about/routes.ts View 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'))
}
]
}
]
: []
}
];

+ 90
- 0
server/sonar-web/src/main/js/apps/about/sonarcloud/AsAService.tsx View File

@@ -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>
);
}

+ 119
- 0
server/sonar-web/src/main/js/apps/about/sonarcloud/BranchAnalysis.tsx View File

@@ -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>
);
}

+ 1
- 2
server/sonar-web/src/main/js/apps/about/sonarcloud/Footer.tsx View 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>

+ 10
- 40
server/sonar-web/src/main/js/apps/about/sonarcloud/Home.tsx View File

@@ -19,33 +19,17 @@
*/
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>
);
}

+ 13
- 29
server/sonar-web/src/main/js/apps/about/sonarcloud/SQHome.tsx View File

@@ -19,48 +19,32 @@
*/
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>

+ 0
- 28
server/sonar-web/src/main/js/apps/about/sonarcloud/SQHomeContainer.tsx View File

@@ -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);

server/sonar-web/src/main/js/apps/about/sonarcloud/HomeContainer.tsx → server/sonar-web/src/main/js/apps/about/sonarcloud/SQStartUsing.tsx View File

@@ -17,12 +17,16 @@
* 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';
import * as React from 'react';
import { Link } from 'react-router';

const mapStateToProps = (state: any) => ({
currentUser: getCurrentUser(state)
});

export default connect(mapStateToProps)(Home);
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>
);
}

+ 57
- 0
server/sonar-web/src/main/js/apps/about/sonarcloud/SQTopNav.tsx View File

@@ -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>
);
}

+ 67
- 0
server/sonar-web/src/main/js/apps/about/sonarcloud/SonarCloudPage.tsx View File

@@ -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)
);

+ 100
- 0
server/sonar-web/src/main/js/apps/about/sonarcloud/SonarLintIntegration.tsx View File

@@ -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>
);
}

+ 1
- 1
server/sonar-web/src/main/js/apps/about/sonarcloud/StartUsing.tsx View 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">

+ 135
- 0
server/sonar-web/src/main/js/apps/about/sonarcloud/VSTS.tsx View File

@@ -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>
);
}

+ 1
- 11
server/sonar-web/src/main/js/apps/about/sonarcloud/__tests__/Home-test.tsx View 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();
});

+ 205
- 25
server/sonar-web/src/main/js/apps/about/sonarcloud/style.css View File

@@ -28,6 +28,41 @@
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;
@@ -77,6 +112,10 @@
font-weight: 300;
}

.sc-feature-description + .sc-feature-description {
margin-top: 16px;
}

.sc-feature-link {
margin-top: 16px;
color: var(--sonarcloudOrange) !important;
@@ -160,15 +199,8 @@
.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,
@@ -327,25 +359,8 @@
}

.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 {
@@ -385,6 +400,9 @@
.sc-integrations {
position: relative;
background-color: var(--sonarcloudBlack200);
margin-left: -20px;
margin-right: -20px;
margin-bottom: -10px;
padding: 44px 0px;
text-align: center;
}
@@ -407,7 +425,7 @@
}

.sc-bottom-note {
margin: 16px 0;
margin: 26px 0 16px;
font-size: 16px;
font-weight: 300;
text-align: center;
@@ -427,3 +445,165 @@
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;
}

+ 2
- 3
sonar-plugin-api/src/main/java/org/sonar/api/web/ServletFilter.java View 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<>();

+ 4
- 3
sonar-plugin-api/src/test/java/org/sonar/api/web/ServletFilterTest.java View 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",

Loading…
Cancel
Save