@@ -18,50 +18,7 @@ | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import { lazyLoad } from 'sonar-ui-common/components/lazyLoad'; | |||
import { isSonarCloud } from '../../helpers/system'; | |||
const routes = [ | |||
{ | |||
indexRoute: { | |||
component: lazyLoad(() => | |||
isSonarCloud() ? import('./sonarcloud/Home') : import('./components/AboutApp') | |||
) | |||
}, | |||
childRoutes: isSonarCloud() | |||
? [ | |||
{ | |||
path: 'contact', | |||
component: lazyLoad(() => import('./sonarcloud/Contact')) | |||
}, | |||
{ | |||
path: 'pricing', | |||
component: lazyLoad(() => import('./sonarcloud/Pricing')) | |||
}, | |||
{ | |||
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/AzureDevOps')) | |||
} | |||
] | |||
} | |||
] | |||
: [] | |||
} | |||
]; | |||
const routes = [{ indexRoute: { component: lazyLoad(() => import('./components/AboutApp')) } }]; | |||
export default routes; |
@@ -1,97 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2020 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 { Helmet } from 'react-helmet-async'; | |||
import { getBaseUrl } from 'sonar-ui-common/helpers/urls'; | |||
import { isLoggedIn } from '../../../helpers/users'; | |||
import SQPageContainer from './components/SQPageContainer'; | |||
import SQStartUsing from './components/SQStartUsing'; | |||
import SQTopNav from './components/SQTopNav'; | |||
import './style.css'; | |||
export default function AsAService() { | |||
return ( | |||
<SQPageContainer> | |||
{({ currentUser }) => ( | |||
<div className="page page-limited sc-page"> | |||
<Helmet title="Get started with SonarQube as a Service | SonarCloud"> | |||
<meta | |||
content="Analyze your code with just a few clicks. Immediate access to the latest features and functionality. You use the service and we take care of the rest." | |||
name="description" | |||
/> | |||
</Helmet> | |||
<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 organization 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> | |||
)} | |||
</SQPageContainer> | |||
); | |||
} |
@@ -1,143 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2020 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 { Helmet } from 'react-helmet-async'; | |||
import { Link } from 'react-router'; | |||
import { getBaseUrl } from 'sonar-ui-common/helpers/urls'; | |||
import { isLoggedIn } from '../../../helpers/users'; | |||
import SQPageContainer from './components/SQPageContainer'; | |||
import './style.css'; | |||
const LANGUAGES = [ | |||
{ name: 'JavaScript', file: 'js.svg', width: 60 }, | |||
{ name: 'TypeScript', file: 'ts.svg', width: 130 }, | |||
{ name: 'C#', file: 'csharp.svg', width: 60 }, | |||
{ name: 'C++', file: 'c-c-plus-plus.svg', width: 53 }, | |||
{ name: 'T-SQL', file: 't-sql.svg', width: 80 }, | |||
{ name: 'VB', file: 'vb.svg', width: 70 } | |||
]; | |||
export default function AzureDevOps() { | |||
return ( | |||
<SQPageContainer> | |||
{({ currentUser }) => ( | |||
<div className="page page-limited sc-page"> | |||
<Helmet title="Continuous Code Quality in Azure Devops | SonarCloud"> | |||
<meta | |||
content="Enhance Azure DevOps with continuous code quality and automatically analyze branches and decorate pull requests." | |||
name="description" | |||
/> | |||
</Helmet> | |||
<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 Azure DevOps</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 Azure DevOps account and the SonarCloud Azure DevOps 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 Azure | |||
DevOps 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="Azure DevOps Extension" | |||
height="38" | |||
src={`${getBaseUrl()}/images/sonarcloud/windows.svg`} | |||
/> | |||
<h3 className="sc-vsts-start-title">Install Azure DevOps 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"> | |||
{LANGUAGES.map(language => ( | |||
<li key={language.name}> | |||
<img | |||
alt={language.name} | |||
src={`${getBaseUrl()}/images/languages/${language.file}`} | |||
style={{ width: `${language.width}px` }} | |||
/> | |||
</li> | |||
))} | |||
</ul> | |||
</div> | |||
</div> | |||
)} | |||
</SQPageContainer> | |||
); | |||
} |
@@ -1,127 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2020 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 { Helmet } from 'react-helmet-async'; | |||
import { getBaseUrl } from 'sonar-ui-common/helpers/urls'; | |||
import { isLoggedIn } from '../../../helpers/users'; | |||
import SQPageContainer from './components/SQPageContainer'; | |||
import SQStartUsing from './components/SQStartUsing'; | |||
import SQTopNav from './components/SQTopNav'; | |||
import './style.css'; | |||
export default function BranchAnalysis() { | |||
return ( | |||
<SQPageContainer> | |||
{({ currentUser }) => ( | |||
<div className="page page-limited sc-page"> | |||
<Helmet title="Pull requests analysis in Github, BitBucket and Azure DevOps | SonarCloud"> | |||
<meta | |||
content="SonarCloud automatically analyzes branches and decorates pull requests with Github, BitBucket and Azure DevOps." | |||
name="description" | |||
/> | |||
</Helmet> | |||
<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 flex-0" | |||
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 className="flex-1"> | |||
<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 className="flex-1"> | |||
<h3 className="sc-feature-title">Decorate PRs on Azure DevOps and GitHub</h3> | |||
<p className="sc-feature-description"> | |||
Pull requests get decorated directly on Azure DevOps 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 flex-0" | |||
height="432" | |||
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 flex-0" | |||
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 className="flex-1"> | |||
<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> | |||
)} | |||
</SQPageContainer> | |||
); | |||
} |
@@ -1,217 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2020 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 { Location } from 'history'; | |||
import * as React from 'react'; | |||
import { Helmet } from 'react-helmet-async'; | |||
import { Link } from 'react-router'; | |||
import Select from 'sonar-ui-common/components/controls/Select'; | |||
import { Alert } from 'sonar-ui-common/components/ui/Alert'; | |||
import { isLoggedIn } from '../../../helpers/users'; | |||
import SQPageContainer from './components/SQPageContainer'; | |||
import './style.css'; | |||
const CATEGORIES = [ | |||
{ label: 'Commercial', value: 'commercial' }, | |||
{ label: 'Confidential Request', value: 'confidential_request' } | |||
]; | |||
interface Props { | |||
location: Location; | |||
} | |||
interface State { | |||
category: string; | |||
organization: string; | |||
question: string; | |||
subject: string; | |||
} | |||
export default class Contact extends React.PureComponent<Props, State> { | |||
constructor(props: Props) { | |||
super(props); | |||
const { query } = props.location; | |||
this.state = { | |||
category: query.category || '', | |||
organization: query.organization || '', | |||
question: query.question || '', | |||
subject: query.subject || '' | |||
}; | |||
} | |||
getOrganizations = (organizations?: T.Organization[]) => { | |||
return (organizations || []).map(org => ({ | |||
label: org.name, | |||
value: org.key | |||
})); | |||
}; | |||
handleCategoryChange = ({ value }: { value: string }) => { | |||
this.setState({ category: value }); | |||
}; | |||
handleOrganizationChange = ({ value }: { value: string }) => { | |||
this.setState({ organization: value }); | |||
}; | |||
handleSubjectChange = (event: React.ChangeEvent<HTMLInputElement>) => { | |||
this.setState({ subject: event.currentTarget.value }); | |||
}; | |||
handleQuestionChange = (event: React.ChangeEvent<HTMLTextAreaElement>) => { | |||
this.setState({ question: event.currentTarget.value }); | |||
}; | |||
render() { | |||
return ( | |||
<SQPageContainer> | |||
{({ currentUser, userOrganizations }) => ( | |||
<div className="page page-limited sc-page sc-contact-page"> | |||
<Helmet title="Contact Us | SonarCloud"> | |||
<meta | |||
content="If you are looking for help with SonarCloud, our Support forum is the best place to get help." | |||
name="description" | |||
/> | |||
</Helmet> | |||
<h1 className="sc-page-title">Contact us</h1> | |||
<Alert display="inline" variant="warning"> | |||
If you are looking for help with SonarCloud, our{' '} | |||
<a | |||
href="https://community.sonarsource.com/c/help/sc" | |||
rel="noopener noreferrer" | |||
target="_blank"> | |||
<strong>Support forum</strong> | |||
</a>{' '} | |||
is the best place to get help. | |||
</Alert> | |||
<br /> | |||
<Alert display="inline" variant="warning"> | |||
Use this contact form for commercial or confidential requests only. | |||
</Alert> | |||
{!isLoggedIn(currentUser) && ( | |||
<p> | |||
You can{' '} | |||
<Link to={{ pathname: '/sessions/new', query: { return_to: '/about/contact' } }}> | |||
log in to SonarCloud | |||
</Link>{' '} | |||
to automatically fill this form information and get better support. | |||
</p> | |||
)} | |||
<form action="https://formspree.io/contact@sonarcloud.io" method="POST"> | |||
<div className="form-group"> | |||
<label htmlFor="contact-name">Name</label> | |||
<input | |||
autoFocus={true} | |||
defaultValue={isLoggedIn(currentUser) ? currentUser.name : ''} | |||
id="contact-name" | |||
name="name" | |||
required={true} | |||
type="text" | |||
/> | |||
</div> | |||
<div className="form-group"> | |||
<label htmlFor="contact-email">Email</label> | |||
<input | |||
defaultValue={isLoggedIn(currentUser) ? currentUser.email : ''} | |||
id="contact-email" | |||
name="_replyto" | |||
required={true} | |||
type="email" | |||
/> | |||
</div> | |||
<div className="form-group category-select"> | |||
<label htmlFor="contact-category">Category</label> | |||
<Select | |||
id="contact-category" | |||
name="category" | |||
onChange={this.handleCategoryChange} | |||
options={CATEGORIES} | |||
placeholder="Choose a category" | |||
required={true} | |||
searchable={false} | |||
value={this.state.category} | |||
/> | |||
<input | |||
className="category-select-helper" | |||
required={true} | |||
tabIndex={-1} | |||
value={this.state.category} | |||
/> | |||
</div> | |||
{isLoggedIn(currentUser) && ( | |||
<div className="form-group category-select"> | |||
<label htmlFor="contact-organization">Organization concerned by the issue</label> | |||
<Select | |||
id="contact-organization" | |||
name="organization" | |||
onChange={this.handleOrganizationChange} | |||
options={this.getOrganizations(userOrganizations)} | |||
placeholder="Choose an organization" | |||
searchable={false} | |||
value={this.state.organization} | |||
/> | |||
</div> | |||
)} | |||
<div className="form-group"> | |||
<label htmlFor="contact-subject">Subject</label> | |||
<input | |||
id="contact-subject" | |||
maxLength={70} | |||
onChange={this.handleSubjectChange} | |||
required={true} | |||
type="text" | |||
value={this.state.subject} | |||
/> | |||
<input | |||
name="_subject" | |||
type="hidden" | |||
value={`[${this.state.category}] ${this.state.subject}`} | |||
/> | |||
</div> | |||
<div className="form-group"> | |||
<label htmlFor="contact-question">How can we help?</label> | |||
<textarea | |||
className="form-control" | |||
id="contact-question" | |||
name="question" | |||
onChange={this.handleQuestionChange} | |||
placeholder="Please describe precisely what is your issue..." | |||
required={true} | |||
rows={8} | |||
value={this.state.question} | |||
/> | |||
</div> | |||
<div className="form-group"> | |||
{ | |||
// The following hidden input field must absolutely be kept | |||
// This is a "honeypot" field to avoid spam by fooling scrapers | |||
} | |||
<input name="_gotcha" type="text" /> | |||
<button type="submit">Send Request</button> | |||
</div> | |||
{isLoggedIn(currentUser) && ( | |||
<input name="login" type="hidden" value={currentUser.login} /> | |||
)} | |||
</form> | |||
</div> | |||
)} | |||
</SQPageContainer> | |||
); | |||
} | |||
} |
@@ -1,377 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2020 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 { Helmet } from 'react-helmet-async'; | |||
import { connect } from 'react-redux'; | |||
import { addWhitePageClass, removeWhitePageClass } from 'sonar-ui-common/helpers/pages'; | |||
import { getBaseUrl } from 'sonar-ui-common/helpers/urls'; | |||
import { getGlobalSettingValue, Store } from '../../../store/rootReducer'; | |||
import FeaturedProjects from './components/FeaturedProjects'; | |||
import Footer from './components/Footer'; | |||
import { Languages } from './components/Languages'; | |||
import LoginButtons from './components/LoginButtons'; | |||
import { FixedNavBar, TopNavBar } from './components/NavBars'; | |||
import Statistics from './components/Statistics'; | |||
import './new_style.css'; | |||
import { FeaturedProject, HomepageData, requestHomepageData } from './utils'; | |||
interface Props { | |||
homePageDataUrl?: string; | |||
} | |||
interface State { | |||
data?: HomepageData; | |||
} | |||
export class Home extends React.PureComponent<Props, State> { | |||
mounted = false; | |||
state: State = {}; | |||
componentDidMount() { | |||
this.mounted = true; | |||
addWhitePageClass(); | |||
this.fetchData(); | |||
} | |||
componentWillUnmount() { | |||
removeWhitePageClass(); | |||
this.mounted = false; | |||
} | |||
fetchData = () => { | |||
const { homePageDataUrl } = this.props; | |||
if (homePageDataUrl) { | |||
requestHomepageData(homePageDataUrl).then( | |||
data => { | |||
if (this.mounted) { | |||
this.setState({ data }); | |||
} | |||
}, | |||
() => { | |||
/* Fail silently */ | |||
} | |||
); | |||
} | |||
}; | |||
render() { | |||
const { data } = this.state; | |||
return ( | |||
<div className="global-container"> | |||
<div className="page-wrapper"> | |||
<div className="page-container sc-page"> | |||
<Helmet title="SonarCloud | Clean Code, Rockstar Status"> | |||
<meta | |||
content="Enhance your workflow with continuous code quality, SonarCloud automatically analyzes and decorates pull requests on GitHub, Bitbucket and Azure DevOps on major languages." | |||
name="description" | |||
/> | |||
</Helmet> | |||
<FixedNavBar /> | |||
<PageBackgroundHeader /> | |||
<TopNavBar /> | |||
<PageTitle /> | |||
<EnhanceWorkflow /> | |||
<Functionality /> | |||
<Languages /> | |||
<Stats data={data} /> | |||
<Projects featuredProjects={(data && data.featuredProjects) || []} /> | |||
</div> | |||
</div> | |||
<Footer /> | |||
</div> | |||
); | |||
} | |||
} | |||
const mapStateToProps = (state: Store) => { | |||
const homePageDataUrl = getGlobalSettingValue(state, 'sonar.homepage.url'); | |||
return { | |||
homePageDataUrl: homePageDataUrl && homePageDataUrl.value | |||
}; | |||
}; | |||
export default connect(mapStateToProps)(Home); | |||
function PageBackgroundHeader() { | |||
return ( | |||
<div className="sc-header-background"> | |||
<div className="sc-background-start" /> | |||
<div className="sc-background-end" /> | |||
<div className="sc-background-center"> | |||
<img alt="" height="418px" src={`${getBaseUrl()}/images/sonarcloud/home-header.svg`} /> | |||
</div> | |||
</div> | |||
); | |||
} | |||
function PageTitle() { | |||
return ( | |||
<div className="sc-section sc-columns big-spacer-top"> | |||
<div className="sc-column sc-column-half display-flex-center"> | |||
<div> | |||
<h1 className="sc-title-orange big-spacer-top">Clean Code</h1> | |||
<h1 className="sc-spacer-bottom">Rockstar Status</h1> | |||
<h5 className="sc-big-spacer-bottom sc-regular-weight"> | |||
Eliminate bugs and vulnerabilities. | |||
<br /> | |||
Champion quality code in your projects. | |||
</h5> | |||
<div> | |||
<h6>Go ahead! Analyze your repo:</h6> | |||
<LoginButtons /> | |||
<p className="sc-mention sc-regular-weight big-spacer-top"> | |||
Free for Open-Source Projects | |||
</p> | |||
</div> | |||
</div> | |||
</div> | |||
<div className="sc-column sc-column-half text-right"> | |||
<img | |||
alt="" | |||
src={`${getBaseUrl()}/images/sonarcloud/home-header-people.png`} | |||
width="430px" | |||
/> | |||
</div> | |||
</div> | |||
); | |||
} | |||
function EnhanceWorkflow() { | |||
return ( | |||
<div className="sc-section sc-columns"> | |||
<div className="sc-column sc-column-full"> | |||
<h3 className="sc-big-spacer-bottom"> | |||
Enhance Your Workflow | |||
<br /> | |||
with Continuous Code Quality | |||
</h3> | |||
<img | |||
alt="" | |||
className="sc-big-spacer-bottom" | |||
src={`${getBaseUrl()}/images/sonarcloud/home-branch.png`} | |||
srcSet={`${getBaseUrl()}/images/sonarcloud/home-branch.png 1x, ${getBaseUrl()}/images/sonarcloud/home-branch@2x.png 2x`} | |||
/> | |||
<h5 className="spacer-bottom">Maximize your throughput and only release clean code</h5> | |||
<h6 className="sc-big-spacer-bottom sc-regular-weight"> | |||
SonarCloud automatically analyzes branches and decorates pull requests | |||
</h6> | |||
</div> | |||
</div> | |||
); | |||
} | |||
function Functionality() { | |||
return ( | |||
<div className="position-relative"> | |||
<div className="sc-functionality-background"> | |||
<div className="sc-background-center"> | |||
<img | |||
alt="" | |||
height="300px" | |||
src={`${getBaseUrl()}/images/sonarcloud/home-grey-background.svg`} | |||
/> | |||
</div> | |||
</div> | |||
<div className="sc-functionality-container"> | |||
<div className="sc-section"> | |||
<h3 className="sc-big-spacer-bottom text-center"> | |||
Functionality | |||
<br /> | |||
that Fits Your Projects | |||
</h3> | |||
<div className="sc-columns"> | |||
<div className="sc-column sc-column-small big-spacer-top"> | |||
<h6 className="sc-regular-weight spacer-bottom">Easy to Use</h6> | |||
<p> | |||
With just a few clicks you’re up and running right where your code lives. Immediate | |||
access to the latest features and enhancements. | |||
</p> | |||
<div className="sc-separator" /> | |||
<span className="big-spacer-bottom sc-with-icon"> | |||
<img | |||
alt="" | |||
className="big-spacer-right" | |||
src={`${getBaseUrl()}/images/sonarcloud/scale.svg`} | |||
/>{' '} | |||
Scale on-demand as your projects grow. | |||
</span> | |||
<span className="sc-with-icon"> | |||
<img | |||
alt="" | |||
className="big-spacer-right" | |||
src={`${getBaseUrl()}/images/sonarcloud/stop.svg`} | |||
/>{' '} | |||
No contracts, stop/start anytime. | |||
</span> | |||
</div> | |||
<div className="sc-column sc-column-big big-spacer-top"> | |||
<img | |||
alt="" | |||
className="sc-rounded-img" | |||
src={`${getBaseUrl()}/images/sonarcloud/home-easy-to-use.png`} | |||
srcSet={`${getBaseUrl()}/images/sonarcloud/home-easy-to-use.png 1x, ${getBaseUrl()}/images/sonarcloud/home-easy-to-use@2x.png 2x`} | |||
/> | |||
</div> | |||
</div> | |||
<div className="sc-columns"> | |||
<div className="sc-column sc-column-big"> | |||
<img | |||
alt="" | |||
className="sc-rounded-img" | |||
src={`${getBaseUrl()}/images/sonarcloud/home-open-transparent.png`} | |||
srcSet={`${getBaseUrl()}/images/sonarcloud/home-open-transparent.png 1x, ${getBaseUrl()}/images/sonarcloud/home-open-transparent@2x.png 2x`} | |||
/> | |||
</div> | |||
<div className="sc-column sc-column-small"> | |||
<div> | |||
<h6 className="sc-regular-weight spacer-bottom">Open and Transparent</h6> | |||
<p className="big-spacer-bottom"> | |||
Project dashboards keep teams and stakeholders informed on code quality and | |||
releasability. | |||
</p> | |||
<p>Display project badges and show your communities you’re all about awesome.</p> | |||
<img | |||
alt="" | |||
className="big-spacer-top" | |||
src={`${getBaseUrl()}/images/project_badges/sonarcloud-black.svg`} | |||
width="200px" | |||
/> | |||
</div> | |||
</div> | |||
</div> | |||
<div className="sc-columns"> | |||
<div className="sc-column sc-column-full big-spacer-bottom"> | |||
<div> | |||
<h6 className="sc-regular-weight spacer-bottom">Effective Collaboration</h6> | |||
<p className="sc-with-inline-icon"> | |||
Use | |||
<img | |||
alt="SonarCloud" | |||
src={`${getBaseUrl()}/images/sonarcloud/sonarcloud-logo-text-only.svg`} | |||
/> | |||
with your team, share best practices and have fun writing quality code! | |||
</p> | |||
<br /> | |||
<p className="sc-with-inline-icon"> | |||
Connect with | |||
<img | |||
alt="SonarCloud" | |||
src={`${getBaseUrl()}/images/sonarcloud/sonarlint-logo.svg`} | |||
/> | |||
and get real-time notifications in your IDE as you work. | |||
</p> | |||
<div className="big-spacer-top"> | |||
<img | |||
alt="" | |||
className="big-spacer-top huge-spacer-bottom" | |||
src={`${getBaseUrl()}/images/sonarcloud/ide.svg`} | |||
width="216px" | |||
/> | |||
</div> | |||
<img alt="" src={`${getBaseUrl()}/images/sonarcloud/collab.svg`} width="540px" /> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
<div className="sc-functionality-background sc-functionality-background-bottom"> | |||
<div className="sc-background-center"> | |||
<img | |||
alt="" | |||
height="140px" | |||
src={`${getBaseUrl()}/images/sonarcloud/home-background-grey-bottom.svg`} | |||
/> | |||
</div> | |||
</div> | |||
</div> | |||
); | |||
} | |||
interface StatsProps { | |||
data?: HomepageData; | |||
} | |||
function Stats({ data }: StatsProps) { | |||
return ( | |||
<div className="sc-section sc-columns"> | |||
<div className="sc-column sc-column-full"> | |||
<h3> | |||
Over 3,000 Projects | |||
<br /> | |||
Continuously Analyzed | |||
</h3> | |||
{data && ( | |||
<Statistics | |||
statistics={[ | |||
{ icon: 'rules', text: 'Static analysis rules checked', value: data.rules }, | |||
{ icon: 'locs', text: 'Lines of code analyzed', value: data.publicLoc }, | |||
{ | |||
icon: 'pull-request', | |||
text: 'Pull Requests decorated/week', | |||
value: data.newPullRequests7d | |||
}, | |||
{ | |||
icon: 'open-source', | |||
text: 'Open-source projects inspected', | |||
value: data.publicProjects | |||
} | |||
]} | |||
/> | |||
)} | |||
</div> | |||
</div> | |||
); | |||
} | |||
interface ProjectsProps { | |||
featuredProjects: FeaturedProject[]; | |||
} | |||
function Projects({ featuredProjects }: ProjectsProps) { | |||
return ( | |||
<div className="sc-section sc-columns"> | |||
<div className="sc-column sc-column-full"> | |||
{featuredProjects.length > 0 && ( | |||
<> | |||
<h6 className="big-spacer-bottom"> | |||
Transparency makes sense | |||
<br /> | |||
and that’s why the trend is growing. | |||
</h6> | |||
<p> | |||
Check out these open-source projects showing users | |||
<br /> | |||
their commitment to quality. | |||
</p> | |||
<FeaturedProjects projects={featuredProjects} /> | |||
</> | |||
)} | |||
<h6 className="spacer-bottom"> | |||
Come join the fun, it’s entirely free for open-source projects! | |||
</h6> | |||
<div className="sc-spacer-bottom"> | |||
<LoginButtons /> | |||
</div> | |||
</div> | |||
</div> | |||
); | |||
} |
@@ -1,273 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2020 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 { Helmet } from 'react-helmet-async'; | |||
import { addWhitePageClass, removeWhitePageClass } from 'sonar-ui-common/helpers/pages'; | |||
import { scrollToElement } from 'sonar-ui-common/helpers/scrolling'; | |||
import { getBaseUrl } from 'sonar-ui-common/helpers/urls'; | |||
import Footer from './components/Footer'; | |||
import { FixedNavBar, TopNavBar } from './components/NavBars'; | |||
import './new_style.css'; | |||
export default class Pricing extends React.PureComponent { | |||
container?: HTMLElement | null; | |||
componentDidMount() { | |||
addWhitePageClass(); | |||
} | |||
componentWillUnmount() { | |||
removeWhitePageClass(); | |||
} | |||
handleClick = (event: React.MouseEvent<HTMLAnchorElement>) => { | |||
event.preventDefault(); | |||
event.stopPropagation(); | |||
if (this.container) { | |||
scrollToElement(this.container, { bottomOffset: window.innerHeight - 200 }); | |||
} | |||
}; | |||
getReference = (node: HTMLElement | null) => { | |||
this.container = node; | |||
}; | |||
render() { | |||
return ( | |||
<div className="global-container"> | |||
<div className="page-wrapper"> | |||
<div className="page-container sc-page"> | |||
<Helmet title="Plans and Pricing | SonarCloud"> | |||
<meta | |||
content="Get all the SonarCloud features and functionality for free on your open-source projects. If you need privacy for your code, we have a pricing plan to fit your needs." | |||
name="description" | |||
/> | |||
</Helmet> | |||
<FixedNavBar onPricingPage={true} /> | |||
<PageBackgroundHeader /> | |||
<TopNavBar onPricingPage={true} whiteLogo={true} /> | |||
<ForEveryoneBlock onClick={this.handleClick} /> | |||
<LoginCTA /> | |||
<PricingFAQ getReference={this.getReference} /> | |||
</div> | |||
</div> | |||
<Footer /> | |||
</div> | |||
); | |||
} | |||
} | |||
function PageBackgroundHeader() { | |||
return ( | |||
<div className="sc-header-background"> | |||
<div className="sc-background-center"> | |||
<img alt="" height="562px" src={`${getBaseUrl()}/images/sonarcloud/pricing-header.svg`} /> | |||
</div> | |||
</div> | |||
); | |||
} | |||
interface ForEveryoneBlockProps { | |||
onClick: (event: React.MouseEvent<HTMLAnchorElement>) => void; | |||
} | |||
function ForEveryoneBlock({ onClick }: ForEveryoneBlockProps) { | |||
return ( | |||
<div className="sc-section big-spacer-top"> | |||
<h2 className="white text-center sc-big-spacer-top sc-big-spacer-bottom"> | |||
SonarCloud is for everyone | |||
</h2> | |||
<div className="sc-pricing-free"> | |||
<h4> | |||
Free for <span className="sc-title-orange">public projects</span> | |||
</h4> | |||
<ul className="big-spacer-top big-spacer-bottom"> | |||
<li> | |||
<em>Unlimited lines of code</em> | |||
</li> | |||
<li> | |||
<em>Anyone can see your project</em> and browse your code | |||
</li> | |||
<li> | |||
You have access to the <em>full SonarCloud feature set</em> | |||
</li> | |||
<li> | |||
<em>Choose members of your team</em> who can work on your projects | |||
</li> | |||
</ul> | |||
<em>Loved by Open-Source Developers</em> | |||
<div className="sc-pricing-privacy"> | |||
<h4 className="white"> | |||
Need <span className="sc-title-orange">privacy?</span> | |||
</h4> | |||
<ul className="big-spacer-top big-spacer-bottom"> | |||
<li> | |||
<em>Create private projects,</em> priced per lines of code.{' '} | |||
<a href="#" onClick={onClick}> | |||
See price list | |||
</a> | |||
</li> | |||
<li> | |||
<em>You have strict control</em> over who can view your private data | |||
</li> | |||
</ul> | |||
<div className="big-spacer-left"> | |||
<div className="starts-at">starts at 10€/month</div> | |||
<em>Free 14-day trial</em> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
); | |||
} | |||
function LoginCTA() { | |||
return ( | |||
<div className="sc-section text-center pricing-section sc-big-spacer-bottom"> | |||
<h5 className="sc-big-spacer-top big-spacer-bottom"> | |||
Log in to SonarCloud and choose your pricing plan | |||
</h5> | |||
<a className="sc-orange-button" href={`${getBaseUrl()}/sessions/new`}> | |||
Start Using SonarCloud | |||
</a> | |||
</div> | |||
); | |||
} | |||
interface PricingFAQProps { | |||
getReference: (node: HTMLDivElement | null) => void; | |||
} | |||
function PricingFAQ({ getReference }: PricingFAQProps) { | |||
return ( | |||
<div className="sc-section pricing-section big-spacer-top sc-big-spacer-bottom"> | |||
<h5 className="text-center sc-big-spacer-top sc-big-spacer-bottom">Pricing FAQ</h5> | |||
<div className="sc-columns"> | |||
<div className="sc-column sc-column-medium display-flex-center"> | |||
<div> | |||
<div className="faq-title" ref={getReference}> | |||
How does pricing work for private projects? | |||
</div> | |||
<p className="big-spacer-bottom"> | |||
Subscribing to a paid plan on SonarCloud allows you to create a private organization | |||
containing private projects. You pay up front for a maximum number of private lines of | |||
code to be analyzed in your organization. | |||
<br /> | |||
<br /> | |||
Find your max LOC below to see what it will cost you per month: | |||
</p> | |||
<table className="loc-price sc-big-spacer-bottom"> | |||
<thead> | |||
<tr> | |||
<th>Up to lines of code</th> | |||
<th>Price per month in €</th> | |||
</tr> | |||
</thead> | |||
<tbody> | |||
<tr> | |||
<td>100k</td> | |||
<td>10</td> | |||
</tr> | |||
<tr> | |||
<td>250k</td> | |||
<td>75</td> | |||
</tr> | |||
<tr> | |||
<td>500k</td> | |||
<td>150</td> | |||
</tr> | |||
<tr> | |||
<td>1M</td> | |||
<td>250</td> | |||
</tr> | |||
<tr> | |||
<td>2M</td> | |||
<td>500</td> | |||
</tr> | |||
<tr> | |||
<td>5M</td> | |||
<td>1500</td> | |||
</tr> | |||
<tr> | |||
<td>10M</td> | |||
<td>3000</td> | |||
</tr> | |||
<tr> | |||
<td>20M</td> | |||
<td>4000</td> | |||
</tr> | |||
</tbody> | |||
</table> | |||
<div className="faq-title">What payment options are available ?</div> | |||
<p> | |||
Payment is done online by credit card and will happen automatically every month, based | |||
on the plan you choose. We also accept to receive a purchase order and a wire transfer | |||
payment, if ordering a yearly subscription for more than 1M LOCs. In this case, you | |||
need to contact us through the Contact form. | |||
</p> | |||
<div className="faq-title">Can I try a private project on SonarCloud for free?</div> | |||
<p> | |||
Your first 14 days are on us. You just have to upgrade your organization to a paid | |||
plan, and fill your credit card information to get started. After your trial, if you | |||
love it you can continue using SonarCloud and you will be charged for the plan you | |||
selected when you first started your free trial. You can cancel anytime. | |||
</p> | |||
</div> | |||
</div> | |||
<div className="sc-column sc-column-medium display-flex-center"> | |||
<div> | |||
<div className="faq-title">What is a Line of Code (LOC) on SonarCloud?</div> | |||
<p> | |||
LOCs are computed by summing up the LOCs of each project analyzed in SonarCloud. The | |||
LOCs used for a project are the LOCs found during the most recent analysis of this | |||
project. | |||
</p> | |||
<div className="faq-title">How are Lines of Code (LOCs) counted towards billing?</div> | |||
<p> | |||
Only LOC from your private projects are counted toward your maximum number of LOCs. If | |||
your project contains branches, the counted LOCs are the ones of the biggest branch. | |||
The count is not related to how frequently the source code is analyzed. If your | |||
private project has a 6K LOCs and you analyze it 100 times in the month, this will be | |||
counted as 6K for the billing. If you are getting close to the threshold you will be | |||
notified to either upgrade your plan or reduce the number of LOCs in your projects. | |||
</p> | |||
<div className="faq-title">When will I be invoiced?</div> | |||
<p> | |||
You will be invoiced once a month, the day of the month after your trial ends. For | |||
example if you start your free trial on January 1st, it will last till January 14th | |||
and you will be first billed on January 15th for your upcoming month, e.g. January | |||
15th to February 15th. | |||
</p> | |||
<div className="faq-title">Can I cancel my subscription?</div> | |||
<p> | |||
Of course! There's no commitment. You can delete your paid organization whenever | |||
you wish, or simply downgrade to the free tier if you wish to keep on analysing some | |||
public projects. | |||
</p> | |||
<div className="faq-title">Still have more questions?</div> | |||
<p> | |||
Contact us <a href={`${getBaseUrl()}/about/contact`}>here</a>. | |||
</p> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
); | |||
} |
@@ -1,229 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2020 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 { Helmet } from 'react-helmet-async'; | |||
import { Link } from 'react-router'; | |||
import { getBaseUrl } from 'sonar-ui-common/helpers/urls'; | |||
import { isLoggedIn } from '../../../helpers/users'; | |||
import LoginButtons from './components/LoginButtons'; | |||
import Pricing from './components/Pricing'; | |||
import SQPageContainer from './components/SQPageContainer'; | |||
import StartUsing from './components/StartUsing'; | |||
import './style.css'; | |||
import { LANGUAGES } from './utils'; | |||
const NB_LANGUAGE_PER_ROW = 8; | |||
export default function SQHome() { | |||
return ( | |||
<SQPageContainer> | |||
{({ currentUser }) => ( | |||
<div className="page sc-page sc-sq-page"> | |||
<Helmet title="Use SonarQube as a Service, sign up for SonarCloud | SonarCloud"> | |||
<meta | |||
content="Enhance your workflow with continuous code quality, SonarCloud automatically analyzes and decorates pull requests on GitHub, Bitbucket and Azure DevOps on major languages." | |||
name="description" | |||
/> | |||
</Helmet> | |||
<Jumbotron /> | |||
<h2 className="sc-sq-header2">You use the service, we take care of the rest</h2> | |||
<Pricing /> | |||
{!isLoggedIn(currentUser) && <StartUsing />} | |||
<Features /> | |||
<Languages /> | |||
<Integrations /> | |||
<BottomNote /> | |||
</div> | |||
)} | |||
</SQPageContainer> | |||
); | |||
} | |||
function Jumbotron() { | |||
return ( | |||
<div className="sc-sq-jumbotron"> | |||
<div className="sc-sq-jumbotron-left"> | |||
<h1 className="sc-sq-jumbotron-title"> | |||
Use SonarQube | |||
<br /> | |||
<span className="sc-sq-jumbotron-title-orange">as a Service</span> | |||
</h1> | |||
<div className="sc-sq-jumbotron-login"> | |||
{'—'} | |||
<br /> | |||
Log in or sign up with | |||
</div> | |||
<LoginButtons /> | |||
</div> | |||
<div className="sc-sq-jumbotron-right"> | |||
<img | |||
alt="SonarCloud project dashboard" | |||
src={`${getBaseUrl()}/images/sonarcloud/sq-homepage.png`} | |||
srcSet={`${getBaseUrl()}/images/sonarcloud/sq-homepage.png 1x, ${getBaseUrl()}/images/sonarcloud/sq-homepage@2x.png 2x`} | |||
/> | |||
</div> | |||
</div> | |||
); | |||
} | |||
function Features() { | |||
return ( | |||
<> | |||
<h2 className="sc-sq-header2">The right solution for developers</h2> | |||
<ul className="sc-features-list"> | |||
<li className="sc-feature"> | |||
<img | |||
alt="" | |||
className="big-spacer-bottom" | |||
height="34" | |||
src={`${getBaseUrl()}/images/sonarcloud/as-a-service.svg`} | |||
/> | |||
<h3 className="sc-feature-title">As a Service</h3> | |||
<p className="sc-feature-description"> | |||
We provide a fully operated version of SonarQube which is hosted on Amazon AWS in Europe | |||
(Frankfurt, Germany). | |||
</p> | |||
<Link className="sc-arrow-link sc-feature-link" to="/about/sq/as-a-service"> | |||
See more | |||
</Link> | |||
</li> | |||
<li className="sc-feature"> | |||
<img | |||
alt="" | |||
className="big-spacer-bottom" | |||
height="34" | |||
src={`${getBaseUrl()}/images/sonarcloud/branch-analysis.svg`} | |||
/> | |||
<h3 className="sc-feature-title">Branch & pull request 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> | |||
<Link | |||
className="sc-arrow-link sc-feature-link" | |||
to="/about/sq/branch-analysis-and-pr-decoration"> | |||
See more | |||
</Link> | |||
</li> | |||
<li className="sc-feature"> | |||
<img | |||
alt="" | |||
className="big-spacer-bottom" | |||
height="34" | |||
src={`${getBaseUrl()}/images/sonarcloud/sonarlint-integration.svg`} | |||
/> | |||
<h3 className="sc-feature-title">SonarLint integration</h3> | |||
<p className="sc-feature-description"> | |||
The full SonarCloud experience can be enhanced with SonarLint, that enables developers | |||
to receive real time information directly in their IDEs. | |||
</p> | |||
<Link className="sc-arrow-link sc-feature-link" to="/about/sq/sonarlint-integration"> | |||
See more | |||
</Link> | |||
</li> | |||
</ul> | |||
</> | |||
); | |||
} | |||
function Languages() { | |||
const languagesPerRow = []; | |||
for (let i = 0; i < LANGUAGES.length / NB_LANGUAGE_PER_ROW; i++) { | |||
languagesPerRow[i] = LANGUAGES.slice(i * NB_LANGUAGE_PER_ROW, (i + 1) * NB_LANGUAGE_PER_ROW); | |||
} | |||
return ( | |||
<div className="sc-languages"> | |||
<h3 className="sc-feature-title">On {LANGUAGES.length} programming languages</h3> | |||
{languagesPerRow.map((languagesRow, idx) => ( | |||
<ul className="sc-languages-list" key={idx}> | |||
{languagesRow.map(language => ( | |||
<li key={language.name}> | |||
<img | |||
alt={language.name} | |||
src={`${getBaseUrl()}/images/languages/${language.file}`} | |||
width={language.width} | |||
/> | |||
</li> | |||
))} | |||
</ul> | |||
))} | |||
</div> | |||
); | |||
} | |||
function Integrations() { | |||
return ( | |||
<div className="sc-integrations"> | |||
<h2 className="sc-sq-header2 sc-integrations-title">Fully integrated experience with</h2> | |||
<ul className="sc-integrations-list"> | |||
<li> | |||
<h3 className="sc-feature-title">GitHub</h3> | |||
<img | |||
alt="GitHub" | |||
className="big-spacer-top" | |||
height="60" | |||
src={`${getBaseUrl()}/images/sonarcloud/github-big.svg`} | |||
/> | |||
</li> | |||
<li> | |||
<h3 className="sc-feature-title">Azure DevOps</h3> | |||
<img | |||
alt="Azure DevOps" | |||
className="big-spacer-top" | |||
height="60" | |||
src={`${getBaseUrl()}/images/sonarcloud/azure.svg`} | |||
/> | |||
<div className="big-spacer-top"> | |||
<Link className="sc-arrow-link sc-feature-link" to="/about/sq/vsts"> | |||
See more | |||
</Link> | |||
</div> | |||
</li> | |||
<li> | |||
<h3 className="sc-feature-title">Bitbucket</h3> | |||
<img | |||
alt="Bitbucket" | |||
className="big-spacer-top" | |||
height="60" | |||
src={`${getBaseUrl()}/images/sonarcloud/bitbucket-big.svg`} | |||
/> | |||
</li> | |||
</ul> | |||
</div> | |||
); | |||
} | |||
function BottomNote() { | |||
return ( | |||
<div className="sc-bottom-note"> | |||
Includes all features of SonarSource{' '} | |||
<a | |||
className="sc-bottom-note-link link-base-color" | |||
href="https://www.sonarsource.com/plans-and-pricing/developer/" | |||
rel="noopener noreferrer" | |||
target="_blank"> | |||
Developer Edition | |||
</a> | |||
</div> | |||
); | |||
} |
@@ -1,107 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2020 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 { Helmet } from 'react-helmet-async'; | |||
import { getBaseUrl } from 'sonar-ui-common/helpers/urls'; | |||
import { isLoggedIn } from '../../../helpers/users'; | |||
import SQPageContainer from './components/SQPageContainer'; | |||
import SQStartUsing from './components/SQStartUsing'; | |||
import SQTopNav from './components/SQTopNav'; | |||
import './style.css'; | |||
export default function SonarLintIntegration() { | |||
return ( | |||
<SQPageContainer> | |||
{({ currentUser }) => ( | |||
<div className="page page-limited sc-page"> | |||
<Helmet title="Enhance SonarCloud experience with SonarLint | SonarCloud"> | |||
<meta | |||
content="SonarLint connected teams are efficient, consistent and get more value. Connect SonarCloud with SonarLint and share consistent rulesets and analysis settings in everyone’s IDE." | |||
name="description" | |||
/> | |||
</Helmet> | |||
<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 exclusions, 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> | |||
)} | |||
</SQPageContainer> | |||
); | |||
} |
@@ -1,37 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2020 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 { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils'; | |||
import BranchAnalysis from '../BranchAnalysis'; | |||
// necessary to make the test run | |||
jest.mock('Docs/EmbedDocsSuggestions.json', () => {}, { virtual: true }); | |||
beforeEach(() => { | |||
jest.clearAllMocks(); | |||
}); | |||
it('should render', async () => { | |||
const wrapper = shallow(<BranchAnalysis />); | |||
await waitAndUpdate(wrapper); | |||
expect(wrapper).toMatchSnapshot(); | |||
}); |
@@ -1,95 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2020 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 { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils'; | |||
import { mockStore } from '../../../../helpers/testMocks'; | |||
import Home from '../Home'; | |||
import { requestHomepageData } from '../utils'; | |||
jest.mock('../utils', () => { | |||
const utils = require.requireActual('../utils'); | |||
utils.requestHomepageData = jest.fn().mockResolvedValue({ | |||
publicProjects: 236, | |||
publicLoc: 12345, | |||
pullRequests: 123456, | |||
rules: 1234, | |||
featuredProjects: [ | |||
{ | |||
key: 'sonarsource-jfrog.simple-js-php-project', | |||
avatarUrl: null, | |||
organizationKey: 'sonarsource-jfrog', | |||
organizationName: 'SonarSource & JFrog', | |||
name: 'Simple JS & PHP project', | |||
bugs: 0, | |||
codeSmells: 7, | |||
coverage: 9.7, | |||
duplications: 56.2, | |||
gateStatus: 'OK', | |||
languages: ['js', 'php'], | |||
maintainabilityRating: 1, | |||
ncloc: 123456, | |||
reliabilityRating: 1, | |||
securityRating: 1, | |||
vulnerabilities: 654321 | |||
} | |||
] | |||
}); | |||
return utils; | |||
}); | |||
beforeEach(() => { | |||
jest.clearAllMocks(); | |||
}); | |||
it('should render', async () => { | |||
const wrapper = shallowRender('https://static.sonarcloud.io/homepage.json'); | |||
expect(requestHomepageData).toBeCalled(); | |||
await waitAndUpdate(wrapper); | |||
expect(wrapper).toMatchSnapshot(); | |||
expect(wrapper.find('PageBackgroundHeader').dive()).toMatchSnapshot(); | |||
expect(wrapper.find('PageTitle').dive()).toMatchSnapshot(); | |||
expect(wrapper.find('EnhanceWorkflow').dive()).toMatchSnapshot(); | |||
expect(wrapper.find('Functionality').dive()).toMatchSnapshot(); | |||
expect(wrapper.find('Languages').dive()).toMatchSnapshot(); | |||
expect(wrapper.find('Stats').dive()).toMatchSnapshot(); | |||
expect(wrapper.find('Projects').dive()).toMatchSnapshot(); | |||
}); | |||
it('should not render real Stats and Projects', () => { | |||
const wrapper = shallowRender(undefined); | |||
expect(requestHomepageData).not.toBeCalled(); | |||
expect(wrapper.find('Stats').dive()).toMatchSnapshot(); | |||
expect(wrapper.find('Projects').dive()).toMatchSnapshot(); | |||
}); | |||
function shallowRender(homePageDataUrl: string | undefined) { | |||
return shallow(<Home />, { | |||
context: { | |||
store: mockStore({ | |||
settingsApp: { | |||
values: { | |||
global: { 'sonar.homepage.url': { key: 'sonar.homepage.url', value: homePageDataUrl } } | |||
} | |||
} | |||
}) | |||
} | |||
}).dive(); | |||
} |
@@ -1,7 +0,0 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render 1`] = ` | |||
<withRouter(Connect(SQPageContainer))> | |||
<Component /> | |||
</withRouter(Connect(SQPageContainer))> | |||
`; |
@@ -1,661 +0,0 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should not render real Stats and Projects 1`] = ` | |||
<div | |||
className="sc-section sc-columns" | |||
> | |||
<div | |||
className="sc-column sc-column-full" | |||
> | |||
<h3> | |||
Over 3,000 Projects | |||
<br /> | |||
Continuously Analyzed | |||
</h3> | |||
</div> | |||
</div> | |||
`; | |||
exports[`should not render real Stats and Projects 2`] = ` | |||
<div | |||
className="sc-section sc-columns" | |||
> | |||
<div | |||
className="sc-column sc-column-full" | |||
> | |||
<h6 | |||
className="spacer-bottom" | |||
> | |||
Come join the fun, it’s entirely free for open-source projects! | |||
</h6> | |||
<div | |||
className="sc-spacer-bottom" | |||
> | |||
<LoginButtons /> | |||
</div> | |||
</div> | |||
</div> | |||
`; | |||
exports[`should render 1`] = ` | |||
<div | |||
className="global-container" | |||
> | |||
<div | |||
className="page-wrapper" | |||
> | |||
<div | |||
className="page-container sc-page" | |||
> | |||
<Helmet | |||
defer={true} | |||
encodeSpecialCharacters={true} | |||
title="SonarCloud | Clean Code, Rockstar Status" | |||
> | |||
<meta | |||
content="Enhance your workflow with continuous code quality, SonarCloud automatically analyzes and decorates pull requests on GitHub, Bitbucket and Azure DevOps on major languages." | |||
name="description" | |||
/> | |||
</Helmet> | |||
<FixedNavBar /> | |||
<PageBackgroundHeader /> | |||
<TopNavBar /> | |||
<PageTitle /> | |||
<EnhanceWorkflow /> | |||
<Functionality /> | |||
<Languages /> | |||
<Stats | |||
data={ | |||
Object { | |||
"featuredProjects": Array [ | |||
Object { | |||
"avatarUrl": null, | |||
"bugs": 0, | |||
"codeSmells": 7, | |||
"coverage": 9.7, | |||
"duplications": 56.2, | |||
"gateStatus": "OK", | |||
"key": "sonarsource-jfrog.simple-js-php-project", | |||
"languages": Array [ | |||
"js", | |||
"php", | |||
], | |||
"maintainabilityRating": 1, | |||
"name": "Simple JS & PHP project", | |||
"ncloc": 123456, | |||
"organizationKey": "sonarsource-jfrog", | |||
"organizationName": "SonarSource & JFrog", | |||
"reliabilityRating": 1, | |||
"securityRating": 1, | |||
"vulnerabilities": 654321, | |||
}, | |||
], | |||
"publicLoc": 12345, | |||
"publicProjects": 236, | |||
"pullRequests": 123456, | |||
"rules": 1234, | |||
} | |||
} | |||
/> | |||
<Projects | |||
featuredProjects={ | |||
Array [ | |||
Object { | |||
"avatarUrl": null, | |||
"bugs": 0, | |||
"codeSmells": 7, | |||
"coverage": 9.7, | |||
"duplications": 56.2, | |||
"gateStatus": "OK", | |||
"key": "sonarsource-jfrog.simple-js-php-project", | |||
"languages": Array [ | |||
"js", | |||
"php", | |||
], | |||
"maintainabilityRating": 1, | |||
"name": "Simple JS & PHP project", | |||
"ncloc": 123456, | |||
"organizationKey": "sonarsource-jfrog", | |||
"organizationName": "SonarSource & JFrog", | |||
"reliabilityRating": 1, | |||
"securityRating": 1, | |||
"vulnerabilities": 654321, | |||
}, | |||
] | |||
} | |||
/> | |||
</div> | |||
</div> | |||
<Footer /> | |||
</div> | |||
`; | |||
exports[`should render 2`] = ` | |||
<div | |||
className="sc-header-background" | |||
> | |||
<div | |||
className="sc-background-start" | |||
/> | |||
<div | |||
className="sc-background-end" | |||
/> | |||
<div | |||
className="sc-background-center" | |||
> | |||
<img | |||
alt="" | |||
height="418px" | |||
src="/images/sonarcloud/home-header.svg" | |||
/> | |||
</div> | |||
</div> | |||
`; | |||
exports[`should render 3`] = ` | |||
<div | |||
className="sc-section sc-columns big-spacer-top" | |||
> | |||
<div | |||
className="sc-column sc-column-half display-flex-center" | |||
> | |||
<div> | |||
<h1 | |||
className="sc-title-orange big-spacer-top" | |||
> | |||
Clean Code | |||
</h1> | |||
<h1 | |||
className="sc-spacer-bottom" | |||
> | |||
Rockstar Status | |||
</h1> | |||
<h5 | |||
className="sc-big-spacer-bottom sc-regular-weight" | |||
> | |||
Eliminate bugs and vulnerabilities. | |||
<br /> | |||
Champion quality code in your projects. | |||
</h5> | |||
<div> | |||
<h6> | |||
Go ahead! Analyze your repo: | |||
</h6> | |||
<LoginButtons /> | |||
<p | |||
className="sc-mention sc-regular-weight big-spacer-top" | |||
> | |||
Free for Open-Source Projects | |||
</p> | |||
</div> | |||
</div> | |||
</div> | |||
<div | |||
className="sc-column sc-column-half text-right" | |||
> | |||
<img | |||
alt="" | |||
src="/images/sonarcloud/home-header-people.png" | |||
width="430px" | |||
/> | |||
</div> | |||
</div> | |||
`; | |||
exports[`should render 4`] = ` | |||
<div | |||
className="sc-section sc-columns" | |||
> | |||
<div | |||
className="sc-column sc-column-full" | |||
> | |||
<h3 | |||
className="sc-big-spacer-bottom" | |||
> | |||
Enhance Your Workflow | |||
<br /> | |||
with Continuous Code Quality | |||
</h3> | |||
<img | |||
alt="" | |||
className="sc-big-spacer-bottom" | |||
src="/images/sonarcloud/home-branch.png" | |||
srcSet="/images/sonarcloud/home-branch.png 1x, /images/sonarcloud/home-branch@2x.png 2x" | |||
/> | |||
<h5 | |||
className="spacer-bottom" | |||
> | |||
Maximize your throughput and only release clean code | |||
</h5> | |||
<h6 | |||
className="sc-big-spacer-bottom sc-regular-weight" | |||
> | |||
SonarCloud automatically analyzes branches and decorates pull requests | |||
</h6> | |||
</div> | |||
</div> | |||
`; | |||
exports[`should render 5`] = ` | |||
<div | |||
className="position-relative" | |||
> | |||
<div | |||
className="sc-functionality-background" | |||
> | |||
<div | |||
className="sc-background-center" | |||
> | |||
<img | |||
alt="" | |||
height="300px" | |||
src="/images/sonarcloud/home-grey-background.svg" | |||
/> | |||
</div> | |||
</div> | |||
<div | |||
className="sc-functionality-container" | |||
> | |||
<div | |||
className="sc-section" | |||
> | |||
<h3 | |||
className="sc-big-spacer-bottom text-center" | |||
> | |||
Functionality | |||
<br /> | |||
that Fits Your Projects | |||
</h3> | |||
<div | |||
className="sc-columns" | |||
> | |||
<div | |||
className="sc-column sc-column-small big-spacer-top" | |||
> | |||
<h6 | |||
className="sc-regular-weight spacer-bottom" | |||
> | |||
Easy to Use | |||
</h6> | |||
<p> | |||
With just a few clicks you’re up and running right where your code lives. Immediate access to the latest features and enhancements. | |||
</p> | |||
<div | |||
className="sc-separator" | |||
/> | |||
<span | |||
className="big-spacer-bottom sc-with-icon" | |||
> | |||
<img | |||
alt="" | |||
className="big-spacer-right" | |||
src="/images/sonarcloud/scale.svg" | |||
/> | |||
Scale on-demand as your projects grow. | |||
</span> | |||
<span | |||
className="sc-with-icon" | |||
> | |||
<img | |||
alt="" | |||
className="big-spacer-right" | |||
src="/images/sonarcloud/stop.svg" | |||
/> | |||
No contracts, stop/start anytime. | |||
</span> | |||
</div> | |||
<div | |||
className="sc-column sc-column-big big-spacer-top" | |||
> | |||
<img | |||
alt="" | |||
className="sc-rounded-img" | |||
src="/images/sonarcloud/home-easy-to-use.png" | |||
srcSet="/images/sonarcloud/home-easy-to-use.png 1x, /images/sonarcloud/home-easy-to-use@2x.png 2x" | |||
/> | |||
</div> | |||
</div> | |||
<div | |||
className="sc-columns" | |||
> | |||
<div | |||
className="sc-column sc-column-big" | |||
> | |||
<img | |||
alt="" | |||
className="sc-rounded-img" | |||
src="/images/sonarcloud/home-open-transparent.png" | |||
srcSet="/images/sonarcloud/home-open-transparent.png 1x, /images/sonarcloud/home-open-transparent@2x.png 2x" | |||
/> | |||
</div> | |||
<div | |||
className="sc-column sc-column-small" | |||
> | |||
<div> | |||
<h6 | |||
className="sc-regular-weight spacer-bottom" | |||
> | |||
Open and Transparent | |||
</h6> | |||
<p | |||
className="big-spacer-bottom" | |||
> | |||
Project dashboards keep teams and stakeholders informed on code quality and releasability. | |||
</p> | |||
<p> | |||
Display project badges and show your communities you’re all about awesome. | |||
</p> | |||
<img | |||
alt="" | |||
className="big-spacer-top" | |||
src="/images/project_badges/sonarcloud-black.svg" | |||
width="200px" | |||
/> | |||
</div> | |||
</div> | |||
</div> | |||
<div | |||
className="sc-columns" | |||
> | |||
<div | |||
className="sc-column sc-column-full big-spacer-bottom" | |||
> | |||
<div> | |||
<h6 | |||
className="sc-regular-weight spacer-bottom" | |||
> | |||
Effective Collaboration | |||
</h6> | |||
<p | |||
className="sc-with-inline-icon" | |||
> | |||
Use | |||
<img | |||
alt="SonarCloud" | |||
src="/images/sonarcloud/sonarcloud-logo-text-only.svg" | |||
/> | |||
with your team, share best practices and have fun writing quality code! | |||
</p> | |||
<br /> | |||
<p | |||
className="sc-with-inline-icon" | |||
> | |||
Connect with | |||
<img | |||
alt="SonarCloud" | |||
src="/images/sonarcloud/sonarlint-logo.svg" | |||
/> | |||
and get real-time notifications in your IDE as you work. | |||
</p> | |||
<div | |||
className="big-spacer-top" | |||
> | |||
<img | |||
alt="" | |||
className="big-spacer-top huge-spacer-bottom" | |||
src="/images/sonarcloud/ide.svg" | |||
width="216px" | |||
/> | |||
</div> | |||
<img | |||
alt="" | |||
src="/images/sonarcloud/collab.svg" | |||
width="540px" | |||
/> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
<div | |||
className="sc-functionality-background sc-functionality-background-bottom" | |||
> | |||
<div | |||
className="sc-background-center" | |||
> | |||
<img | |||
alt="" | |||
height="140px" | |||
src="/images/sonarcloud/home-background-grey-bottom.svg" | |||
/> | |||
</div> | |||
</div> | |||
</div> | |||
`; | |||
exports[`should render 6`] = ` | |||
<div | |||
className="position-relative" | |||
> | |||
<div | |||
className="sc-languages-container clearfix" | |||
> | |||
<div | |||
className="sc-section sc-columns" | |||
> | |||
<div | |||
className="sc-column-full" | |||
> | |||
<h3 | |||
className="sc-big-spacer-bottom" | |||
> | |||
SonarCloud speaks your language | |||
</h3> | |||
<ul | |||
className="sc-languages-list" | |||
style={ | |||
Object { | |||
"height": undefined, | |||
} | |||
} | |||
> | |||
<li | |||
key="Java" | |||
> | |||
<img | |||
alt="Java" | |||
src="/images/languages/java.svg" | |||
width={65} | |||
/> | |||
</li> | |||
<li | |||
key="JavaScript" | |||
> | |||
<img | |||
alt="JavaScript" | |||
src="/images/languages/js.svg" | |||
width={60} | |||
/> | |||
</li> | |||
<li | |||
key="TypeScript" | |||
> | |||
<img | |||
alt="TypeScript" | |||
src="/images/languages/ts.svg" | |||
width={100} | |||
/> | |||
</li> | |||
<li | |||
key="C#" | |||
> | |||
<img | |||
alt="C#" | |||
src="/images/languages/csharp.svg" | |||
width={60} | |||
/> | |||
</li> | |||
<li | |||
key="Python" | |||
> | |||
<img | |||
alt="Python" | |||
src="/images/languages/python.svg" | |||
width={65} | |||
/> | |||
</li> | |||
<li | |||
key="C++" | |||
> | |||
<img | |||
alt="C++" | |||
src="/images/languages/c-c-plus-plus.svg" | |||
width={53} | |||
/> | |||
</li> | |||
<li | |||
key="Go" | |||
> | |||
<img | |||
alt="Go" | |||
src="/images/languages/go.svg" | |||
width={91} | |||
/> | |||
</li> | |||
<li | |||
key="Kotlin" | |||
> | |||
<img | |||
alt="Kotlin" | |||
src="/images/languages/kotlin.svg" | |||
width={42} | |||
/> | |||
</li> | |||
<li | |||
key="Ruby" | |||
> | |||
<img | |||
alt="Ruby" | |||
src="/images/languages/ruby.svg" | |||
width={43} | |||
/> | |||
</li> | |||
<li | |||
key="Swift" | |||
> | |||
<img | |||
alt="Swift" | |||
src="/images/languages/swift.svg" | |||
width={64} | |||
/> | |||
</li> | |||
</ul> | |||
<a | |||
className="bt bt-large bt-nav bt-orange2 display-inline-flex-center" | |||
href="#" | |||
onClick={[Function]} | |||
> | |||
See All Languages | |||
<SCChevronDownIcon | |||
className="little-spacer-left" | |||
/> | |||
</a> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
`; | |||
exports[`should render 7`] = ` | |||
<div | |||
className="sc-section sc-columns" | |||
> | |||
<div | |||
className="sc-column sc-column-full" | |||
> | |||
<h3> | |||
Over 3,000 Projects | |||
<br /> | |||
Continuously Analyzed | |||
</h3> | |||
<Statistics | |||
statistics={ | |||
Array [ | |||
Object { | |||
"icon": "rules", | |||
"text": "Static analysis rules checked", | |||
"value": 1234, | |||
}, | |||
Object { | |||
"icon": "locs", | |||
"text": "Lines of code analyzed", | |||
"value": 12345, | |||
}, | |||
Object { | |||
"icon": "pull-request", | |||
"text": "Pull Requests decorated/week", | |||
"value": undefined, | |||
}, | |||
Object { | |||
"icon": "open-source", | |||
"text": "Open-source projects inspected", | |||
"value": 236, | |||
}, | |||
] | |||
} | |||
/> | |||
</div> | |||
</div> | |||
`; | |||
exports[`should render 8`] = ` | |||
<div | |||
className="sc-section sc-columns" | |||
> | |||
<div | |||
className="sc-column sc-column-full" | |||
> | |||
<h6 | |||
className="big-spacer-bottom" | |||
> | |||
Transparency makes sense | |||
<br /> | |||
and that’s why the trend is growing. | |||
</h6> | |||
<p> | |||
Check out these open-source projects showing users | |||
<br /> | |||
their commitment to quality. | |||
</p> | |||
<FeaturedProjects | |||
projects={ | |||
Array [ | |||
Object { | |||
"avatarUrl": null, | |||
"bugs": 0, | |||
"codeSmells": 7, | |||
"coverage": 9.7, | |||
"duplications": 56.2, | |||
"gateStatus": "OK", | |||
"key": "sonarsource-jfrog.simple-js-php-project", | |||
"languages": Array [ | |||
"js", | |||
"php", | |||
], | |||
"maintainabilityRating": 1, | |||
"name": "Simple JS & PHP project", | |||
"ncloc": 123456, | |||
"organizationKey": "sonarsource-jfrog", | |||
"organizationName": "SonarSource & JFrog", | |||
"reliabilityRating": 1, | |||
"securityRating": 1, | |||
"vulnerabilities": 654321, | |||
}, | |||
] | |||
} | |||
/> | |||
<h6 | |||
className="spacer-bottom" | |||
> | |||
Come join the fun, it’s entirely free for open-source projects! | |||
</h6> | |||
<div | |||
className="sc-spacer-bottom" | |||
> | |||
<LoginButtons /> | |||
</div> | |||
</div> | |||
</div> | |||
`; |
@@ -1,135 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2020 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. | |||
*/ | |||
.sc-featured-projects { | |||
margin-top: 40px; | |||
position: relative; | |||
} | |||
.sc-featured-projects-container { | |||
margin: 0 40px; | |||
overflow: hidden; | |||
padding: 10px 8px 20px; | |||
max-width: 985px; | |||
} | |||
.sc-featured-projects-inner { | |||
display: flex; | |||
order: 2; | |||
position: relative; | |||
left: calc(100% / -3); | |||
transform: translateX(calc(100% / 3)); | |||
} | |||
.sc-featured-projects-inner.reversing { | |||
transform: translateX(calc(100% / -3)); | |||
} | |||
.sc-featured-projects-inner.ready { | |||
transform: translateX(0); | |||
transition: transform 0.5s cubic-bezier(0.23, 1, 0.32, 1); | |||
} | |||
.sc-project-card-container { | |||
flex: 1 0 calc(100% / 3); | |||
} | |||
.sc-project-card { | |||
width: 255px; | |||
display: inline-block; | |||
margin: 0 10px; | |||
padding: 25px; | |||
border: 1px solid var(--sonarcloudBlack300) !important; | |||
border-radius: 5px; | |||
box-shadow: 0 1px 1px rgba(7, 7, 6, 0.1); | |||
transition: all 0.1s ease-in; | |||
color: inherit; | |||
} | |||
.sc-project-card:hover, | |||
.sc-project-card:focus { | |||
box-shadow: 0 10px 30px rgba(7, 7, 6, 0.2); | |||
transform: translateY(-4px); | |||
color: inherit; | |||
} | |||
.sc-project-card-header { | |||
padding: 0 10px 16px; | |||
} | |||
.sc-project-card-limited { | |||
max-width: 100%; | |||
overflow: hidden; | |||
text-overflow: ellipsis; | |||
white-space: nowrap; | |||
} | |||
.sc-project-card-measures li { | |||
display: flex; | |||
align-items: baseline; | |||
justify-content: space-between; | |||
padding: 6px 0 4px; | |||
border-bottom: 1px solid var(--sonarcloudBlack250); | |||
} | |||
.sc-project-card-measures li:last-of-type { | |||
border: none; | |||
} | |||
.sc-project-card-measures li div { | |||
display: inline-flex; | |||
} | |||
.sc-project-card .sc-mention { | |||
color: var(--sonarcloudBlack500); | |||
} | |||
.sc-project-button { | |||
display: block; | |||
position: absolute; | |||
top: 50%; | |||
margin: 0; | |||
padding: 4px; | |||
border: none; | |||
background: transparent; | |||
color: var(--sonarcloudBlack300); | |||
text-decoration: none; | |||
cursor: pointer; | |||
outline: none; | |||
transition: all 0.2s ease; | |||
} | |||
.sc-project-button img { | |||
opacity: 0.5; | |||
width: 19px; | |||
} | |||
.sc-project-button:hover img { | |||
opacity: 1; | |||
} | |||
.sc-project-button:last-child { | |||
right: 0; | |||
} | |||
.sc-project-button:hover, | |||
.sc-project-button:active, | |||
.sc-project-button:focus { | |||
color: var(--sonarcloudBlack500); | |||
} |
@@ -1,304 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2020 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 classNames from 'classnames'; | |||
import { throttle } from 'lodash'; | |||
import * as React from 'react'; | |||
import CountUp from 'react-countup'; | |||
import DuplicationsRating from 'sonar-ui-common/components/ui/DuplicationsRating'; | |||
import Rating from 'sonar-ui-common/components/ui/Rating'; | |||
import { formatMeasure } from 'sonar-ui-common/helpers/measures'; | |||
import { getBaseUrl, getPathUrlAsString } from 'sonar-ui-common/helpers/urls'; | |||
import OrganizationAvatar from '../../../../components/common/OrganizationAvatar'; | |||
import CoverageRating from '../../../../components/ui/CoverageRating'; | |||
import { getProjectUrl } from '../../../../helpers/urls'; | |||
import { getMetricName } from '../../../overview/utils'; | |||
import ProjectCardLanguagesContainer from '../../../projects/components/ProjectCardLanguagesContainer'; | |||
import { FeaturedProject } from '../utils'; | |||
import './FeaturedProjects.css'; | |||
interface Props { | |||
projects: FeaturedProject[]; | |||
} | |||
interface State { | |||
reversing: boolean; | |||
slides: Array<{ | |||
order: number; | |||
project: FeaturedProject; | |||
}>; | |||
sliding: boolean; | |||
viewable: boolean; | |||
} | |||
export default class FeaturedProjects extends React.PureComponent<Props, State> { | |||
container?: HTMLElement | null; | |||
mounted = false; | |||
constructor(props: Props) { | |||
super(props); | |||
this.state = { | |||
reversing: false, | |||
slides: this.orderProjectsFromProps(), | |||
sliding: false, | |||
viewable: false | |||
}; | |||
this.handleScroll = throttle(this.handleScroll, 10); | |||
} | |||
componentDidMount() { | |||
this.mounted = true; | |||
document.addEventListener('scroll', this.handleScroll, true); | |||
} | |||
componentDidUpdate(prevProps: Props) { | |||
if (prevProps.projects !== this.props.projects) { | |||
this.setState({ slides: this.orderProjectsFromProps() }); | |||
} | |||
} | |||
componentWillUnmount() { | |||
this.mounted = false; | |||
document.removeEventListener('scroll', this.handleScroll, true); | |||
} | |||
handleScroll = () => { | |||
if (this.container) { | |||
const rect = this.container.getBoundingClientRect(); | |||
const windowHeight = | |||
window.innerHeight || | |||
(document.documentElement ? document.documentElement.clientHeight : 0); | |||
if (rect.top <= windowHeight && rect.top + rect.height >= 0) { | |||
this.setState({ viewable: true }); | |||
} | |||
} | |||
}; | |||
orderProjectsFromProps = () => { | |||
const { projects } = this.props; | |||
if (projects.length === 0) { | |||
return []; | |||
} | |||
// Last element should be put at the begining for proper carousel animation | |||
return [projects.pop(), ...projects].map((project: FeaturedProject, id) => { | |||
return { | |||
order: id, | |||
project | |||
}; | |||
}); | |||
}; | |||
handlePrevClick = () => { | |||
this.setState(({ slides }) => ({ | |||
reversing: true, | |||
sliding: true, | |||
slides: slides.map(slide => { | |||
slide.order = slide.order === slides.length - 1 ? 0 : slide.order + 1; | |||
return slide; | |||
}) | |||
})); | |||
setTimeout(() => { | |||
if (this.mounted) { | |||
this.setState({ sliding: false }); | |||
} | |||
}, 50); | |||
}; | |||
handleNextClick = () => { | |||
this.setState(({ slides }) => ({ | |||
reversing: false, | |||
sliding: true, | |||
slides: slides.map(slide => { | |||
slide.order = slide.order === 0 ? slides.length - 1 : slide.order - 1; | |||
return slide; | |||
}) | |||
})); | |||
setTimeout(() => { | |||
this.setState({ sliding: false }); | |||
}, 50); | |||
}; | |||
render() { | |||
const { reversing, sliding, viewable } = this.state; | |||
return ( | |||
<div | |||
className="sc-featured-projects sc-big-spacer-bottom" | |||
ref={node => (this.container = node)}> | |||
<button className="js-prev sc-project-button" onClick={this.handlePrevClick} type="button"> | |||
<img alt="" src={`${getBaseUrl()}/images/sonarcloud/chevron-left.svg`} /> | |||
</button> | |||
<div className="sc-featured-projects-container"> | |||
<div | |||
className={classNames('sc-featured-projects-inner', { | |||
reversing, | |||
ready: !sliding | |||
})}> | |||
{this.state.slides.map(slide => ( | |||
<ProjectCard | |||
key={slide.project.key} | |||
order={slide.order} | |||
project={slide.project} | |||
viewable={viewable} | |||
/> | |||
))} | |||
</div> | |||
</div> | |||
<button className="js-next sc-project-button" onClick={this.handleNextClick} type="button"> | |||
<img alt="" src={`${getBaseUrl()}/images/sonarcloud/chevron-right.svg`} /> | |||
</button> | |||
</div> | |||
); | |||
} | |||
} | |||
interface ProjectCardProps { | |||
order: number; | |||
project: FeaturedProject; | |||
viewable: boolean; | |||
} | |||
export function ProjectCard({ project, order, viewable }: ProjectCardProps) { | |||
return ( | |||
<div className="sc-project-card-container" style={{ order }}> | |||
<a className="sc-project-card" href={getPathUrlAsString(getProjectUrl(project.key))}> | |||
<div className="sc-project-card-header"> | |||
<OrganizationAvatar | |||
className="no-border spacer-bottom" | |||
organization={{ | |||
name: project.organizationName, | |||
avatar: project.avatarUrl || undefined | |||
}} | |||
/> | |||
<p className="sc-project-card-limited" title={project.organizationName}> | |||
{project.organizationName} | |||
</p> | |||
<h5 className="sc-project-card-limited big-spacer-bottom" title={project.name}> | |||
{project.name} | |||
</h5> | |||
</div> | |||
<ul className="sc-project-card-measures"> | |||
<ProjectIssues | |||
metric={project.bugs} | |||
metricKey="bugs" | |||
ratingMetric={project.reliabilityRating} | |||
viewable={viewable} | |||
/> | |||
<ProjectIssues | |||
metric={project.vulnerabilities} | |||
metricKey="vulnerabilities" | |||
ratingMetric={project.securityRating} | |||
viewable={viewable} | |||
/> | |||
<ProjectIssues | |||
metric={project.codeSmells} | |||
metricKey="code_smells" | |||
ratingMetric={project.maintainabilityRating} | |||
viewable={viewable} | |||
/> | |||
<li> | |||
<span>{getMetricName('coverage')}</span> | |||
{project.coverage !== undefined ? ( | |||
<div> | |||
{viewable && ( | |||
<CountUp | |||
decimal="." | |||
decimals={1} | |||
delay={0} | |||
duration={4} | |||
end={project.coverage} | |||
suffix="%"> | |||
{(data: { countUpRef?: React.RefObject<HTMLHeadingElement> }) => ( | |||
<h6 className="display-inline-block big-spacer-right" ref={data.countUpRef}> | |||
0 | |||
</h6> | |||
)} | |||
</CountUp> | |||
)} | |||
<CoverageRating value={project.coverage} /> | |||
</div> | |||
) : ( | |||
<span className="huge little-spacer-right">—</span> | |||
)} | |||
</li> | |||
<li> | |||
<span>{getMetricName('duplications')}</span> | |||
<div> | |||
{viewable && ( | |||
<CountUp | |||
decimal="." | |||
decimals={1} | |||
delay={0} | |||
duration={4} | |||
end={project.duplications} | |||
suffix="%"> | |||
{(data: { countUpRef?: React.RefObject<HTMLHeadingElement> }) => ( | |||
<h6 className="display-inline-block big-spacer-right" ref={data.countUpRef}> | |||
0 | |||
</h6> | |||
)} | |||
</CountUp> | |||
)} | |||
<DuplicationsRating value={project.duplications} /> | |||
</div> | |||
</li> | |||
</ul> | |||
<div className="sc-mention text-left big-spacer-top"> | |||
{formatMeasure(project.ncloc, 'SHORT_INT')} lines of code /{' '} | |||
<ProjectCardLanguagesContainer | |||
className="display-inline-block" | |||
distribution={project.languages.join(';')} | |||
/> | |||
</div> | |||
</a> | |||
</div> | |||
); | |||
} | |||
interface ProjectIssues { | |||
metricKey: string; | |||
metric: number; | |||
ratingMetric: number; | |||
viewable: boolean; | |||
} | |||
export function ProjectIssues({ metric, metricKey, ratingMetric, viewable }: ProjectIssues) { | |||
const formattedValue = formatMeasure(metric, 'SHORT_INT'); | |||
const value = parseFloat(formattedValue); | |||
const suffix = formattedValue.replace(value.toString(), ''); | |||
return ( | |||
<li> | |||
<span>{getMetricName(metricKey)}</span> | |||
<div> | |||
{viewable && ( | |||
<CountUp delay={0} duration={4} end={value} suffix={suffix}> | |||
{(data: { countUpRef?: React.RefObject<HTMLHeadingElement> }) => ( | |||
<h6 className="display-inline-block big-spacer-right" ref={data.countUpRef}> | |||
0 | |||
</h6> | |||
)} | |||
</CountUp> | |||
)} | |||
<Rating value={ratingMetric} /> | |||
</div> | |||
</li> | |||
); | |||
} |
@@ -1,87 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2020 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. | |||
*/ | |||
.sc-footer { | |||
background-color: var(--sonarcloudBlack800); | |||
color: var(--sonarcloudBlack300); | |||
font-size: 12px; | |||
min-width: var(--minPageWidth); | |||
} | |||
.sc-footer *:focus { | |||
box-shadow: 0 0 0 3px rgba(230, 92, 0, 0.25); | |||
} | |||
.sc-footer-limited { | |||
position: relative; | |||
max-width: 1280px; | |||
margin-left: auto; | |||
margin-right: auto; | |||
padding-left: 20px; | |||
padding-right: 20px; | |||
} | |||
.sc-footer-copy { | |||
padding: 20px 0; | |||
border-top: 1px solid var(--sonarcloudBlack700); | |||
line-height: 16px; | |||
font-size: 11px; | |||
text-align: center; | |||
} | |||
.sc-footer-copy-link { | |||
text-decoration: underline; | |||
} | |||
.sc-footer-nav { | |||
display: flex; | |||
padding: 30px 0; | |||
} | |||
.sc-footer-nav-column { | |||
margin-right: 60px; | |||
} | |||
.sc-footer-nav-column-title { | |||
line-height: 1; | |||
margin-bottom: 16px; | |||
color: #fff; | |||
font-size: 12px; | |||
font-weight: 700; | |||
text-transform: uppercase; | |||
} | |||
.sc-footer-link { | |||
border: none; | |||
color: inherit; | |||
} | |||
.sc-footer-link:hover { | |||
color: #fff; | |||
} | |||
.sc-footer-link:focus { | |||
color: var(--sonarcloudOrange500); | |||
} | |||
.sc-footer-logo { | |||
position: absolute; | |||
top: 30px; | |||
right: 20px; | |||
} |
@@ -1,172 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2020 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 { getBaseUrl } from 'sonar-ui-common/helpers/urls'; | |||
import './Footer.css'; | |||
export default function Footer() { | |||
return ( | |||
<footer className="sc-footer"> | |||
<div className="sc-footer-limited"> | |||
<nav className="sc-footer-nav"> | |||
<div className="sc-footer-nav-column"> | |||
<h4 className="sc-footer-nav-column-title">Need Help</h4> | |||
<ul> | |||
<li className="spacer-top"> | |||
<Link className="sc-footer-link" to="/documentation"> | |||
Documentation | |||
</Link> | |||
</li> | |||
<li className="spacer-top"> | |||
<a | |||
className="sc-footer-link" | |||
href="https://community.sonarsource.com/c/help/sc" | |||
rel="noopener noreferrer" | |||
target="_blank"> | |||
Support Forum | |||
</a> | |||
</li> | |||
<li className="spacer-top"> | |||
<Link className="sc-footer-link" to="/about/contact"> | |||
Contact Us | |||
</Link> | |||
</li> | |||
<li className="spacer-top"> | |||
<a | |||
className="sc-footer-link" | |||
href="https://sonarcloud.statuspage.io/" | |||
rel="noopener noreferrer" | |||
target="_blank"> | |||
Status | |||
</a> | |||
</li> | |||
</ul> | |||
</div> | |||
<div className="sc-footer-nav-column"> | |||
<h4 className="sc-footer-nav-column-title">News</h4> | |||
<ul> | |||
<li className="spacer-top"> | |||
<a | |||
className="sc-footer-link" | |||
href="https://blog.sonarsource.com/product/SonarCloud" | |||
rel="noopener noreferrer" | |||
target="_blank"> | |||
SonarCloud News | |||
</a> | |||
</li> | |||
<li className="spacer-top"> | |||
<a | |||
className="sc-footer-link" | |||
href="https://twitter.com/sonarcloud" | |||
rel="noopener noreferrer" | |||
target="_blank"> | |||
</a> | |||
</li> | |||
</ul> | |||
</div> | |||
<div className="sc-footer-nav-column"> | |||
<h4 className="sc-footer-nav-column-title">About</h4> | |||
<ul> | |||
<li className="spacer-top"> | |||
<Link | |||
className="sc-footer-link" | |||
rel="noopener noreferrer" | |||
target="_blank" | |||
to="/terms.pdf"> | |||
Terms | |||
</Link> | |||
</li> | |||
<li className="spacer-top"> | |||
<Link className="sc-footer-link" to="/about/pricing/"> | |||
Pricing | |||
</Link> | |||
</li> | |||
<li className="spacer-top"> | |||
<Link className="sc-footer-link" to="/documentation/privacy/"> | |||
Privacy | |||
</Link> | |||
</li> | |||
<li className="spacer-top"> | |||
<Link className="sc-footer-link" to="/documentation/security/"> | |||
Security | |||
</Link> | |||
</li> | |||
</ul> | |||
</div> | |||
</nav> | |||
<div className="sc-footer-logo"> | |||
<Link className="display-inline-block link-no-underline" to="/"> | |||
<img alt="SonarCloud" height="45" src={`${getBaseUrl()}/images/sonarcloud-logo.svg`} /> | |||
</Link> | |||
<div> | |||
<a | |||
className="sc-footer-link" | |||
href="https://www.sonarsource.com" | |||
rel="noopener noreferrer" | |||
target="_blank"> | |||
A SonarSource™ product | |||
</a> | |||
</div> | |||
</div> | |||
</div> | |||
<div className="sc-footer-copy"> | |||
<div className="sc-footer-limited"> | |||
© 2008-2019, SonarCloud by{' '} | |||
<a | |||
className="sc-footer-link sc-footer-copy-link" | |||
href="https://www.sonarsource.com" | |||
rel="noopener noreferrer" | |||
target="_blank"> | |||
SonarSource SA | |||
</a> | |||
. All rights reserved. SonarCloud is a service operated by{' '} | |||
<a | |||
className="sc-footer-link sc-footer-copy-link" | |||
href="https://www.sonarsource.com" | |||
rel="noopener noreferrer" | |||
target="_blank"> | |||
SonarSource | |||
</a> | |||
, the company that develops and promotes open source{' '} | |||
<a | |||
className="sc-footer-link sc-footer-copy-link" | |||
href="http://sonarqube.org" | |||
rel="noopener noreferrer" | |||
target="_blank"> | |||
SonarQube | |||
</a>{' '} | |||
and{' '} | |||
<a | |||
className="sc-footer-link sc-footer-copy-link" | |||
href="http://sonarlint.org" | |||
rel="noopener noreferrer" | |||
target="_blank"> | |||
SonarLint | |||
</a> | |||
. | |||
</div> | |||
</div> | |||
</footer> | |||
); | |||
} |
@@ -1,85 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2020 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 { getBaseUrl } from 'sonar-ui-common/helpers/urls'; | |||
import { LANGUAGES } from '../utils'; | |||
import SCChevronDownIcon from './SCChevronDownIcon'; | |||
interface State { | |||
height?: number; | |||
open: boolean; | |||
} | |||
export class Languages extends React.PureComponent<{}, State> { | |||
container?: HTMLElement | null; | |||
state: State = { open: false }; | |||
componentDidUpdate() { | |||
if (this.container && this.container.clientHeight !== this.container.scrollHeight) { | |||
this.setState({ height: this.container.scrollHeight }); | |||
} | |||
} | |||
handleOpenClick = (event: React.MouseEvent<HTMLAnchorElement>) => { | |||
event.preventDefault(); | |||
event.stopPropagation(); | |||
this.setState({ height: this.container ? this.container.clientHeight : undefined, open: true }); | |||
}; | |||
render() { | |||
const { open } = this.state; | |||
const languages = open ? LANGUAGES : LANGUAGES.slice(0, 10); | |||
return ( | |||
<div className="position-relative"> | |||
<div className="sc-languages-container clearfix"> | |||
<div className="sc-section sc-columns"> | |||
<div className="sc-column-full"> | |||
<h3 className="sc-big-spacer-bottom">SonarCloud speaks your language</h3> | |||
<ul | |||
className="sc-languages-list" | |||
ref={node => (this.container = node)} | |||
style={{ height: this.state.height }}> | |||
{languages.map(language => ( | |||
<li key={language.name}> | |||
<img | |||
alt={language.name} | |||
src={`${getBaseUrl()}/images/languages/${language.file}`} | |||
width={language.width} | |||
/> | |||
</li> | |||
))} | |||
</ul> | |||
{!open && ( | |||
<a | |||
className="bt bt-large bt-nav bt-orange2 display-inline-flex-center" | |||
href="#" | |||
onClick={this.handleOpenClick}> | |||
See All Languages | |||
<SCChevronDownIcon className="little-spacer-left" /> | |||
</a> | |||
)} | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
); | |||
} | |||
} |
@@ -1,48 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2020 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. | |||
*/ | |||
.sc-login-button { | |||
display: inline-block; | |||
background-color: var(--sonarcloudBlack100); | |||
border: 1px solid var(--sonarcloudBlack300) !important; | |||
color: var(--sonarcloudBlack800); | |||
margin: 10px 12px auto auto; | |||
font-size: 18px; | |||
font-weight: 700; | |||
padding: 0 15px; | |||
border-radius: 4px; | |||
height: 44px; | |||
line-height: 44px; | |||
white-space: nowrap; | |||
transition: all 0.2s ease; | |||
box-shadow: 0 1px 2px rgba(7, 7, 6, 0.1); | |||
} | |||
.sc-login-button > img { | |||
height: 25px; | |||
padding-top: 10px; | |||
margin-right: 12px; | |||
margin-bottom: 1px; | |||
} | |||
.sc-login-button:hover { | |||
box-shadow: 0 10px 20px rgba(7, 7, 6, 0.2); | |||
transform: translate(0, -2px); | |||
color: var(--sonarcloudBlack800); | |||
} |
@@ -1,41 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2020 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 { getBaseUrl } from 'sonar-ui-common/helpers/urls'; | |||
import './LoginButtons.css'; | |||
export default function LoginButtons() { | |||
return ( | |||
<div> | |||
<a className="sc-login-button" href={`${getBaseUrl()}/sessions/init/github`}> | |||
<img alt="" height="25" src={`${getBaseUrl()}/images/sonarcloud/github.svg`} /> | |||
GitHub | |||
</a> | |||
<a className="sc-login-button" href={`${getBaseUrl()}/sessions/init/bitbucket`}> | |||
<img alt="" height="25" src={`${getBaseUrl()}/images/sonarcloud/bitbucket.svg`} /> | |||
Bitbucket | |||
</a> | |||
<a className="sc-login-button" href={`${getBaseUrl()}/sessions/init/microsoft`}> | |||
<img alt="" height="25" src={`${getBaseUrl()}/images/sonarcloud/azure.svg`} /> | |||
Azure DevOps | |||
</a> | |||
</div> | |||
); | |||
} |
@@ -1,139 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2020 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. | |||
*/ | |||
.sc-page .navbar { | |||
position: fixed; | |||
background-color: #fff; | |||
width: 100%; | |||
display: block; | |||
transition: top 0.3s; | |||
height: 60px; | |||
line-height: 60px; | |||
z-index: 10; | |||
border-bottom: 1px solid var(--sonarcloudBlack300); | |||
top: -100px; | |||
} | |||
.sc-page .navbar-inner { | |||
position: relative; | |||
} | |||
.top-navbar { | |||
height: 60px; | |||
line-height: 60px; | |||
} | |||
.top-navbar img { | |||
height: 48px; | |||
vertical-align: middle; | |||
margin-top: 12px; | |||
} | |||
.sc-page .navbar img { | |||
height: 40px; | |||
vertical-align: middle; | |||
} | |||
.top-navbar ul, | |||
.sc-page .navbar ul { | |||
float: right; | |||
} | |||
.top-navbar ul { | |||
margin-top: 10px; | |||
} | |||
.top-navbar ul li, | |||
.sc-page .navbar ul li { | |||
display: inline-block; | |||
margin: 0 0 0 30px; | |||
line-height: 30px; | |||
border-color: #fff; | |||
transition: all 0.2s ease; | |||
} | |||
.sc-page .navbar ul li { | |||
line-height: 54px; | |||
} | |||
.top-navbar ul li a, | |||
.sc-page .navbar ul li a { | |||
font-family: var(--sonarcloudFontFamily); | |||
color: var(--sonarcloudBlack800); | |||
font-weight: 700; | |||
display: inline-block; | |||
} | |||
.sc-page .navbar ul li.outline { | |||
line-height: 30px; | |||
} | |||
.top-navbar ul li a { | |||
color: #fff; | |||
} | |||
.top-navbar ul li.outline a, | |||
.sc-page .navbar ul li.outline a { | |||
height: 30px; | |||
border: 1px solid var(--sonarcloudBlack800); | |||
padding: 0 10px; | |||
border-radius: 3px; | |||
transition: all 0.2s ease; | |||
} | |||
.top-navbar ul li.outline a { | |||
border: 1px solid #fff; | |||
} | |||
.top-navbar ul li a.active, | |||
.top-navbar ul li a:hover { | |||
border-bottom: 2px solid #fff; | |||
} | |||
.sc-page .navbar ul li a.active, | |||
.sc-page .navbar ul li a:hover { | |||
border-bottom: 2px solid var(--sonarcloudOrange500); | |||
color: var(--sonarcloudOrange500); | |||
} | |||
.top-navbar ul li.outline a:hover, | |||
.sc-page .navbar ul li.outline a:hover { | |||
border-bottom-width: 1px; | |||
background: var(--sonarcloudOrange500); | |||
color: #fff; | |||
} | |||
.top-navbar ul li.outline:hover a { | |||
background: #fff; | |||
color: var(--sonarcloudOrange500); | |||
} | |||
.sc-page .navbar ul li.outline:hover a { | |||
border-color: var(--sonarcloudOrange500); | |||
} | |||
.sc-page .top-navbar a, | |||
.sc-page .navbar a { | |||
border-bottom: 2px solid rgba(255, 255, 255, 0); | |||
transition: border-color 0.2s ease; | |||
} | |||
.sc-page .navbar-limited > a { | |||
border: none !important; | |||
} |
@@ -1,110 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2020 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 { throttle } from 'lodash'; | |||
import * as React from 'react'; | |||
import NavBar from 'sonar-ui-common/components/ui/NavBar'; | |||
import { getBaseUrl } from 'sonar-ui-common/helpers/urls'; | |||
import './NavBars.css'; | |||
interface Props { | |||
onPricingPage?: boolean; | |||
} | |||
interface State { | |||
top: number; | |||
} | |||
export class FixedNavBar extends React.PureComponent<Props, State> { | |||
constructor(props: Props) { | |||
super(props); | |||
this.state = { top: -100 }; | |||
this.handleScroll = throttle(this.handleScroll, 10); | |||
} | |||
componentDidMount() { | |||
document.addEventListener('scroll', this.handleScroll, true); | |||
} | |||
componentWillUnmount() { | |||
document.removeEventListener('scroll', this.handleScroll, true); | |||
} | |||
handleScroll = () => { | |||
const scrollTop = | |||
document.body.scrollTop || | |||
(document.documentElement ? document.documentElement.scrollTop : 0); | |||
if (scrollTop > 100) { | |||
this.setState({ top: 0 }); | |||
} else { | |||
this.setState({ top: -100 }); | |||
} | |||
}; | |||
render() { | |||
return ( | |||
<NavBar height={60} top={this.state.top}> | |||
<NavBarLinks onPricingPage={this.props.onPricingPage} /> | |||
</NavBar> | |||
); | |||
} | |||
} | |||
interface TopNavBarProps { | |||
onPricingPage?: boolean; | |||
whiteLogo?: boolean; | |||
} | |||
export function TopNavBar({ onPricingPage, whiteLogo }: TopNavBarProps) { | |||
return ( | |||
<div className="top-navbar"> | |||
<div className="navbar-limited"> | |||
<NavBarLinks onPricingPage={onPricingPage} whiteLogo={whiteLogo} /> | |||
</div> | |||
</div> | |||
); | |||
} | |||
interface NavBarLinksProps { | |||
onPricingPage?: boolean; | |||
whiteLogo?: boolean; | |||
} | |||
function NavBarLinks({ onPricingPage, whiteLogo }: NavBarLinksProps) { | |||
return ( | |||
<> | |||
<a href={`${getBaseUrl()}/`}> | |||
<img | |||
alt="SonarCloud" | |||
src={`${getBaseUrl()}/images/sonarcloud-logo-${whiteLogo ? 'white' : 'black'}.svg`} | |||
/> | |||
</a> | |||
<ul> | |||
<li> | |||
<a className={onPricingPage ? 'active' : ''} href={`${getBaseUrl()}/about/pricing`}> | |||
Pricing | |||
</a> | |||
</li> | |||
<li className="outline"> | |||
<a href={`${getBaseUrl()}/sessions/new`}>Log in</a> | |||
</li> | |||
</ul> | |||
</> | |||
); | |||
} |
@@ -1,45 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2020 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 Pricing() { | |||
return ( | |||
<div className="sc-pricing sc-narrow-container"> | |||
<div className="sc-pricing-block"> | |||
<h3 className="sc-pricing-title">Open Source Projects</h3> | |||
<span className="sc-pricing-small"> </span> | |||
<span className="sc-pricing-price">Free</span> | |||
</div> | |||
<div className="sc-pricing-block"> | |||
<h3 className="sc-pricing-title">Private Projects</h3> | |||
<span className="sc-pricing-small">14 days free trial</span> | |||
<strong> | |||
From <span className="sc-pricing-price">10€</span> | |||
/mo | |||
</strong> | |||
<Link className="sc-news-link" to="/about/pricing/"> | |||
see prices | |||
</Link> | |||
</div> | |||
</div> | |||
); | |||
} |
@@ -1,32 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2020 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 Icon, { IconProps } from 'sonar-ui-common/components/icons/Icon'; | |||
export default function SCChevronDownIcon({ className, fill = 'currentColor', size }: IconProps) { | |||
return ( | |||
<Icon className={className} size={size} viewBox="0 0 24 24"> | |||
<path | |||
d="M4 9a1 1 0 0 1 .29-.71 1 1 0 0 1 1.42 0l6.29 6.3 6.29-6.3a1.0041 1.0041 0 0 1 1.42 1.42l-7 7a1 1 0 0 1-1.42 0l-7-7A1 1 0 0 1 4 9z" | |||
style={{ fill }} | |||
/> | |||
</Icon> | |||
); | |||
} |
@@ -1,63 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2020 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 { addWhitePageClass, removeWhitePageClass } from 'sonar-ui-common/helpers/pages'; | |||
import GlobalContainer from '../../../../app/components/GlobalContainer'; | |||
import { getCurrentUser, getMyOrganizations, Store } from '../../../../store/rootReducer'; | |||
import Footer from './Footer'; | |||
interface StateProps { | |||
currentUser: T.CurrentUser; | |||
userOrganizations?: T.Organization[]; | |||
} | |||
interface OwnProps { | |||
children: (props: StateProps) => React.ReactNode; | |||
} | |||
type Props = StateProps & WithRouterProps & OwnProps; | |||
class SQPageContainer extends React.Component<Props> { | |||
componentDidMount() { | |||
addWhitePageClass(); | |||
} | |||
componentWillUnmount() { | |||
removeWhitePageClass(); | |||
} | |||
render() { | |||
const { children, currentUser, userOrganizations } = this.props; | |||
return ( | |||
<GlobalContainer footer={<Footer />} location={this.props.location}> | |||
{children({ currentUser, userOrganizations })} | |||
</GlobalContainer> | |||
); | |||
} | |||
} | |||
const mapStateToProps = (state: Store) => ({ | |||
currentUser: getCurrentUser(state), | |||
userOrganizations: getMyOrganizations(state) | |||
}); | |||
export default withRouter<OwnProps>(connect(mapStateToProps)(SQPageContainer)); |
@@ -1,32 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2020 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program is free software; you can redistribute it and/or | |||
* modify it under the terms of the GNU Lesser General Public | |||
* License as published by the Free Software Foundation; either | |||
* version 3 of the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||
* Lesser General Public License for more details. | |||
* | |||
* You should have received a copy of the GNU Lesser General Public License | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import * as React from 'react'; | |||
import { Link } from 'react-router'; | |||
export default function SQStartUsing() { | |||
return ( | |||
<div className="sc-child-start-using"> | |||
<div className="sc-child-start-using-text">Start using SonarCloud</div> | |||
<Link className="sc-orange-button sc-child-start-using-link" to="/sessions/new"> | |||
Sign up now | |||
</Link> | |||
</div> | |||
); | |||
} |
@@ -1,52 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2020 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 | |||
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> | |||
); | |||
} |
@@ -1,41 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2020 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 ChevronRightIcon from 'sonar-ui-common/components/icons/ChevronRightIcon'; | |||
export default function StartUsing() { | |||
return ( | |||
<div className="sc-narrow-container text-center"> | |||
<Link className="sc-orange-button sc-start" to="/sessions/new"> | |||
Start using SonarCloud <ChevronRightIcon className="spacer-left" /> | |||
</Link> | |||
<div className="big-spacer-top"> | |||
<a | |||
className="text-muted" | |||
href="https://community.sonarsource.com/c/help/sc" | |||
rel="noopener noreferrer" | |||
target="_blank"> | |||
Need help? | |||
</a> | |||
</div> | |||
</div> | |||
); | |||
} |
@@ -1,46 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2020 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. | |||
*/ | |||
.sc-stats { | |||
display: flex; | |||
justify-content: space-around; | |||
} | |||
.sc-stat-card { | |||
flex: 0 0 244px; | |||
display: flex; | |||
align-items: center; | |||
border: 1px solid var(--sonarcloudBlack300); | |||
border-radius: 3px; | |||
} | |||
.sc-stat-icon { | |||
background-color: var(--sonarcloudBlack200); | |||
padding: 32px 20px; | |||
} | |||
.sc-stat-content { | |||
padding: 0 20px; | |||
text-align: left; | |||
} | |||
.sc-page .sc-stat-content span { | |||
font-family: var(--sonarcloudFontFamily); | |||
font-weight: 500; | |||
} |
@@ -1,113 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2020 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 { throttle } from 'lodash'; | |||
import * as React from 'react'; | |||
import CountUp from 'react-countup'; | |||
import { translate } from 'sonar-ui-common/helpers/l10n'; | |||
import { formatMeasure } from 'sonar-ui-common/helpers/measures'; | |||
import { getBaseUrl } from 'sonar-ui-common/helpers/urls'; | |||
import './Statistics.css'; | |||
interface Statistic { | |||
icon: string; | |||
text: string; | |||
value: number; | |||
} | |||
interface Props { | |||
statistics: Statistic[]; | |||
} | |||
export default function Statistics({ statistics }: Props) { | |||
return ( | |||
<div className="sc-stats"> | |||
{statistics.map(stat => ( | |||
<StatisticCard key={stat.icon} statistic={stat} /> | |||
))} | |||
</div> | |||
); | |||
} | |||
interface StatisticCardProps { | |||
statistic: Statistic; | |||
} | |||
interface StatisticCardState { | |||
viewable: boolean; | |||
} | |||
export class StatisticCard extends React.PureComponent<StatisticCardProps, StatisticCardState> { | |||
container?: HTMLElement | null; | |||
constructor(props: StatisticCardProps) { | |||
super(props); | |||
this.state = { viewable: false }; | |||
this.handleScroll = throttle(this.handleScroll, 10); | |||
} | |||
componentDidMount() { | |||
document.addEventListener('scroll', this.handleScroll, true); | |||
} | |||
componentWillUnmount() { | |||
document.removeEventListener('scroll', this.handleScroll, true); | |||
} | |||
handleScroll = () => { | |||
if (this.container) { | |||
const rect = this.container.getBoundingClientRect(); | |||
const windowHeight = | |||
window.innerHeight || | |||
(document.documentElement ? document.documentElement.clientHeight : 0); | |||
if (rect.top <= windowHeight && rect.top + rect.height >= 0) { | |||
this.setState({ viewable: true }); | |||
} | |||
} | |||
}; | |||
render() { | |||
const { statistic } = this.props; | |||
const formattedString = formatMeasure(statistic.value, 'SHORT_INT', { | |||
roundingFunc: Math.floor | |||
}); | |||
const value = parseFloat(formattedString); | |||
let suffix = formattedString.replace(value.toString(), ''); | |||
if (suffix === translate('short_number_suffix.g')) { | |||
suffix = ' ' + translate('billion'); | |||
} | |||
return ( | |||
<div className="sc-stat-card sc-big-spacer-top" ref={node => (this.container = node)}> | |||
<div className="sc-stat-icon"> | |||
<img alt="" height={28} src={`${getBaseUrl()}/images/sonarcloud/${statistic.icon}.svg`} /> | |||
</div> | |||
<div className="sc-stat-content"> | |||
{this.state.viewable && ( | |||
<CountUp delay={0} duration={4} end={value} suffix={suffix}> | |||
{(data: { countUpRef?: React.RefObject<HTMLHeadingElement> }) => ( | |||
<h5 ref={data.countUpRef}>0</h5> | |||
)} | |||
</CountUp> | |||
)} | |||
<span>{statistic.text}</span> | |||
</div> | |||
</div> | |||
); | |||
} | |||
} |
@@ -1,26 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2020 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'; | |||
export default class CountUp extends React.Component<any> { | |||
render() { | |||
return <div />; | |||
} | |||
} |
@@ -1,162 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2020 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 { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import { click } from 'sonar-ui-common/helpers/testUtils'; | |||
import FeaturedProjects, { ProjectCard, ProjectIssues } from '../FeaturedProjects'; | |||
const PROJECTS = [ | |||
{ | |||
key: 'sonarsource-jfrog.simple-js-php-project', | |||
avatarUrl: null, | |||
organizationKey: 'sonarsource-jfrog', | |||
organizationName: 'SonarSource & JFrog', | |||
name: 'Simple JS & PHP project', | |||
bugs: 0, | |||
codeSmells: 7, | |||
coverage: 9.7, | |||
duplications: 56.2, | |||
gateStatus: 'OK', | |||
languages: ['js', 'php'], | |||
maintainabilityRating: 1, | |||
ncloc: 324, | |||
reliabilityRating: 1, | |||
securityRating: 1, | |||
vulnerabilities: 0 | |||
}, | |||
{ | |||
key: 'example-js', | |||
avatarUrl: null, | |||
organizationKey: 'autoscan', | |||
organizationName: 'AutoScan', | |||
name: 'example-js', | |||
bugs: 13, | |||
codeSmells: 5, | |||
coverage: 0, | |||
duplications: 0, | |||
gateStatus: 'OK', | |||
languages: ['go', 'js', 'php', 'py'], | |||
maintainabilityRating: 1, | |||
ncloc: 80, | |||
reliabilityRating: 1, | |||
securityRating: 1, | |||
vulnerabilities: 0 | |||
}, | |||
{ | |||
key: 'example-js-2', | |||
avatarUrl: null, | |||
organizationKey: 'autoscan', | |||
organizationName: 'AutoScan', | |||
name: 'example-js', | |||
bugs: 13, | |||
codeSmells: 5, | |||
coverage: 0, | |||
duplications: 0, | |||
gateStatus: 'OK', | |||
languages: ['go', 'js', 'php', 'py'], | |||
maintainabilityRating: 1, | |||
ncloc: 80, | |||
reliabilityRating: 1, | |||
securityRating: 1, | |||
vulnerabilities: 0 | |||
}, | |||
{ | |||
key: 'example-js-3', | |||
avatarUrl: null, | |||
organizationKey: 'autoscan', | |||
organizationName: 'AutoScan', | |||
name: 'example-js', | |||
bugs: 13, | |||
codeSmells: 5, | |||
coverage: 0, | |||
duplications: 0, | |||
gateStatus: 'OK', | |||
languages: ['go', 'js', 'php', 'py'], | |||
maintainabilityRating: 1, | |||
ncloc: 80, | |||
reliabilityRating: 1, | |||
securityRating: 1, | |||
vulnerabilities: 0 | |||
}, | |||
{ | |||
key: 'example-js-4', | |||
avatarUrl: null, | |||
organizationKey: 'autoscan', | |||
organizationName: 'AutoScan', | |||
name: 'example-js', | |||
bugs: 13, | |||
codeSmells: 5, | |||
coverage: 0, | |||
duplications: 0, | |||
gateStatus: 'OK', | |||
languages: ['go', 'js', 'php', 'py'], | |||
maintainabilityRating: 1, | |||
ncloc: 80, | |||
reliabilityRating: 1, | |||
securityRating: 1, | |||
vulnerabilities: 0 | |||
} | |||
]; | |||
it('should render ProjectIssues correctly', () => { | |||
expect( | |||
shallow(<ProjectIssues metric={5} metricKey="foo" ratingMetric={20} viewable={true} />) | |||
).toMatchSnapshot(); | |||
expect( | |||
shallow(<ProjectIssues metric={15000} metricKey="foo" ratingMetric={20} viewable={true} />) | |||
).toMatchSnapshot(); | |||
}); | |||
it('should render ProjectCard correctly', () => { | |||
expect( | |||
shallow(<ProjectCard order={1} project={PROJECTS[0]} viewable={true} />) | |||
).toMatchSnapshot(); | |||
}); | |||
it('should render ProjectCard correctly when there is no coverage', () => { | |||
expect( | |||
shallow( | |||
<ProjectCard order={1} project={{ ...PROJECTS[0], coverage: undefined }} viewable={true} /> | |||
) | |||
.find('li') | |||
.first() | |||
).toMatchSnapshot(); | |||
}); | |||
it('should render correctly', () => { | |||
const wrapper = shallow(<FeaturedProjects projects={PROJECTS} />); | |||
expect(wrapper).toMatchSnapshot(); | |||
}); | |||
it('should cycle through projects', () => { | |||
const wrapper = shallow<FeaturedProjects>(<FeaturedProjects projects={PROJECTS} />); | |||
expect(wrapper.state().slides.map((slide: any) => slide.order)).toEqual([0, 1, 2, 3]); | |||
click(wrapper.find('.js-next')); | |||
expect(wrapper.state().slides.map((slide: any) => slide.order)).toEqual([3, 0, 1, 2]); | |||
click(wrapper.find('.js-next')); | |||
click(wrapper.find('.js-next')); | |||
expect(wrapper.state().slides.map((slide: any) => slide.order)).toEqual([1, 2, 3, 0]); | |||
click(wrapper.find('.js-prev')); | |||
click(wrapper.find('.js-prev')); | |||
expect(wrapper.state().slides.map((slide: any) => slide.order)).toEqual([3, 0, 1, 2]); | |||
}); |
@@ -1,26 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2020 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 { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import Footer from '../Footer'; | |||
it('should render', () => { | |||
expect(shallow(<Footer />)).toBeDefined(); | |||
}); |
@@ -1,26 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2020 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 { shallow } from 'enzyme'; | |||
import * as React from 'react'; | |||
import LoginButtons from '../LoginButtons'; | |||
it('should render', () => { | |||
expect(shallow(<LoginButtons />)).toMatchSnapshot(); | |||
}); |
@@ -1,57 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2020 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 { shallow, ShallowWrapper } from 'enzyme'; | |||
import * as React from 'react'; | |||
import Statistics, { StatisticCard } from '../Statistics'; | |||
const STATISTICS = { icon: 'stat-icon', text: 'my stat', value: 26666 }; | |||
it('should render', () => { | |||
expect(shallow(<Statistics statistics={[STATISTICS]} />)).toMatchSnapshot(); | |||
}); | |||
it('should render StatisticCard', () => { | |||
expect(shallowRender()).toMatchSnapshot(); | |||
}); | |||
it('should render big numbers correctly', () => { | |||
function checkCountUp(wrapper: ShallowWrapper, end: number, suffix: string) { | |||
expect(wrapper.find('CountUp').prop('end')).toBe(end); | |||
expect(wrapper.find('CountUp').prop('suffix')).toBe(suffix); | |||
} | |||
checkCountUp( | |||
shallowRender({ statistic: { ...STATISTICS, value: 999003632 } }), | |||
999, | |||
'short_number_suffix.m' | |||
); | |||
checkCountUp( | |||
shallowRender({ statistic: { ...STATISTICS, value: 999861538 } }), | |||
999, | |||
'short_number_suffix.m' | |||
); | |||
checkCountUp(shallowRender({ statistic: { ...STATISTICS, value: 1100021731 } }), 1.1, ' billion'); | |||
}); | |||
function shallowRender(props: Partial<StatisticCard['props']> = {}) { | |||
const wrapper = shallow(<StatisticCard statistic={STATISTICS} {...props} />); | |||
wrapper.setState({ viewable: true }); | |||
return wrapper; | |||
} |
@@ -1,354 +0,0 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render ProjectCard correctly 1`] = ` | |||
<div | |||
className="sc-project-card-container" | |||
style={ | |||
Object { | |||
"order": 1, | |||
} | |||
} | |||
> | |||
<a | |||
className="sc-project-card" | |||
href="/dashboard?id=sonarsource-jfrog.simple-js-php-project" | |||
> | |||
<div | |||
className="sc-project-card-header" | |||
> | |||
<OrganizationAvatar | |||
className="no-border spacer-bottom" | |||
organization={ | |||
Object { | |||
"avatar": undefined, | |||
"name": "SonarSource & JFrog", | |||
} | |||
} | |||
/> | |||
<p | |||
className="sc-project-card-limited" | |||
title="SonarSource & JFrog" | |||
> | |||
SonarSource & JFrog | |||
</p> | |||
<h5 | |||
className="sc-project-card-limited big-spacer-bottom" | |||
title="Simple JS & PHP project" | |||
> | |||
Simple JS & PHP project | |||
</h5> | |||
</div> | |||
<ul | |||
className="sc-project-card-measures" | |||
> | |||
<ProjectIssues | |||
metric={0} | |||
metricKey="bugs" | |||
ratingMetric={1} | |||
viewable={true} | |||
/> | |||
<ProjectIssues | |||
metric={0} | |||
metricKey="vulnerabilities" | |||
ratingMetric={1} | |||
viewable={true} | |||
/> | |||
<ProjectIssues | |||
metric={7} | |||
metricKey="code_smells" | |||
ratingMetric={1} | |||
viewable={true} | |||
/> | |||
<li> | |||
<span> | |||
overview.metric.coverage | |||
</span> | |||
<div> | |||
<CountUp | |||
decimal="." | |||
decimals={1} | |||
delay={0} | |||
duration={4} | |||
end={9.7} | |||
suffix="%" | |||
> | |||
<Component /> | |||
</CountUp> | |||
<CoverageRating | |||
value={9.7} | |||
/> | |||
</div> | |||
</li> | |||
<li> | |||
<span> | |||
overview.metric.duplications | |||
</span> | |||
<div> | |||
<CountUp | |||
decimal="." | |||
decimals={1} | |||
delay={0} | |||
duration={4} | |||
end={56.2} | |||
suffix="%" | |||
> | |||
<Component /> | |||
</CountUp> | |||
<DuplicationsRating | |||
value={56.2} | |||
/> | |||
</div> | |||
</li> | |||
</ul> | |||
<div | |||
className="sc-mention text-left big-spacer-top" | |||
> | |||
324 | |||
lines of code / | |||
<Connect(ProjectCardLanguages) | |||
className="display-inline-block" | |||
distribution="js;php" | |||
/> | |||
</div> | |||
</a> | |||
</div> | |||
`; | |||
exports[`should render ProjectCard correctly when there is no coverage 1`] = ` | |||
<li> | |||
<span> | |||
overview.metric.coverage | |||
</span> | |||
<span | |||
className="huge little-spacer-right" | |||
> | |||
— | |||
</span> | |||
</li> | |||
`; | |||
exports[`should render ProjectIssues correctly 1`] = ` | |||
<li> | |||
<span> | |||
overview.metric.foo | |||
</span> | |||
<div> | |||
<CountUp | |||
delay={0} | |||
duration={4} | |||
end={5} | |||
suffix="" | |||
> | |||
<Component /> | |||
</CountUp> | |||
<Rating | |||
value={20} | |||
/> | |||
</div> | |||
</li> | |||
`; | |||
exports[`should render ProjectIssues correctly 2`] = ` | |||
<li> | |||
<span> | |||
overview.metric.foo | |||
</span> | |||
<div> | |||
<CountUp | |||
delay={0} | |||
duration={4} | |||
end={15} | |||
suffix="short_number_suffix.k" | |||
> | |||
<Component /> | |||
</CountUp> | |||
<Rating | |||
value={20} | |||
/> | |||
</div> | |||
</li> | |||
`; | |||
exports[`should render correctly 1`] = ` | |||
<div | |||
className="sc-featured-projects sc-big-spacer-bottom" | |||
> | |||
<button | |||
className="js-prev sc-project-button" | |||
onClick={[Function]} | |||
type="button" | |||
> | |||
<img | |||
alt="" | |||
src="/images/sonarcloud/chevron-left.svg" | |||
/> | |||
</button> | |||
<div | |||
className="sc-featured-projects-container" | |||
> | |||
<div | |||
className="sc-featured-projects-inner ready" | |||
> | |||
<ProjectCard | |||
key="example-js-4" | |||
order={0} | |||
project={ | |||
Object { | |||
"avatarUrl": null, | |||
"bugs": 13, | |||
"codeSmells": 5, | |||
"coverage": 0, | |||
"duplications": 0, | |||
"gateStatus": "OK", | |||
"key": "example-js-4", | |||
"languages": Array [ | |||
"go", | |||
"js", | |||
"php", | |||
"py", | |||
], | |||
"maintainabilityRating": 1, | |||
"name": "example-js", | |||
"ncloc": 80, | |||
"organizationKey": "autoscan", | |||
"organizationName": "AutoScan", | |||
"reliabilityRating": 1, | |||
"securityRating": 1, | |||
"vulnerabilities": 0, | |||
} | |||
} | |||
viewable={false} | |||
/> | |||
<ProjectCard | |||
key="sonarsource-jfrog.simple-js-php-project" | |||
order={1} | |||
project={ | |||
Object { | |||
"avatarUrl": null, | |||
"bugs": 0, | |||
"codeSmells": 7, | |||
"coverage": 9.7, | |||
"duplications": 56.2, | |||
"gateStatus": "OK", | |||
"key": "sonarsource-jfrog.simple-js-php-project", | |||
"languages": Array [ | |||
"js", | |||
"php", | |||
], | |||
"maintainabilityRating": 1, | |||
"name": "Simple JS & PHP project", | |||
"ncloc": 324, | |||
"organizationKey": "sonarsource-jfrog", | |||
"organizationName": "SonarSource & JFrog", | |||
"reliabilityRating": 1, | |||
"securityRating": 1, | |||
"vulnerabilities": 0, | |||
} | |||
} | |||
viewable={false} | |||
/> | |||
<ProjectCard | |||
key="example-js" | |||
order={2} | |||
project={ | |||
Object { | |||
"avatarUrl": null, | |||
"bugs": 13, | |||
"codeSmells": 5, | |||
"coverage": 0, | |||
"duplications": 0, | |||
"gateStatus": "OK", | |||
"key": "example-js", | |||
"languages": Array [ | |||
"go", | |||
"js", | |||
"php", | |||
"py", | |||
], | |||
"maintainabilityRating": 1, | |||
"name": "example-js", | |||
"ncloc": 80, | |||
"organizationKey": "autoscan", | |||
"organizationName": "AutoScan", | |||
"reliabilityRating": 1, | |||
"securityRating": 1, | |||
"vulnerabilities": 0, | |||
} | |||
} | |||
viewable={false} | |||
/> | |||
<ProjectCard | |||
key="example-js-2" | |||
order={3} | |||
project={ | |||
Object { | |||
"avatarUrl": null, | |||
"bugs": 13, | |||
"codeSmells": 5, | |||
"coverage": 0, | |||
"duplications": 0, | |||
"gateStatus": "OK", | |||
"key": "example-js-2", | |||
"languages": Array [ | |||
"go", | |||
"js", | |||
"php", | |||
"py", | |||
], | |||
"maintainabilityRating": 1, | |||
"name": "example-js", | |||
"ncloc": 80, | |||
"organizationKey": "autoscan", | |||
"organizationName": "AutoScan", | |||
"reliabilityRating": 1, | |||
"securityRating": 1, | |||
"vulnerabilities": 0, | |||
} | |||
} | |||
viewable={false} | |||
/> | |||
<ProjectCard | |||
key="example-js-3" | |||
order={4} | |||
project={ | |||
Object { | |||
"avatarUrl": null, | |||
"bugs": 13, | |||
"codeSmells": 5, | |||
"coverage": 0, | |||
"duplications": 0, | |||
"gateStatus": "OK", | |||
"key": "example-js-3", | |||
"languages": Array [ | |||
"go", | |||
"js", | |||
"php", | |||
"py", | |||
], | |||
"maintainabilityRating": 1, | |||
"name": "example-js", | |||
"ncloc": 80, | |||
"organizationKey": "autoscan", | |||
"organizationName": "AutoScan", | |||
"reliabilityRating": 1, | |||
"securityRating": 1, | |||
"vulnerabilities": 0, | |||
} | |||
} | |||
viewable={false} | |||
/> | |||
</div> | |||
</div> | |||
<button | |||
className="js-next sc-project-button" | |||
onClick={[Function]} | |||
type="button" | |||
> | |||
<img | |||
alt="" | |||
src="/images/sonarcloud/chevron-right.svg" | |||
/> | |||
</button> | |||
</div> | |||
`; |
@@ -1,39 +0,0 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render 1`] = ` | |||
<div> | |||
<a | |||
className="sc-login-button" | |||
href="/sessions/init/github" | |||
> | |||
<img | |||
alt="" | |||
height="25" | |||
src="/images/sonarcloud/github.svg" | |||
/> | |||
GitHub | |||
</a> | |||
<a | |||
className="sc-login-button" | |||
href="/sessions/init/bitbucket" | |||
> | |||
<img | |||
alt="" | |||
height="25" | |||
src="/images/sonarcloud/bitbucket.svg" | |||
/> | |||
Bitbucket | |||
</a> | |||
<a | |||
className="sc-login-button" | |||
href="/sessions/init/microsoft" | |||
> | |||
<img | |||
alt="" | |||
height="25" | |||
src="/images/sonarcloud/azure.svg" | |||
/> | |||
Azure DevOps | |||
</a> | |||
</div> | |||
`; |
@@ -1,49 +0,0 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render 1`] = ` | |||
<div | |||
className="sc-stats" | |||
> | |||
<StatisticCard | |||
key="stat-icon" | |||
statistic={ | |||
Object { | |||
"icon": "stat-icon", | |||
"text": "my stat", | |||
"value": 26666, | |||
} | |||
} | |||
/> | |||
</div> | |||
`; | |||
exports[`should render StatisticCard 1`] = ` | |||
<div | |||
className="sc-stat-card sc-big-spacer-top" | |||
> | |||
<div | |||
className="sc-stat-icon" | |||
> | |||
<img | |||
alt="" | |||
height={28} | |||
src="/images/sonarcloud/stat-icon.svg" | |||
/> | |||
</div> | |||
<div | |||
className="sc-stat-content" | |||
> | |||
<CountUp | |||
delay={0} | |||
duration={4} | |||
end={26} | |||
suffix="short_number_suffix.k" | |||
> | |||
<Component /> | |||
</CountUp> | |||
<span> | |||
my stat | |||
</span> | |||
</div> | |||
</div> | |||
`; |
@@ -1,502 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2020 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 url('https://fonts.googleapis.com/css?family=Roboto:300,400,500,700,900'); | |||
.sc-page, | |||
.sc-page span, | |||
.sc-page li, | |||
.sc-page p { | |||
font-family: var(--baseFontFamily); | |||
font-size: 15px; | |||
} | |||
.sc-page h1, | |||
.sc-page h2, | |||
.sc-page h3, | |||
.sc-page h4, | |||
.sc-page h5, | |||
.sc-page h6 { | |||
font-family: var(--sonarcloudFontFamily); | |||
color: var(--sonarcloudBlack800); | |||
} | |||
.sc-page h1, | |||
.sc-page h2, | |||
.sc-page h3, | |||
.sc-page h4, | |||
.sc-page h5 { | |||
font-weight: 700; | |||
} | |||
.sc-page h1 { | |||
line-height: 62px; | |||
font-size: 60px; | |||
font-weight: 900; | |||
} | |||
.sc-page h2 { | |||
line-height: 50px; | |||
font-size: 44px; | |||
} | |||
.sc-page h3 { | |||
line-height: 42px; | |||
font-size: 36px; | |||
} | |||
.sc-page h4 { | |||
line-height: 38px; | |||
font-size: 32px; | |||
} | |||
.sc-page h5 { | |||
line-height: 32px; | |||
font-size: 26px; | |||
} | |||
.sc-page h6 { | |||
line-height: 26px; | |||
font-size: 21px; | |||
} | |||
.sc-page p { | |||
line-height: 21px; | |||
} | |||
.sc-page a { | |||
border-bottom: 1px solid rgba(255, 255, 255, 0.3); | |||
} | |||
.sc-page a:hover { | |||
border-bottom: 1px solid var(--sonarcloudBlack100); | |||
} | |||
.sc-section { | |||
position: relative; | |||
max-width: 1040px; | |||
padding: 0px 20px; | |||
margin-left: auto; | |||
margin-right: auto; | |||
overflow: hidden; | |||
} | |||
.sc-mention, | |||
.sc-mention span { | |||
font-size: 12px; | |||
font-style: italic; | |||
} | |||
.sc-light-weight { | |||
font-weight: 300 !important; | |||
} | |||
.sc-regular-weight { | |||
font-weight: 400 !important; | |||
} | |||
.sc-medium-weight { | |||
font-weight: 500 !important; | |||
} | |||
.sc-bold-weight { | |||
font-weight: 700 !important; | |||
} | |||
.sc-columns { | |||
display: flex; | |||
justify-content: space-around; | |||
margin: 0 auto 80px; | |||
} | |||
.sc-column-half { | |||
width: 50%; | |||
} | |||
.sc-column-full { | |||
flex-grow: 1; | |||
text-align: center; | |||
} | |||
.sc-column-small { | |||
display: flex; | |||
flex-direction: column; | |||
justify-content: center; | |||
max-width: 38%; | |||
} | |||
.sc-column-medium { | |||
display: flex; | |||
flex-direction: column; | |||
justify-content: top; | |||
max-width: 44%; | |||
} | |||
.sc-column-big { | |||
max-width: 52%; | |||
} | |||
.sc-spacer-bottom { | |||
margin-bottom: 20px; | |||
} | |||
.sc-big-spacer-top { | |||
margin-top: 50px; | |||
} | |||
.sc-big-spacer-bottom { | |||
margin-bottom: 50px; | |||
} | |||
.sc-title-orange { | |||
color: var(--sonarcloudOrange500) !important; | |||
} | |||
.sc-separator { | |||
margin: 20px 0; | |||
width: 42px; | |||
border-top: 1px solid var(--sonarcloudBlack300); | |||
} | |||
.sc-rounded-img { | |||
border-radius: 3px; | |||
box-shadow: 0 3px 40px rgba(0, 0, 0, 0.05); | |||
} | |||
.sc-header-background { | |||
position: absolute; | |||
width: 100%; | |||
min-width: var(--minPageWidth); | |||
z-index: 0; | |||
} | |||
.sc-functionality-background { | |||
position: relative; | |||
width: 100%; | |||
min-width: var(--minPageWidth); | |||
margin-top: -150px; | |||
z-index: 0; | |||
} | |||
.sc-functionality-background-bottom { | |||
margin-top: 0; | |||
} | |||
.sc-background-start { | |||
position: absolute; | |||
background-color: #fdc300; | |||
height: 5px; | |||
width: 50%; | |||
left: 0; | |||
z-index: 0; | |||
} | |||
.sc-background-end { | |||
position: absolute; | |||
background-color: var(--sonarcloudOrange500); | |||
height: 5px; | |||
width: 50%; | |||
right: 0; | |||
z-index: 0; | |||
} | |||
.sc-background-center { | |||
display: flex; | |||
justify-content: center; | |||
overflow: hidden; | |||
} | |||
.sc-background-center img { | |||
flex-grow: 0; | |||
flex-shrink: 0; | |||
z-index: 10; | |||
} | |||
.sc-with-icon, | |||
.sc-with-inline-icon { | |||
display: inline-flex; | |||
align-items: center; | |||
white-space: nowrap; | |||
} | |||
.sc-with-icon img { | |||
height: 16px; | |||
} | |||
.sc-with-inline-icon img { | |||
max-height: 21px; | |||
padding: 0 6px; | |||
} | |||
.sc-functionality-container { | |||
background-color: var(--sonarcloudBlack200); | |||
} | |||
.sc-functionality-container .sc-columns:last-of-type { | |||
margin-bottom: 20px; | |||
} | |||
.sc-languages-container { | |||
padding: 60px 0 0; | |||
background-color: var(--sonarcloudBlack100); | |||
margin-bottom: 90px; | |||
box-sizing: border-box; | |||
} | |||
.sc-languages-container::after { | |||
content: ''; | |||
display: block; | |||
margin: 0 auto; | |||
height: 1px; | |||
background-color: var(--sonarcloudBlack300); | |||
width: 100px; | |||
} | |||
.sc-languages-container .sc-section { | |||
margin-bottom: 60px; | |||
} | |||
.sc-languages-list { | |||
display: flex; | |||
flex-wrap: wrap; | |||
width: 800px; | |||
margin: auto; | |||
transition: height 0.3s ease; | |||
} | |||
.sc-languages-list > li { | |||
display: inline-block; | |||
text-align: center; | |||
margin-bottom: 45px; | |||
line-height: 60px; | |||
width: 160px; | |||
} | |||
.sc-languages-list > li img { | |||
vertical-align: middle; | |||
} | |||
.sc-languages-container a { | |||
color: var(--sonarcloudBlack700); | |||
border-bottom-color: var(--sonarcloudBlack300); | |||
} | |||
.sc-languages-container a:hover { | |||
color: var(--sonarcloudBlack900); | |||
border-bottom-color: var(--sonarcloudBlack900); | |||
} | |||
.sc-languages-container a.show-more { | |||
display: inline-block; | |||
font-weight: 700; | |||
font-family: var(--sonarcloudFontFamily); | |||
line-height: 33px; | |||
font-size: 36px; | |||
border: none; | |||
border-radius: 50%; | |||
height: 50px; | |||
width: 50px; | |||
} | |||
.sc-languages-container a.show-more:hover { | |||
background: var(--sonarcloudBlack700); | |||
color: var(--sonarcloudBlack100); | |||
} | |||
.sc-page .white { | |||
color: var(--sonarcloudBlack100) !important; | |||
} | |||
.sc-page h4 span { | |||
font-family: var(--sonarcloudFontFamily); | |||
font-size: 32px; | |||
} | |||
.sc-pricing-free { | |||
font-family: var(--sonarcloudFontFamily); | |||
box-sizing: border-box; | |||
position: relative; | |||
background: white; | |||
border-radius: 6px; | |||
box-shadow: rgba(0, 0, 0, 0.16) 0 10px 40px; | |||
margin: 40px; | |||
padding: 40px 50px; | |||
width: 880px; | |||
} | |||
.sc-pricing-free ul { | |||
width: 530px; | |||
} | |||
.sc-pricing-free ul li { | |||
font-family: var(--sonarcloudFontFamily); | |||
background: url(/images/sonarcloud/check.svg) no-repeat 0 19px; | |||
background-size: 18px; | |||
font-size: 21px; | |||
line-height: 30px; | |||
padding: 10px 10px 10px 32px; | |||
} | |||
.sc-pricing-privacy ul li, | |||
.sc-pricing-privacy em { | |||
color: var(--sonarcloudBlack100); | |||
} | |||
.sc-pricing-free ul li em { | |||
font-weight: 700; | |||
font-style: normal; | |||
} | |||
.sc-pricing-privacy { | |||
box-sizing: border-box; | |||
position: absolute; | |||
border-radius: 7px; | |||
background: linear-gradient(214deg, var(--sonarcloudBlack700) 0%, var(--sonarcloudBlack800) 100%); | |||
color: var(--sonarcloudBlack100); | |||
width: 350px; | |||
right: -70px; | |||
top: -20px; | |||
padding: 60px 40px 40px; | |||
} | |||
.sc-pricing-privacy ul { | |||
width: 100%; | |||
} | |||
.sc-pricing-privacy a { | |||
color: var(--sonarcloudBlack100); | |||
} | |||
.sc-pricing-privacy .starts-at { | |||
font-family: var(--sonarcloudFontFamily); | |||
font-size: 26px; | |||
font-weight: 700; | |||
line-height: 40px; | |||
} | |||
a.sc-orange-button { | |||
display: inline-block; | |||
background-color: var(--sonarcloudOrange500); | |||
color: var(--sonarcloudBlack100); | |||
font-size: 18px; | |||
font-weight: 700; | |||
padding: 0 15px; | |||
border-radius: 4px; | |||
height: 44px; | |||
line-height: 44px; | |||
box-shadow: none; | |||
border-bottom: none !important; | |||
} | |||
a.sc-orange-button:hover { | |||
color: var(--sonarcloudBlack100); | |||
background-color: var(--sonarcloudOrange700); | |||
} | |||
.pricing-section .faq-title { | |||
font-family: var(--sonarcloudFontFamily); | |||
font-size: 21px; | |||
padding-bottom: 10px; | |||
} | |||
.pricing-section p { | |||
font-size: 15px; | |||
margin-bottom: 35px; | |||
} | |||
.pricing-section p a { | |||
color: var(--sonarcloudOrange500); | |||
border-bottom: 1px solid rgba(253, 106, 0, 0.3); | |||
} | |||
.pricing-section p a:hover { | |||
color: var(--sonarcloudOrange700); | |||
border-bottom: 1px solid var(--sonarcloudOrange700); | |||
} | |||
table.loc-price th { | |||
padding: 0 30px 20px 0; | |||
font-size: 15px; | |||
font-weight: 700; | |||
} | |||
table.loc-price td { | |||
line-height: 30px; | |||
border-bottom: 1px solid var(--sonarcloudBlack300); | |||
} | |||
table.loc-price tr td:first-child { | |||
font-weight: 700; | |||
} | |||
.sc-page .bt { | |||
display: inline-block; | |||
border-radius: 3px; | |||
font-weight: 700; | |||
cursor: pointer; | |||
white-space: nowrap; | |||
transition: all 0.2s ease; | |||
margin-right: 4px; | |||
} | |||
.sc-page .bt-nav { | |||
color: var(--sonarcloudBlack500); | |||
border: none; | |||
background: transparent; | |||
padding: 5px 8px; | |||
} | |||
.sc-page .bt-nav:hover { | |||
color: var(--sonarcloudBlack600); | |||
} | |||
.sc-page .bt-large { | |||
height: 48px; | |||
padding: 0 16px; | |||
font-size: 18px; | |||
} | |||
.sc-page .bt-nav.bt-large { | |||
height: 24px; | |||
padding: 8px 8px; | |||
} | |||
.sc-page .bt-orange2 { | |||
border: 1px solid var(--sonarcloudOrange500); | |||
background-color: transparent; | |||
color: var(--sonarcloudOrange500); | |||
} | |||
.sc-page .bt-orange2:hover, | |||
.sc-page .bt-orange2:focus { | |||
border: 1px solid var(--sonarcloudOrange700); | |||
background-color: var(--sonarcloudOrange700); | |||
} | |||
.sc-page .bt-nav.bt-orange2 { | |||
border: none; | |||
color: var(--sonarcloudOrange500); | |||
} | |||
.sc-page .bt-nav.bt-orange2:hover, | |||
.sc-page .bt-nav.bt-orange2:focus { | |||
border: none; | |||
background-color: transparent; | |||
color: var(--sonarcloudOrange700); | |||
} |
@@ -1,658 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2020 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 url('https://fonts.googleapis.com/css?family=Roboto:300,400,500,700'); | |||
.sc-page { | |||
font-family: var(--sonarcloudFontFamily); | |||
} | |||
.sc-page p { | |||
font-family: var(--systemFontFamily); | |||
} | |||
.sc-page *:focus { | |||
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(--sonarcloudOrange500); | |||
} | |||
.sc-orange-button:hover, | |||
.sc-orange-button:focus { | |||
background-color: var(--sonarcloudOrange700); | |||
color: #fff; | |||
} | |||
.sc-page-title { | |||
line-height: 56px; | |||
margin-top: 40px; | |||
margin-bottom: 20px; | |||
font-size: 50px; | |||
font-weight: 700; | |||
text-align: center; | |||
} | |||
.sc-page-subtitle { | |||
line-height: 32px; | |||
margin-bottom: 50px; | |||
font-size: 22px; | |||
font-weight: 300; | |||
text-align: center; | |||
} | |||
.sc-features-list { | |||
display: flex; | |||
flex-wrap: wrap; | |||
justify-content: space-between; | |||
align-items: stretch; | |||
max-width: 1000px; | |||
margin-left: auto; | |||
margin-right: auto; | |||
} | |||
.sc-feature { | |||
display: flex; | |||
flex-direction: column; | |||
align-items: flex-start; | |||
width: 30%; | |||
margin-bottom: 40px; | |||
} | |||
.sc-feature-title { | |||
line-height: 28px; | |||
margin-bottom: 13px; | |||
font-size: 21px; | |||
font-weight: 400; | |||
} | |||
.sc-feature-description { | |||
flex: 1 1 auto; | |||
line-height: 22px; | |||
font-size: 15px; | |||
} | |||
.sc-feature-description + .sc-feature-description { | |||
margin-top: 10px; | |||
} | |||
.sc-feature-link { | |||
margin-top: 16px; | |||
color: var(--sonarcloudOrange500) !important; | |||
font-size: 16px; | |||
font-weight: 400; | |||
} | |||
.sc-feature-link:hover, | |||
.sc-feature-link:focus { | |||
color: var(--sonarcloudOrange700) !important; | |||
} | |||
.sc-narrow-container { | |||
width: 700px; | |||
margin: 40px auto; | |||
} | |||
.sc-pricing { | |||
display: flex; | |||
justify-content: space-between; | |||
} | |||
.sc-pricing-block { | |||
display: flex; | |||
flex-direction: column; | |||
align-items: center; | |||
width: 330px; | |||
padding: 20px 20px 30px; | |||
border: 1px solid var(--sonarcloudBlack300); | |||
border-radius: 6px; | |||
box-sizing: border-box; | |||
line-height: 20px; | |||
font-size: 16px; | |||
} | |||
.sc-pricing-title { | |||
line-height: 34px; | |||
margin-bottom: 20px; | |||
color: var(--sonarcloudOrange500); | |||
font-size: 24px; | |||
font-weight: 400; | |||
} | |||
.sc-pricing-price { | |||
line-height: 72px; | |||
color: var(--sonarcloudBlack800); | |||
font-size: 65px; | |||
font-weight: 700; | |||
} | |||
.sc-pricing-small { | |||
font-size: 14px; | |||
} | |||
.sc-arrow-link { | |||
position: relative; | |||
border: none; | |||
color: #444; | |||
} | |||
.sc-arrow-link:after { | |||
content: '\2192'; | |||
position: absolute; | |||
top: 0; | |||
left: calc(100% + 5px); | |||
transition: left 0.3s ease; | |||
} | |||
.sc-arrow-link:hover { | |||
color: var(--baseFontColor); | |||
} | |||
.sc-arrow-link:focus { | |||
color: var(--sonarcloudOrange500); | |||
} | |||
.sc-arrow-link:hover::after { | |||
left: calc(100% + 10px); | |||
} | |||
.sc-start { | |||
display: inline-flex; | |||
align-items: center; | |||
font-size: 16px; | |||
font-weight: 700; | |||
} | |||
.sc-start:hover, | |||
.sc-start:focus { | |||
background-color: var(--sonarcloudOrange700); | |||
color: #fff; | |||
} | |||
.sc-browse { | |||
display: inline-flex; | |||
align-items: center; | |||
height: 33px; | |||
line-height: 33px; | |||
padding: 0 16px; | |||
border-radius: 5px; | |||
border: 1px solid var(--sonarcloudOrange500); | |||
box-sizing: border-box; | |||
color: var(--sonarcloudOrange500); | |||
font-size: 16px; | |||
font-weight: 700; | |||
transition: box-shadow 0.3s ease; | |||
} | |||
.sc-browse:hover, | |||
.sc-browse:focus { | |||
background-color: var(--sonarcloudOrange500); | |||
color: #fff; | |||
} | |||
.sc-news { | |||
display: flex; | |||
justify-content: center; | |||
align-items: center; | |||
border-top: 1px solid var(--sonarcloudBlack300); | |||
padding-top: 32px; | |||
} | |||
.sc-news-title { | |||
display: inline-block; | |||
font-size: 18px; | |||
} | |||
.sc-news-link { | |||
border-bottom-color: var(--sonarcloudBlack300); | |||
color: var(--baseFontColor); | |||
font-size: 12px; | |||
} | |||
.sc-news-link:hover, | |||
.sc-news-link:focus { | |||
border-bottom-color: var(--sonarcloudOrange500); | |||
color: var(--sonarcloudOrange500); | |||
} | |||
.sc-sq-jumbotron { | |||
display: flex; | |||
justify-content: space-between; | |||
max-width: 1160px; | |||
margin: 30px auto 0; | |||
color: var(--sonarcloudBlack800); | |||
} | |||
.sc-sq-jumbotron-left { | |||
min-width: 540px; | |||
} | |||
.sc-sq-jumbotron-right { | |||
max-width: 725px; | |||
} | |||
.sc-sq-jumbotron-right img { | |||
max-width: 100%; | |||
border-radius: 6px; | |||
box-shadow: 0px 15px 50px rgba(0, 0, 0, 0.21); | |||
} | |||
.sc-sq-jumbotron-title { | |||
line-height: 61px; | |||
margin-top: 90px; | |||
margin-bottom: 20px; | |||
color: var(--sonarcloudBlack800); | |||
font-size: 60px; | |||
font-weight: 700; | |||
} | |||
.sc-sq-jumbotron-title-orange { | |||
color: var(--sonarcloudOrange500); | |||
} | |||
.sc-sq-jumbotron-login { | |||
line-height: 25px; | |||
font-size: 18px; | |||
} | |||
.sc-sq-header2 { | |||
margin: 80px 0 40px; | |||
line-height: 45px; | |||
font-size: 32px; | |||
font-weight: 300; | |||
text-align: center; | |||
} | |||
.sc-languages { | |||
margin: 60px 0; | |||
text-align: center; | |||
} | |||
.sc-languages-list { | |||
display: flex; | |||
justify-content: center; | |||
margin-top: 20px; | |||
align-items: center; | |||
} | |||
.sc-languages-list > li { | |||
text-align: center; | |||
margin: 5px 8px; | |||
width: 100px; | |||
} | |||
.sc-integrations { | |||
position: relative; | |||
background-color: var(--sonarcloudBlack200); | |||
margin-left: -20px; | |||
margin-right: -20px; | |||
margin-bottom: -10px; | |||
padding: 44px 0px; | |||
text-align: center; | |||
} | |||
.sc-integrations-title { | |||
margin-top: 0; | |||
} | |||
.sc-integrations-list { | |||
display: flex; | |||
justify-content: center; | |||
} | |||
.sc-integrations-list > li { | |||
width: 200px; | |||
} | |||
.sc-integrations-list > li + li { | |||
border-left: 1px solid var(--sonarcloudBorderGray); | |||
} | |||
.sc-bottom-note { | |||
margin: 36px 0 16px; | |||
font-size: 16px; | |||
font-weight: 300; | |||
text-align: center; | |||
} | |||
.sc-bottom-note > a { | |||
font-weight: 500; | |||
} | |||
.sc-bottom-note-link:hover, | |||
.sc-bottom-note-link:focus { | |||
border-bottom-color: var(--sonarcloudOrange500); | |||
color: var(--sonarcloudOrange500); | |||
} | |||
.sc-sq-page { | |||
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(--sonarcloudOrange500); | |||
color: var(--sonarcloudOrange500); | |||
} | |||
.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; | |||
font-family: var(--sonarcloudFontFamily); | |||
} | |||
.sc-child-lead-link { | |||
border-bottom-color: rgba(255, 102, 0, 0.2); | |||
color: var(--sonarcloudOrange500); | |||
} | |||
.sc-child-lead-link:hover, | |||
.sc-child-lead-link:focus { | |||
border-bottom-color: var(--sonarcloudOrange700); | |||
color: var(--sonarcloudOrange700); | |||
} | |||
.sc-child-feature { | |||
width: calc(50% - 40px); | |||
} | |||
.sc-child-start-using { | |||
display: flex; | |||
align-items: center; | |||
justify-content: space-between; | |||
width: 600px; | |||
margin: 20px auto; | |||
padding: 30px; | |||
border: 1px solid var(--sonarcloudBorderGray); | |||
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 var(--sonarcloudBorderGray); | |||
} | |||
.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 var(--sonarcloudBorderGray); | |||
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 var(--sonarcloudBorderGray); | |||
} | |||
.sc-vsts-start-title { | |||
margin: 16px 0 24px; | |||
font-size: 21px; | |||
font-weight: 300; | |||
} | |||
.sc-contact-page label { | |||
display: block; | |||
max-width: 100%; | |||
margin-bottom: 5px; | |||
font-size: 14px; | |||
font-weight: 700; | |||
} | |||
.sc-contact-page input, | |||
.sc-contact-page textarea { | |||
display: block; | |||
width: 100%; | |||
max-width: 100%; | |||
height: 30px; | |||
padding: 6px 12px; | |||
font-size: 14px; | |||
font-family: inherit; | |||
line-height: 1.42857143; | |||
color: #555; | |||
background-color: white; | |||
border: 1px solid var(--gray80); | |||
border-radius: 2px; | |||
transition: border-color ease 0.3s; | |||
} | |||
.sc-contact-page input:focus, | |||
.sc-contact-page textarea:focus { | |||
border-color: #4b9fd5; | |||
outline: none !important; | |||
box-shadow: none; | |||
} | |||
.sc-contact-page input, | |||
.sc-contact-page .Select { | |||
width: 300px; | |||
} | |||
.sc-contact-page .Select-control { | |||
height: 30px; | |||
} | |||
.sc-contact-page .Select-value, | |||
.sc-contact-page .Select-placeholder { | |||
margin-top: 4px; | |||
} | |||
.sc-contact-page .Select-placeholder { | |||
font-style: italic; | |||
color: var(--disableGrayText); | |||
} | |||
.sc-contact-page .Select-input { | |||
box-shadow: none; | |||
} | |||
.sc-contact-page .category-select { | |||
position: relative; | |||
} | |||
.sc-contact-page .category-select-helper { | |||
opacity: 0; | |||
z-index: -1; | |||
position: absolute; | |||
bottom: 0px; | |||
} | |||
.sc-contact-page input[name='_gotcha'] { | |||
display: none !important; | |||
} | |||
.sc-contact-page textarea { | |||
height: auto; | |||
} | |||
.sc-contact-page button { | |||
padding: 6px 12px; | |||
background: none; | |||
color: var(--sonarcloudOrange500); | |||
border: 1px solid var(--sonarcloudOrange500); | |||
border-radius: 5px; | |||
font-size: 12px; | |||
font-weight: 400; | |||
cursor: pointer; | |||
} | |||
.sc-contact-page button:hover { | |||
color: white; | |||
background-color: var(--sonarcloudOrange500); | |||
} | |||
.sc-contact-page button:focus { | |||
color: white; | |||
background-color: var(--sonarcloudOrange500); | |||
outline: none; | |||
} | |||
.sc-contact-page button:active { | |||
color: white; | |||
background-color: var(--sonarcloudOrange500); | |||
} | |||
.sc-contact-page .form-group { | |||
margin-bottom: 15px; | |||
} | |||
.sc-contact-page .sc-page-title { | |||
text-align: left; | |||
margin-top: 0; | |||
} | |||
.sc-contact-page p { | |||
margin-bottom: 20px; | |||
} | |||
.sc-contact-page a { | |||
color: var(--sonarcloudOrange500) !important; | |||
border: none; | |||
} | |||
.sc-contact-page a:hover { | |||
color: #cc5200 !important; | |||
} |
@@ -1,78 +0,0 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2020 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 { getJSON } from 'sonar-ui-common/helpers/request'; | |||
export interface FeaturedProject { | |||
key: string; | |||
avatarUrl: string | null; | |||
organizationKey: string; | |||
organizationName: string; | |||
name: string; | |||
bugs: number; | |||
codeSmells: number; | |||
coverage?: number; | |||
duplications: number; | |||
gateStatus: string; | |||
languages: string[]; | |||
maintainabilityRating: number; | |||
ncloc: number; | |||
reliabilityRating: number; | |||
securityRating: number; | |||
vulnerabilities: number; | |||
} | |||
export interface HomepageData { | |||
generatedAt: string; | |||
publicProjects: number; | |||
publicLoc: number; | |||
rules: number; | |||
featuredProjects: FeaturedProject[]; | |||
newPullRequests7d: number; | |||
} | |||
export const LANGUAGES = [ | |||
{ name: 'Java', file: 'java.svg', width: 65 }, | |||
{ name: 'JavaScript', file: 'js.svg', width: 60 }, | |||
{ name: 'TypeScript', file: 'ts.svg', width: 100 }, | |||
{ name: 'C#', file: 'csharp.svg', width: 60 }, | |||
{ name: 'Python', file: 'python.svg', width: 65 }, | |||
{ name: 'C++', file: 'c-c-plus-plus.svg', width: 53 }, | |||
{ name: 'Go', file: 'go.svg', width: 91 }, | |||
{ name: 'Kotlin', file: 'kotlin.svg', width: 42 }, | |||
{ name: 'Ruby', file: 'ruby.svg', width: 43 }, | |||
{ name: 'Swift', file: 'swift.svg', width: 64 }, | |||
{ name: 'ABAP', file: 'abap.svg', width: 62 }, | |||
{ name: 'Apex', file: 'apex.svg', width: 62 }, | |||
{ name: 'Flex', file: 'flex.png', width: 85 }, | |||
{ name: 'CSS', file: 'css.svg', width: 40 }, | |||
{ name: 'HTML', file: 'html5.svg', width: 40 }, | |||
{ name: 'Objective-C', file: 'obj-c.svg', width: 63 }, | |||
{ name: 'PHP', file: 'php.svg', width: 57 }, | |||
{ name: 'Scala', file: 'scala.svg', width: 29 }, | |||
{ name: 'T-SQL', file: 't-sql.svg', width: 53 }, | |||
{ name: 'PL/SQL', file: 'pl-sql.svg', width: 65 }, | |||
{ name: 'VB', file: 'vb.svg', width: 55 }, | |||
{ name: 'XML', file: 'xml.svg', width: 67 }, | |||
{ name: 'COBOL', file: 'cobol.svg', width: 65 } | |||
]; | |||
export function requestHomepageData(url: string): Promise<HomepageData> { | |||
return getJSON(url); | |||
} |