* extract SonarCloudPage * add "As a Service" page * add "Branch analysis & PR decoration" page * add "SonarLint integration" page * add VSTS page * Move terms.pdftags/7.5
@@ -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> |
@@ -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> |
@@ -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> |
@@ -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')) | |||
} | |||
] | |||
} | |||
] | |||
: [] | |||
} | |||
]; |
@@ -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> | |||
); | |||
} |
@@ -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> | |||
); | |||
} |
@@ -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> |
@@ -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> | |||
); | |||
} |
@@ -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> |
@@ -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); |
@@ -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> | |||
); | |||
} |
@@ -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> | |||
); | |||
} |
@@ -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) | |||
); |
@@ -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> | |||
); | |||
} |
@@ -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"> |
@@ -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> | |||
); | |||
} |
@@ -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(); | |||
}); |
@@ -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; | |||
} |
@@ -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<>(); |
@@ -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", |