diff options
author | Stas Vilchik <stas.vilchik@sonarsource.com> | 2018-06-15 11:25:03 +0200 |
---|---|---|
committer | SonarTech <sonartech@sonarsource.com> | 2018-06-21 20:21:28 +0200 |
commit | 7a8b69cb8e9e6cd0d47b5dc3f5dc4ab9e2368661 (patch) | |
tree | db858a7b02ebcf20fb0b763918721b83fe90bd89 /server/sonar-web | |
parent | c4803912bda0edfceeb09d9115c1dd2cdf8db96e (diff) | |
download | sonarqube-7a8b69cb8e9e6cd0d47b5dc3f5dc4ab9e2368661.tar.gz sonarqube-7a8b69cb8e9e6cd0d47b5dc3f5dc4ab9e2368661.zip |
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
Diffstat (limited to 'server/sonar-web')
29 files changed, 843 insertions, 149 deletions
diff --git a/server/sonar-web/public/images/sonarcloud/branch-01.png b/server/sonar-web/public/images/sonarcloud/branch-01.png Binary files differnew file mode 100644 index 00000000000..43de1451f25 --- /dev/null +++ b/server/sonar-web/public/images/sonarcloud/branch-01.png diff --git a/server/sonar-web/public/images/sonarcloud/branch-01@2x.png b/server/sonar-web/public/images/sonarcloud/branch-01@2x.png Binary files differnew file mode 100644 index 00000000000..263b0947cda --- /dev/null +++ b/server/sonar-web/public/images/sonarcloud/branch-01@2x.png diff --git a/server/sonar-web/public/images/sonarcloud/branch-02.png b/server/sonar-web/public/images/sonarcloud/branch-02.png Binary files differnew file mode 100644 index 00000000000..f772222acb4 --- /dev/null +++ b/server/sonar-web/public/images/sonarcloud/branch-02.png diff --git a/server/sonar-web/public/images/sonarcloud/branch-02@2x.png b/server/sonar-web/public/images/sonarcloud/branch-02@2x.png Binary files differnew file mode 100644 index 00000000000..556232b3e36 --- /dev/null +++ b/server/sonar-web/public/images/sonarcloud/branch-02@2x.png diff --git a/server/sonar-web/public/images/sonarcloud/branch-03.png b/server/sonar-web/public/images/sonarcloud/branch-03.png Binary files differnew file mode 100644 index 00000000000..effbe5613e9 --- /dev/null +++ b/server/sonar-web/public/images/sonarcloud/branch-03.png diff --git a/server/sonar-web/public/images/sonarcloud/branch-03@2x.png b/server/sonar-web/public/images/sonarcloud/branch-03@2x.png Binary files differnew file mode 100644 index 00000000000..ed85c2bde14 --- /dev/null +++ b/server/sonar-web/public/images/sonarcloud/branch-03@2x.png diff --git a/server/sonar-web/public/images/sonarcloud/gears.png b/server/sonar-web/public/images/sonarcloud/gears.png Binary files differnew file mode 100644 index 00000000000..231685ec991 --- /dev/null +++ b/server/sonar-web/public/images/sonarcloud/gears.png diff --git a/server/sonar-web/public/images/sonarcloud/gears@2x.png b/server/sonar-web/public/images/sonarcloud/gears@2x.png Binary files differnew file mode 100644 index 00000000000..95f79dd1359 --- /dev/null +++ b/server/sonar-web/public/images/sonarcloud/gears@2x.png diff --git a/server/sonar-web/public/images/sonarcloud/sl-notif.png b/server/sonar-web/public/images/sonarcloud/sl-notif.png Binary files differnew file mode 100644 index 00000000000..fdb0daf15e4 --- /dev/null +++ b/server/sonar-web/public/images/sonarcloud/sl-notif.png diff --git a/server/sonar-web/public/images/sonarcloud/sl-notif@2x.png b/server/sonar-web/public/images/sonarcloud/sl-notif@2x.png Binary files differnew file mode 100644 index 00000000000..ae07309c008 --- /dev/null +++ b/server/sonar-web/public/images/sonarcloud/sl-notif@2x.png diff --git a/server/sonar-web/public/images/sonarcloud/windows.svg b/server/sonar-web/public/images/sonarcloud/windows.svg new file mode 100644 index 00000000000..b0155ea5706 --- /dev/null +++ b/server/sonar-web/public/images/sonarcloud/windows.svg @@ -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 Binary files differnew file mode 100644 index 00000000000..75fd88a5d5e --- /dev/null +++ b/server/sonar-web/public/sonarcloud-terms.pdf diff --git a/server/sonar-web/src/main/js/app/components/GlobalFooterSonarCloud.tsx b/server/sonar-web/src/main/js/app/components/GlobalFooterSonarCloud.tsx index 44dd558676a..d1ffc010768 100644 --- a/server/sonar-web/src/main/js/app/components/GlobalFooterSonarCloud.tsx +++ b/server/sonar-web/src/main/js/app/components/GlobalFooterSonarCloud.tsx @@ -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> diff --git a/server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/GlobalFooterSonarCloud-test.tsx.snap b/server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/GlobalFooterSonarCloud-test.tsx.snap index 4593fe94ca2..89bb14e6625 100644 --- a/server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/GlobalFooterSonarCloud-test.tsx.snap +++ b/server/sonar-web/src/main/js/app/components/__tests__/__snapshots__/GlobalFooterSonarCloud-test.tsx.snap @@ -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> diff --git a/server/sonar-web/src/main/js/apps/about/routes.ts b/server/sonar-web/src/main/js/apps/about/routes.ts index 7758ecaa78e..a042681c66c 100644 --- a/server/sonar-web/src/main/js/apps/about/routes.ts +++ b/server/sonar-web/src/main/js/apps/about/routes.ts @@ -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 index 00000000000..8c4938558db --- /dev/null +++ b/server/sonar-web/src/main/js/apps/about/sonarcloud/AsAService.tsx @@ -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 index 00000000000..49b8f302b1c --- /dev/null +++ b/server/sonar-web/src/main/js/apps/about/sonarcloud/BranchAnalysis.tsx @@ -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> + ); +} diff --git a/server/sonar-web/src/main/js/apps/about/sonarcloud/Footer.tsx b/server/sonar-web/src/main/js/apps/about/sonarcloud/Footer.tsx index 48cd48d5cc8..f7634e2479f 100644 --- a/server/sonar-web/src/main/js/apps/about/sonarcloud/Footer.tsx +++ b/server/sonar-web/src/main/js/apps/about/sonarcloud/Footer.tsx @@ -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> diff --git a/server/sonar-web/src/main/js/apps/about/sonarcloud/Home.tsx b/server/sonar-web/src/main/js/apps/about/sonarcloud/Home.tsx index e5d99cc504f..629a1730dba 100644 --- a/server/sonar-web/src/main/js/apps/about/sonarcloud/Home.tsx +++ b/server/sonar-web/src/main/js/apps/about/sonarcloud/Home.tsx @@ -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> @@ -123,20 +107,6 @@ export default class Home extends React.PureComponent<Props> { <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" rel="noopener noreferrer" target="_blank"> @@ -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/SQHome.tsx b/server/sonar-web/src/main/js/apps/about/sonarcloud/SQHome.tsx index 80fce789569..f495891978d 100644 --- a/server/sonar-web/src/main/js/apps/about/sonarcloud/SQHome.tsx +++ b/server/sonar-web/src/main/js/apps/about/sonarcloud/SQHome.tsx @@ -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> 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 index 33be1be21d8..00000000000 --- a/server/sonar-web/src/main/js/apps/about/sonarcloud/SQHomeContainer.tsx +++ /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/HomeContainer.tsx b/server/sonar-web/src/main/js/apps/about/sonarcloud/SQStartUsing.tsx index 3fc215348bb..f7d6693df92 100644 --- a/server/sonar-web/src/main/js/apps/about/sonarcloud/HomeContainer.tsx +++ b/server/sonar-web/src/main/js/apps/about/sonarcloud/SQStartUsing.tsx @@ -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> + ); +} 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 index 00000000000..0a6055820b5 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/about/sonarcloud/SQTopNav.tsx @@ -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 index 00000000000..84b4a99ade7 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/about/sonarcloud/SonarCloudPage.tsx @@ -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 index 00000000000..17fe58eee42 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/about/sonarcloud/SonarLintIntegration.tsx @@ -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> + ); +} diff --git a/server/sonar-web/src/main/js/apps/about/sonarcloud/StartUsing.tsx b/server/sonar-web/src/main/js/apps/about/sonarcloud/StartUsing.tsx index cade5100554..c640474aa76 100644 --- a/server/sonar-web/src/main/js/apps/about/sonarcloud/StartUsing.tsx +++ b/server/sonar-web/src/main/js/apps/about/sonarcloud/StartUsing.tsx @@ -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 index 00000000000..f641ea825bf --- /dev/null +++ b/server/sonar-web/src/main/js/apps/about/sonarcloud/VSTS.tsx @@ -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> + ); +} diff --git a/server/sonar-web/src/main/js/apps/about/sonarcloud/__tests__/Home-test.tsx b/server/sonar-web/src/main/js/apps/about/sonarcloud/__tests__/Home-test.tsx index 9c5caa9619c..a4368fec7a7 100644 --- a/server/sonar-web/src/main/js/apps/about/sonarcloud/__tests__/Home-test.tsx +++ b/server/sonar-web/src/main/js/apps/about/sonarcloud/__tests__/Home-test.tsx @@ -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(); }); diff --git a/server/sonar-web/src/main/js/apps/about/sonarcloud/style.css b/server/sonar-web/src/main/js/apps/about/sonarcloud/style.css index 1c3d8ada395..f05b2e23fcb 100644 --- a/server/sonar-web/src/main/js/apps/about/sonarcloud/style.css +++ b/server/sonar-web/src/main/js/apps/about/sonarcloud/style.css @@ -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; +} |