.alert-info {
border-color: #bce8f1;
background-color: #d9edf7;
- color: #31708f;
+ color: #666666;
}
.alert-success {
differenceBy(newTasksInProgress, tasksInProgress, 'id').length > 0);
shouldFetchComponent = Boolean(currentTaskChanged || progressChanged);
- if (!shouldFetchComponent && component && newTasksInProgress.length > 0) {
+ if (
+ !shouldFetchComponent &&
+ component &&
+ (newTasksInProgress.length > 0 || !component.analysisDate)
+ ) {
+ // Refresh the status as long as there is tasks in progress or no analysis
window.clearTimeout(this.watchStatusTimer);
this.watchStatusTimer = window.setTimeout(
() => this.fetchStatus(component),
const CreateOrganizationForm = lazyLoad(() =>
import('../../apps/account/organizations/CreateOrganizationForm')
);
-const Onboarding = lazyLoad(() => import('../../apps/tutorials/Onboarding'));
+const OnboardingModal = lazyLoad(() => import('../../apps/tutorials/onboarding/OnboardingModal'));
const LicensePromptModal = lazyLoad(
() => import('../../apps/marketplace/components/LicensePromptModal'),
'LicensePromptModal'
openProjectOnboarding = () => {
if (isSonarCloud()) {
this.setState({ automatic: false, modal: undefined });
- this.context.router.push(`/onboarding`);
+ this.context.router.push(`/projects/create`);
} else {
this.setState({ modal: ModalKey.projectOnboarding });
}
{this.props.children}
{modal === ModalKey.license && <LicensePromptModal onClose={this.closeLicense} />}
{modal === ModalKey.onboarding && (
- <Onboarding
+ <OnboardingModal
onClose={this.closeOnboarding}
onOpenOrganizationOnboarding={this.openOrganizationOnboarding}
onOpenProjectOnboarding={this.openProjectOnboarding}
import { waitAndUpdate } from '../../../helpers/testUtils';
jest.mock('../../../api/branches', () => ({
- getBranches: jest.fn(() => Promise.resolve([])),
- getPullRequests: jest.fn(() => Promise.resolve([]))
+ getBranches: jest.fn().mockResolvedValue([]),
+ getPullRequests: jest.fn().mockResolvedValue([])
}));
jest.mock('../../../api/ce', () => ({
- getTasksForComponent: jest.fn(() => Promise.resolve({ queue: [] }))
+ getTasksForComponent: jest.fn().mockResolvedValue({ queue: [] })
}));
jest.mock('../../../api/components', () => ({
- getComponentData: jest.fn(() => Promise.resolve({}))
+ getComponentData: jest.fn().mockResolvedValue({ analysisDate: '2018-07-30' })
}));
jest.mock('../../../api/nav', () => ({
- getComponentNavigation: jest.fn(() =>
- Promise.resolve({
- breadcrumbs: [{ key: 'portfolioKey', name: 'portfolio', qualifier: 'VW' }],
- key: 'portfolioKey'
- })
- )
+ getComponentNavigation: jest.fn().mockResolvedValue({
+ breadcrumbs: [{ key: 'portfolioKey', name: 'portfolio', qualifier: 'VW' }],
+ key: 'portfolioKey'
+ })
}));
// mock this, because some of its children are using redux store
});
it("loads branches for module's project", async () => {
- (getComponentNavigation as jest.Mock<any>).mockImplementationOnce(() =>
- Promise.resolve({
- breadcrumbs: [
- { key: 'projectKey', name: 'project', qualifier: 'TRK' },
- { key: 'moduleKey', name: 'module', qualifier: 'BRC' }
- ]
- })
- );
+ (getComponentNavigation as jest.Mock<any>).mockResolvedValueOnce({
+ breadcrumbs: [
+ { key: 'projectKey', name: 'project', qualifier: 'TRK' },
+ { key: 'moduleKey', name: 'module', qualifier: 'BRC' }
+ ]
+ });
mount(
<ComponentContainer fetchOrganizations={jest.fn()} location={{ query: { id: 'moduleKey' } }}>
});
it('loads organization', async () => {
- (getComponentData as jest.Mock<any>).mockImplementationOnce(() =>
- Promise.resolve({ organization: 'org' })
- );
+ (getComponentData as jest.Mock<any>).mockResolvedValueOnce({ organization: 'org' });
const fetchOrganizations = jest.fn();
mount(
});
it('fetches status', async () => {
- (getComponentData as jest.Mock<any>).mockImplementationOnce(() =>
- Promise.resolve({ organization: 'org' })
- );
+ (getComponentData as jest.Mock<any>).mockResolvedValueOnce({ organization: 'org' });
mount(
<ComponentContainer fetchOrganizations={jest.fn()} location={{ query: { id: 'foo' } }}>
.alert-info {
border-color: #bce8f1;
background-color: #d9edf7;
- color: #31708f;
+ color: #666666;
}
.alert-success {
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
.boxed-group {
- margin-bottom: 20px;
+ margin-bottom: calc(2.5 * var(--gridSize));
border: 1px solid var(--barBorderColor);
border-radius: 2px;
background-color: #fff;
}
.page-sidebar-fixed {
- width: 30%;
min-width: 300px;
flex-shrink: 0;
padding-left: 40px;
}
}
-.page-sidebar-sticky .page-sidebar-sticky-inner .search-navigator-facets-list {
- width: 260px;
- margin-left: calc(50vw - 640px + 290px - 260px - 37px);
-}
-
-@media (max-width: 1335px) {
- .page-sidebar-sticky .page-sidebar-sticky-inner .search-navigator-facets-list {
- margin-left: 20px;
- }
-}
-
.layout-page {
display: flex;
align-items: stretch;
flex-direction: row;
}
+.display-flex-column {
+ display: flex !important;
+ flex-direction: column;
+}
+
.display-flex-center {
display: flex !important;
align-items: center;
display: flex;
clear: left;
margin-bottom: calc(3 * var(--gridSize));
- box-shadow: 0 1px 0 var(--barBorderColor);
+ border-bottom: 1px solid var(--barBorderColor);
+ font-size: var(--mediumFontSize);
}
.sonarcloud .flex-tabs > li > a {
+ position: relative;
display: block;
+ top: 1px;
height: 100%;
width: 100%;
box-sizing: border-box;
color: var(--secondFontColor);
font-weight: 600;
cursor: pointer;
- padding-bottom: var(--gridSize);
- border-bottom: 2px solid transparent;
+ padding-bottom: calc(1.5 * var(--gridSize));
+ border-bottom: 3px solid transparent;
transition: color 0.2s ease;
}
}
export interface Component extends LightComponent {
+ almId?: string;
+ almRepoUrl?: string;
analysisDate?: string;
breadcrumbs: Breadcrumb[];
configuration?: ComponentConfiguration;
props.selectedProfile === undefined ||
!props.query.activation;
return (
- <div className="search-navigator-facets-list">
+ <>
<LanguageFacet
onChange={props.onFilterChange}
onToggle={props.onFacetToggle}
/>
</>
)}
- </div>
+ </>
);
}
render() {
return (
- <div className="search-navigator-facets-list">
+ <div>
<ProjectOverviewFacet
onChange={this.changeMetric}
selected={this.props.selectedMetric}
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`should display two facets 1`] = `
-<div
- className="search-navigator-facets-list"
->
+<div>
<ProjectOverviewFacet
onChange={[Function]}
selected="duplicated_lines_density"
(this.props.organization && this.props.organization.key);
return (
- <div className="search-navigator-facets-list">
+ <>
<TypeFacet
fetching={this.props.loadingFacets.types === true}
loading={this.props.loading}
stats={facets.authors}
/>
)}
- </div>
+ </>
);
}
}
*/
import * as React from 'react';
import * as PropTypes from 'prop-types';
-import OverviewApp from './OverviewApp';
+import { Helmet } from 'react-helmet';
import EmptyOverview from './EmptyOverview';
+import OverviewApp from './OverviewApp';
+import SonarCloudEmptyOverview from './SonarCloudEmptyOverview';
+import Suggestions from '../../../app/components/embed-docs-modal/Suggestions';
import { Component, BranchLike } from '../../../app/types';
import { isShortLivingBranch } from '../../../helpers/branches';
-import { getShortLivingBranchUrl, getCodeUrl } from '../../../helpers/urls';
+import {
+ getShortLivingBranchUrl,
+ getCodeUrl,
+ getProjectUrl,
+ getBaseUrl,
+ getPathUrlAsString
+} from '../../../helpers/urls';
+import { isSonarCloud } from '../../../helpers/system';
interface Props {
branchLike?: BranchLike;
return null;
}
- if (!component.analysisDate) {
- return (
- <EmptyOverview
- component={component.key}
- hasBranches={branchLikes.length > 1}
- showWarning={!this.props.isPending && !this.props.isInProgress}
- />
- );
- }
-
return (
- <OverviewApp
- branchLike={branchLike}
- component={component}
- onComponentChange={this.props.onComponentChange}
- />
+ <>
+ {isSonarCloud() && (
+ <Helmet>
+ <link
+ href={getBaseUrl() + getPathUrlAsString(getProjectUrl(component.key))}
+ rel="canonical"
+ />
+ </Helmet>
+ )}
+ <Suggestions suggestions="overview" />
+
+ {!component.analysisDate &&
+ (isSonarCloud() ? (
+ <SonarCloudEmptyOverview
+ branchLike={branchLike}
+ branchLikes={branchLikes}
+ component={component}
+ hasAnalyses={this.props.isPending || this.props.isInProgress}
+ onComponentChange={this.props.onComponentChange}
+ />
+ ) : (
+ <EmptyOverview
+ branchLike={branchLike}
+ branchLikes={branchLikes}
+ component={component.key}
+ showWarning={!this.props.isPending && !this.props.isInProgress}
+ />
+ ))}
+ {component.analysisDate && (
+ <OverviewApp
+ branchLike={branchLike}
+ component={component}
+ onComponentChange={this.props.onComponentChange}
+ />
+ )}
+ </>
);
}
}
import { Link } from 'react-router';
import { FormattedMessage } from 'react-intl';
import { translate } from '../../../helpers/l10n';
+import { BranchLike } from '../../../app/types';
+import { isBranch, isLongLivingBranch } from '../../../helpers/branches';
interface Props {
+ branchLike?: BranchLike;
+ branchLikes: BranchLike[];
component: string;
- hasBranches?: boolean;
showWarning?: boolean;
}
-export default function EmptyOverview({ component, hasBranches, showWarning }: Props) {
- const rawMessage = translate('provisioning.no_analysis.delete');
- const head = rawMessage.substr(0, rawMessage.indexOf('{0}'));
- const tail = rawMessage.substr(rawMessage.indexOf('{0}') + 3);
+export default function EmptyOverview({ branchLike, branchLikes, component, showWarning }: Props) {
+ const hasBranches = branchLikes.length > 1;
+ const hasBadConfig =
+ branchLikes.length > 2 ||
+ (branchLikes.length === 2 && branchLikes.some(branch => isLongLivingBranch(branch)));
+
+ const branchWarnMsg = hasBadConfig
+ ? translate('provisioning.no_analysis_on_main_branch.bad_configuration')
+ : translate('provisioning.no_analysis_on_main_branch');
return (
<div className="page page-limited">
{showWarning && (
<div className="big-spacer-bottom">
<div className="alert alert-warning">
- {hasBranches ? (
+ {hasBranches && isBranch(branchLike) ? (
<FormattedMessage
- defaultMessage={translate('provisioning.no_analysis_on_main_branch')}
- id="provisioning.no_analysis_on_main_branch"
+ defaultMessage={branchWarnMsg}
+ id={branchWarnMsg}
values={{
- branch: (
- <div className="outline-badge text-baseline little-spacer-right">
+ branchName: branchLike.name,
+ branchType: (
+ <div className="outline-badge text-baseline">
{translate('branches.main_branch')}
</div>
)
{!hasBranches && (
<div className="big-spacer-top">
- {head}
- <Link
- className="text-danger"
- to={{ pathname: '/project/deletion', query: { id: component } }}>
- {translate('provisioning.no_analysis.delete_project')}
- </Link>
- {tail}
+ <FormattedMessage
+ defaultMessage={translate('provisioning.no_analysis.delete')}
+ id={'provisioning.no_analysis.delete'}
+ values={{
+ link: (
+ <Link
+ className="text-danger"
+ to={{ pathname: '/project/deletion', query: { id: component } }}>
+ {translate('provisioning.no_analysis.delete_project')}
+ </Link>
+ )
+ }}
+ />
</div>
)}
</div>
import * as React from 'react';
import { uniq } from 'lodash';
import { connect } from 'react-redux';
-import { Helmet } from 'react-helmet';
-import QualityGate from '../qualityGate/QualityGate';
import ApplicationQualityGate from '../qualityGate/ApplicationQualityGate';
import BugsAndVulnerabilities from '../main/BugsAndVulnerabilities';
import CodeSmells from '../main/CodeSmells';
import Coverage from '../main/Coverage';
import Duplications from '../main/Duplications';
import MetaContainer from '../meta/MetaContainer';
+import QualityGate from '../qualityGate/QualityGate';
import throwGlobalError from '../../../app/utils/throwGlobalError';
-import Suggestions from '../../../app/components/embed-docs-modal/Suggestions';
import { getMeasuresAndMeta } from '../../../api/measures';
import { getAllTimeMachineData, History } from '../../../api/time-machine';
import { parseDate } from '../../../helpers/dates';
import { getMetrics } from '../../../store/rootReducer';
import { BranchLike, Component, Metric } from '../../../app/types';
import { translate } from '../../../helpers/l10n';
-import { getProjectUrl, getSonarCloudUrlAsString } from '../../../helpers/urls';
-import { isSonarCloud } from '../../../helpers/system';
import '../styles.css';
interface OwnProps {
return (
<div className="page page-limited">
<div className="overview page-with-sidebar">
- <Suggestions suggestions="overview" />
-
- {isSonarCloud() && (
- <Helmet>
- <link href={getSonarCloudUrlAsString(getProjectUrl(component.key))} rel="canonical" />
- </Helmet>
- )}
-
{this.renderMain()}
<div className="overview-sidebar page-sidebar-fixed">
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { connect } from 'react-redux';
+import { FormattedMessage } from 'react-intl';
+import AnalyzeTutorial from '../../tutorials/analyzeProject/AnalyzeTutorial';
+import MetaContainer from '../meta/MetaContainer';
+import { BranchLike, Component, CurrentUser, isLoggedIn } from '../../../app/types';
+import { isLongLivingBranch, isBranch, isMainBranch } from '../../../helpers/branches';
+import { translate } from '../../../helpers/l10n';
+import { getCurrentUser } from '../../../store/rootReducer';
+import '../../../app/styles/sonarcloud.css';
+
+interface OwnProps {
+ branchLike?: BranchLike;
+ branchLikes: BranchLike[];
+ component: Component;
+ hasAnalyses?: boolean;
+ onComponentChange: (changes: {}) => void;
+}
+
+interface StateProps {
+ currentUser: CurrentUser;
+}
+
+type Props = OwnProps & StateProps;
+
+export function SonarCloudEmptyOverview({
+ branchLike,
+ branchLikes,
+ component,
+ currentUser,
+ hasAnalyses,
+ onComponentChange
+}: Props) {
+ const hasBranches = branchLikes.length > 1;
+ const hasBadBranchConfig =
+ branchLikes.length > 2 ||
+ (branchLikes.length === 2 && branchLikes.some(branch => isLongLivingBranch(branch)));
+ return (
+ <div className="page page-limited">
+ <div className="overview page-with-sidebar">
+ <div className="overview-main page-main sonarcloud">
+ {isLoggedIn(currentUser) && isMainBranch(branchLike) ? (
+ <>
+ {hasBranches && (
+ <WarningMessage
+ branchLike={branchLike}
+ message={
+ hasBadBranchConfig
+ ? translate('provisioning.no_analysis_on_main_branch.bad_configuration')
+ : translate('provisioning.no_analysis_on_main_branch')
+ }
+ />
+ )}
+ {!hasBranches &&
+ !hasAnalyses && <AnalyzeTutorial component={component} currentUser={currentUser} />}
+ </>
+ ) : (
+ <WarningMessage
+ branchLike={branchLike}
+ message={translate('provisioning.no_analysis_on_main_branch')}
+ />
+ )}
+ </div>
+
+ <div className="overview-sidebar page-sidebar-fixed">
+ <MetaContainer
+ branchLike={branchLike}
+ component={component}
+ onComponentChange={onComponentChange}
+ />
+ </div>
+ </div>
+ </div>
+ );
+}
+
+export function WarningMessage({
+ branchLike,
+ message
+}: {
+ branchLike?: BranchLike;
+ message: string;
+}) {
+ if (!isBranch(branchLike)) {
+ return null;
+ }
+ return (
+ <div className="alert alert-warning">
+ <FormattedMessage
+ defaultMessage={message}
+ id={message}
+ values={{
+ branchName: branchLike.name,
+ branchType: (
+ <div className="outline-badge text-baseline">{translate('branches.main_branch')}</div>
+ )
+ }}
+ />
+ </div>
+ );
+}
+
+const mapStateToProps = (state: any) => ({
+ currentUser: getCurrentUser(state)
+});
+
+export default connect<StateProps, {}, OwnProps>(mapStateToProps)(SonarCloudEmptyOverview);
import * as React from 'react';
import { mount, shallow } from 'enzyme';
import App from '../App';
-import OverviewApp from '../OverviewApp';
-import EmptyOverview from '../EmptyOverview';
import { BranchType, LongLivingBranch } from '../../../../app/types';
+import { isSonarCloud } from '../../../../helpers/system';
+
+jest.mock('../../../../helpers/system', () => ({ isSonarCloud: jest.fn() }));
const component = {
key: 'foo',
version: '0.0.1'
};
+beforeEach(() => {
+ (isSonarCloud as jest.Mock<any>).mockClear();
+ (isSonarCloud as jest.Mock<any>).mockReturnValue(false);
+});
+
it('should render OverviewApp', () => {
- expect(getWrapper().type()).toBe(OverviewApp);
+ expect(
+ getWrapper()
+ .find('Connect(OverviewApp)')
+ .exists()
+ ).toBeTruthy();
});
it('should render EmptyOverview', () => {
- const output = getWrapper({ component: { key: 'foo' } });
- expect(output.type()).toBe(EmptyOverview);
+ expect(
+ getWrapper({ component: { key: 'foo' } })
+ .find('EmptyOverview')
+ .exists()
+ ).toBeTruthy();
+});
+
+it('should render SonarCloudEmptyOverview', () => {
+ (isSonarCloud as jest.Mock<any>).mockReturnValue(true);
+ expect(
+ getWrapper({ component: { key: 'foo' } })
+ .find('Connect(SonarCloudEmptyOverview)')
+ .exists()
+ ).toBeTruthy();
});
it('redirects on Code page for files', () => {
import * as React from 'react';
import { shallow } from 'enzyme';
import EmptyOverview from '../EmptyOverview';
+import { BranchType } from '../../../../app/types';
+
+const branch = { isMain: true, name: 'b', type: BranchType.LONG };
it('renders', () => {
- expect(shallow(<EmptyOverview component="abcd" showWarning={true} />)).toMatchSnapshot();
+ expect(
+ shallow(<EmptyOverview branchLikes={[]} component="abcd" showWarning={true} />)
+ ).toMatchSnapshot();
});
it('does not render warning', () => {
- expect(shallow(<EmptyOverview component="abcd" showWarning={false} />)).toMatchSnapshot();
+ expect(
+ shallow(<EmptyOverview branchLikes={[]} component="abcd" showWarning={false} />)
+ ).toMatchSnapshot();
});
it('should render another message when there are branches', () => {
expect(
- shallow(<EmptyOverview component="abcd" hasBranches={true} showWarning={true} />)
+ shallow(
+ <EmptyOverview
+ branchLike={branch}
+ branchLikes={[branch, branch]}
+ component="abcd"
+ showWarning={true}
+ />
+ )
+ ).toMatchSnapshot();
+ expect(
+ shallow(
+ <EmptyOverview
+ branchLike={branch}
+ branchLikes={[branch, branch, branch]}
+ component="abcd"
+ showWarning={true}
+ />
+ )
).toMatchSnapshot();
});
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import { SonarCloudEmptyOverview, WarningMessage } from '../SonarCloudEmptyOverview';
+import { BranchType } from '../../../../app/types';
+
+const branch = { isMain: true, name: 'b', type: BranchType.LONG };
+
+const component = {
+ key: 'foo',
+ analysisDate: '2016-01-01',
+ breadcrumbs: [],
+ name: 'Foo',
+ organization: 'org',
+ qualifier: 'TRK',
+ version: '0.0.1'
+};
+
+const LoggedInUser = {
+ isLoggedIn: true,
+ login: 'luke',
+ name: 'Skywalker'
+};
+
+it('renders correctly', () => {
+ expect(
+ shallow(
+ <SonarCloudEmptyOverview
+ branchLike={branch}
+ branchLikes={[branch]}
+ component={component}
+ currentUser={LoggedInUser}
+ onComponentChange={jest.fn()}
+ />
+ )
+ ).toMatchSnapshot();
+});
+
+it('should render another message when there are branches', () => {
+ expect(
+ shallow(
+ <SonarCloudEmptyOverview
+ branchLike={branch}
+ branchLikes={[branch, branch]}
+ component={component}
+ currentUser={LoggedInUser}
+ onComponentChange={jest.fn()}
+ />
+ )
+ ).toMatchSnapshot();
+ expect(
+ shallow(
+ <SonarCloudEmptyOverview
+ branchLike={branch}
+ branchLikes={[branch, branch, branch]}
+ component={component}
+ currentUser={LoggedInUser}
+ onComponentChange={jest.fn()}
+ />
+ )
+ ).toMatchSnapshot();
+});
+
+it('should not render the tutorial', () => {
+ expect(
+ shallow(
+ <SonarCloudEmptyOverview
+ branchLike={branch}
+ branchLikes={[branch]}
+ component={component}
+ currentUser={LoggedInUser}
+ hasAnalyses={true}
+ onComponentChange={jest.fn()}
+ />
+ )
+ ).toMatchSnapshot();
+});
+
+it('should render warning message', () => {
+ expect(shallow(<WarningMessage branchLike={branch} message="foo" />)).toMatchSnapshot();
+});
+
+it('should not render warning message', () => {
+ expect(
+ shallow(
+ <WarningMessage
+ branchLike={{
+ base: 'foo',
+ branch: 'bar',
+ key: '1',
+ title: 'PR bar'
+ }}
+ message="foo"
+ />
+ )
+ .find('FormattedMessage')
+ .exists()
+ ).toBeFalsy();
+});
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import React from 'react';
-import { shallow } from 'enzyme';
-import Timeline from '../Timeline';
-import { parseDate } from '../../../../helpers/dates';
-
-const range = parseDate('2017-05-01T00:00:00.000Z');
-const history = [
- { date: parseDate('2017-04-08T00:00:00.000Z'), value: '29.6' },
- { date: parseDate('2017-04-09T00:00:00.000Z'), value: '170.8' },
- { date: parseDate('2017-05-08T00:00:00.000Z'), value: '360' },
- { date: parseDate('2017-05-09T00:00:00.000Z'), value: '39' }
-];
-
-it('should render correctly with an "after" range', () => {
- expect(shallow(<Timeline after={range} history={history} />)).toMatchSnapshot();
-});
-
-it('should render correctly with a "before" range', () => {
- expect(shallow(<Timeline before={range} history={history} />)).toMatchSnapshot();
-});
-
-it('should have a correct domain with strings or numbers', () => {
- const date = parseDate('2017-05-08T00:00:00.000Z');
- const wrapper = shallow(<Timeline after={range} history={history} />);
- expect(wrapper.find('LineChart').props().domain).toEqual([0, 360]);
-
- wrapper.setProps({ history: [{ date, value: '360.33' }, { date, value: '39.54' }] });
- expect(wrapper.find('LineChart').props().domain).toEqual([0, 360.33]);
-
- wrapper.setProps({ history: [{ date, value: 360 }, { date, value: 39 }] });
- expect(wrapper.find('LineChart').props().domain).toEqual([0, 360]);
-});
<div
className="big-spacer-top"
>
- <Link
- className="text-danger"
- onlyActiveOnIndex={false}
- style={Object {}}
- to={
+ <FormattedMessage
+ defaultMessage="provisioning.no_analysis.delete"
+ id="provisioning.no_analysis.delete"
+ values={
Object {
- "pathname": "/project/deletion",
- "query": Object {
- "id": "abcd",
- },
+ "link": <Link
+ className="text-danger"
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to={
+ Object {
+ "pathname": "/project/deletion",
+ "query": Object {
+ "id": "abcd",
+ },
+ }
+ }
+ >
+ provisioning.no_analysis.delete_project
+ </Link>,
}
}
- >
- provisioning.no_analysis.delete_project
- </Link>
- ovisioning.no_analysis.delete
+ />
</div>
</div>
<div>
id="provisioning.no_analysis_on_main_branch"
values={
Object {
- "branch": <div
- className="outline-badge text-baseline little-spacer-right"
+ "branchName": "b",
+ "branchType": <div
+ className="outline-badge text-baseline"
+ >
+ branches.main_branch
+ </div>,
+ }
+ }
+ />
+ </div>
+ </div>
+ <div>
+ <h4>
+ key
+ </h4>
+ <code>
+ abcd
+ </code>
+ </div>
+</div>
+`;
+
+exports[`should render another message when there are branches 2`] = `
+<div
+ className="page page-limited"
+>
+ <div
+ className="big-spacer-bottom"
+ >
+ <div
+ className="alert alert-warning"
+ >
+ <FormattedMessage
+ defaultMessage="provisioning.no_analysis_on_main_branch.bad_configuration"
+ id="provisioning.no_analysis_on_main_branch.bad_configuration"
+ values={
+ Object {
+ "branchName": "b",
+ "branchType": <div
+ className="outline-badge text-baseline"
>
branches.main_branch
</div>,
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+<div
+ className="page page-limited"
+>
+ <div
+ className="overview page-with-sidebar"
+ >
+ <div
+ className="overview-main page-main sonarcloud"
+ >
+ <React.Fragment>
+ <AnalyzeTutorial
+ component={
+ Object {
+ "analysisDate": "2016-01-01",
+ "breadcrumbs": Array [],
+ "key": "foo",
+ "name": "Foo",
+ "organization": "org",
+ "qualifier": "TRK",
+ "version": "0.0.1",
+ }
+ }
+ currentUser={
+ Object {
+ "isLoggedIn": true,
+ "login": "luke",
+ "name": "Skywalker",
+ }
+ }
+ />
+ </React.Fragment>
+ </div>
+ <div
+ className="overview-sidebar page-sidebar-fixed"
+ >
+ <Connect(Meta)
+ branchLike={
+ Object {
+ "isMain": true,
+ "name": "b",
+ "type": "LONG",
+ }
+ }
+ component={
+ Object {
+ "analysisDate": "2016-01-01",
+ "breadcrumbs": Array [],
+ "key": "foo",
+ "name": "Foo",
+ "organization": "org",
+ "qualifier": "TRK",
+ "version": "0.0.1",
+ }
+ }
+ onComponentChange={[MockFunction]}
+ />
+ </div>
+ </div>
+</div>
+`;
+
+exports[`should not render the tutorial 1`] = `
+<div
+ className="page page-limited"
+>
+ <div
+ className="overview page-with-sidebar"
+ >
+ <div
+ className="overview-main page-main sonarcloud"
+ >
+ <React.Fragment />
+ </div>
+ <div
+ className="overview-sidebar page-sidebar-fixed"
+ >
+ <Connect(Meta)
+ branchLike={
+ Object {
+ "isMain": true,
+ "name": "b",
+ "type": "LONG",
+ }
+ }
+ component={
+ Object {
+ "analysisDate": "2016-01-01",
+ "breadcrumbs": Array [],
+ "key": "foo",
+ "name": "Foo",
+ "organization": "org",
+ "qualifier": "TRK",
+ "version": "0.0.1",
+ }
+ }
+ onComponentChange={[MockFunction]}
+ />
+ </div>
+ </div>
+</div>
+`;
+
+exports[`should render another message when there are branches 1`] = `
+<div
+ className="page page-limited"
+>
+ <div
+ className="overview page-with-sidebar"
+ >
+ <div
+ className="overview-main page-main sonarcloud"
+ >
+ <React.Fragment>
+ <WarningMessage
+ branchLike={
+ Object {
+ "isMain": true,
+ "name": "b",
+ "type": "LONG",
+ }
+ }
+ message="provisioning.no_analysis_on_main_branch"
+ />
+ </React.Fragment>
+ </div>
+ <div
+ className="overview-sidebar page-sidebar-fixed"
+ >
+ <Connect(Meta)
+ branchLike={
+ Object {
+ "isMain": true,
+ "name": "b",
+ "type": "LONG",
+ }
+ }
+ component={
+ Object {
+ "analysisDate": "2016-01-01",
+ "breadcrumbs": Array [],
+ "key": "foo",
+ "name": "Foo",
+ "organization": "org",
+ "qualifier": "TRK",
+ "version": "0.0.1",
+ }
+ }
+ onComponentChange={[MockFunction]}
+ />
+ </div>
+ </div>
+</div>
+`;
+
+exports[`should render another message when there are branches 2`] = `
+<div
+ className="page page-limited"
+>
+ <div
+ className="overview page-with-sidebar"
+ >
+ <div
+ className="overview-main page-main sonarcloud"
+ >
+ <React.Fragment>
+ <WarningMessage
+ branchLike={
+ Object {
+ "isMain": true,
+ "name": "b",
+ "type": "LONG",
+ }
+ }
+ message="provisioning.no_analysis_on_main_branch.bad_configuration"
+ />
+ </React.Fragment>
+ </div>
+ <div
+ className="overview-sidebar page-sidebar-fixed"
+ >
+ <Connect(Meta)
+ branchLike={
+ Object {
+ "isMain": true,
+ "name": "b",
+ "type": "LONG",
+ }
+ }
+ component={
+ Object {
+ "analysisDate": "2016-01-01",
+ "breadcrumbs": Array [],
+ "key": "foo",
+ "name": "Foo",
+ "organization": "org",
+ "qualifier": "TRK",
+ "version": "0.0.1",
+ }
+ }
+ onComponentChange={[MockFunction]}
+ />
+ </div>
+ </div>
+</div>
+`;
+
+exports[`should render warning message 1`] = `
+<div
+ className="alert alert-warning"
+>
+ <FormattedMessage
+ defaultMessage="foo"
+ id="foo"
+ values={
+ Object {
+ "branchName": "b",
+ "branchType": <div
+ className="outline-badge text-baseline"
+ >
+ branches.main_branch
+ </div>,
+ }
+ }
+ />
+</div>
+`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly with a "before" range 1`] = `
-<LineChart
- data={
- Array [
- Object {
- "x": 0,
- "y": 29.6,
- },
- Object {
- "x": 1,
- "y": 170.8,
- },
- ]
- }
- displayBackdrop={true}
- displayPoints={false}
- displayVerticalGrid={false}
- domain={
- Array [
- 0,
- 360,
- ]
- }
- height={80}
- padding={
- Array [
- 0,
- 0,
- 0,
- 0,
- ]
- }
-/>
-`;
-
-exports[`should render correctly with an "after" range 1`] = `
-<LineChart
- data={
- Array [
- Object {
- "x": 0,
- "y": 360,
- },
- Object {
- "x": 1,
- "y": 39,
- },
- ]
- }
- displayBackdrop={true}
- displayPoints={false}
- displayVerticalGrid={false}
- domain={
- Array [
- 0,
- 360,
- ]
- }
- height={80}
- padding={
- Array [
- 0,
- 0,
- 0,
- 0,
- ]
- }
-/>
-`;
branchLike?: BranchLike;
component: Component;
history?: History;
- measures: MeasureEnhanced[];
- metrics: { [key: string]: Metric };
+ measures?: MeasureEnhanced[];
+ metrics?: { [key: string]: Metric };
onComponentChange: (changes: {}) => void;
}
render() {
const { organizationsEnabled } = this.context;
- const { branchLike, component, metrics, organization } = this.props;
+ const { branchLike, component, measures, metrics, organization } = this.props;
const { qualifier, description, visibility } = component;
const isProject = qualifier === 'TRK';
{isProject && (
<MetaTags component={component} onComponentChange={this.props.onComponentChange} />
)}
- <MetaSize branchLike={branchLike} component={component} measures={this.props.measures} />
+ {measures && (
+ <MetaSize branchLike={branchLike} component={component} measures={measures} />
+ )}
</div>
- <AnalysesList
- branchLike={branchLike}
- component={component}
- history={this.props.history}
- metrics={metrics}
- qualifier={component.qualifier}
- />
+ {metrics && (
+ <AnalysesList
+ branchLike={branchLike}
+ component={component}
+ history={this.props.history}
+ metrics={metrics}
+ qualifier={component.qualifier}
+ />
+ )}
{this.renderQualityInfos()}
</div>
{!isPrivate &&
- (isProject || isApp) && (
+ (isProject || isApp) &&
+ metrics && (
<BadgesModal
branchLike={branchLike}
metrics={metrics}
.overview-main {
background-color: var(--barBackgroundColor);
transition: transform 0.5s ease, opacity 0.5s ease;
+ width: calc(100% - 300px);
}
.overview-sidebar {
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import Checkbox from '../../../components/controls/Checkbox';
+import { AlmRepository, IdentityProvider } from '../../../app/types';
+import { getBaseUrl } from '../../../helpers/urls';
+import { translate } from '../../../helpers/l10n';
+import CheckIcon from '../../../components/icons-components/CheckIcon';
+
+interface Props {
+ identityProvider: IdentityProvider;
+ repository: AlmRepository;
+ selected: boolean;
+ toggleRepository: (repository: AlmRepository) => void;
+}
+
+export default class AlmRepositoryItem extends React.PureComponent<Props> {
+ handleChange = () => {
+ this.props.toggleRepository(this.props.repository);
+ };
+
+ render() {
+ const { identityProvider, repository, selected } = this.props;
+ const alreadyImported = Boolean(repository.linkedProjectKey);
+ return (
+ <Checkbox
+ checked={selected || alreadyImported}
+ disabled={alreadyImported}
+ onCheck={this.handleChange}>
+ <img
+ alt={identityProvider.name}
+ className="spacer-left"
+ height={14}
+ src={getBaseUrl() + identityProvider.iconPath}
+ style={{ filter: alreadyImported ? 'invert(50%)' : 'invert(100%)' }}
+ width={14}
+ />
+ <span className="spacer-left">{this.props.repository.label}</span>
+ {alreadyImported && (
+ <span className="big-spacer-left">
+ <CheckIcon className="little-spacer-right" />
+ {translate('onboarding.create_project.already_imported')}
+ </span>
+ )}
+ </Checkbox>
+ );
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import AlmRepositoryItem from './AlmRepositoryItem';
+import DeferredSpinner from '../../../components/common/DeferredSpinner';
+import IdentityProviderLink from '../../../components/ui/IdentityProviderLink';
+import { getIdentityProviders } from '../../../api/users';
+import { getRepositories, provisionProject } from '../../../api/alm-integration';
+import { IdentityProvider, LoggedInUser, AlmRepository } from '../../../app/types';
+import { ProjectBase } from '../../../api/components';
+import { SubmitButton } from '../../../components/ui/buttons';
+import { translateWithParameters, translate } from '../../../helpers/l10n';
+
+interface Props {
+ currentUser: LoggedInUser;
+ onProjectCreate: (project: ProjectBase[]) => void;
+}
+
+interface State {
+ identityProviders: IdentityProvider[];
+ installationUrl?: string;
+ installed?: boolean;
+ loading: boolean;
+ repositories: AlmRepository[];
+ selectedRepositories: { [key: string]: AlmRepository | undefined };
+ submitting: boolean;
+}
+
+export default class AutoProjectCreate extends React.PureComponent<Props, State> {
+ mounted = false;
+ state: State = {
+ identityProviders: [],
+ loading: true,
+ repositories: [],
+ selectedRepositories: {},
+ submitting: false
+ };
+
+ componentDidMount() {
+ this.mounted = true;
+ Promise.all([this.fetchIdentityProviders(), this.fetchRepositories()]).then(
+ this.stopLoading,
+ this.stopLoading
+ );
+ }
+
+ componentWillUnmount() {
+ this.mounted = false;
+ }
+
+ fetchIdentityProviders = () => {
+ return getIdentityProviders().then(
+ ({ identityProviders }) => {
+ if (this.mounted) {
+ this.setState({ identityProviders });
+ }
+ },
+ () => {
+ return Promise.resolve();
+ }
+ );
+ };
+
+ fetchRepositories = () => {
+ return getRepositories().then(({ almIntegration, repositories }) => {
+ if (this.mounted) {
+ this.setState({ ...almIntegration, repositories });
+ }
+ });
+ };
+
+ handleFormSubmit = (event: React.FormEvent<HTMLFormElement>) => {
+ event.preventDefault();
+
+ if (this.isValid()) {
+ const { selectedRepositories } = this.state;
+ this.setState({ submitting: true });
+ provisionProject({
+ repositories: Object.keys(selectedRepositories).filter(key =>
+ Boolean(selectedRepositories[key])
+ )
+ }).then(
+ ({ project }) => this.props.onProjectCreate([project]),
+ () => {
+ if (this.mounted) {
+ this.setState({ submitting: false });
+ this.reloadRepositories();
+ }
+ }
+ );
+ }
+ };
+
+ isValid = () => {
+ return this.state.repositories.some(repo =>
+ Boolean(this.state.selectedRepositories[repo.installationKey])
+ );
+ };
+
+ reloadRepositories = () => {
+ this.setState({ loading: true });
+ this.fetchRepositories().then(this.stopLoading, this.stopLoading);
+ };
+
+ stopLoading = () => {
+ if (this.mounted) {
+ this.setState({ loading: false });
+ }
+ };
+
+ toggleRepository = (repository: AlmRepository) => {
+ this.setState(({ selectedRepositories }) => ({
+ selectedRepositories: {
+ ...selectedRepositories,
+ [repository.installationKey]: selectedRepositories[repository.installationKey]
+ ? undefined
+ : repository
+ }
+ }));
+ };
+
+ render() {
+ if (this.state.loading) {
+ return <DeferredSpinner />;
+ }
+
+ const { currentUser } = this.props;
+ const identityProvider = this.state.identityProviders.find(
+ identityProvider => identityProvider.key === currentUser.externalProvider
+ );
+
+ if (!identityProvider) {
+ return null;
+ }
+
+ const { selectedRepositories, submitting } = this.state;
+
+ return (
+ <>
+ <p className="alert alert-info width-60 big-spacer-bottom">
+ {translateWithParameters(
+ 'onboarding.create_project.beta_feature_x',
+ identityProvider.name
+ )}
+ </p>
+ {this.state.installed ? (
+ <form onSubmit={this.handleFormSubmit}>
+ <ul>
+ {this.state.repositories.map(repo => (
+ <li className="big-spacer-bottom" key={repo.installationKey}>
+ <AlmRepositoryItem
+ identityProvider={identityProvider}
+ repository={repo}
+ selected={Boolean(selectedRepositories[repo.installationKey])}
+ toggleRepository={this.toggleRepository}
+ />
+ </li>
+ ))}
+ </ul>
+ <SubmitButton disabled={!this.isValid() || submitting}>
+ {translate('onboarding.create_project.create_project')}
+ </SubmitButton>
+ <DeferredSpinner className="spacer-left" loading={submitting} />
+ </form>
+ ) : (
+ <div>
+ <p className="spacer-bottom">
+ {translateWithParameters(
+ 'onboarding.create_project.install_app_x',
+ identityProvider.name
+ )}
+ </p>
+ <IdentityProviderLink
+ className="display-inline-block"
+ identityProvider={identityProvider}
+ small={true}
+ url={this.state.installationUrl}>
+ {translateWithParameters(
+ 'onboarding.create_project.install_app_x.button',
+ identityProvider.name
+ )}
+ </IdentityProviderLink>
+ </div>
+ )}
+ </>
+ );
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import * as classNames from 'classnames';
+import { connect } from 'react-redux';
+import { InjectedRouter } from 'react-router';
+import { Location } from 'history';
+import Helmet from 'react-helmet';
+import AutoProjectCreate from './AutoProjectCreate';
+import ManualProjectCreate from './ManualProjectCreate';
+import { serializeQuery, Query, parseQuery } from './utils';
+import handleRequiredAuthentication from '../../../app/utils/handleRequiredAuthentication';
+import { getCurrentUser } from '../../../store/rootReducer';
+import { skipOnboarding } from '../../../store/users/actions';
+import { CurrentUser, isLoggedIn } from '../../../app/types';
+import { translate } from '../../../helpers/l10n';
+import { ProjectBase } from '../../../api/components';
+import { getProjectUrl, getOrganizationUrl } from '../../../helpers/urls';
+import '../../../app/styles/sonarcloud.css';
+
+interface OwnProps {
+ location: Location;
+ onFinishOnboarding: () => void;
+ router: Pick<InjectedRouter, 'push' | 'replace'>;
+}
+
+interface StateProps {
+ currentUser: CurrentUser;
+}
+
+interface DispatchProps {
+ skipOnboarding: () => void;
+}
+
+type Props = OwnProps & StateProps & DispatchProps;
+
+export class CreateProjectPage extends React.PureComponent<Props> {
+ mounted = false;
+
+ constructor(props: Props) {
+ super(props);
+ if (!this.canAutoCreate(props)) {
+ this.updateQuery({ manual: true });
+ }
+ }
+
+ componentDidMount() {
+ this.mounted = true;
+ if (!isLoggedIn(this.props.currentUser)) {
+ handleRequiredAuthentication();
+ }
+ document.body.classList.add('white-page');
+ document.documentElement.classList.add('white-page');
+ }
+
+ componentWillUnmount() {
+ this.mounted = false;
+ document.body.classList.remove('white-page');
+ document.documentElement.classList.remove('white-page');
+ }
+
+ handleProjectCreate = (projects: Pick<ProjectBase, 'key'>[], organization?: string) => {
+ if (projects.length > 1 && organization) {
+ this.props.router.push(getOrganizationUrl(organization) + '/projects');
+ } else if (projects.length === 1) {
+ this.props.router.push(getProjectUrl(projects[0].key));
+ }
+ };
+
+ canAutoCreate = ({ currentUser } = this.props) => {
+ return (
+ isLoggedIn(currentUser) &&
+ ['bitbucket', 'github'].includes(currentUser.externalProvider || '')
+ );
+ };
+
+ showAuto = (event: React.MouseEvent<HTMLAnchorElement>) => {
+ event.preventDefault();
+ this.updateQuery({ manual: false });
+ };
+
+ showManual = (event: React.MouseEvent<HTMLAnchorElement>) => {
+ event.preventDefault();
+ this.updateQuery({ manual: true });
+ };
+
+ updateQuery = (changes: Partial<Query>) => {
+ this.props.router.replace({
+ pathname: this.props.location.pathname,
+ query: serializeQuery({ ...parseQuery(this.props.location.query), ...changes })
+ });
+ };
+
+ render() {
+ const { currentUser } = this.props;
+ if (!isLoggedIn(currentUser)) {
+ return null;
+ }
+ const displayManual = parseQuery(this.props.location.query).manual;
+ const header = translate('onboarding.create_project.header');
+ return (
+ <>
+ <Helmet title={header} titleTemplate="%s" />
+ <div className="sonarcloud page page-limited">
+ <div className="page-header">
+ <h1 className="page-title">{header}</h1>
+ </div>
+
+ {this.canAutoCreate() && (
+ <ul className="flex-tabs">
+ <li>
+ <a
+ className={classNames('js-auto', { selected: !displayManual })}
+ href="#"
+ onClick={this.showAuto}>
+ {translate('onboarding.create_project.select_repositories')}
+ <span
+ className={classNames(
+ 'rounded alert alert-small spacer-left display-inline-block',
+ {
+ 'alert-info': !displayManual,
+ 'alert-muted': displayManual
+ }
+ )}>
+ {translate('beta')}
+ </span>
+ </a>
+ </li>
+ <li>
+ <a
+ className={classNames('js-manual', { selected: displayManual })}
+ href="#"
+ onClick={this.showManual}>
+ {translate('onboarding.create_project.create_manually')}
+ </a>
+ </li>
+ </ul>
+ )}
+
+ {displayManual || !this.canAutoCreate() ? (
+ <ManualProjectCreate
+ currentUser={currentUser}
+ onProjectCreate={this.handleProjectCreate}
+ />
+ ) : (
+ <AutoProjectCreate
+ currentUser={currentUser}
+ onProjectCreate={this.handleProjectCreate}
+ />
+ )}
+ </div>
+ </>
+ );
+ }
+}
+
+const mapStateToProps = (state: any): StateProps => {
+ return {
+ currentUser: getCurrentUser(state)
+ };
+};
+
+const mapDispatchToProps: DispatchProps = { skipOnboarding };
+
+export default connect<StateProps, DispatchProps, OwnProps>(mapStateToProps, mapDispatchToProps)(
+ CreateProjectPage
+);
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { sortBy } from 'lodash';
+import { connect } from 'react-redux';
+import CreateOrganizationForm from '../../account/organizations/CreateOrganizationForm';
+import Select from '../../../components/controls/Select';
+import { Button, SubmitButton } from '../../../components/ui/buttons';
+import { LoggedInUser, Organization } from '../../../app/types';
+import { fetchMyOrganizations } from '../../account/organizations/actions';
+import { getMyOrganizations } from '../../../store/rootReducer';
+import { translate } from '../../../helpers/l10n';
+import { createProject, ProjectBase } from '../../../api/components';
+import DeferredSpinner from '../../../components/common/DeferredSpinner';
+
+interface StateProps {
+ userOrganizations: Organization[];
+}
+
+interface DispatchProps {
+ fetchMyOrganizations: () => Promise<void>;
+}
+
+interface OwnProps {
+ currentUser: LoggedInUser;
+ onProjectCreate: (project: ProjectBase[]) => void;
+}
+
+type Props = OwnProps & StateProps & DispatchProps;
+
+interface State {
+ createOrganizationModal: boolean;
+ projectName: string;
+ projectKey: string;
+ selectedOrganization: string;
+ submitting: boolean;
+}
+
+export class ManualProjectCreate extends React.PureComponent<Props, State> {
+ mounted = false;
+
+ constructor(props: Props) {
+ super(props);
+ this.state = {
+ createOrganizationModal: false,
+ projectName: '',
+ projectKey: '',
+ selectedOrganization:
+ props.userOrganizations.length === 1 ? props.userOrganizations[0].key : '',
+ submitting: false
+ };
+ }
+
+ componentDidMount() {
+ this.mounted = true;
+ }
+
+ componentWillUnmount() {
+ this.mounted = false;
+ }
+
+ closeCreateOrganization = () => {
+ this.setState({ createOrganizationModal: false });
+ };
+
+ handleFormSubmit = (event: React.FormEvent<HTMLFormElement>) => {
+ event.preventDefault();
+
+ if (this.isValid()) {
+ const { projectKey, projectName, selectedOrganization } = this.state;
+ this.setState({ submitting: true });
+ createProject({
+ project: projectKey,
+ name: projectName,
+ organization: selectedOrganization
+ }).then(
+ ({ project }) => this.props.onProjectCreate([project]),
+ () => {
+ if (this.mounted) {
+ this.setState({ submitting: false });
+ }
+ }
+ );
+ }
+ };
+
+ handleOrganizationSelect = ({ value }: { value: string }) => {
+ this.setState({ selectedOrganization: value });
+ };
+
+ handleProjectNameChange = (event: React.ChangeEvent<HTMLInputElement>) => {
+ this.setState({ projectName: event.currentTarget.value });
+ };
+
+ handleProjectKeyChange = (event: React.ChangeEvent<HTMLInputElement>) => {
+ this.setState({ projectKey: event.currentTarget.value });
+ };
+
+ isValid = () => {
+ const { projectKey, projectName, selectedOrganization } = this.state;
+ return Boolean(projectKey && projectName && selectedOrganization);
+ };
+
+ onCreateOrganization = (organization: { key: string }) => {
+ this.props.fetchMyOrganizations().then(
+ () => {
+ this.handleOrganizationSelect({ value: organization.key });
+ this.closeCreateOrganization();
+ },
+ () => {
+ this.closeCreateOrganization();
+ }
+ );
+ };
+
+ showCreateOrganization = () => {
+ this.setState({ createOrganizationModal: true });
+ };
+
+ render() {
+ const { submitting } = this.state;
+ return (
+ <>
+ <form onSubmit={this.handleFormSubmit}>
+ <div className="form-field">
+ <label htmlFor="select-organization">
+ {translate('onboarding.create_project.organization')}
+ <em className="mandatory">*</em>
+ </label>
+ <Select
+ autoFocus={true}
+ className="input-super-large"
+ clearable={false}
+ id="select-organization"
+ onChange={this.handleOrganizationSelect}
+ options={sortBy(this.props.userOrganizations, o => o.name.toLowerCase()).map(
+ organization => ({
+ label: organization.name,
+ value: organization.key
+ })
+ )}
+ required={true}
+ value={this.state.selectedOrganization}
+ />
+ <Button
+ className="button-link big-spacer-left js-new-org"
+ onClick={this.showCreateOrganization}>
+ {translate('onboarding.create_project.create_new_org')}
+ </Button>
+ </div>
+ <div className="form-field">
+ <label htmlFor="project-name">
+ {translate('onboarding.create_project.project_name')}
+ <em className="mandatory">*</em>
+ </label>
+ <input
+ className="input-super-large"
+ id="project-name"
+ maxLength={400}
+ minLength={1}
+ onChange={this.handleProjectNameChange}
+ required={true}
+ type="text"
+ value={this.state.projectName}
+ />
+ </div>
+ <div className="form-field">
+ <label htmlFor="project-key">
+ {translate('onboarding.create_project.project_key')}
+ <em className="mandatory">*</em>
+ </label>
+ <input
+ className="input-super-large"
+ id="project-key"
+ maxLength={400}
+ minLength={1}
+ onChange={this.handleProjectKeyChange}
+ required={true}
+ type="text"
+ value={this.state.projectKey}
+ />
+ </div>
+ <SubmitButton disabled={!this.isValid() || submitting}>
+ {translate('onboarding.create_project.create_project')}
+ </SubmitButton>
+ <DeferredSpinner className="spacer-left" loading={submitting} />
+ </form>
+ {this.state.createOrganizationModal && (
+ <CreateOrganizationForm
+ onClose={this.closeCreateOrganization}
+ onCreate={this.onCreateOrganization}
+ />
+ )}
+ </>
+ );
+ }
+}
+
+const mapDispatchToProps = ({
+ fetchMyOrganizations
+} as any) as DispatchProps;
+
+const mapStateToProps = (state: any): StateProps => {
+ return {
+ userOrganizations: getMyOrganizations(state)
+ };
+};
+export default connect<StateProps, DispatchProps, OwnProps>(mapStateToProps, mapDispatchToProps)(
+ ManualProjectCreate
+);
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import AlmRepositoryItem from '../AlmRepositoryItem';
+
+const identityProviders = {
+ backgroundColor: 'blue',
+ iconPath: 'icon/path',
+ key: 'foo',
+ name: 'Foo Provider'
+};
+
+const repositories = [
+ {
+ label: 'Cool Project',
+ installationKey: 'github/cool',
+ linkedProjectKey: 'proj_cool',
+ linkedProjectName: 'Proj Cool'
+ },
+ {
+ label: 'Awesome Project',
+ installationKey: 'github/awesome'
+ }
+];
+
+it('should render correctly', () => {
+ expect(getWrapper()).toMatchSnapshot();
+});
+
+it('should render selected', () => {
+ expect(getWrapper({ selected: true })).toMatchSnapshot();
+});
+
+it('should render disabled', () => {
+ expect(getWrapper({ repository: repositories[0] })).toMatchSnapshot();
+});
+
+function getWrapper(props = {}) {
+ return shallow(
+ <AlmRepositoryItem
+ identityProvider={identityProviders}
+ repository={repositories[1]}
+ selected={false}
+ toggleRepository={jest.fn()}
+ {...props}
+ />
+ );
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import AutoProjectCreate from '../AutoProjectCreate';
+import { getIdentityProviders } from '../../../../api/users';
+import { getRepositories } from '../../../../api/alm-integration';
+import { LoggedInUser } from '../../../../app/types';
+import { waitAndUpdate } from '../../../../helpers/testUtils';
+
+jest.mock('../../../../api/users', () => ({
+ getIdentityProviders: jest.fn().mockResolvedValue({
+ identityProviders: [
+ {
+ backgroundColor: 'blue',
+ iconPath: 'icon/path',
+ key: 'foo',
+ name: 'Foo Provider'
+ }
+ ]
+ })
+}));
+
+jest.mock('../../../../api/alm-integration', () => ({
+ getRepositories: jest.fn().mockResolvedValue({
+ almIntegration: {
+ installationUrl: 'https://alm.foo.com/install',
+ installed: false
+ },
+ repositories: []
+ }),
+ provisionProject: jest.fn().mockResolvedValue({ projects: [] })
+}));
+
+const user: LoggedInUser = { isLoggedIn: true, login: 'foo', name: 'Foo', externalProvider: 'foo' };
+const repositories = [
+ {
+ label: 'Cool Project',
+ installationKey: 'github/cool',
+ linkedProjectKey: 'proj_cool',
+ linkedProjectName: 'Proj Cool'
+ },
+ {
+ label: 'Awesome Project',
+ installationKey: 'github/awesome'
+ }
+];
+
+beforeEach(() => {
+ (getIdentityProviders as jest.Mock<any>).mockClear();
+ (getRepositories as jest.Mock<any>).mockClear();
+});
+
+it('should display the provider app install button', async () => {
+ const wrapper = getWrapper();
+ expect(wrapper).toMatchSnapshot();
+ expect(getIdentityProviders).toHaveBeenCalled();
+ expect(getRepositories).toHaveBeenCalled();
+
+ await waitAndUpdate(wrapper);
+ expect(wrapper).toMatchSnapshot();
+});
+
+it('should display the list of repositories', async () => {
+ (getRepositories as jest.Mock<any>).mockResolvedValue({
+ almIntegration: {
+ installationUrl: 'https://alm.foo.com/install',
+ installed: true
+ },
+ repositories
+ });
+ const wrapper = getWrapper();
+ await waitAndUpdate(wrapper);
+ expect(wrapper).toMatchSnapshot();
+});
+
+function getWrapper(props = {}) {
+ return shallow(<AutoProjectCreate currentUser={user} onProjectCreate={jest.fn()} {...props} />);
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import { Location } from 'history';
+import { CreateProjectPage } from '../CreateProjectPage';
+import { LoggedInUser } from '../../../../app/types';
+import { click } from '../../../../helpers/testUtils';
+
+const user: LoggedInUser = {
+ externalProvider: 'github',
+ isLoggedIn: true,
+ login: 'foo',
+ name: 'Foo'
+};
+
+it('should render correctly', () => {
+ expect(getWrapper()).toMatchSnapshot();
+});
+
+it('should render with Manual creation only', () => {
+ expect(getWrapper({ currentUser: { ...user, externalProvider: 'microsoft' } })).toMatchSnapshot();
+});
+
+it('should switch tabs', () => {
+ const replace = jest.fn();
+ const wrapper = getWrapper({ router: { replace } });
+ replace.mockImplementation(location => {
+ wrapper.setProps({ location }).update();
+ });
+
+ click(wrapper.find('.js-manual'));
+ expect(wrapper.find('Connect(ManualProjectCreate)').exists()).toBeTruthy();
+ click(wrapper.find('.js-auto'));
+ expect(wrapper.find('AutoProjectCreate').exists()).toBeTruthy();
+});
+
+function getWrapper(props = {}) {
+ return shallow(
+ <CreateProjectPage
+ currentUser={user}
+ location={{ pathname: 'foo', query: { manual: 'false' } } as Location}
+ onFinishOnboarding={jest.fn()}
+ router={{ push: jest.fn(), replace: jest.fn() }}
+ skipOnboarding={jest.fn()}
+ {...props}
+ />
+ );
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import { ManualProjectCreate } from '../ManualProjectCreate';
+import { change, click, submit, waitAndUpdate } from '../../../../helpers/testUtils';
+import { createProject } from '../../../../api/components';
+
+jest.mock('../../../../api/components', () => ({
+ createProject: jest.fn().mockResolvedValue({ project: { key: 'bar', name: 'Bar' } })
+}));
+
+beforeEach(() => {
+ (createProject as jest.Mock<any>).mockClear();
+});
+
+it('should render correctly', () => {
+ expect(getWrapper()).toMatchSnapshot();
+});
+
+it('should allow to create a new org', async () => {
+ const fetchMyOrganizations = jest.fn().mockResolvedValueOnce([]);
+ const wrapper = getWrapper({ fetchMyOrganizations });
+
+ click(wrapper.find('.js-new-org'));
+ const createForm = wrapper.find('Connect(CreateOrganizationForm)');
+ expect(createForm.exists()).toBeTruthy();
+
+ createForm.prop<Function>('onCreate')({ key: 'baz' });
+ expect(fetchMyOrganizations).toHaveBeenCalled();
+ await waitAndUpdate(wrapper);
+ expect(wrapper.state('selectedOrganization')).toBe('baz');
+});
+
+it('should correctly create a project', async () => {
+ const onProjectCreate = jest.fn();
+ const wrapper = getWrapper({ onProjectCreate });
+ wrapper.find('Select').prop<Function>('onChange')({ value: 'foo' });
+ change(wrapper.find('#project-name'), 'Bar');
+ expect(wrapper.find('SubmitButton')).toMatchSnapshot();
+
+ change(wrapper.find('#project-key'), 'bar');
+ expect(wrapper.find('SubmitButton')).toMatchSnapshot();
+
+ submit(wrapper.find('form'));
+ expect(createProject).toBeCalledWith({ project: 'bar', name: 'Bar', organization: 'foo' });
+
+ await waitAndUpdate(wrapper);
+ expect(onProjectCreate).toBeCalledWith([{ key: 'bar', name: 'Bar' }]);
+});
+
+function getWrapper(props = {}) {
+ return shallow(
+ <ManualProjectCreate
+ currentUser={{ isLoggedIn: true, login: 'foo', name: 'Foo' }}
+ fetchMyOrganizations={jest.fn()}
+ onProjectCreate={jest.fn()}
+ userOrganizations={[{ key: 'foo', name: 'Foo' }, { key: 'bar', name: 'Bar' }]}
+ {...props}
+ />
+ );
+}
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<Checkbox
+ checked={false}
+ disabled={false}
+ onCheck={[Function]}
+ thirdState={false}
+>
+ <img
+ alt="Foo Provider"
+ className="spacer-left"
+ height={14}
+ src="icon/path"
+ style={
+ Object {
+ "filter": "invert(100%)",
+ }
+ }
+ width={14}
+ />
+ <span
+ className="spacer-left"
+ >
+ Awesome Project
+ </span>
+</Checkbox>
+`;
+
+exports[`should render disabled 1`] = `
+<Checkbox
+ checked={true}
+ disabled={true}
+ onCheck={[Function]}
+ thirdState={false}
+>
+ <img
+ alt="Foo Provider"
+ className="spacer-left"
+ height={14}
+ src="icon/path"
+ style={
+ Object {
+ "filter": "invert(50%)",
+ }
+ }
+ width={14}
+ />
+ <span
+ className="spacer-left"
+ >
+ Cool Project
+ </span>
+ <span
+ className="big-spacer-left"
+ >
+ <CheckIcon
+ className="little-spacer-right"
+ />
+ onboarding.create_project.already_imported
+ </span>
+</Checkbox>
+`;
+
+exports[`should render selected 1`] = `
+<Checkbox
+ checked={true}
+ disabled={false}
+ onCheck={[Function]}
+ thirdState={false}
+>
+ <img
+ alt="Foo Provider"
+ className="spacer-left"
+ height={14}
+ src="icon/path"
+ style={
+ Object {
+ "filter": "invert(100%)",
+ }
+ }
+ width={14}
+ />
+ <span
+ className="spacer-left"
+ >
+ Awesome Project
+ </span>
+</Checkbox>
+`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should display the list of repositories 1`] = `
+<React.Fragment>
+ <p
+ className="alert alert-info width-60 big-spacer-bottom"
+ >
+ onboarding.create_project.beta_feature_x.Foo Provider
+ </p>
+ <form
+ onSubmit={[Function]}
+ >
+ <ul>
+ <li
+ className="big-spacer-bottom"
+ key="github/cool"
+ >
+ <AlmRepositoryItem
+ identityProvider={
+ Object {
+ "backgroundColor": "blue",
+ "iconPath": "icon/path",
+ "key": "foo",
+ "name": "Foo Provider",
+ }
+ }
+ repository={
+ Object {
+ "installationKey": "github/cool",
+ "label": "Cool Project",
+ "linkedProjectKey": "proj_cool",
+ "linkedProjectName": "Proj Cool",
+ }
+ }
+ selected={false}
+ toggleRepository={[Function]}
+ />
+ </li>
+ <li
+ className="big-spacer-bottom"
+ key="github/awesome"
+ >
+ <AlmRepositoryItem
+ identityProvider={
+ Object {
+ "backgroundColor": "blue",
+ "iconPath": "icon/path",
+ "key": "foo",
+ "name": "Foo Provider",
+ }
+ }
+ repository={
+ Object {
+ "installationKey": "github/awesome",
+ "label": "Awesome Project",
+ }
+ }
+ selected={false}
+ toggleRepository={[Function]}
+ />
+ </li>
+ </ul>
+ <SubmitButton
+ disabled={true}
+ >
+ onboarding.create_project.create_project
+ </SubmitButton>
+ <DeferredSpinner
+ className="spacer-left"
+ loading={false}
+ timeout={100}
+ />
+ </form>
+</React.Fragment>
+`;
+
+exports[`should display the provider app install button 1`] = `
+<DeferredSpinner
+ timeout={100}
+/>
+`;
+
+exports[`should display the provider app install button 2`] = `
+<React.Fragment>
+ <p
+ className="alert alert-info width-60 big-spacer-bottom"
+ >
+ onboarding.create_project.beta_feature_x.Foo Provider
+ </p>
+ <div>
+ <p
+ className="spacer-bottom"
+ >
+ onboarding.create_project.install_app_x.Foo Provider
+ </p>
+ <IdentityProviderLink
+ className="display-inline-block"
+ identityProvider={
+ Object {
+ "backgroundColor": "blue",
+ "iconPath": "icon/path",
+ "key": "foo",
+ "name": "Foo Provider",
+ }
+ }
+ small={true}
+ url="https://alm.foo.com/install"
+ >
+ onboarding.create_project.install_app_x.button.Foo Provider
+ </IdentityProviderLink>
+ </div>
+</React.Fragment>
+`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should render correctly 1`] = `
+<React.Fragment>
+ <HelmetWrapper
+ defer={true}
+ encodeSpecialCharacters={true}
+ title="onboarding.create_project.header"
+ titleTemplate="%s"
+ />
+ <div
+ className="sonarcloud page page-limited"
+ >
+ <div
+ className="page-header"
+ >
+ <h1
+ className="page-title"
+ >
+ onboarding.create_project.header
+ </h1>
+ </div>
+ <ul
+ className="flex-tabs"
+ >
+ <li>
+ <a
+ className="js-auto selected"
+ href="#"
+ onClick={[Function]}
+ >
+ onboarding.create_project.select_repositories
+ <span
+ className="rounded alert alert-small spacer-left display-inline-block alert-info"
+ >
+ beta
+ </span>
+ </a>
+ </li>
+ <li>
+ <a
+ className="js-manual"
+ href="#"
+ onClick={[Function]}
+ >
+ onboarding.create_project.create_manually
+ </a>
+ </li>
+ </ul>
+ <AutoProjectCreate
+ currentUser={
+ Object {
+ "externalProvider": "github",
+ "isLoggedIn": true,
+ "login": "foo",
+ "name": "Foo",
+ }
+ }
+ onProjectCreate={[Function]}
+ />
+ </div>
+</React.Fragment>
+`;
+
+exports[`should render with Manual creation only 1`] = `
+<React.Fragment>
+ <HelmetWrapper
+ defer={true}
+ encodeSpecialCharacters={true}
+ title="onboarding.create_project.header"
+ titleTemplate="%s"
+ />
+ <div
+ className="sonarcloud page page-limited"
+ >
+ <div
+ className="page-header"
+ >
+ <h1
+ className="page-title"
+ >
+ onboarding.create_project.header
+ </h1>
+ </div>
+ <Connect(ManualProjectCreate)
+ currentUser={
+ Object {
+ "externalProvider": "microsoft",
+ "isLoggedIn": true,
+ "login": "foo",
+ "name": "Foo",
+ }
+ }
+ onProjectCreate={[Function]}
+ />
+ </div>
+</React.Fragment>
+`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`should correctly create a project 1`] = `
+<SubmitButton
+ disabled={true}
+>
+ onboarding.create_project.create_project
+</SubmitButton>
+`;
+
+exports[`should correctly create a project 2`] = `
+<SubmitButton
+ disabled={false}
+>
+ onboarding.create_project.create_project
+</SubmitButton>
+`;
+
+exports[`should render correctly 1`] = `
+<React.Fragment>
+ <form
+ onSubmit={[Function]}
+ >
+ <div
+ className="form-field"
+ >
+ <label
+ htmlFor="select-organization"
+ >
+ onboarding.create_project.organization
+ <em
+ className="mandatory"
+ >
+ *
+ </em>
+ </label>
+ <Select
+ autoFocus={true}
+ className="input-super-large"
+ clearable={false}
+ id="select-organization"
+ onChange={[Function]}
+ options={
+ Array [
+ Object {
+ "label": "Bar",
+ "value": "bar",
+ },
+ Object {
+ "label": "Foo",
+ "value": "foo",
+ },
+ ]
+ }
+ required={true}
+ value=""
+ />
+ <Button
+ className="button-link big-spacer-left js-new-org"
+ onClick={[Function]}
+ >
+ onboarding.create_project.create_new_org
+ </Button>
+ </div>
+ <div
+ className="form-field"
+ >
+ <label
+ htmlFor="project-name"
+ >
+ onboarding.create_project.project_name
+ <em
+ className="mandatory"
+ >
+ *
+ </em>
+ </label>
+ <input
+ className="input-super-large"
+ id="project-name"
+ maxLength={400}
+ minLength={1}
+ onChange={[Function]}
+ required={true}
+ type="text"
+ value=""
+ />
+ </div>
+ <div
+ className="form-field"
+ >
+ <label
+ htmlFor="project-key"
+ >
+ onboarding.create_project.project_key
+ <em
+ className="mandatory"
+ >
+ *
+ </em>
+ </label>
+ <input
+ className="input-super-large"
+ id="project-key"
+ maxLength={400}
+ minLength={1}
+ onChange={[Function]}
+ required={true}
+ type="text"
+ value=""
+ />
+ </div>
+ <SubmitButton
+ disabled={true}
+ >
+ onboarding.create_project.create_project
+ </SubmitButton>
+ <DeferredSpinner
+ className="spacer-left"
+ loading={false}
+ timeout={100}
+ />
+ </form>
+</React.Fragment>
+`;
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import { memoize } from 'lodash';
+import {
+ cleanQuery,
+ RawQuery,
+ parseAsBoolean,
+ serializeOptionalBoolean
+} from '../../../helpers/query';
+
+export interface Query {
+ manual: boolean;
+}
+
+export const parseQuery = memoize((urlQuery: RawQuery): Query => {
+ return {
+ manual: parseAsBoolean(urlQuery['manual'], false)
+ };
+});
+
+export const serializeQuery = memoize((query: Query): RawQuery =>
+ cleanQuery({
+ manual: serializeOptionalBoolean(query.manual || undefined)
+ })
+);
import FavoriteProjectsContainer from './components/FavoriteProjectsContainer';
import { PROJECTS_DEFAULT_FILTER, PROJECTS_ALL } from './utils';
import { save } from '../../helpers/storage';
+import { isSonarCloud } from '../../helpers/system';
+import { lazyLoad } from '../../components/lazyLoad';
const routes = [
{ indexRoute: { component: DefaultPageSelectorContainer } },
replace('/projects');
}
},
- { path: 'favorite', component: FavoriteProjectsContainer }
-];
+ { path: 'favorite', component: FavoriteProjectsContainer },
+ isSonarCloud() && {
+ path: 'create',
+ component: lazyLoad(() => import('./create/CreateProjectPage'))
+ }
+].filter(Boolean);
export default routes;
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { connect } from 'react-redux';
-import handleRequiredAuthentication from '../../app/utils/handleRequiredAuthentication';
-import Modal from '../../components/controls/Modal';
-import OnboardingPrivateIcon from '../../components/icons-components/OnboardingPrivateIcon';
-import OnboardingProjectIcon from '../../components/icons-components/OnboardingProjectIcon';
-import OnboardingTeamIcon from '../../components/icons-components/OnboardingTeamIcon';
-import { Button, ResetButtonLink } from '../../components/ui/buttons';
-import { translate } from '../../helpers/l10n';
-import { CurrentUser, isLoggedIn } from '../../app/types';
-import { getCurrentUser } from '../../store/rootReducer';
-import './styles.css';
-
-interface OwnProps {
- onClose: () => void;
- onOpenOrganizationOnboarding: () => void;
- onOpenProjectOnboarding: () => void;
- onOpenTeamOnboarding: () => void;
-}
-
-interface StateProps {
- currentUser: CurrentUser;
-}
-
-type Props = OwnProps & StateProps;
-
-export class Onboarding extends React.PureComponent<Props> {
- componentDidMount() {
- if (!isLoggedIn(this.props.currentUser)) {
- handleRequiredAuthentication();
- }
- }
-
- render() {
- if (!isLoggedIn(this.props.currentUser)) {
- return null;
- }
-
- const header = translate('onboarding.header');
- return (
- <Modal
- contentLabel={header}
- medium={true}
- onRequestClose={this.props.onClose}
- shouldCloseOnOverlayClick={false}>
- <div className="modal-simple-head text-center">
- <h1>{translate('onboarding.header')}</h1>
- <p className="spacer-top">{translate('onboarding.header.description')}</p>
- </div>
- <div className="modal-simple-body text-center onboarding-choices">
- <Button className="onboarding-choice" onClick={this.props.onOpenProjectOnboarding}>
- <OnboardingProjectIcon />
- <span>{translate('onboarding.analyze_public_code')}</span>
- <p className="note">{translate('onboarding.analyze_public_code.note')}</p>
- </Button>
- <Button className="onboarding-choice" onClick={this.props.onOpenOrganizationOnboarding}>
- <OnboardingPrivateIcon />
- <span>{translate('onboarding.analyze_private_code')}</span>
- <p className="note">{translate('onboarding.analyze_private_code.note')}</p>
- </Button>
- <Button className="onboarding-choice" onClick={this.props.onOpenTeamOnboarding}>
- <OnboardingTeamIcon />
- <span>{translate('onboarding.contribute_existing_project')}</span>
- <p className="note">{translate('onboarding.contribute_existing_project.note')}</p>
- </Button>
- </div>
- <div className="modal-simple-footer text-center">
- <ResetButtonLink className="spacer-bottom" onClick={this.props.onClose}>
- {translate('not_now')}
- </ResetButtonLink>
- <p className="note">{translate('onboarding.footer')}</p>
- </div>
- </Modal>
- );
- }
-}
-
-const mapStateToProps = (state: any): StateProps => ({ currentUser: getCurrentUser(state) });
-
-export default connect<StateProps, {}, OwnProps>(mapStateToProps)(Onboarding);
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { shallow } from 'enzyme';
-import { Onboarding } from '../Onboarding';
-import { click } from '../../../helpers/testUtils';
-
-it('renders correctly', () => {
- expect(
- shallow(
- <Onboarding
- currentUser={{ isLoggedIn: true }}
- onClose={jest.fn()}
- onOpenOrganizationOnboarding={jest.fn()}
- onOpenProjectOnboarding={jest.fn()}
- onOpenTeamOnboarding={jest.fn()}
- />
- )
- ).toMatchSnapshot();
-});
-
-it('should correctly open the different tutorials', () => {
- const onClose = jest.fn();
- const onOpenOrganizationOnboarding = jest.fn();
- const onOpenProjectOnboarding = jest.fn();
- const onOpenTeamOnboarding = jest.fn();
- const push = jest.fn();
- const wrapper = shallow(
- <Onboarding
- currentUser={{ isLoggedIn: true }}
- onClose={onClose}
- onOpenOrganizationOnboarding={onOpenOrganizationOnboarding}
- onOpenProjectOnboarding={onOpenProjectOnboarding}
- onOpenTeamOnboarding={onOpenTeamOnboarding}
- />,
- { context: { router: { push } } }
- );
-
- click(wrapper.find('ResetButtonLink'));
- expect(onClose).toHaveBeenCalled();
-
- wrapper.find('Button').forEach(button => click(button));
- expect(onOpenOrganizationOnboarding).toHaveBeenCalled();
- expect(onOpenProjectOnboarding).toHaveBeenCalled();
- expect(onOpenTeamOnboarding).toHaveBeenCalled();
-});
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`renders correctly 1`] = `
-<Modal
- contentLabel="onboarding.header"
- medium={true}
- onRequestClose={[MockFunction]}
- shouldCloseOnOverlayClick={false}
->
- <div
- className="modal-simple-head text-center"
- >
- <h1>
- onboarding.header
- </h1>
- <p
- className="spacer-top"
- >
- onboarding.header.description
- </p>
- </div>
- <div
- className="modal-simple-body text-center onboarding-choices"
- >
- <Button
- className="onboarding-choice"
- onClick={[MockFunction]}
- >
- <OnboardingProjectIcon />
- <span>
- onboarding.analyze_public_code
- </span>
- <p
- className="note"
- >
- onboarding.analyze_public_code.note
- </p>
- </Button>
- <Button
- className="onboarding-choice"
- onClick={[MockFunction]}
- >
- <OnboardingPrivateIcon />
- <span>
- onboarding.analyze_private_code
- </span>
- <p
- className="note"
- >
- onboarding.analyze_private_code.note
- </p>
- </Button>
- <Button
- className="onboarding-choice"
- onClick={[MockFunction]}
- >
- <OnboardingTeamIcon />
- <span>
- onboarding.contribute_existing_project
- </span>
- <p
- className="note"
- >
- onboarding.contribute_existing_project.note
- </p>
- </Button>
- </div>
- <div
- className="modal-simple-footer text-center"
- >
- <ResetButtonLink
- className="spacer-bottom"
- onClick={[MockFunction]}
- >
- not_now
- </ResetButtonLink>
- <p
- className="note"
- >
- onboarding.footer
- </p>
- </div>
-</Modal>
-`;
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import AnalyzeTutorialSuggestion from './AnalyzeTutorialSuggestion';
+import ProjectAnalysisStep from '../components/ProjectAnalysisStep';
+import TokenStep from '../components/TokenStep';
+import { Component, LoggedInUser } from '../../../app/types';
+import { translate } from '../../../helpers/l10n';
+import '../styles.css';
+
+enum Steps {
+ ANALYSIS,
+ TOKEN
+}
+
+interface Props {
+ component: Component;
+ currentUser: LoggedInUser;
+}
+
+interface State {
+ step: Steps;
+ token?: string;
+}
+
+export default class AnalyzeTutorial extends React.PureComponent<Props, State> {
+ state: State = { step: Steps.TOKEN };
+
+ handleTokenDone = (token: string) => {
+ this.setState({ step: Steps.ANALYSIS, token });
+ };
+
+ handleTokenOpen = () => {
+ this.setState({ step: Steps.TOKEN });
+ };
+
+ render() {
+ const { component, currentUser } = this.props;
+ const { step, token } = this.state;
+ let stepNumber = 1;
+
+ const almId = component.almId || currentUser.externalProvider;
+ const showTutorial = almId !== 'microsoft';
+ return (
+ <>
+ <div className="page-header big-spacer-bottom">
+ <h1 className="page-title">{translate('onboarding.project_analysis.header')}</h1>
+ <p className="page-description">{translate('onboarding.project_analysis.description')}</p>
+ </div>
+
+ <AnalyzeTutorialSuggestion almId={almId} />
+
+ {showTutorial && (
+ <>
+ <TokenStep
+ currentUser={currentUser}
+ finished={Boolean(this.state.token)}
+ onContinue={this.handleTokenDone}
+ onOpen={this.handleTokenOpen}
+ open={step === Steps.TOKEN}
+ stepNumber={stepNumber++}
+ />
+
+ <ProjectAnalysisStep
+ component={component}
+ displayRowLayout={true}
+ open={step === Steps.ANALYSIS}
+ organization={component.organization}
+ stepNumber={stepNumber++}
+ token={token}
+ />
+ </>
+ )}
+ </>
+ );
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { FormattedMessage } from 'react-intl';
+import { translate } from '../../../helpers/l10n';
+import { getBaseUrl } from '../../../helpers/urls';
+
+export default function AnalyzeTutorialSuggestion({ almId }: { almId?: string }) {
+ if (almId && almId.startsWith('bitbucket')) {
+ return (
+ <div className="alert alert-info big-spacer-bottom">
+ <p>{translate('onboarding.project_analysis.commands_for_analysis')}</p>
+ <p>{translate('onboarding.project_analysis.suggestions.bitbucket')}</p>
+ <FormattedMessage
+ defaultMessage={translate('onboarding.project_analysis.simply_link')}
+ id={'onboarding.project_analysis.simply_link'}
+ values={{
+ link: (
+ <a
+ href={
+ getBaseUrl() +
+ '/documentation/integrations/bitbucketcloud#analyzing-with-pipelines'
+ }
+ target="_blank">
+ {translate('onboarding.project_analysis.guide_to_integrate_piplines')}
+ </a>
+ )
+ }}
+ />
+ </div>
+ );
+ } else if (almId === 'github') {
+ return (
+ <div className="alert alert-info big-spacer-bottom">
+ <p>{translate('onboarding.project_analysis.commands_for_analysis')} </p>
+ <p>{translate('onboarding.project_analysis.suggestions.github')}</p>
+ <FormattedMessage
+ defaultMessage={translate('onboarding.project_analysis.simply_link')}
+ id={'onboarding.project_analysis.simply_link'}
+ values={{
+ link: (
+ <a
+ href="https://docs.travis-ci.com/user/sonarcloud/"
+ rel="noopener noreferrer"
+ target="_blank">
+ {translate('onboarding.project_analysis.guide_to_integrate_travis')}
+ </a>
+ )
+ }}
+ />
+ </div>
+ );
+ } else if (almId === 'microsoft') {
+ return (
+ <p className="alert alert-info big-spacer-bottom">
+ <FormattedMessage
+ defaultMessage={translate('onboarding.project_analysis.simply_link')}
+ id={'onboarding.project_analysis.simply_link'}
+ values={{
+ link: (
+ <a href={getBaseUrl() + '/documentation/integrations/vsts'} target="_blank">
+ {translate('onboarding.project_analysis.guide_to_integrate_vsts')}
+ </a>
+ )
+ }}
+ />
+ </p>
+ );
+ }
+ return null;
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import AnalyzeTutorial from '../AnalyzeTutorial';
+import { LoggedInUser } from '../../../../app/types';
+
+const component = {
+ key: 'foo',
+ analysisDate: '2016-01-01',
+ breadcrumbs: [],
+ name: 'Foo',
+ organization: 'org',
+ qualifier: 'TRK',
+ version: '0.0.1'
+};
+
+const loggedInUser: LoggedInUser = {
+ isLoggedIn: true,
+ login: 'luke',
+ name: 'Skywalker'
+};
+
+it('renders correctly', () => {
+ expect(getWrapper()).toMatchSnapshot();
+});
+
+function getWrapper(props = {}) {
+ return shallow(<AnalyzeTutorial component={component} currentUser={loggedInUser} {...props} />);
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import AnalyzeTutorialSuggestion from '../AnalyzeTutorialSuggestion';
+
+it('should not render', () => {
+ expect(shallow(<AnalyzeTutorialSuggestion almId={undefined} />).type()).toBeNull();
+});
+
+it('renders bitbucket suggestions correctly', () => {
+ expect(shallow(<AnalyzeTutorialSuggestion almId="bitbucket" />)).toMatchSnapshot();
+});
+
+it('renders github suggestions correctly', () => {
+ expect(shallow(<AnalyzeTutorialSuggestion almId="github" />)).toMatchSnapshot();
+});
+
+it('renders vsts suggestions correctly', () => {
+ expect(shallow(<AnalyzeTutorialSuggestion almId="microsoft" />)).toMatchSnapshot();
+});
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+<React.Fragment>
+ <div
+ className="page-header big-spacer-bottom"
+ >
+ <h1
+ className="page-title"
+ >
+ onboarding.project_analysis.header
+ </h1>
+ <p
+ className="page-description"
+ >
+ onboarding.project_analysis.description
+ </p>
+ </div>
+ <AnalyzeTutorialSuggestion />
+ <React.Fragment>
+ <TokenStep
+ currentUser={
+ Object {
+ "isLoggedIn": true,
+ "login": "luke",
+ "name": "Skywalker",
+ }
+ }
+ finished={false}
+ onContinue={[Function]}
+ onOpen={[Function]}
+ open={true}
+ stepNumber={1}
+ />
+ <ProjectAnalysisStep
+ component={
+ Object {
+ "analysisDate": "2016-01-01",
+ "breadcrumbs": Array [],
+ "key": "foo",
+ "name": "Foo",
+ "organization": "org",
+ "qualifier": "TRK",
+ "version": "0.0.1",
+ }
+ }
+ displayRowLayout={true}
+ open={false}
+ organization="org"
+ stepNumber={2}
+ />
+ </React.Fragment>
+</React.Fragment>
+`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders bitbucket suggestions correctly 1`] = `
+<div
+ className="alert alert-info big-spacer-bottom"
+>
+ <p>
+ onboarding.project_analysis.commands_for_analysis
+ </p>
+ <p>
+ onboarding.project_analysis.suggestions.bitbucket
+ </p>
+ <FormattedMessage
+ defaultMessage="onboarding.project_analysis.simply_link"
+ id="onboarding.project_analysis.simply_link"
+ values={
+ Object {
+ "link": <a
+ href="/documentation/integrations/bitbucketcloud#analyzing-with-pipelines"
+ target="_blank"
+ >
+ onboarding.project_analysis.guide_to_integrate_piplines
+ </a>,
+ }
+ }
+ />
+</div>
+`;
+
+exports[`renders github suggestions correctly 1`] = `
+<div
+ className="alert alert-info big-spacer-bottom"
+>
+ <p>
+ onboarding.project_analysis.commands_for_analysis
+
+ </p>
+ <p>
+ onboarding.project_analysis.suggestions.github
+ </p>
+ <FormattedMessage
+ defaultMessage="onboarding.project_analysis.simply_link"
+ id="onboarding.project_analysis.simply_link"
+ values={
+ Object {
+ "link": <a
+ href="https://docs.travis-ci.com/user/sonarcloud/"
+ rel="noopener noreferrer"
+ target="_blank"
+ >
+ onboarding.project_analysis.guide_to_integrate_travis
+ </a>,
+ }
+ }
+ />
+</div>
+`;
+
+exports[`renders vsts suggestions correctly 1`] = `
+<p
+ className="alert alert-info big-spacer-bottom"
+>
+ <FormattedMessage
+ defaultMessage="onboarding.project_analysis.simply_link"
+ id="onboarding.project_analysis.simply_link"
+ values={
+ Object {
+ "link": <a
+ href="/documentation/integrations/vsts"
+ target="_blank"
+ >
+ onboarding.project_analysis.guide_to_integrate_vsts
+ </a>,
+ }
+ }
+ />
+</p>
+`;
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+import * as React from 'react';
+import NewProjectForm from './NewProjectForm';
+import RadioToggle from '../../../components/controls/RadioToggle';
+import { translate } from '../../../helpers/l10n';
+import { isSonarCloud } from '../../../helpers/system';
+import { Component } from '../../../app/types';
+import { isLanguageConfigured, LanguageConfig } from '../utils';
+
+interface Props {
+ component?: Component;
+ config?: LanguageConfig;
+ onDone: (config: LanguageConfig) => void;
+ onReset: () => void;
+ organization?: string;
+}
+
+type State = LanguageConfig;
+
+export default class LanguageForm extends React.PureComponent<Props, State> {
+ constructor(props: Props) {
+ super(props);
+ this.state = {
+ ...(this.props.config || {}),
+ projectKey: props.component ? props.component.key : undefined
+ };
+ }
+
+ handleChange = () => {
+ if (isLanguageConfigured(this.state)) {
+ this.props.onDone(this.state);
+ } else {
+ this.props.onReset();
+ }
+ };
+
+ handleLanguageChange = (language: string) => {
+ this.setState({ language }, this.handleChange);
+ };
+
+ handleJavaBuildChange = (javaBuild: string) => {
+ this.setState({ javaBuild }, this.handleChange);
+ };
+
+ handleCFamilyCompilerChange = (cFamilyCompiler: string) => {
+ this.setState({ cFamilyCompiler }, this.handleChange);
+ };
+
+ handleOSChange = (os: string) => {
+ this.setState({ os }, this.handleChange);
+ };
+
+ handleProjectKeyDone = (projectKey: string) => {
+ this.setState({ projectKey }, this.handleChange);
+ };
+
+ handleProjectKeyDelete = () => {
+ this.setState({ projectKey: undefined }, this.handleChange);
+ };
+
+ renderJavaBuild = () => (
+ <div className="big-spacer-top">
+ <h4 className="spacer-bottom">{translate('onboarding.language.java.build_technology')}</h4>
+ <RadioToggle
+ name="java-build"
+ onCheck={this.handleJavaBuildChange}
+ options={['maven', 'gradle'].map(build => ({
+ label: translate('onboarding.language.java.build_technology', build),
+ value: build
+ }))}
+ value={this.state.javaBuild}
+ />
+ </div>
+ );
+
+ renderCFamilyCompiler = () => (
+ <div className="big-spacer-top">
+ <h4 className="spacer-bottom">{translate('onboarding.language.c-family.compiler')}</h4>
+ <RadioToggle
+ name="c-family-compiler"
+ onCheck={this.handleCFamilyCompilerChange}
+ options={['msvc', 'clang-gcc'].map(compiler => ({
+ label: translate('onboarding.language.c-family.compiler', compiler),
+ value: compiler
+ }))}
+ value={this.state.cFamilyCompiler}
+ />
+ </div>
+ );
+
+ renderOS = () => (
+ <div className="big-spacer-top">
+ <h4 className="spacer-bottom">{translate('onboarding.language.os')}</h4>
+ <RadioToggle
+ name="os"
+ onCheck={this.handleOSChange}
+ options={['linux', 'win', 'mac'].map(os => ({
+ label: translate('onboarding.language.os', os),
+ value: os
+ }))}
+ value={this.state.os}
+ />
+ </div>
+ );
+
+ renderProjectKey = () => {
+ const { cFamilyCompiler, language, os } = this.state;
+ const needProjectKey =
+ language === 'dotnet' ||
+ (language === 'c-family' &&
+ (cFamilyCompiler === 'msvc' || (cFamilyCompiler === 'clang-gcc' && os !== undefined))) ||
+ (language === 'other' && os !== undefined);
+
+ if (!needProjectKey || this.props.component) {
+ return null;
+ }
+
+ return (
+ <NewProjectForm
+ onDelete={this.handleProjectKeyDelete}
+ onDone={this.handleProjectKeyDone}
+ organization={this.props.organization}
+ projectKey={this.state.projectKey}
+ />
+ );
+ };
+
+ render() {
+ const { cFamilyCompiler, language } = this.state;
+ const languages = isSonarCloud()
+ ? ['java', 'dotnet', 'c-family', 'other']
+ : ['java', 'dotnet', 'other'];
+
+ return (
+ <>
+ <div>
+ <h4 className="spacer-bottom">{translate('onboarding.language')}</h4>
+ <RadioToggle
+ name="language"
+ onCheck={this.handleLanguageChange}
+ options={languages.map(language => ({
+ label: translate('onboarding.language', language),
+ value: language
+ }))}
+ value={language}
+ />
+ </div>
+ {language === 'java' && this.renderJavaBuild()}
+ {language === 'c-family' && this.renderCFamilyCompiler()}
+ {((language === 'c-family' && cFamilyCompiler === 'clang-gcc') || language === 'other') &&
+ this.renderOS()}
+ {this.renderProjectKey()}
+ </>
+ );
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { debounce } from 'lodash';
+import {
+ createOrganization,
+ deleteOrganization,
+ getOrganization
+} from '../../../api/organizations';
+import AlertErrorIcon from '../../../components/icons-components/AlertErrorIcon';
+import { DeleteButton, SubmitButton } from '../../../components/ui/buttons';
+import { translate } from '../../../helpers/l10n';
+
+interface Props {
+ onDelete: () => void;
+ onDone: (organization: string) => void;
+ organization?: string;
+}
+
+interface State {
+ done: boolean;
+ loading: boolean;
+ organization: string;
+ unique: boolean;
+}
+
+export default class NewOrganizationForm extends React.PureComponent<Props, State> {
+ mounted = false;
+
+ constructor(props: Props) {
+ super(props);
+ this.state = {
+ done: props.organization != null,
+ loading: false,
+ organization: props.organization || '',
+ unique: true
+ };
+ this.validateOrganization = debounce(this.validateOrganization, 500);
+ }
+
+ componentDidMount() {
+ this.mounted = true;
+ }
+
+ componentWillUnmount() {
+ this.mounted = false;
+ }
+
+ stopLoading = () => {
+ if (this.mounted) {
+ this.setState({ loading: false });
+ }
+ };
+
+ validateOrganization = (organization: string) => {
+ getOrganization(organization).then(
+ response => {
+ if (this.mounted) {
+ this.setState({ unique: response == null });
+ }
+ },
+ () => {}
+ );
+ };
+
+ sanitizeOrganization = (organization: string) =>
+ organization
+ .toLowerCase()
+ .replace(/[^a-z0-9-]/, '')
+ .replace(/^-/, '');
+
+ handleOrganizationChange = (event: React.ChangeEvent<HTMLInputElement>) => {
+ const organization = this.sanitizeOrganization(event.target.value);
+ this.setState({ organization });
+ this.validateOrganization(organization);
+ };
+
+ handleOrganizationCreate = (event: React.FormEvent<HTMLFormElement>) => {
+ event.preventDefault();
+ const { organization } = this.state;
+ if (organization) {
+ this.setState({ loading: true });
+ createOrganization({ key: organization, name: organization }).then(() => {
+ if (this.mounted) {
+ this.setState({ done: true, loading: false });
+ this.props.onDone(organization);
+ }
+ }, this.stopLoading);
+ }
+ };
+
+ handleOrganizationDelete = () => {
+ const { organization } = this.state;
+ if (organization) {
+ this.setState({ loading: true });
+ deleteOrganization(organization).then(() => {
+ if (this.mounted) {
+ this.setState({ done: false, loading: false, organization: '' });
+ this.props.onDelete();
+ }
+ }, this.stopLoading);
+ }
+ };
+
+ render() {
+ const { done, loading, organization, unique } = this.state;
+
+ const valid = unique && organization.length >= 2;
+
+ return done ? (
+ <div>
+ <span className="spacer-right text-middle">{organization}</span>
+ {loading ? (
+ <i className="spinner text-middle" />
+ ) : (
+ <DeleteButton className="button-small" onClick={this.handleOrganizationDelete} />
+ )}
+ </div>
+ ) : (
+ <form onSubmit={this.handleOrganizationCreate}>
+ <input
+ autoFocus={true}
+ className="input-super-large spacer-right text-middle"
+ maxLength={32}
+ minLength={2}
+ onChange={this.handleOrganizationChange}
+ placeholder={translate('onboarding.organization.placeholder')}
+ required={true}
+ type="text"
+ value={organization}
+ />
+ {loading ? (
+ <i className="spinner text-middle" />
+ ) : (
+ <SubmitButton className="text-middle" disabled={!valid}>
+ {translate('create')}
+ </SubmitButton>
+ )}
+ {!unique && (
+ <span className="big-spacer-left text-danger text-middle">
+ <AlertErrorIcon className="little-spacer-right text-text-top" />
+ {translate('this_name_is_already_taken')}
+ </span>
+ )}
+ <div className="note spacer-top abs-width-300">
+ {translate('onboarding.organization.key_requirement')}
+ </div>
+ </form>
+ );
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { createProject, deleteProject } from '../../../api/components';
+import { DeleteButton, SubmitButton } from '../../../components/ui/buttons';
+import { translate } from '../../../helpers/l10n';
+
+interface Props {
+ onDelete: () => void;
+ onDone: (projectKey: string) => void;
+ organization?: string;
+ projectKey?: string;
+}
+
+interface State {
+ done: boolean;
+ loading: boolean;
+ projectKey: string;
+}
+
+export default class NewProjectForm extends React.PureComponent<Props, State> {
+ mounted = false;
+
+ constructor(props: Props) {
+ super(props);
+ this.state = {
+ done: props.projectKey != null,
+ loading: false,
+ projectKey: props.projectKey || ''
+ };
+ }
+
+ componentDidMount() {
+ this.mounted = true;
+ }
+
+ componentWillUnmount() {
+ this.mounted = false;
+ }
+
+ stopLoading = () => {
+ if (this.mounted) {
+ this.setState({ loading: false });
+ }
+ };
+
+ sanitizeProjectKey = (projectKey: string) => projectKey.replace(/[^-_a-zA-Z0-9.:]/, '');
+
+ handleProjectKeyChange = (event: React.ChangeEvent<HTMLInputElement>) => {
+ this.setState({ projectKey: this.sanitizeProjectKey(event.target.value) });
+ };
+
+ handleProjectCreate = (event: React.FormEvent<HTMLFormElement>) => {
+ event.preventDefault();
+ const { projectKey } = this.state;
+ const data: {
+ name: string;
+ project: string;
+ organization?: string;
+ } = {
+ name: projectKey,
+ project: projectKey
+ };
+ if (this.props.organization) {
+ data.organization = this.props.organization;
+ }
+ this.setState({ loading: true });
+ createProject(data).then(() => {
+ if (this.mounted) {
+ this.setState({ done: true, loading: false });
+ this.props.onDone(projectKey);
+ }
+ }, this.stopLoading);
+ };
+
+ handleProjectDelete = () => {
+ const { projectKey } = this.state;
+ this.setState({ loading: true });
+ deleteProject(projectKey).then(() => {
+ if (this.mounted) {
+ this.setState({ done: false, loading: false, projectKey: '' });
+ this.props.onDelete();
+ }
+ }, this.stopLoading);
+ };
+
+ render() {
+ const { done, loading, projectKey } = this.state;
+
+ const valid = projectKey.length > 0;
+
+ const form = done ? (
+ <div>
+ <span className="spacer-right text-middle">{projectKey}</span>
+ {loading ? (
+ <i className="spinner text-middle" />
+ ) : (
+ <DeleteButton className="button-small text-middle" onClick={this.handleProjectDelete} />
+ )}
+ </div>
+ ) : (
+ <form onSubmit={this.handleProjectCreate}>
+ <input
+ autoFocus={true}
+ className="input-large spacer-right text-middle"
+ maxLength={400}
+ minLength={1}
+ onChange={this.handleProjectKeyChange}
+ required={true}
+ type="text"
+ value={projectKey}
+ />
+ {loading ? (
+ <i className="spinner text-middle" />
+ ) : (
+ <SubmitButton className="text-middle" disabled={!valid}>
+ {translate('Done')}
+ </SubmitButton>
+ )}
+ <div className="note spacer-top abs-width-300">
+ {translate('onboarding.project_key_requirement')}
+ </div>
+ </form>
+ );
+
+ return (
+ <div className="big-spacer-top">
+ <h4 className="spacer-bottom">{translate('onboarding.language.project_key')}</h4>
+ {form}
+ </div>
+ );
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import * as classNames from 'classnames';
+import { sortBy } from 'lodash';
+import Step from './Step';
+import NewOrganizationForm from './NewOrganizationForm';
+import DocTooltip from '../../../components/docs/DocTooltip';
+import AlertSuccessIcon from '../../../components/icons-components/AlertSuccessIcon';
+import { getOrganizations } from '../../../api/organizations';
+import Select from '../../../components/controls/Select';
+import { translate } from '../../../helpers/l10n';
+import { Button } from '../../../components/ui/buttons';
+
+interface Props {
+ currentUser: { login: string; isLoggedIn: boolean };
+ finished: boolean;
+ onOpen: () => void;
+ onContinue: (organization: string) => void;
+ open: boolean;
+ stepNumber: number;
+}
+
+interface State {
+ loading: boolean;
+ newOrganization?: string;
+ existingOrganization?: string;
+ existingOrganizations: Array<string>;
+ personalOrganization?: string;
+ selection: 'personal' | 'existing' | 'new';
+}
+
+export default class OrganizationStep extends React.PureComponent<Props, State> {
+ mounted = false;
+ state: State = {
+ loading: true,
+ existingOrganizations: [],
+ selection: 'personal'
+ };
+
+ componentDidMount() {
+ this.mounted = true;
+ this.fetchOrganizations();
+ }
+
+ componentWillUnmount() {
+ this.mounted = false;
+ }
+
+ fetchOrganizations = () => {
+ getOrganizations({ member: true }).then(
+ ({ organizations }) => {
+ if (this.mounted) {
+ const organizationKeys = organizations.filter(o => o.isAdmin).map(o => o.key);
+ // best guess: if there is only one organization, then it is personal
+ // otherwise, we can't guess, let's display them all as just "existing organizations"
+ const personalOrganization =
+ organizationKeys.length === 1 ? organizationKeys[0] : undefined;
+ const existingOrganizations = organizationKeys.length > 1 ? sortBy(organizationKeys) : [];
+ const selection = personalOrganization
+ ? 'personal'
+ : existingOrganizations.length > 0 ? 'existing' : 'new';
+ this.setState({
+ loading: false,
+ existingOrganizations,
+ personalOrganization,
+ selection
+ });
+ }
+ },
+ () => {
+ if (this.mounted) {
+ this.setState({ loading: false });
+ }
+ }
+ );
+ };
+
+ getSelectedOrganization = () => {
+ switch (this.state.selection) {
+ case 'personal':
+ return this.state.personalOrganization;
+ case 'existing':
+ return this.state.existingOrganization;
+ case 'new':
+ return this.state.newOrganization;
+ default:
+ return null;
+ }
+ };
+
+ handlePersonalClick = (event: React.MouseEvent<HTMLAnchorElement>) => {
+ event.preventDefault();
+ this.setState({ selection: 'personal' });
+ };
+
+ handleExistingClick = (event: React.MouseEvent<HTMLAnchorElement>) => {
+ event.preventDefault();
+ this.setState({ selection: 'existing' });
+ };
+
+ handleNewClick = (event: React.MouseEvent<HTMLAnchorElement>) => {
+ event.preventDefault();
+ this.setState({ selection: 'new' });
+ };
+
+ handleOrganizationCreate = (newOrganization: string) => {
+ this.setState({ newOrganization });
+ };
+
+ handleOrganizationDelete = () => {
+ this.setState({ newOrganization: undefined });
+ };
+
+ handleExistingOrganizationSelect = ({ value }: { value: string }) => {
+ this.setState({ existingOrganization: value });
+ };
+
+ handleContinueClick = () => {
+ const organization = this.getSelectedOrganization();
+ if (organization) {
+ this.props.onContinue(organization);
+ }
+ };
+
+ renderPersonalOrganizationOption = () => (
+ <div>
+ <a className="link-base-color link-no-underline" href="#" onClick={this.handlePersonalClick}>
+ <i
+ className={classNames('icon-radio', 'spacer-right', {
+ 'is-checked': this.state.selection === 'personal'
+ })}
+ />
+ {translate('onboarding.organization.my_personal_organization')}
+ <span className="note spacer-left">{this.state.personalOrganization}</span>
+ </a>
+ </div>
+ );
+
+ renderExistingOrganizationOption = () => (
+ <div className="big-spacer-top">
+ <a
+ className="js-existing link-base-color link-no-underline"
+ href="#"
+ onClick={this.handleExistingClick}>
+ <i
+ className={classNames('icon-radio', 'spacer-right', {
+ 'is-checked': this.state.selection === 'existing'
+ })}
+ />
+ {translate('onboarding.organization.exising_organization')}
+ </a>
+ {this.state.selection === 'existing' && (
+ <div className="big-spacer-top">
+ <Select
+ className="input-super-large"
+ clearable={false}
+ onChange={this.handleExistingOrganizationSelect}
+ options={this.state.existingOrganizations.map(organization => ({
+ label: organization,
+ value: organization
+ }))}
+ value={this.state.existingOrganization}
+ />
+ </div>
+ )}
+ </div>
+ );
+
+ renderNewOrganizationOption = () => (
+ <div className="big-spacer-top">
+ <a
+ className="js-new link-base-color link-no-underline"
+ href="#"
+ onClick={this.handleNewClick}>
+ <i
+ className={classNames('icon-radio', 'spacer-right', {
+ 'is-checked': this.state.selection === 'new'
+ })}
+ />
+ {translate('onboarding.organization.create_another_organization')}
+ </a>
+ {this.state.selection === 'new' && (
+ <div className="big-spacer-top">
+ <NewOrganizationForm
+ onDelete={this.handleOrganizationDelete}
+ onDone={this.handleOrganizationCreate}
+ organization={this.state.newOrganization}
+ />
+ </div>
+ )}
+ </div>
+ );
+
+ renderForm = () => {
+ return (
+ <div className="boxed-group-inner">
+ <div className="big-spacer-bottom width-50">
+ {translate('onboarding.organization.text')}
+ </div>
+
+ {this.state.loading ? (
+ <i className="spinner" />
+ ) : (
+ <div>
+ {this.state.personalOrganization && this.renderPersonalOrganizationOption()}
+ {this.state.existingOrganizations.length > 0 && this.renderExistingOrganizationOption()}
+ {this.renderNewOrganizationOption()}
+ </div>
+ )}
+
+ {this.getSelectedOrganization() != null &&
+ !this.state.loading && (
+ <div className="big-spacer-top">
+ <Button className="js-continue" onClick={this.handleContinueClick}>
+ {translate('continue')}
+ </Button>
+ </div>
+ )}
+ </div>
+ );
+ };
+
+ renderResult = () => {
+ const result = this.getSelectedOrganization();
+
+ return result != null ? (
+ <div className="boxed-group-actions display-flex-center">
+ <AlertSuccessIcon className="spacer-right" />
+ <strong>{result}</strong>
+ </div>
+ ) : null;
+ };
+
+ render() {
+ return (
+ <Step
+ finished={this.props.finished}
+ onOpen={this.props.onOpen}
+ open={this.props.open}
+ renderForm={this.renderForm}
+ renderResult={this.renderResult}
+ stepNumber={this.props.stepNumber}
+ stepTitle={
+ <span>
+ {translate('onboarding.organization.header')}
+ <DocTooltip
+ className="little-spacer-left"
+ doc={import(/* webpackMode: "eager" */ 'Docs/tooltips/organizations/organization.md')}
+ />
+ </span>
+ }
+ />
+ );
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import Step from './Step';
+import LanguageForm from './LanguageForm';
+import AnalysisCommand from './commands/AnalysisCommand';
+import { translate } from '../../../helpers/l10n';
+import { Component } from '../../../app/types';
+import { LanguageConfig } from '../utils';
+
+interface Props {
+ component?: Component;
+ displayRowLayout?: boolean;
+ onFinish?: (projectKey?: string) => void;
+ onReset?: () => void;
+ open: boolean;
+ organization?: string;
+ stepNumber: number;
+ token?: string;
+}
+
+interface State {
+ config?: LanguageConfig;
+}
+
+export default class ProjectAnalysisStep extends React.PureComponent<Props, State> {
+ state: State = {};
+
+ getProjectKey = ({ config } = this.state, { component } = this.props) => {
+ return (component && component.key) || (config && config.projectKey);
+ };
+
+ handleLanguageSelect = (config: LanguageConfig) => {
+ this.setState({ config });
+ if (this.props.onFinish) {
+ const projectKey = config.language !== 'java' ? this.getProjectKey({ config }) : undefined;
+ this.props.onFinish(projectKey);
+ }
+ };
+
+ handleLanguageReset = () => {
+ this.setState({ config: undefined });
+ if (this.props.onReset) {
+ this.props.onReset();
+ }
+ };
+
+ renderForm = () => {
+ const languageComponent = (
+ <LanguageForm
+ component={this.props.component}
+ onDone={this.handleLanguageSelect}
+ onReset={this.handleLanguageReset}
+ organization={this.props.organization}
+ />
+ );
+ const analysisComponent = this.state.config && (
+ <AnalysisCommand
+ component={this.props.component}
+ languageConfig={this.state.config}
+ organization={this.props.organization}
+ small={true}
+ token={this.props.token}
+ />
+ );
+
+ if (this.props.displayRowLayout) {
+ return (
+ <div className="boxed-group-inner">
+ <div className="display-flex-column">
+ {languageComponent}
+ {analysisComponent && <div className="huge-spacer-top">{analysisComponent}</div>}
+ </div>
+ </div>
+ );
+ }
+
+ return (
+ <div className="boxed-group-inner">
+ <div className="flex-columns">
+ <div className="flex-column flex-column-half bordered-right">{languageComponent}</div>
+ <div className="flex-column flex-column-half">{analysisComponent}</div>
+ </div>
+ </div>
+ );
+ };
+
+ renderResult = () => null;
+
+ render() {
+ return (
+ <Step
+ finished={false}
+ onOpen={() => {}}
+ open={this.props.open}
+ renderForm={this.renderForm}
+ renderResult={this.renderResult}
+ stepNumber={this.props.stepNumber}
+ stepTitle={translate('onboarding.analysis.header')}
+ />
+ );
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+/* eslint-disable jsx-a11y/no-static-element-interactions, jsx-a11y/no-noninteractive-tabindex */
+import * as React from 'react';
+import * as classNames from 'classnames';
+
+interface Props {
+ finished: boolean;
+ onOpen: () => void;
+ open: boolean;
+ renderForm: () => React.ReactNode;
+ renderResult: () => React.ReactNode;
+ stepNumber: number;
+ stepTitle: React.ReactNode;
+}
+
+export default function Step(props: Props) {
+ const className = classNames('boxed-group', 'onboarding-step', {
+ 'is-open': props.open,
+ 'is-finished': props.finished
+ });
+
+ const clickable = !props.open && props.finished;
+
+ const handleClick = (event: React.MouseEvent<HTMLDivElement>) => {
+ event.preventDefault();
+ props.onOpen();
+ };
+
+ return (
+ <div
+ className={className}
+ onClick={clickable ? handleClick : undefined}
+ role={clickable ? 'button' : undefined}
+ tabIndex={clickable ? 0 : undefined}>
+ <div className="onboarding-step-number">{props.stepNumber}</div>
+ {!props.open && props.renderResult()}
+ <div className="boxed-group-header">
+ <h2>{props.stepTitle}</h2>
+ </div>
+ {props.open ? props.renderForm() : <div className="boxed-group-inner" />}
+ </div>
+ );
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+import * as React from 'react';
+import * as classNames from 'classnames';
+import Step from './Step';
+import { getTokens, generateToken, revokeToken } from '../../../api/user-tokens';
+import AlertErrorIcon from '../../../components/icons-components/AlertErrorIcon';
+import AlertSuccessIcon from '../../../components/icons-components/AlertSuccessIcon';
+import { DeleteButton, SubmitButton, Button } from '../../../components/ui/buttons';
+import { translate } from '../../../helpers/l10n';
+
+interface Props {
+ currentUser: { login: string };
+ finished: boolean;
+ open: boolean;
+ onContinue: (token: string) => void;
+ onOpen: () => void;
+ stepNumber: number;
+}
+
+interface State {
+ canUseExisting: boolean;
+ existingToken: string;
+ loading: boolean;
+ selection: string;
+ tokenName?: string;
+ token?: string;
+}
+
+export default class TokenStep extends React.PureComponent<Props, State> {
+ mounted = false;
+
+ state: State = {
+ canUseExisting: false,
+ existingToken: '',
+ loading: false,
+ selection: 'generate'
+ };
+
+ componentDidMount() {
+ this.mounted = true;
+ getTokens(this.props.currentUser.login).then(
+ tokens => {
+ if (this.mounted) {
+ this.setState({ canUseExisting: tokens.length > 0 });
+ }
+ },
+ () => {}
+ );
+ }
+
+ componentWillUnmount() {
+ this.mounted = false;
+ }
+
+ getToken = () =>
+ this.state.selection === 'generate' ? this.state.token : this.state.existingToken;
+
+ canContinue = () => {
+ const { existingToken, selection, token } = this.state;
+ const validExistingToken = existingToken.match(/^[a-z0-9]+$/) != null;
+ return (
+ (selection === 'generate' && token != null) ||
+ (selection === 'use-existing' && existingToken && validExistingToken)
+ );
+ };
+
+ handleTokenNameChange = (event: React.ChangeEvent<HTMLInputElement>) => {
+ this.setState({ tokenName: event.target.value });
+ };
+
+ handleTokenGenerate = (event: React.FormEvent<HTMLFormElement>) => {
+ event.preventDefault();
+ const { tokenName } = this.state;
+ if (tokenName) {
+ this.setState({ loading: true });
+ generateToken({ name: tokenName }).then(({ token }) => {
+ if (this.mounted) {
+ this.setState({ loading: false, token });
+ }
+ }, this.stopLoading);
+ }
+ };
+
+ handleTokenRevoke = () => {
+ const { tokenName } = this.state;
+ if (tokenName) {
+ this.setState({ loading: true });
+ revokeToken({ name: tokenName }).then(() => {
+ if (this.mounted) {
+ this.setState({ loading: false, token: undefined, tokenName: undefined });
+ }
+ }, this.stopLoading);
+ }
+ };
+
+ handleContinueClick = () => {
+ const token = this.getToken();
+ if (token) {
+ this.props.onContinue(token);
+ }
+ };
+
+ handleGenerateClick = (event: React.MouseEvent<HTMLAnchorElement>) => {
+ event.preventDefault();
+ this.setState({ selection: 'generate' });
+ };
+
+ handleUseExistingClick = (event: React.MouseEvent<HTMLAnchorElement>) => {
+ event.preventDefault();
+ this.setState({ selection: 'use-existing' });
+ };
+
+ handleExisingTokenChange = (event: React.ChangeEvent<HTMLInputElement>) => {
+ this.setState({ existingToken: event.currentTarget.value });
+ };
+
+ stopLoading = () => {
+ if (this.mounted) {
+ this.setState({ loading: false });
+ }
+ };
+
+ renderGenerateOption = () => (
+ <div>
+ {this.state.canUseExisting ? (
+ <a
+ className="js-new link-base-color link-no-underline"
+ href="#"
+ onClick={this.handleGenerateClick}>
+ <i
+ className={classNames('icon-radio', 'spacer-right', {
+ 'is-checked': this.state.selection === 'generate'
+ })}
+ />
+ {translate('onboarding.token.generate_token')}
+ </a>
+ ) : (
+ translate('onboarding.token.generate_token')
+ )}
+ {this.state.selection === 'generate' && (
+ <div className="big-spacer-top">
+ <form onSubmit={this.handleTokenGenerate}>
+ <input
+ autoFocus={true}
+ className="input-large spacer-right text-middle"
+ onChange={this.handleTokenNameChange}
+ placeholder={translate('onboarding.token.generate_token.placeholder')}
+ required={true}
+ type="text"
+ value={this.state.tokenName || ''}
+ />
+ {this.state.loading ? (
+ <i className="spinner text-middle" />
+ ) : (
+ <SubmitButton className="text-middle" disabled={!this.state.tokenName}>
+ {translate('onboarding.token.generate')}
+ </SubmitButton>
+ )}
+ </form>
+ </div>
+ )}
+ </div>
+ );
+
+ renderUseExistingOption = () => {
+ const { existingToken } = this.state;
+ const validInput = !existingToken || existingToken.match(/^[a-z0-9]+$/) != null;
+
+ return (
+ <div className="big-spacer-top">
+ <a
+ className="js-new link-base-color link-no-underline"
+ href="#"
+ onClick={this.handleUseExistingClick}>
+ <i
+ className={classNames('icon-radio', 'spacer-right', {
+ 'is-checked': this.state.selection === 'use-existing'
+ })}
+ />
+ {translate('onboarding.token.use_existing_token')}
+ </a>
+ {this.state.selection === 'use-existing' && (
+ <div className="big-spacer-top">
+ <input
+ autoFocus={true}
+ className="input-large spacer-right text-middle"
+ onChange={this.handleExisingTokenChange}
+ placeholder={translate('onboarding.token.use_existing_token.placeholder')}
+ required={true}
+ type="text"
+ value={this.state.existingToken}
+ />
+ {!validInput && (
+ <span className="text-danger">
+ <AlertErrorIcon className="little-spacer-right text-text-top" />
+ {translate('onboarding.token.invalid_format')}
+ </span>
+ )}
+ </div>
+ )}
+ </div>
+ );
+ };
+
+ renderForm = () => {
+ const { canUseExisting, loading, token, tokenName } = this.state;
+
+ return (
+ <div className="boxed-group-inner">
+ {token != null ? (
+ <form onSubmit={this.handleTokenRevoke}>
+ <span className="text-middle">
+ {tokenName}
+ {': '}
+ </span>
+ <strong className="spacer-right text-middle">{token}</strong>
+ {loading ? (
+ <i className="spinner text-middle" />
+ ) : (
+ <DeleteButton className="button-small text-middle" onClick={this.handleTokenRevoke} />
+ )}
+ </form>
+ ) : (
+ <div>
+ {this.renderGenerateOption()}
+ {canUseExisting && this.renderUseExistingOption()}
+ </div>
+ )}
+
+ <div className="note big-spacer-top width-50">{translate('onboarding.token.text')}</div>
+
+ {this.canContinue() && (
+ <div className="big-spacer-top">
+ <Button className="js-continue" onClick={this.handleContinueClick}>
+ {translate('continue')}
+ </Button>
+ </div>
+ )}
+ </div>
+ );
+ };
+
+ renderResult = () => {
+ const { selection, tokenName } = this.state;
+ const token = this.getToken();
+
+ if (!token) {
+ return null;
+ }
+
+ return (
+ <div className="boxed-group-actions display-flex-center">
+ <AlertSuccessIcon className="spacer-right" />
+ {selection === 'generate' && tokenName && `${tokenName}: `}
+ <strong>{token}</strong>
+ </div>
+ );
+ };
+
+ render() {
+ return (
+ <Step
+ finished={this.props.finished}
+ onOpen={this.props.onOpen}
+ open={this.props.open}
+ renderForm={this.renderForm}
+ renderResult={this.renderResult}
+ stepNumber={this.props.stepNumber}
+ stepTitle={translate('onboarding.token.header')}
+ />
+ );
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import LanguageForm from '../LanguageForm';
+import { isSonarCloud } from '../../../../helpers/system';
+
+jest.mock('../../../../helpers/system', () => ({ isSonarCloud: jest.fn() }));
+
+beforeEach(() => {
+ (isSonarCloud as jest.Mock<any>).mockImplementation(() => false);
+});
+
+it('selects java', () => {
+ const onDone = jest.fn();
+ const wrapper = shallow(<LanguageForm onDone={onDone} onReset={jest.fn()} />);
+
+ (wrapper.find('RadioToggle').prop('onCheck') as Function)('java');
+ wrapper.update();
+ expect(wrapper).toMatchSnapshot();
+
+ (wrapper
+ .find('RadioToggle')
+ .at(1)
+ .prop('onCheck') as Function)('maven');
+ wrapper.update();
+ expect(wrapper).toMatchSnapshot();
+ expect(onDone).lastCalledWith({ language: 'java', javaBuild: 'maven' });
+
+ (wrapper
+ .find('RadioToggle')
+ .at(1)
+ .prop('onCheck') as Function)('gradle');
+ wrapper.update();
+ expect(wrapper).toMatchSnapshot();
+ expect(onDone).lastCalledWith({ language: 'java', javaBuild: 'gradle' });
+});
+
+it('selects c#', () => {
+ const onDone = jest.fn();
+ const wrapper = shallow(<LanguageForm onDone={onDone} onReset={jest.fn()} />);
+
+ (wrapper.find('RadioToggle').prop('onCheck') as Function)('dotnet');
+ wrapper.update();
+ expect(wrapper).toMatchSnapshot();
+
+ (wrapper.find('NewProjectForm').prop('onDone') as Function)('project-foo');
+ expect(onDone).lastCalledWith({ language: 'dotnet', projectKey: 'project-foo' });
+});
+
+it('selects c-family', () => {
+ (isSonarCloud as jest.Mock<any>).mockImplementation(() => true);
+ const onDone = jest.fn();
+ const wrapper = shallow(<LanguageForm onDone={onDone} onReset={jest.fn()} />);
+
+ (wrapper.find('RadioToggle').prop('onCheck') as Function)('c-family');
+ wrapper.update();
+ expect(wrapper).toMatchSnapshot();
+
+ (wrapper
+ .find('RadioToggle')
+ .at(1)
+ .prop('onCheck') as Function)('msvc');
+ wrapper.update();
+ expect(wrapper).toMatchSnapshot();
+
+ (wrapper.find('NewProjectForm').prop('onDone') as Function)('project-foo');
+ expect(onDone).lastCalledWith({
+ language: 'c-family',
+ cFamilyCompiler: 'msvc',
+ projectKey: 'project-foo'
+ });
+
+ (wrapper
+ .find('RadioToggle')
+ .at(1)
+ .prop('onCheck') as Function)('clang-gcc');
+ wrapper.update();
+ expect(wrapper).toMatchSnapshot();
+
+ (wrapper
+ .find('RadioToggle')
+ .at(2)
+ .prop('onCheck') as Function)('linux');
+ wrapper.update();
+ expect(wrapper).toMatchSnapshot();
+
+ (wrapper.find('NewProjectForm').prop('onDone') as Function)('project-foo');
+ expect(onDone).lastCalledWith({
+ language: 'c-family',
+ cFamilyCompiler: 'clang-gcc',
+ os: 'linux',
+ projectKey: 'project-foo'
+ });
+});
+
+it('selects other', () => {
+ const onDone = jest.fn();
+ const wrapper = shallow(<LanguageForm onDone={onDone} onReset={jest.fn()} />);
+
+ (wrapper.find('RadioToggle').prop('onCheck') as Function)('other');
+ wrapper.update();
+ expect(wrapper).toMatchSnapshot();
+
+ (wrapper
+ .find('RadioToggle')
+ .at(1)
+ .prop('onCheck') as Function)('mac');
+ wrapper.update();
+ expect(wrapper).toMatchSnapshot();
+
+ (wrapper.find('NewProjectForm').prop('onDone') as Function)('project-foo');
+ expect(onDone).lastCalledWith({ language: 'other', os: 'mac', projectKey: 'project-foo' });
+});
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { mount } from 'enzyme';
+import NewOrganizationForm from '../NewOrganizationForm';
+import { change, submit, waitAndUpdate } from '../../../../helpers/testUtils';
+
+jest.mock('../../../../api/organizations', () => ({
+ createOrganization: () => Promise.resolve(),
+ deleteOrganization: () => Promise.resolve(),
+ getOrganization: () => Promise.resolve(null)
+}));
+
+jest.mock('../../../../components/icons-components/ClearIcon');
+
+it('creates new organization', async () => {
+ const onDone = jest.fn();
+ const wrapper = mount(<NewOrganizationForm onDelete={jest.fn()} onDone={onDone} />);
+ expect(wrapper).toMatchSnapshot();
+ change(wrapper.find('input'), 'foo');
+ submit(wrapper.find('form'));
+ expect(wrapper).toMatchSnapshot(); // spinner
+ await waitAndUpdate(wrapper);
+ expect(wrapper).toMatchSnapshot();
+ expect(onDone).toBeCalledWith('foo');
+});
+
+it('deletes organization', async () => {
+ const onDelete = jest.fn();
+ const wrapper = mount(<NewOrganizationForm onDelete={onDelete} onDone={jest.fn()} />);
+ wrapper.setState({ done: true, loading: false, organization: 'foo' });
+ expect(wrapper).toMatchSnapshot();
+ (wrapper.find('DeleteButton').prop('onClick') as Function)();
+ wrapper.update();
+ expect(wrapper).toMatchSnapshot(); // spinner
+ await waitAndUpdate(wrapper);
+ expect(wrapper).toMatchSnapshot();
+ expect(onDelete).toBeCalled();
+});
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { mount } from 'enzyme';
+import NewProjectForm from '../NewProjectForm';
+import { change, submit, waitAndUpdate } from '../../../../helpers/testUtils';
+
+jest.mock('../../../../api/components', () => ({
+ createProject: () => Promise.resolve(),
+ deleteProject: () => Promise.resolve()
+}));
+
+jest.mock('../../../../components/icons-components/ClearIcon');
+
+it('creates new project', async () => {
+ const onDone = jest.fn();
+ const wrapper = mount(<NewProjectForm onDelete={jest.fn()} onDone={onDone} />);
+ expect(wrapper).toMatchSnapshot();
+ change(wrapper.find('input'), 'foo');
+ submit(wrapper.find('form'));
+ expect(wrapper).toMatchSnapshot(); // spinner
+ await waitAndUpdate(wrapper);
+ expect(wrapper).toMatchSnapshot();
+ expect(onDone).toBeCalledWith('foo');
+});
+
+it('deletes project', async () => {
+ const onDelete = jest.fn();
+ const wrapper = mount(<NewProjectForm onDelete={onDelete} onDone={jest.fn()} />);
+ wrapper.setState({ done: true, loading: false, projectKey: 'foo' });
+ expect(wrapper).toMatchSnapshot();
+ (wrapper.find('DeleteButton').prop('onClick') as Function)();
+ wrapper.update();
+ expect(wrapper).toMatchSnapshot(); // spinner
+ await waitAndUpdate(wrapper);
+ expect(wrapper).toMatchSnapshot();
+ expect(onDelete).toBeCalled();
+});
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { mount } from 'enzyme';
+import OrganizationStep from '../OrganizationStep';
+import { click, waitAndUpdate } from '../../../../helpers/testUtils';
+import { getOrganizations } from '../../../../api/organizations';
+
+jest.mock('../../../../api/organizations', () => ({
+ getOrganizations: jest.fn(() =>
+ Promise.resolve({
+ organizations: [{ isAdmin: true, key: 'user' }, { isAdmin: true, key: 'another' }]
+ })
+ )
+}));
+
+const currentUser = { isLoggedIn: true, login: 'user' };
+
+beforeEach(() => {
+ (getOrganizations as jest.Mock<any>).mockClear();
+});
+
+// FIXME
+// - if `mount` is used, then it's not possible to correctly set the state,
+// because the mocked api call is used
+// - if `shallow` is used, then the continue button is not rendered
+it.skip('works with personal organization', () => {
+ const onContinue = jest.fn();
+ const wrapper = mount(
+ <OrganizationStep
+ currentUser={currentUser}
+ finished={false}
+ onContinue={onContinue}
+ onOpen={jest.fn()}
+ open={true}
+ stepNumber={1}
+ />
+ );
+ click(wrapper.find('.js-continue'));
+ expect(onContinue).toBeCalledWith('user');
+});
+
+it('works with existing organization', async () => {
+ const onContinue = jest.fn();
+ const wrapper = mount(
+ <OrganizationStep
+ currentUser={currentUser}
+ finished={false}
+ onContinue={onContinue}
+ onOpen={jest.fn()}
+ open={true}
+ stepNumber={1}
+ />
+ );
+ await waitAndUpdate(wrapper);
+ click(wrapper.find('.js-existing'));
+ expect(wrapper).toMatchSnapshot();
+ (wrapper
+ .find('Select')
+ .first()
+ .prop('onChange') as Function)({ value: 'another' });
+ wrapper.update();
+ click(wrapper.find('[className="js-continue"]'));
+ expect(onContinue).toBeCalledWith('another');
+});
+
+it('works with new organization', async () => {
+ const onContinue = jest.fn();
+ const wrapper = mount(
+ <OrganizationStep
+ currentUser={currentUser}
+ finished={false}
+ onContinue={onContinue}
+ onOpen={jest.fn()}
+ open={true}
+ stepNumber={1}
+ />
+ );
+ await waitAndUpdate(wrapper);
+ click(wrapper.find('.js-new'));
+ (wrapper.find('NewOrganizationForm').prop('onDone') as Function)('new');
+ wrapper.update();
+ click(wrapper.find('[className="js-continue"]'));
+ expect(onContinue).toBeCalledWith('new');
+});
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import Step from '../Step';
+import { click } from '../../../../helpers/testUtils';
+
+it('renders', () => {
+ const wrapper = shallow(
+ <Step
+ finished={true}
+ onOpen={jest.fn()}
+ open={true}
+ renderForm={() => <div>form</div>}
+ renderResult={() => <div>result</div>}
+ stepNumber={1}
+ stepTitle="First Step"
+ />
+ );
+ expect(wrapper).toMatchSnapshot();
+ wrapper.setProps({ open: false });
+ expect(wrapper).toMatchSnapshot();
+});
+
+it('re-opens', () => {
+ const onOpen = jest.fn();
+ const wrapper = shallow(
+ <Step
+ finished={true}
+ onOpen={onOpen}
+ open={false}
+ renderForm={() => <div>form</div>}
+ renderResult={() => <div>result</div>}
+ stepNumber={1}
+ stepTitle="First Step"
+ />
+ );
+ click(wrapper);
+ expect(onOpen).toBeCalled();
+});
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { mount } from 'enzyme';
+import TokenStep from '../TokenStep';
+import { change, click, submit, waitAndUpdate } from '../../../../helpers/testUtils';
+
+jest.mock('../../../../api/user-tokens', () => ({
+ getTokens: () => Promise.resolve([{ name: 'foo' }]),
+ generateToken: () => Promise.resolve({ token: 'abcd1234' }),
+ revokeToken: () => Promise.resolve()
+}));
+
+jest.mock('../../../../components/icons-components/ClearIcon');
+
+const currentUser = { login: 'user' };
+
+it('generates token', async () => {
+ const wrapper = mount(
+ <TokenStep
+ currentUser={currentUser}
+ finished={false}
+ onContinue={jest.fn()}
+ onOpen={jest.fn()}
+ open={true}
+ stepNumber={1}
+ />
+ );
+ await waitAndUpdate(wrapper);
+ expect(wrapper).toMatchSnapshot();
+ change(wrapper.find('input'), 'my token');
+ submit(wrapper.find('form'));
+ expect(wrapper).toMatchSnapshot(); // spinner
+ await waitAndUpdate(wrapper);
+ expect(wrapper).toMatchSnapshot();
+});
+
+it('revokes token', async () => {
+ const wrapper = mount(
+ <TokenStep
+ currentUser={currentUser}
+ finished={false}
+ onContinue={jest.fn()}
+ onOpen={jest.fn()}
+ open={true}
+ stepNumber={1}
+ />
+ );
+ await new Promise(setImmediate);
+ wrapper.setState({ token: 'abcd1234', tokenName: 'my token' });
+ expect(wrapper).toMatchSnapshot();
+ (wrapper.find('DeleteButton').prop('onClick') as Function)();
+ wrapper.update();
+ expect(wrapper).toMatchSnapshot(); // spinner
+ await waitAndUpdate(wrapper);
+ expect(wrapper).toMatchSnapshot();
+});
+
+it('continues', async () => {
+ const onContinue = jest.fn();
+ const wrapper = mount(
+ <TokenStep
+ currentUser={currentUser}
+ finished={false}
+ onContinue={onContinue}
+ onOpen={jest.fn()}
+ open={true}
+ stepNumber={1}
+ />
+ );
+ await new Promise(setImmediate);
+ wrapper.setState({ token: 'abcd1234', tokenName: 'my token' });
+ click(wrapper.find('[className="js-continue"]'));
+ expect(onContinue).toBeCalledWith('abcd1234');
+});
+
+it('uses existing token', async () => {
+ const onContinue = jest.fn();
+ const wrapper = mount(
+ <TokenStep
+ currentUser={currentUser}
+ finished={false}
+ onContinue={onContinue}
+ onOpen={jest.fn()}
+ open={true}
+ stepNumber={1}
+ />
+ );
+ await new Promise(setImmediate);
+ wrapper.setState({ existingToken: 'abcd1234', selection: 'use-existing' });
+ click(wrapper.find('[className="js-continue"]'));
+ expect(onContinue).toBeCalledWith('abcd1234');
+});
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`selects c# 1`] = `
+<React.Fragment>
+ <div>
+ <h4
+ className="spacer-bottom"
+ >
+ onboarding.language
+ </h4>
+ <RadioToggle
+ disabled={false}
+ name="language"
+ onCheck={[Function]}
+ options={
+ Array [
+ Object {
+ "label": "onboarding.language.java",
+ "value": "java",
+ },
+ Object {
+ "label": "onboarding.language.dotnet",
+ "value": "dotnet",
+ },
+ Object {
+ "label": "onboarding.language.other",
+ "value": "other",
+ },
+ ]
+ }
+ value="dotnet"
+ />
+ </div>
+ <NewProjectForm
+ onDelete={[Function]}
+ onDone={[Function]}
+ />
+</React.Fragment>
+`;
+
+exports[`selects c-family 1`] = `
+<React.Fragment>
+ <div>
+ <h4
+ className="spacer-bottom"
+ >
+ onboarding.language
+ </h4>
+ <RadioToggle
+ disabled={false}
+ name="language"
+ onCheck={[Function]}
+ options={
+ Array [
+ Object {
+ "label": "onboarding.language.java",
+ "value": "java",
+ },
+ Object {
+ "label": "onboarding.language.dotnet",
+ "value": "dotnet",
+ },
+ Object {
+ "label": "onboarding.language.c-family",
+ "value": "c-family",
+ },
+ Object {
+ "label": "onboarding.language.other",
+ "value": "other",
+ },
+ ]
+ }
+ value="c-family"
+ />
+ </div>
+ <div
+ className="big-spacer-top"
+ >
+ <h4
+ className="spacer-bottom"
+ >
+ onboarding.language.c-family.compiler
+ </h4>
+ <RadioToggle
+ disabled={false}
+ name="c-family-compiler"
+ onCheck={[Function]}
+ options={
+ Array [
+ Object {
+ "label": "onboarding.language.c-family.compiler.msvc",
+ "value": "msvc",
+ },
+ Object {
+ "label": "onboarding.language.c-family.compiler.clang-gcc",
+ "value": "clang-gcc",
+ },
+ ]
+ }
+ value={null}
+ />
+ </div>
+</React.Fragment>
+`;
+
+exports[`selects c-family 2`] = `
+<React.Fragment>
+ <div>
+ <h4
+ className="spacer-bottom"
+ >
+ onboarding.language
+ </h4>
+ <RadioToggle
+ disabled={false}
+ name="language"
+ onCheck={[Function]}
+ options={
+ Array [
+ Object {
+ "label": "onboarding.language.java",
+ "value": "java",
+ },
+ Object {
+ "label": "onboarding.language.dotnet",
+ "value": "dotnet",
+ },
+ Object {
+ "label": "onboarding.language.c-family",
+ "value": "c-family",
+ },
+ Object {
+ "label": "onboarding.language.other",
+ "value": "other",
+ },
+ ]
+ }
+ value="c-family"
+ />
+ </div>
+ <div
+ className="big-spacer-top"
+ >
+ <h4
+ className="spacer-bottom"
+ >
+ onboarding.language.c-family.compiler
+ </h4>
+ <RadioToggle
+ disabled={false}
+ name="c-family-compiler"
+ onCheck={[Function]}
+ options={
+ Array [
+ Object {
+ "label": "onboarding.language.c-family.compiler.msvc",
+ "value": "msvc",
+ },
+ Object {
+ "label": "onboarding.language.c-family.compiler.clang-gcc",
+ "value": "clang-gcc",
+ },
+ ]
+ }
+ value="msvc"
+ />
+ </div>
+ <NewProjectForm
+ onDelete={[Function]}
+ onDone={[Function]}
+ />
+</React.Fragment>
+`;
+
+exports[`selects c-family 3`] = `
+<React.Fragment>
+ <div>
+ <h4
+ className="spacer-bottom"
+ >
+ onboarding.language
+ </h4>
+ <RadioToggle
+ disabled={false}
+ name="language"
+ onCheck={[Function]}
+ options={
+ Array [
+ Object {
+ "label": "onboarding.language.java",
+ "value": "java",
+ },
+ Object {
+ "label": "onboarding.language.dotnet",
+ "value": "dotnet",
+ },
+ Object {
+ "label": "onboarding.language.c-family",
+ "value": "c-family",
+ },
+ Object {
+ "label": "onboarding.language.other",
+ "value": "other",
+ },
+ ]
+ }
+ value="c-family"
+ />
+ </div>
+ <div
+ className="big-spacer-top"
+ >
+ <h4
+ className="spacer-bottom"
+ >
+ onboarding.language.c-family.compiler
+ </h4>
+ <RadioToggle
+ disabled={false}
+ name="c-family-compiler"
+ onCheck={[Function]}
+ options={
+ Array [
+ Object {
+ "label": "onboarding.language.c-family.compiler.msvc",
+ "value": "msvc",
+ },
+ Object {
+ "label": "onboarding.language.c-family.compiler.clang-gcc",
+ "value": "clang-gcc",
+ },
+ ]
+ }
+ value="clang-gcc"
+ />
+ </div>
+ <div
+ className="big-spacer-top"
+ >
+ <h4
+ className="spacer-bottom"
+ >
+ onboarding.language.os
+ </h4>
+ <RadioToggle
+ disabled={false}
+ name="os"
+ onCheck={[Function]}
+ options={
+ Array [
+ Object {
+ "label": "onboarding.language.os.linux",
+ "value": "linux",
+ },
+ Object {
+ "label": "onboarding.language.os.win",
+ "value": "win",
+ },
+ Object {
+ "label": "onboarding.language.os.mac",
+ "value": "mac",
+ },
+ ]
+ }
+ value={null}
+ />
+ </div>
+</React.Fragment>
+`;
+
+exports[`selects c-family 4`] = `
+<React.Fragment>
+ <div>
+ <h4
+ className="spacer-bottom"
+ >
+ onboarding.language
+ </h4>
+ <RadioToggle
+ disabled={false}
+ name="language"
+ onCheck={[Function]}
+ options={
+ Array [
+ Object {
+ "label": "onboarding.language.java",
+ "value": "java",
+ },
+ Object {
+ "label": "onboarding.language.dotnet",
+ "value": "dotnet",
+ },
+ Object {
+ "label": "onboarding.language.c-family",
+ "value": "c-family",
+ },
+ Object {
+ "label": "onboarding.language.other",
+ "value": "other",
+ },
+ ]
+ }
+ value="c-family"
+ />
+ </div>
+ <div
+ className="big-spacer-top"
+ >
+ <h4
+ className="spacer-bottom"
+ >
+ onboarding.language.c-family.compiler
+ </h4>
+ <RadioToggle
+ disabled={false}
+ name="c-family-compiler"
+ onCheck={[Function]}
+ options={
+ Array [
+ Object {
+ "label": "onboarding.language.c-family.compiler.msvc",
+ "value": "msvc",
+ },
+ Object {
+ "label": "onboarding.language.c-family.compiler.clang-gcc",
+ "value": "clang-gcc",
+ },
+ ]
+ }
+ value="clang-gcc"
+ />
+ </div>
+ <div
+ className="big-spacer-top"
+ >
+ <h4
+ className="spacer-bottom"
+ >
+ onboarding.language.os
+ </h4>
+ <RadioToggle
+ disabled={false}
+ name="os"
+ onCheck={[Function]}
+ options={
+ Array [
+ Object {
+ "label": "onboarding.language.os.linux",
+ "value": "linux",
+ },
+ Object {
+ "label": "onboarding.language.os.win",
+ "value": "win",
+ },
+ Object {
+ "label": "onboarding.language.os.mac",
+ "value": "mac",
+ },
+ ]
+ }
+ value="linux"
+ />
+ </div>
+ <NewProjectForm
+ onDelete={[Function]}
+ onDone={[Function]}
+ projectKey="project-foo"
+ />
+</React.Fragment>
+`;
+
+exports[`selects java 1`] = `
+<React.Fragment>
+ <div>
+ <h4
+ className="spacer-bottom"
+ >
+ onboarding.language
+ </h4>
+ <RadioToggle
+ disabled={false}
+ name="language"
+ onCheck={[Function]}
+ options={
+ Array [
+ Object {
+ "label": "onboarding.language.java",
+ "value": "java",
+ },
+ Object {
+ "label": "onboarding.language.dotnet",
+ "value": "dotnet",
+ },
+ Object {
+ "label": "onboarding.language.other",
+ "value": "other",
+ },
+ ]
+ }
+ value="java"
+ />
+ </div>
+ <div
+ className="big-spacer-top"
+ >
+ <h4
+ className="spacer-bottom"
+ >
+ onboarding.language.java.build_technology
+ </h4>
+ <RadioToggle
+ disabled={false}
+ name="java-build"
+ onCheck={[Function]}
+ options={
+ Array [
+ Object {
+ "label": "onboarding.language.java.build_technology.maven",
+ "value": "maven",
+ },
+ Object {
+ "label": "onboarding.language.java.build_technology.gradle",
+ "value": "gradle",
+ },
+ ]
+ }
+ value={null}
+ />
+ </div>
+</React.Fragment>
+`;
+
+exports[`selects java 2`] = `
+<React.Fragment>
+ <div>
+ <h4
+ className="spacer-bottom"
+ >
+ onboarding.language
+ </h4>
+ <RadioToggle
+ disabled={false}
+ name="language"
+ onCheck={[Function]}
+ options={
+ Array [
+ Object {
+ "label": "onboarding.language.java",
+ "value": "java",
+ },
+ Object {
+ "label": "onboarding.language.dotnet",
+ "value": "dotnet",
+ },
+ Object {
+ "label": "onboarding.language.other",
+ "value": "other",
+ },
+ ]
+ }
+ value="java"
+ />
+ </div>
+ <div
+ className="big-spacer-top"
+ >
+ <h4
+ className="spacer-bottom"
+ >
+ onboarding.language.java.build_technology
+ </h4>
+ <RadioToggle
+ disabled={false}
+ name="java-build"
+ onCheck={[Function]}
+ options={
+ Array [
+ Object {
+ "label": "onboarding.language.java.build_technology.maven",
+ "value": "maven",
+ },
+ Object {
+ "label": "onboarding.language.java.build_technology.gradle",
+ "value": "gradle",
+ },
+ ]
+ }
+ value="maven"
+ />
+ </div>
+</React.Fragment>
+`;
+
+exports[`selects java 3`] = `
+<React.Fragment>
+ <div>
+ <h4
+ className="spacer-bottom"
+ >
+ onboarding.language
+ </h4>
+ <RadioToggle
+ disabled={false}
+ name="language"
+ onCheck={[Function]}
+ options={
+ Array [
+ Object {
+ "label": "onboarding.language.java",
+ "value": "java",
+ },
+ Object {
+ "label": "onboarding.language.dotnet",
+ "value": "dotnet",
+ },
+ Object {
+ "label": "onboarding.language.other",
+ "value": "other",
+ },
+ ]
+ }
+ value="java"
+ />
+ </div>
+ <div
+ className="big-spacer-top"
+ >
+ <h4
+ className="spacer-bottom"
+ >
+ onboarding.language.java.build_technology
+ </h4>
+ <RadioToggle
+ disabled={false}
+ name="java-build"
+ onCheck={[Function]}
+ options={
+ Array [
+ Object {
+ "label": "onboarding.language.java.build_technology.maven",
+ "value": "maven",
+ },
+ Object {
+ "label": "onboarding.language.java.build_technology.gradle",
+ "value": "gradle",
+ },
+ ]
+ }
+ value="gradle"
+ />
+ </div>
+</React.Fragment>
+`;
+
+exports[`selects other 1`] = `
+<React.Fragment>
+ <div>
+ <h4
+ className="spacer-bottom"
+ >
+ onboarding.language
+ </h4>
+ <RadioToggle
+ disabled={false}
+ name="language"
+ onCheck={[Function]}
+ options={
+ Array [
+ Object {
+ "label": "onboarding.language.java",
+ "value": "java",
+ },
+ Object {
+ "label": "onboarding.language.dotnet",
+ "value": "dotnet",
+ },
+ Object {
+ "label": "onboarding.language.other",
+ "value": "other",
+ },
+ ]
+ }
+ value="other"
+ />
+ </div>
+ <div
+ className="big-spacer-top"
+ >
+ <h4
+ className="spacer-bottom"
+ >
+ onboarding.language.os
+ </h4>
+ <RadioToggle
+ disabled={false}
+ name="os"
+ onCheck={[Function]}
+ options={
+ Array [
+ Object {
+ "label": "onboarding.language.os.linux",
+ "value": "linux",
+ },
+ Object {
+ "label": "onboarding.language.os.win",
+ "value": "win",
+ },
+ Object {
+ "label": "onboarding.language.os.mac",
+ "value": "mac",
+ },
+ ]
+ }
+ value={null}
+ />
+ </div>
+</React.Fragment>
+`;
+
+exports[`selects other 2`] = `
+<React.Fragment>
+ <div>
+ <h4
+ className="spacer-bottom"
+ >
+ onboarding.language
+ </h4>
+ <RadioToggle
+ disabled={false}
+ name="language"
+ onCheck={[Function]}
+ options={
+ Array [
+ Object {
+ "label": "onboarding.language.java",
+ "value": "java",
+ },
+ Object {
+ "label": "onboarding.language.dotnet",
+ "value": "dotnet",
+ },
+ Object {
+ "label": "onboarding.language.other",
+ "value": "other",
+ },
+ ]
+ }
+ value="other"
+ />
+ </div>
+ <div
+ className="big-spacer-top"
+ >
+ <h4
+ className="spacer-bottom"
+ >
+ onboarding.language.os
+ </h4>
+ <RadioToggle
+ disabled={false}
+ name="os"
+ onCheck={[Function]}
+ options={
+ Array [
+ Object {
+ "label": "onboarding.language.os.linux",
+ "value": "linux",
+ },
+ Object {
+ "label": "onboarding.language.os.win",
+ "value": "win",
+ },
+ Object {
+ "label": "onboarding.language.os.mac",
+ "value": "mac",
+ },
+ ]
+ }
+ value="mac"
+ />
+ </div>
+ <NewProjectForm
+ onDelete={[Function]}
+ onDone={[Function]}
+ />
+</React.Fragment>
+`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`creates new organization 1`] = `
+<NewOrganizationForm
+ onDelete={[MockFunction]}
+ onDone={[MockFunction]}
+>
+ <form
+ onSubmit={[Function]}
+ >
+ <input
+ autoFocus={true}
+ className="input-super-large spacer-right text-middle"
+ maxLength={32}
+ minLength={2}
+ onChange={[Function]}
+ placeholder="onboarding.organization.placeholder"
+ required={true}
+ type="text"
+ value=""
+ />
+ <SubmitButton
+ className="text-middle"
+ disabled={true}
+ >
+ <Button
+ className="text-middle"
+ disabled={true}
+ preventDefault={false}
+ type="submit"
+ >
+ <button
+ className="button text-middle"
+ disabled={true}
+ onClick={[Function]}
+ type="submit"
+ >
+ create
+ </button>
+ </Button>
+ </SubmitButton>
+ <div
+ className="note spacer-top abs-width-300"
+ >
+ onboarding.organization.key_requirement
+ </div>
+ </form>
+</NewOrganizationForm>
+`;
+
+exports[`creates new organization 2`] = `
+<NewOrganizationForm
+ onDelete={[MockFunction]}
+ onDone={[MockFunction]}
+>
+ <form
+ onSubmit={[Function]}
+ >
+ <input
+ autoFocus={true}
+ className="input-super-large spacer-right text-middle"
+ maxLength={32}
+ minLength={2}
+ onChange={[Function]}
+ placeholder="onboarding.organization.placeholder"
+ required={true}
+ type="text"
+ value="foo"
+ />
+ <i
+ className="spinner text-middle"
+ />
+ <div
+ className="note spacer-top abs-width-300"
+ >
+ onboarding.organization.key_requirement
+ </div>
+ </form>
+</NewOrganizationForm>
+`;
+
+exports[`creates new organization 3`] = `
+<NewOrganizationForm
+ onDelete={[MockFunction]}
+ onDone={
+ [MockFunction] {
+ "calls": Array [
+ Array [
+ "foo",
+ ],
+ ],
+ "results": Array [
+ Object {
+ "isThrow": false,
+ "value": undefined,
+ },
+ ],
+ }
+ }
+>
+ <div>
+ <span
+ className="spacer-right text-middle"
+ >
+ foo
+ </span>
+ <DeleteButton
+ className="button-small"
+ onClick={[Function]}
+ >
+ <ButtonIcon
+ className="button-small"
+ color="#d4333f"
+ onClick={[Function]}
+ >
+ <Button
+ className="button-small button-icon"
+ onClick={[Function]}
+ stopPropagation={true}
+ style={
+ Object {
+ "color": "#d4333f",
+ }
+ }
+ >
+ <button
+ className="button button-small button-icon"
+ onClick={[Function]}
+ style={
+ Object {
+ "color": "#d4333f",
+ }
+ }
+ type="button"
+ >
+ <ClearIcon />
+ </button>
+ </Button>
+ </ButtonIcon>
+ </DeleteButton>
+ </div>
+</NewOrganizationForm>
+`;
+
+exports[`deletes organization 1`] = `
+<NewOrganizationForm
+ onDelete={[MockFunction]}
+ onDone={[MockFunction]}
+>
+ <div>
+ <span
+ className="spacer-right text-middle"
+ >
+ foo
+ </span>
+ <DeleteButton
+ className="button-small"
+ onClick={[Function]}
+ >
+ <ButtonIcon
+ className="button-small"
+ color="#d4333f"
+ onClick={[Function]}
+ >
+ <Button
+ className="button-small button-icon"
+ onClick={[Function]}
+ stopPropagation={true}
+ style={
+ Object {
+ "color": "#d4333f",
+ }
+ }
+ >
+ <button
+ className="button button-small button-icon"
+ onClick={[Function]}
+ style={
+ Object {
+ "color": "#d4333f",
+ }
+ }
+ type="button"
+ >
+ <ClearIcon />
+ </button>
+ </Button>
+ </ButtonIcon>
+ </DeleteButton>
+ </div>
+</NewOrganizationForm>
+`;
+
+exports[`deletes organization 2`] = `
+<NewOrganizationForm
+ onDelete={[MockFunction]}
+ onDone={[MockFunction]}
+>
+ <div>
+ <span
+ className="spacer-right text-middle"
+ >
+ foo
+ </span>
+ <i
+ className="spinner text-middle"
+ />
+ </div>
+</NewOrganizationForm>
+`;
+
+exports[`deletes organization 3`] = `
+<NewOrganizationForm
+ onDelete={
+ [MockFunction] {
+ "calls": Array [
+ Array [],
+ ],
+ "results": Array [
+ Object {
+ "isThrow": false,
+ "value": undefined,
+ },
+ ],
+ }
+ }
+ onDone={[MockFunction]}
+>
+ <form
+ onSubmit={[Function]}
+ >
+ <input
+ autoFocus={true}
+ className="input-super-large spacer-right text-middle"
+ maxLength={32}
+ minLength={2}
+ onChange={[Function]}
+ placeholder="onboarding.organization.placeholder"
+ required={true}
+ type="text"
+ value=""
+ />
+ <SubmitButton
+ className="text-middle"
+ disabled={true}
+ >
+ <Button
+ className="text-middle"
+ disabled={true}
+ preventDefault={false}
+ type="submit"
+ >
+ <button
+ className="button text-middle"
+ disabled={true}
+ onClick={[Function]}
+ type="submit"
+ >
+ create
+ </button>
+ </Button>
+ </SubmitButton>
+ <div
+ className="note spacer-top abs-width-300"
+ >
+ onboarding.organization.key_requirement
+ </div>
+ </form>
+</NewOrganizationForm>
+`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`creates new project 1`] = `
+<NewProjectForm
+ onDelete={[MockFunction]}
+ onDone={[MockFunction]}
+>
+ <div
+ className="big-spacer-top"
+ >
+ <h4
+ className="spacer-bottom"
+ >
+ onboarding.language.project_key
+ </h4>
+ <form
+ onSubmit={[Function]}
+ >
+ <input
+ autoFocus={true}
+ className="input-large spacer-right text-middle"
+ maxLength={400}
+ minLength={1}
+ onChange={[Function]}
+ required={true}
+ type="text"
+ value=""
+ />
+ <SubmitButton
+ className="text-middle"
+ disabled={true}
+ >
+ <Button
+ className="text-middle"
+ disabled={true}
+ preventDefault={false}
+ type="submit"
+ >
+ <button
+ className="button text-middle"
+ disabled={true}
+ onClick={[Function]}
+ type="submit"
+ >
+ Done
+ </button>
+ </Button>
+ </SubmitButton>
+ <div
+ className="note spacer-top abs-width-300"
+ >
+ onboarding.project_key_requirement
+ </div>
+ </form>
+ </div>
+</NewProjectForm>
+`;
+
+exports[`creates new project 2`] = `
+<NewProjectForm
+ onDelete={[MockFunction]}
+ onDone={[MockFunction]}
+>
+ <div
+ className="big-spacer-top"
+ >
+ <h4
+ className="spacer-bottom"
+ >
+ onboarding.language.project_key
+ </h4>
+ <form
+ onSubmit={[Function]}
+ >
+ <input
+ autoFocus={true}
+ className="input-large spacer-right text-middle"
+ maxLength={400}
+ minLength={1}
+ onChange={[Function]}
+ required={true}
+ type="text"
+ value="foo"
+ />
+ <i
+ className="spinner text-middle"
+ />
+ <div
+ className="note spacer-top abs-width-300"
+ >
+ onboarding.project_key_requirement
+ </div>
+ </form>
+ </div>
+</NewProjectForm>
+`;
+
+exports[`creates new project 3`] = `
+<NewProjectForm
+ onDelete={[MockFunction]}
+ onDone={
+ [MockFunction] {
+ "calls": Array [
+ Array [
+ "foo",
+ ],
+ ],
+ "results": Array [
+ Object {
+ "isThrow": false,
+ "value": undefined,
+ },
+ ],
+ }
+ }
+>
+ <div
+ className="big-spacer-top"
+ >
+ <h4
+ className="spacer-bottom"
+ >
+ onboarding.language.project_key
+ </h4>
+ <div>
+ <span
+ className="spacer-right text-middle"
+ >
+ foo
+ </span>
+ <DeleteButton
+ className="button-small text-middle"
+ onClick={[Function]}
+ >
+ <ButtonIcon
+ className="button-small text-middle"
+ color="#d4333f"
+ onClick={[Function]}
+ >
+ <Button
+ className="button-small text-middle button-icon"
+ onClick={[Function]}
+ stopPropagation={true}
+ style={
+ Object {
+ "color": "#d4333f",
+ }
+ }
+ >
+ <button
+ className="button button-small text-middle button-icon"
+ onClick={[Function]}
+ style={
+ Object {
+ "color": "#d4333f",
+ }
+ }
+ type="button"
+ >
+ <ClearIcon />
+ </button>
+ </Button>
+ </ButtonIcon>
+ </DeleteButton>
+ </div>
+ </div>
+</NewProjectForm>
+`;
+
+exports[`deletes project 1`] = `
+<NewProjectForm
+ onDelete={[MockFunction]}
+ onDone={[MockFunction]}
+>
+ <div
+ className="big-spacer-top"
+ >
+ <h4
+ className="spacer-bottom"
+ >
+ onboarding.language.project_key
+ </h4>
+ <div>
+ <span
+ className="spacer-right text-middle"
+ >
+ foo
+ </span>
+ <DeleteButton
+ className="button-small text-middle"
+ onClick={[Function]}
+ >
+ <ButtonIcon
+ className="button-small text-middle"
+ color="#d4333f"
+ onClick={[Function]}
+ >
+ <Button
+ className="button-small text-middle button-icon"
+ onClick={[Function]}
+ stopPropagation={true}
+ style={
+ Object {
+ "color": "#d4333f",
+ }
+ }
+ >
+ <button
+ className="button button-small text-middle button-icon"
+ onClick={[Function]}
+ style={
+ Object {
+ "color": "#d4333f",
+ }
+ }
+ type="button"
+ >
+ <ClearIcon />
+ </button>
+ </Button>
+ </ButtonIcon>
+ </DeleteButton>
+ </div>
+ </div>
+</NewProjectForm>
+`;
+
+exports[`deletes project 2`] = `
+<NewProjectForm
+ onDelete={[MockFunction]}
+ onDone={[MockFunction]}
+>
+ <div
+ className="big-spacer-top"
+ >
+ <h4
+ className="spacer-bottom"
+ >
+ onboarding.language.project_key
+ </h4>
+ <div>
+ <span
+ className="spacer-right text-middle"
+ >
+ foo
+ </span>
+ <i
+ className="spinner text-middle"
+ />
+ </div>
+ </div>
+</NewProjectForm>
+`;
+
+exports[`deletes project 3`] = `
+<NewProjectForm
+ onDelete={
+ [MockFunction] {
+ "calls": Array [
+ Array [],
+ ],
+ "results": Array [
+ Object {
+ "isThrow": false,
+ "value": undefined,
+ },
+ ],
+ }
+ }
+ onDone={[MockFunction]}
+>
+ <div
+ className="big-spacer-top"
+ >
+ <h4
+ className="spacer-bottom"
+ >
+ onboarding.language.project_key
+ </h4>
+ <form
+ onSubmit={[Function]}
+ >
+ <input
+ autoFocus={true}
+ className="input-large spacer-right text-middle"
+ maxLength={400}
+ minLength={1}
+ onChange={[Function]}
+ required={true}
+ type="text"
+ value=""
+ />
+ <SubmitButton
+ className="text-middle"
+ disabled={true}
+ >
+ <Button
+ className="text-middle"
+ disabled={true}
+ preventDefault={false}
+ type="submit"
+ >
+ <button
+ className="button text-middle"
+ disabled={true}
+ onClick={[Function]}
+ type="submit"
+ >
+ Done
+ </button>
+ </Button>
+ </SubmitButton>
+ <div
+ className="note spacer-top abs-width-300"
+ >
+ onboarding.project_key_requirement
+ </div>
+ </form>
+ </div>
+</NewProjectForm>
+`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`works with existing organization 1`] = `
+<OrganizationStep
+ currentUser={
+ Object {
+ "isLoggedIn": true,
+ "login": "user",
+ }
+ }
+ finished={false}
+ onContinue={[MockFunction]}
+ onOpen={[MockFunction]}
+ open={true}
+ stepNumber={1}
+>
+ <Step
+ finished={false}
+ onOpen={[MockFunction]}
+ open={true}
+ renderForm={[Function]}
+ renderResult={[Function]}
+ stepNumber={1}
+ stepTitle={
+ <span>
+ onboarding.organization.header
+ <DocTooltip
+ className="little-spacer-left"
+ doc={Promise {}}
+ />
+ </span>
+ }
+ >
+ <div
+ className="boxed-group onboarding-step is-open"
+ >
+ <div
+ className="onboarding-step-number"
+ >
+ 1
+ </div>
+ <div
+ className="boxed-group-header"
+ >
+ <h2>
+ <span>
+ onboarding.organization.header
+ <DocTooltip
+ className="little-spacer-left"
+ doc={Promise {}}
+ />
+ </span>
+ </h2>
+ </div>
+ <div
+ className="boxed-group-inner"
+ >
+ <div
+ className="big-spacer-bottom width-50"
+ >
+ onboarding.organization.text
+ </div>
+ <div>
+ <div
+ className="big-spacer-top"
+ >
+ <a
+ className="js-existing link-base-color link-no-underline"
+ href="#"
+ onClick={[Function]}
+ >
+ <i
+ className="icon-radio spacer-right is-checked"
+ />
+ onboarding.organization.exising_organization
+ </a>
+ <div
+ className="big-spacer-top"
+ >
+ <Select
+ className="input-super-large"
+ clearable={false}
+ onChange={[Function]}
+ options={
+ Array [
+ Object {
+ "label": "another",
+ "value": "another",
+ },
+ Object {
+ "label": "user",
+ "value": "user",
+ },
+ ]
+ }
+ >
+ <LazyLoader
+ className="input-super-large"
+ clearRenderer={[Function]}
+ clearable={false}
+ onChange={[Function]}
+ options={
+ Array [
+ Object {
+ "label": "another",
+ "value": "another",
+ },
+ Object {
+ "label": "user",
+ "value": "user",
+ },
+ ]
+ }
+ >
+ <Select
+ arrowRenderer={[Function]}
+ autosize={true}
+ backspaceRemoves={true}
+ backspaceToRemoveMessage="Press backspace to remove {label}"
+ className="input-super-large"
+ clearAllText="Clear all"
+ clearRenderer={[Function]}
+ clearValueText="Clear value"
+ clearable={false}
+ closeOnSelect={true}
+ deleteRemoves={true}
+ delimiter=","
+ disabled={false}
+ escapeClearsValue={true}
+ filterOptions={[Function]}
+ ignoreAccents={true}
+ ignoreCase={true}
+ inputProps={Object {}}
+ isLoading={false}
+ joinValues={false}
+ labelKey="label"
+ matchPos="any"
+ matchProp="any"
+ menuBuffer={0}
+ menuRenderer={[Function]}
+ multi={false}
+ noResultsText="No results found"
+ onBlurResetsInput={true}
+ onChange={[Function]}
+ onCloseResetsInput={true}
+ onSelectResetsInput={true}
+ openOnClick={true}
+ optionComponent={[Function]}
+ options={
+ Array [
+ Object {
+ "label": "another",
+ "value": "another",
+ },
+ Object {
+ "label": "user",
+ "value": "user",
+ },
+ ]
+ }
+ pageSize={5}
+ placeholder="Select..."
+ removeSelected={true}
+ required={false}
+ rtl={false}
+ scrollMenuIntoView={true}
+ searchable={true}
+ simpleValue={false}
+ tabSelectsValue={true}
+ trimFilter={true}
+ valueComponent={[Function]}
+ valueKey="value"
+ >
+ <div
+ className="Select input-super-large is-searchable Select--single"
+ >
+ <div
+ className="Select-control"
+ onKeyDown={[Function]}
+ onMouseDown={[Function]}
+ onTouchEnd={[Function]}
+ onTouchMove={[Function]}
+ onTouchStart={[Function]}
+ >
+ <span
+ className="Select-multi-value-wrapper"
+ id="react-select-2--value"
+ >
+ <div
+ className="Select-placeholder"
+ >
+ Select...
+ </div>
+ <AutosizeInput
+ aria-activedescendant="react-select-2--value"
+ aria-expanded="false"
+ aria-haspopup="false"
+ aria-owns=""
+ className="Select-input"
+ injectStyles={true}
+ minWidth="5"
+ onBlur={[Function]}
+ onChange={[Function]}
+ onFocus={[Function]}
+ required={false}
+ role="combobox"
+ value=""
+ >
+ <div
+ className="Select-input"
+ style={
+ Object {
+ "display": "inline-block",
+ }
+ }
+ >
+ <input
+ aria-activedescendant="react-select-2--value"
+ aria-expanded="false"
+ aria-haspopup="false"
+ aria-owns=""
+ onBlur={[Function]}
+ onChange={[Function]}
+ onFocus={[Function]}
+ required={false}
+ role="combobox"
+ style={
+ Object {
+ "boxSizing": "content-box",
+ "width": "5px",
+ }
+ }
+ value=""
+ />
+ <div
+ style={
+ Object {
+ "height": 0,
+ "left": 0,
+ "overflow": "scroll",
+ "position": "absolute",
+ "top": 0,
+ "visibility": "hidden",
+ "whiteSpace": "pre",
+ }
+ }
+ />
+ </div>
+ </AutosizeInput>
+ </span>
+ <span
+ className="Select-arrow-zone"
+ onMouseDown={[Function]}
+ >
+ <span
+ className="Select-arrow"
+ onMouseDown={[Function]}
+ />
+ </span>
+ </div>
+ </div>
+ </Select>
+ </LazyLoader>
+ </Select>
+ </div>
+ </div>
+ <div
+ className="big-spacer-top"
+ >
+ <a
+ className="js-new link-base-color link-no-underline"
+ href="#"
+ onClick={[Function]}
+ >
+ <i
+ className="icon-radio spacer-right"
+ />
+ onboarding.organization.create_another_organization
+ </a>
+ </div>
+ </div>
+ </div>
+ </div>
+ </Step>
+</OrganizationStep>
+`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders 1`] = `
+<div
+ className="boxed-group onboarding-step is-open is-finished"
+>
+ <div
+ className="onboarding-step-number"
+ >
+ 1
+ </div>
+ <div
+ className="boxed-group-header"
+ >
+ <h2>
+ First Step
+ </h2>
+ </div>
+ <div>
+ form
+ </div>
+</div>
+`;
+
+exports[`renders 2`] = `
+<div
+ className="boxed-group onboarding-step is-finished"
+ onClick={[Function]}
+ role="button"
+ tabIndex={0}
+>
+ <div
+ className="onboarding-step-number"
+ >
+ 1
+ </div>
+ <div>
+ result
+ </div>
+ <div
+ className="boxed-group-header"
+ >
+ <h2>
+ First Step
+ </h2>
+ </div>
+ <div
+ className="boxed-group-inner"
+ />
+</div>
+`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`generates token 1`] = `
+<TokenStep
+ currentUser={
+ Object {
+ "login": "user",
+ }
+ }
+ finished={false}
+ onContinue={[MockFunction]}
+ onOpen={[MockFunction]}
+ open={true}
+ stepNumber={1}
+>
+ <Step
+ finished={false}
+ onOpen={[MockFunction]}
+ open={true}
+ renderForm={[Function]}
+ renderResult={[Function]}
+ stepNumber={1}
+ stepTitle="onboarding.token.header"
+ >
+ <div
+ className="boxed-group onboarding-step is-open"
+ >
+ <div
+ className="onboarding-step-number"
+ >
+ 1
+ </div>
+ <div
+ className="boxed-group-header"
+ >
+ <h2>
+ onboarding.token.header
+ </h2>
+ </div>
+ <div
+ className="boxed-group-inner"
+ >
+ <div>
+ <div>
+ <a
+ className="js-new link-base-color link-no-underline"
+ href="#"
+ onClick={[Function]}
+ >
+ <i
+ className="icon-radio spacer-right is-checked"
+ />
+ onboarding.token.generate_token
+ </a>
+ <div
+ className="big-spacer-top"
+ >
+ <form
+ onSubmit={[Function]}
+ >
+ <input
+ autoFocus={true}
+ className="input-large spacer-right text-middle"
+ onChange={[Function]}
+ placeholder="onboarding.token.generate_token.placeholder"
+ required={true}
+ type="text"
+ value=""
+ />
+ <SubmitButton
+ className="text-middle"
+ disabled={true}
+ >
+ <Button
+ className="text-middle"
+ disabled={true}
+ preventDefault={false}
+ type="submit"
+ >
+ <button
+ className="button text-middle"
+ disabled={true}
+ onClick={[Function]}
+ type="submit"
+ >
+ onboarding.token.generate
+ </button>
+ </Button>
+ </SubmitButton>
+ </form>
+ </div>
+ </div>
+ <div
+ className="big-spacer-top"
+ >
+ <a
+ className="js-new link-base-color link-no-underline"
+ href="#"
+ onClick={[Function]}
+ >
+ <i
+ className="icon-radio spacer-right"
+ />
+ onboarding.token.use_existing_token
+ </a>
+ </div>
+ </div>
+ <div
+ className="note big-spacer-top width-50"
+ >
+ onboarding.token.text
+ </div>
+ </div>
+ </div>
+ </Step>
+</TokenStep>
+`;
+
+exports[`generates token 2`] = `
+<TokenStep
+ currentUser={
+ Object {
+ "login": "user",
+ }
+ }
+ finished={false}
+ onContinue={[MockFunction]}
+ onOpen={[MockFunction]}
+ open={true}
+ stepNumber={1}
+>
+ <Step
+ finished={false}
+ onOpen={[MockFunction]}
+ open={true}
+ renderForm={[Function]}
+ renderResult={[Function]}
+ stepNumber={1}
+ stepTitle="onboarding.token.header"
+ >
+ <div
+ className="boxed-group onboarding-step is-open"
+ >
+ <div
+ className="onboarding-step-number"
+ >
+ 1
+ </div>
+ <div
+ className="boxed-group-header"
+ >
+ <h2>
+ onboarding.token.header
+ </h2>
+ </div>
+ <div
+ className="boxed-group-inner"
+ >
+ <div>
+ <div>
+ <a
+ className="js-new link-base-color link-no-underline"
+ href="#"
+ onClick={[Function]}
+ >
+ <i
+ className="icon-radio spacer-right is-checked"
+ />
+ onboarding.token.generate_token
+ </a>
+ <div
+ className="big-spacer-top"
+ >
+ <form
+ onSubmit={[Function]}
+ >
+ <input
+ autoFocus={true}
+ className="input-large spacer-right text-middle"
+ onChange={[Function]}
+ placeholder="onboarding.token.generate_token.placeholder"
+ required={true}
+ type="text"
+ value="my token"
+ />
+ <i
+ className="spinner text-middle"
+ />
+ </form>
+ </div>
+ </div>
+ <div
+ className="big-spacer-top"
+ >
+ <a
+ className="js-new link-base-color link-no-underline"
+ href="#"
+ onClick={[Function]}
+ >
+ <i
+ className="icon-radio spacer-right"
+ />
+ onboarding.token.use_existing_token
+ </a>
+ </div>
+ </div>
+ <div
+ className="note big-spacer-top width-50"
+ >
+ onboarding.token.text
+ </div>
+ </div>
+ </div>
+ </Step>
+</TokenStep>
+`;
+
+exports[`generates token 3`] = `
+<TokenStep
+ currentUser={
+ Object {
+ "login": "user",
+ }
+ }
+ finished={false}
+ onContinue={[MockFunction]}
+ onOpen={[MockFunction]}
+ open={true}
+ stepNumber={1}
+>
+ <Step
+ finished={false}
+ onOpen={[MockFunction]}
+ open={true}
+ renderForm={[Function]}
+ renderResult={[Function]}
+ stepNumber={1}
+ stepTitle="onboarding.token.header"
+ >
+ <div
+ className="boxed-group onboarding-step is-open"
+ >
+ <div
+ className="onboarding-step-number"
+ >
+ 1
+ </div>
+ <div
+ className="boxed-group-header"
+ >
+ <h2>
+ onboarding.token.header
+ </h2>
+ </div>
+ <div
+ className="boxed-group-inner"
+ >
+ <form
+ onSubmit={[Function]}
+ >
+ <span
+ className="text-middle"
+ >
+ my token
+ :
+ </span>
+ <strong
+ className="spacer-right text-middle"
+ >
+ abcd1234
+ </strong>
+ <DeleteButton
+ className="button-small text-middle"
+ onClick={[Function]}
+ >
+ <ButtonIcon
+ className="button-small text-middle"
+ color="#d4333f"
+ onClick={[Function]}
+ >
+ <Button
+ className="button-small text-middle button-icon"
+ onClick={[Function]}
+ stopPropagation={true}
+ style={
+ Object {
+ "color": "#d4333f",
+ }
+ }
+ >
+ <button
+ className="button button-small text-middle button-icon"
+ onClick={[Function]}
+ style={
+ Object {
+ "color": "#d4333f",
+ }
+ }
+ type="button"
+ >
+ <ClearIcon />
+ </button>
+ </Button>
+ </ButtonIcon>
+ </DeleteButton>
+ </form>
+ <div
+ className="note big-spacer-top width-50"
+ >
+ onboarding.token.text
+ </div>
+ <div
+ className="big-spacer-top"
+ >
+ <Button
+ className="js-continue"
+ onClick={[Function]}
+ >
+ <button
+ className="button js-continue"
+ onClick={[Function]}
+ type="button"
+ >
+ continue
+ </button>
+ </Button>
+ </div>
+ </div>
+ </div>
+ </Step>
+</TokenStep>
+`;
+
+exports[`revokes token 1`] = `
+<TokenStep
+ currentUser={
+ Object {
+ "login": "user",
+ }
+ }
+ finished={false}
+ onContinue={[MockFunction]}
+ onOpen={[MockFunction]}
+ open={true}
+ stepNumber={1}
+>
+ <Step
+ finished={false}
+ onOpen={[MockFunction]}
+ open={true}
+ renderForm={[Function]}
+ renderResult={[Function]}
+ stepNumber={1}
+ stepTitle="onboarding.token.header"
+ >
+ <div
+ className="boxed-group onboarding-step is-open"
+ >
+ <div
+ className="onboarding-step-number"
+ >
+ 1
+ </div>
+ <div
+ className="boxed-group-header"
+ >
+ <h2>
+ onboarding.token.header
+ </h2>
+ </div>
+ <div
+ className="boxed-group-inner"
+ >
+ <form
+ onSubmit={[Function]}
+ >
+ <span
+ className="text-middle"
+ >
+ my token
+ :
+ </span>
+ <strong
+ className="spacer-right text-middle"
+ >
+ abcd1234
+ </strong>
+ <DeleteButton
+ className="button-small text-middle"
+ onClick={[Function]}
+ >
+ <ButtonIcon
+ className="button-small text-middle"
+ color="#d4333f"
+ onClick={[Function]}
+ >
+ <Button
+ className="button-small text-middle button-icon"
+ onClick={[Function]}
+ stopPropagation={true}
+ style={
+ Object {
+ "color": "#d4333f",
+ }
+ }
+ >
+ <button
+ className="button button-small text-middle button-icon"
+ onClick={[Function]}
+ style={
+ Object {
+ "color": "#d4333f",
+ }
+ }
+ type="button"
+ >
+ <ClearIcon />
+ </button>
+ </Button>
+ </ButtonIcon>
+ </DeleteButton>
+ </form>
+ <div
+ className="note big-spacer-top width-50"
+ >
+ onboarding.token.text
+ </div>
+ <div
+ className="big-spacer-top"
+ >
+ <Button
+ className="js-continue"
+ onClick={[Function]}
+ >
+ <button
+ className="button js-continue"
+ onClick={[Function]}
+ type="button"
+ >
+ continue
+ </button>
+ </Button>
+ </div>
+ </div>
+ </div>
+ </Step>
+</TokenStep>
+`;
+
+exports[`revokes token 2`] = `
+<TokenStep
+ currentUser={
+ Object {
+ "login": "user",
+ }
+ }
+ finished={false}
+ onContinue={[MockFunction]}
+ onOpen={[MockFunction]}
+ open={true}
+ stepNumber={1}
+>
+ <Step
+ finished={false}
+ onOpen={[MockFunction]}
+ open={true}
+ renderForm={[Function]}
+ renderResult={[Function]}
+ stepNumber={1}
+ stepTitle="onboarding.token.header"
+ >
+ <div
+ className="boxed-group onboarding-step is-open"
+ >
+ <div
+ className="onboarding-step-number"
+ >
+ 1
+ </div>
+ <div
+ className="boxed-group-header"
+ >
+ <h2>
+ onboarding.token.header
+ </h2>
+ </div>
+ <div
+ className="boxed-group-inner"
+ >
+ <form
+ onSubmit={[Function]}
+ >
+ <span
+ className="text-middle"
+ >
+ my token
+ :
+ </span>
+ <strong
+ className="spacer-right text-middle"
+ >
+ abcd1234
+ </strong>
+ <i
+ className="spinner text-middle"
+ />
+ </form>
+ <div
+ className="note big-spacer-top width-50"
+ >
+ onboarding.token.text
+ </div>
+ <div
+ className="big-spacer-top"
+ >
+ <Button
+ className="js-continue"
+ onClick={[Function]}
+ >
+ <button
+ className="button js-continue"
+ onClick={[Function]}
+ type="button"
+ >
+ continue
+ </button>
+ </Button>
+ </div>
+ </div>
+ </div>
+ </Step>
+</TokenStep>
+`;
+
+exports[`revokes token 3`] = `
+<TokenStep
+ currentUser={
+ Object {
+ "login": "user",
+ }
+ }
+ finished={false}
+ onContinue={[MockFunction]}
+ onOpen={[MockFunction]}
+ open={true}
+ stepNumber={1}
+>
+ <Step
+ finished={false}
+ onOpen={[MockFunction]}
+ open={true}
+ renderForm={[Function]}
+ renderResult={[Function]}
+ stepNumber={1}
+ stepTitle="onboarding.token.header"
+ >
+ <div
+ className="boxed-group onboarding-step is-open"
+ >
+ <div
+ className="onboarding-step-number"
+ >
+ 1
+ </div>
+ <div
+ className="boxed-group-header"
+ >
+ <h2>
+ onboarding.token.header
+ </h2>
+ </div>
+ <div
+ className="boxed-group-inner"
+ >
+ <div>
+ <div>
+ <a
+ className="js-new link-base-color link-no-underline"
+ href="#"
+ onClick={[Function]}
+ >
+ <i
+ className="icon-radio spacer-right is-checked"
+ />
+ onboarding.token.generate_token
+ </a>
+ <div
+ className="big-spacer-top"
+ >
+ <form
+ onSubmit={[Function]}
+ >
+ <input
+ autoFocus={true}
+ className="input-large spacer-right text-middle"
+ onChange={[Function]}
+ placeholder="onboarding.token.generate_token.placeholder"
+ required={true}
+ type="text"
+ value=""
+ />
+ <SubmitButton
+ className="text-middle"
+ disabled={true}
+ >
+ <Button
+ className="text-middle"
+ disabled={true}
+ preventDefault={false}
+ type="submit"
+ >
+ <button
+ className="button text-middle"
+ disabled={true}
+ onClick={[Function]}
+ type="submit"
+ >
+ onboarding.token.generate
+ </button>
+ </Button>
+ </SubmitButton>
+ </form>
+ </div>
+ </div>
+ <div
+ className="big-spacer-top"
+ >
+ <a
+ className="js-new link-base-color link-no-underline"
+ href="#"
+ onClick={[Function]}
+ >
+ <i
+ className="icon-radio spacer-right"
+ />
+ onboarding.token.use_existing_token
+ </a>
+ </div>
+ </div>
+ <div
+ className="note big-spacer-top width-50"
+ >
+ onboarding.token.text
+ </div>
+ </div>
+ </div>
+ </Step>
+</TokenStep>
+`;
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import JavaMaven from './JavaMaven';
+import JavaGradle from './JavaGradle';
+import DotNet from './DotNet';
+import Msvc from './Msvc';
+import ClangGCC from './ClangGCC';
+import Other from './Other';
+import { getHostUrl } from '../../../../helpers/urls';
+import { Component } from '../../../../app/types';
+import { LanguageConfig } from '../../utils';
+
+interface Props {
+ component?: Component;
+ organization?: string;
+ languageConfig: LanguageConfig;
+ small?: boolean;
+ token?: string;
+}
+
+export default class AnalysisCommand extends React.PureComponent<Props> {
+ getProjectKey = ({ component, languageConfig } = this.props) => {
+ return (component && component.key) || languageConfig.projectKey;
+ };
+
+ renderCommandForMaven = () => {
+ const { token } = this.props;
+ if (!token) {
+ return null;
+ }
+ return <JavaMaven host={getHostUrl()} organization={this.props.organization} token={token} />;
+ };
+
+ renderCommandForGradle = () => {
+ const { token } = this.props;
+ if (!token) {
+ return null;
+ }
+ return <JavaGradle host={getHostUrl()} organization={this.props.organization} token={token} />;
+ };
+
+ renderCommandForDotNet = () => {
+ const { small, token } = this.props;
+ const projectKey = this.getProjectKey();
+ if (!projectKey || !token) {
+ return null;
+ }
+ return (
+ <DotNet
+ host={getHostUrl()}
+ organization={this.props.organization}
+ projectKey={projectKey}
+ small={small}
+ token={token}
+ />
+ );
+ };
+
+ renderCommandForMSVC = () => {
+ const { small, token } = this.props;
+ const projectKey = this.getProjectKey();
+ if (!projectKey || !token) {
+ return null;
+ }
+ return (
+ <Msvc
+ host={getHostUrl()}
+ organization={this.props.organization}
+ projectKey={projectKey}
+ small={small}
+ token={token}
+ />
+ );
+ };
+
+ renderCommandForClangGCC = () => {
+ const { languageConfig, small, token } = this.props;
+ const projectKey = this.getProjectKey();
+ if (!languageConfig || !projectKey || !languageConfig.os || !token) {
+ return null;
+ }
+ return (
+ <ClangGCC
+ host={getHostUrl()}
+ organization={this.props.organization}
+ os={languageConfig.os}
+ projectKey={projectKey}
+ small={small}
+ token={token}
+ />
+ );
+ };
+
+ renderCommandForOther = () => {
+ const { languageConfig, token } = this.props;
+ const projectKey = this.getProjectKey();
+ if (!languageConfig || !projectKey || !languageConfig.os || !token) {
+ return null;
+ }
+ return (
+ <Other
+ host={getHostUrl()}
+ organization={this.props.organization}
+ os={languageConfig.os}
+ projectKey={projectKey}
+ token={token}
+ />
+ );
+ };
+
+ render() {
+ const { languageConfig } = this.props;
+
+ if (languageConfig.language === 'java') {
+ return languageConfig.javaBuild === 'maven'
+ ? this.renderCommandForMaven()
+ : this.renderCommandForGradle();
+ } else if (languageConfig.language === 'dotnet') {
+ return this.renderCommandForDotNet();
+ } else if (languageConfig.language === 'c-family') {
+ return languageConfig.cFamilyCompiler === 'msvc'
+ ? this.renderCommandForMSVC()
+ : this.renderCommandForClangGCC();
+ } else {
+ return this.renderCommandForOther();
+ }
+ }
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { translate } from '../../../../helpers/l10n';
+import { getBaseUrl } from '../../../../helpers/urls';
+
+interface Props {
+ className?: string;
+ os: string;
+}
+
+const filenames: { [key: string]: string } = {
+ win: 'build-wrapper-win-x86.zip',
+ linux: 'build-wrapper-linux-x86.zip',
+ mac: 'build-wrapper-macosx-x86.zip'
+};
+
+export default function BuildWrapper(props: Props) {
+ return (
+ <div className={props.className}>
+ <h4 className="spacer-bottom">
+ {translate('onboarding.analysis.build_wrapper.header', props.os)}
+ </h4>
+ <p
+ className="spacer-bottom markdown"
+ dangerouslySetInnerHTML={{
+ __html: translate('onboarding.analysis.build_wrapper.text', props.os)
+ }}
+ />
+ <p>
+ <a
+ className="button"
+ download={filenames[props.os]}
+ href={`${getBaseUrl()}/static/cpp/${filenames[props.os]}`}
+ target="_blank">
+ {translate('download_verb')}
+ </a>
+ </p>
+ </div>
+ );
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import SQScanner from './SQScanner';
+import BuildWrapper from './BuildWrapper';
+import CodeSnippet from '../../../../components/common/CodeSnippet';
+import InstanceMessage from '../../../../components/common/InstanceMessage';
+import { translate } from '../../../../helpers/l10n';
+
+interface Props {
+ host: string;
+ os: string;
+ organization?: string;
+ projectKey: string;
+ small?: boolean;
+ token: string;
+}
+
+const executables: { [key: string]: string } = {
+ linux: 'build-wrapper-linux-x86-64',
+ win: 'build-wrapper-win-x86-64.exe',
+ mac: 'build-wrapper-macosx-x86'
+};
+
+export default function ClangGCC(props: Props) {
+ const command1 = `${executables[props.os]} --out-dir bw-output make clean all`;
+
+ const command2 = [
+ props.os === 'win' ? 'sonar-scanner.bat' : 'sonar-scanner',
+ `-Dsonar.projectKey=${props.projectKey}`,
+ props.organization && `-Dsonar.organization=${props.organization}`,
+ '-Dsonar.sources=.',
+ '-Dsonar.cfamily.build-wrapper-output=bw-output',
+ `-Dsonar.host.url=${props.host}`,
+ `-Dsonar.login=${props.token}`
+ ];
+
+ return (
+ <div>
+ <SQScanner os={props.os} />
+ <BuildWrapper className="huge-spacer-top" os={props.os} />
+
+ <h4 className="huge-spacer-top spacer-bottom">
+ {translate('onboarding.analysis.sq_scanner.execute')}
+ </h4>
+ <InstanceMessage message={translate('onboarding.analysis.sq_scanner.execute.text')}>
+ {transformedMessage => (
+ <p
+ className="spacer-bottom markdown"
+ dangerouslySetInnerHTML={{ __html: transformedMessage }}
+ />
+ )}
+ </InstanceMessage>
+ <CodeSnippet isOneLine={props.small} snippet={command1} />
+ <CodeSnippet isOneLine={props.os === 'win'} snippet={command2} />
+ <p
+ className="big-spacer-top markdown"
+ dangerouslySetInnerHTML={{ __html: translate('onboarding.analysis.sq_scanner.docs') }}
+ />
+ </div>
+ );
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import MSBuildScanner from './MSBuildScanner';
+import CodeSnippet from '../../../../components/common/CodeSnippet';
+import InstanceMessage from '../../../../components/common/InstanceMessage';
+import { translate } from '../../../../helpers/l10n';
+
+interface Props {
+ host: string;
+ organization?: string;
+ projectKey: string;
+ small?: boolean;
+ token: string;
+}
+
+export default function DotNet(props: Props) {
+ const command1 = [
+ 'SonarScanner.MSBuild.exe begin',
+ `/k:"${props.projectKey}"`,
+ props.organization && `/d:sonar.organization="${props.organization}"`,
+ `/d:sonar.host.url="${props.host}"`,
+ `/d:sonar.login="${props.token}"`
+ ];
+
+ const command2 = 'MsBuild.exe /t:Rebuild';
+
+ const command3 = ['SonarScanner.MSBuild.exe end', `/d:sonar.login="${props.token}"`];
+
+ return (
+ <div>
+ <MSBuildScanner />
+
+ <h4 className="huge-spacer-top spacer-bottom">
+ {translate('onboarding.analysis.msbuild.execute')}
+ </h4>
+ <InstanceMessage message={translate('onboarding.analysis.msbuild.execute.text')}>
+ {transformedMessage => (
+ <p
+ className="spacer-bottom markdown"
+ dangerouslySetInnerHTML={{ __html: transformedMessage }}
+ />
+ )}
+ </InstanceMessage>
+ <CodeSnippet isOneLine={true} snippet={command1} />
+ <CodeSnippet isOneLine={false} snippet={command2} />
+ <CodeSnippet isOneLine={props.small} snippet={command3} />
+ <p
+ className="big-spacer-top markdown"
+ dangerouslySetInnerHTML={{ __html: translate('onboarding.analysis.msbuild.docs') }}
+ />
+ </div>
+ );
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import CodeSnippet from '../../../../components/common/CodeSnippet';
+import InstanceMessage from '../../../../components/common/InstanceMessage';
+import { translate } from '../../../../helpers/l10n';
+
+interface Props {
+ host: string;
+ organization?: string;
+ token: string;
+}
+
+export default function JavaGradle(props: Props) {
+ const config = 'plugins {\n id "org.sonarqube" version "2.6"\n}';
+
+ const command = [
+ './gradlew sonarqube',
+ props.organization && `-Dsonar.organization=${props.organization}`,
+ `-Dsonar.host.url=${props.host}`,
+ `-Dsonar.login=${props.token}`
+ ];
+
+ return (
+ <div>
+ <h4 className="spacer-bottom">{translate('onboarding.analysis.java.gradle.header')}</h4>
+ <InstanceMessage message={translate('onboarding.analysis.java.gradle.text.1')}>
+ {transformedMessage => (
+ <p
+ className="spacer-bottom markdown"
+ dangerouslySetInnerHTML={{ __html: transformedMessage }}
+ />
+ )}
+ </InstanceMessage>
+ <CodeSnippet snippet={config} />
+ <p className="spacer-top spacer-bottom markdown">
+ {translate('onboarding.analysis.java.gradle.text.2')}
+ </p>
+ <CodeSnippet snippet={command} />
+ <p
+ className="big-spacer-top markdown"
+ dangerouslySetInnerHTML={{ __html: translate('onboarding.analysis.java.gradle.docs') }}
+ />
+ <p
+ className="big-spacer-top markdown"
+ dangerouslySetInnerHTML={{
+ __html: props.projectKey
+ ? translate('onboarding.analysis.auto_refresh_after_analysis')
+ : translate('onboarding.analysis.browse_url_after_analysis')
+ }}
+ />
+ </div>
+ );
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import CodeSnippet from '../../../../components/common/CodeSnippet';
+import InstanceMessage from '../../../../components/common/InstanceMessage';
+import { translate } from '../../../../helpers/l10n';
+
+interface Props {
+ host: string;
+ organization?: string;
+ token: string;
+}
+
+export default function JavaMaven(props: Props) {
+ const command = [
+ 'mvn sonar:sonar',
+ props.organization && `-Dsonar.organization=${props.organization}`,
+ `-Dsonar.host.url=${props.host}`,
+ `-Dsonar.login=${props.token}`
+ ];
+
+ return (
+ <div>
+ <h4 className="spacer-bottom">{translate('onboarding.analysis.java.maven.header')}</h4>
+ <p className="spacer-bottom markdown">
+ <InstanceMessage message={translate('onboarding.analysis.java.maven.text')} />
+ </p>
+ <CodeSnippet snippet={command} />
+ <p
+ className="big-spacer-top markdown"
+ dangerouslySetInnerHTML={{ __html: translate('onboarding.analysis.java.maven.docs') }}
+ />
+ <p
+ className="big-spacer-top markdown"
+ dangerouslySetInnerHTML={{
+ __html: props.projectKey
+ ? translate('onboarding.analysis.auto_refresh_after_analysis')
+ : translate('onboarding.analysis.browse_url_after_analysis')
+ }}
+ />
+ </div>
+ );
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+import * as React from 'react';
+import { translate } from '../../../../helpers/l10n';
+
+interface Props {
+ className?: string;
+}
+
+export default function MSBuildScanner(props: Props) {
+ return (
+ <div className={props.className}>
+ <h4 className="spacer-bottom">{translate('onboarding.analysis.msbuild.header')}</h4>
+ <p
+ className="spacer-bottom markdown"
+ dangerouslySetInnerHTML={{ __html: translate('onboarding.analysis.msbuild.text') }}
+ />
+ <p>
+ <a
+ className="button"
+ href="http://redirect.sonarsource.com/doc/install-configure-scanner-msbuild.html"
+ rel="noopener noreferrer"
+ target="_blank">
+ {translate('download_verb')}
+ </a>
+ </p>
+ </div>
+ );
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import MSBuildScanner from './MSBuildScanner';
+import BuildWrapper from './BuildWrapper';
+import CodeSnippet from '../../../../components/common/CodeSnippet';
+import InstanceMessage from '../../../../components/common/InstanceMessage';
+import { translate } from '../../../../helpers/l10n';
+
+interface Props {
+ host: string;
+ organization?: string;
+ projectKey: string;
+ small?: boolean;
+ token: string;
+}
+
+export default function Msvc(props: Props) {
+ const command1 = [
+ 'SonarQube.Scanner.MSBuild.exe begin',
+ `/k:"${props.projectKey}"`,
+ props.organization && `/d:sonar.organization="${props.organization}"`,
+ '/d:sonar.cfamily.build-wrapper-output=bw-output',
+ `/d:sonar.host.url="${props.host}"`,
+ `/d:sonar.login="${props.token}"`
+ ];
+
+ const command2 = 'build-wrapper-win-x86-64.exe --out-dir bw-output MsBuild.exe /t:Rebuild';
+
+ const command3 = ['SonarQube.Scanner.MSBuild.exe end', `/d:sonar.login="${props.token}"`];
+
+ return (
+ <div>
+ <MSBuildScanner />
+ <BuildWrapper className="huge-spacer-top" os="win" />
+
+ <h4 className="huge-spacer-top spacer-bottom">
+ {translate('onboarding.analysis.msbuild.execute')}
+ </h4>
+ <InstanceMessage message={translate('onboarding.analysis.msbuild.execute.text')}>
+ {transformedMessage => (
+ <p
+ className="spacer-bottom markdown"
+ dangerouslySetInnerHTML={{ __html: transformedMessage }}
+ />
+ )}
+ </InstanceMessage>
+ <CodeSnippet isOneLine={true} snippet={command1} />
+ <CodeSnippet isOneLine={props.small} snippet={command2} />
+ <CodeSnippet isOneLine={props.small} snippet={command3} />
+ <p
+ className="big-spacer-top markdown"
+ dangerouslySetInnerHTML={{ __html: translate('onboarding.analysis.msbuild.docs') }}
+ />
+ </div>
+ );
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import SQScanner from './SQScanner';
+import CodeSnippet from '../../../../components/common/CodeSnippet';
+import InstanceMessage from '../../../../components/common/InstanceMessage';
+import { translate } from '../../../../helpers/l10n';
+
+interface Props {
+ host: string;
+ organization?: string;
+ os: string;
+ projectKey: string;
+ token: string;
+}
+
+export default function Other(props: Props) {
+ const command = [
+ props.os === 'win' ? 'sonar-scanner.bat' : 'sonar-scanner',
+ `-Dsonar.projectKey=${props.projectKey}`,
+ props.organization && `-Dsonar.organization=${props.organization}`,
+ '-Dsonar.sources=.',
+ `-Dsonar.host.url=${props.host}`,
+ `-Dsonar.login=${props.token}`
+ ];
+
+ return (
+ <div>
+ <SQScanner os={props.os} />
+
+ <h4 className="huge-spacer-top spacer-bottom">
+ {translate('onboarding.analysis.sq_scanner.execute')}
+ </h4>
+ <InstanceMessage message={translate('onboarding.analysis.sq_scanner.execute.text')}>
+ {transformedMessage => (
+ <p
+ className="spacer-bottom markdown"
+ dangerouslySetInnerHTML={{ __html: transformedMessage }}
+ />
+ )}
+ </InstanceMessage>
+ <CodeSnippet isOneLine={props.os === 'win'} snippet={command} />
+ <p
+ className="big-spacer-top markdown"
+ dangerouslySetInnerHTML={{ __html: translate('onboarding.analysis.sq_scanner.docs') }}
+ />
+ </div>
+ );
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+import * as React from 'react';
+import { translate } from '../../../../helpers/l10n';
+
+interface Props {
+ className?: string;
+ os: string;
+}
+
+export default function SQScanner(props: Props) {
+ return (
+ <div className={props.className}>
+ <h4 className="spacer-bottom">
+ {translate('onboarding.analysis.sq_scanner.header', props.os)}
+ </h4>
+ <p
+ className="spacer-bottom markdown"
+ dangerouslySetInnerHTML={{
+ __html: translate('onboarding.analysis.sq_scanner.text', props.os)
+ }}
+ />
+ <p>
+ <a
+ className="button"
+ href="http://redirect.sonarsource.com/doc/install-configure-scanner.html"
+ rel="noopener noreferrer"
+ target="_blank">
+ {translate('download_verb')}
+ </a>
+ </p>
+ </div>
+ );
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import AnalysisCommand from '../AnalysisCommand';
+
+jest.mock('../../../../../helpers/system', () => ({
+ isSonarCloud: jest.fn().mockReturnValue(true)
+}));
+
+it('display java command', () => {
+ expect(
+ getWrapper({ languageConfig: { language: 'java', javaBuild: 'gradle' } })
+ ).toMatchSnapshot();
+ expect(
+ getWrapper({ languageConfig: { language: 'java', javaBuild: 'maven' } })
+ ).toMatchSnapshot();
+});
+
+it('display c# command', () => {
+ expect(
+ getWrapper({ languageConfig: { language: 'dotnet', projectKey: 'project-foo' } })
+ ).toMatchSnapshot();
+});
+
+it('display c-family command', () => {
+ expect(
+ getWrapper({
+ languageConfig: { language: 'c-family', cFamilyCompiler: 'msvc', projectKey: 'project-foo' }
+ })
+ ).toMatchSnapshot();
+ expect(
+ getWrapper({
+ languageConfig: {
+ language: 'c-family',
+ cFamilyCompiler: 'clang-gcc',
+ os: 'linux',
+ projectKey: 'project-foo'
+ }
+ })
+ ).toMatchSnapshot();
+});
+
+it('display others command', () => {
+ expect(
+ getWrapper({
+ languageConfig: { language: 'other', os: 'window', projectKey: 'project-foo' }
+ })
+ ).toMatchSnapshot();
+});
+
+function getWrapper(props = {}) {
+ return shallow(<AnalysisCommand languageConfig={{}} token="myToken" {...props} />);
+}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import BuildWrapper from '../BuildWrapper';
+
+it('renders correctly', () => {
+ expect(shallow(<BuildWrapper os="win" />)).toMatchSnapshot();
+ expect(shallow(<BuildWrapper os="linux" />)).toMatchSnapshot();
+ expect(shallow(<BuildWrapper os="mac" />)).toMatchSnapshot();
+});
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import ClangGCC from '../ClangGCC';
+
+it('renders correctly', () => {
+ expect(
+ shallow(<ClangGCC host="host" os="win" projectKey="projectKey" token="token" />)
+ ).toMatchSnapshot();
+
+ expect(
+ shallow(<ClangGCC host="host" os="linux" projectKey="projectKey" token="token" />)
+ ).toMatchSnapshot();
+
+ expect(
+ shallow(
+ <ClangGCC
+ host="host"
+ organization="organization"
+ os="linux"
+ projectKey="projectKey"
+ small={true}
+ token="token"
+ />
+ )
+ ).toMatchSnapshot();
+});
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import DotNet from '../DotNet';
+
+it('renders correctly', () => {
+ expect(shallow(<DotNet host="host" projectKey="projectKey" token="token" />)).toMatchSnapshot();
+ expect(
+ shallow(
+ <DotNet
+ host="host"
+ organization="organization"
+ projectKey="projectKey"
+ small={true}
+ token="token"
+ />
+ )
+ ).toMatchSnapshot();
+});
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import JavaGradle from '../JavaGradle';
+
+it('renders correctly', () => {
+ expect(shallow(<JavaGradle host="host" token="token" />)).toMatchSnapshot();
+ expect(
+ shallow(<JavaGradle host="host" organization="organization" token="token" />)
+ ).toMatchSnapshot();
+});
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import JavaMaven from '../JavaMaven';
+
+it('renders correctly', () => {
+ expect(shallow(<JavaMaven host="host" token="token" />)).toMatchSnapshot();
+ expect(
+ shallow(<JavaMaven host="host" organization="organization" token="token" />)
+ ).toMatchSnapshot();
+});
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import MSBuildScanner from '../MSBuildScanner';
+
+it('renders correctly', () => {
+ expect(shallow(<MSBuildScanner />)).toMatchSnapshot();
+});
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import Msvc from '../Msvc';
+
+it('renders correctly', () => {
+ expect(shallow(<Msvc host="host" projectKey="projectKey" token="token" />)).toMatchSnapshot();
+ expect(
+ shallow(
+ <Msvc
+ host="host"
+ organization="organization"
+ projectKey="projectKey"
+ small={true}
+ token="token"
+ />
+ )
+ ).toMatchSnapshot();
+});
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import Other from '../Other';
+
+it('renders correctly', () => {
+ expect(
+ shallow(<Other host="host" os="win" projectKey="projectKey" token="token" />)
+ ).toMatchSnapshot();
+
+ expect(
+ shallow(<Other host="host" os="linux" projectKey="projectKey" token="token" />)
+ ).toMatchSnapshot();
+
+ expect(
+ shallow(
+ <Other
+ host="host"
+ organization="organization"
+ os="linux"
+ projectKey="projectKey"
+ token="token"
+ />
+ )
+ ).toMatchSnapshot();
+});
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import SQScanner from '../SQScanner';
+
+it('renders correctly', () => {
+ expect(shallow(<SQScanner os="win" />)).toMatchSnapshot();
+ expect(shallow(<SQScanner os="linux" />)).toMatchSnapshot();
+ expect(shallow(<SQScanner os="mac" />)).toMatchSnapshot();
+});
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`display c# command 1`] = `
+<DotNet
+ host="null"
+ projectKey="project-foo"
+ token="myToken"
+/>
+`;
+
+exports[`display c-family command 1`] = `
+<Msvc
+ host="null"
+ projectKey="project-foo"
+ token="myToken"
+/>
+`;
+
+exports[`display c-family command 2`] = `
+<ClangGCC
+ host="null"
+ os="linux"
+ projectKey="project-foo"
+ token="myToken"
+/>
+`;
+
+exports[`display java command 1`] = `
+<JavaGradle
+ host="null"
+ token="myToken"
+/>
+`;
+
+exports[`display java command 2`] = `
+<JavaMaven
+ host="null"
+ token="myToken"
+/>
+`;
+
+exports[`display others command 1`] = `
+<Other
+ host="null"
+ os="window"
+ projectKey="project-foo"
+ token="myToken"
+/>
+`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+<div>
+ <h4
+ className="spacer-bottom"
+ >
+ onboarding.analysis.build_wrapper.header.win
+ </h4>
+ <p
+ className="spacer-bottom markdown"
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "onboarding.analysis.build_wrapper.text.win",
+ }
+ }
+ />
+ <p>
+ <a
+ className="button"
+ download="build-wrapper-win-x86.zip"
+ href="/static/cpp/build-wrapper-win-x86.zip"
+ target="_blank"
+ >
+ download_verb
+ </a>
+ </p>
+</div>
+`;
+
+exports[`renders correctly 2`] = `
+<div>
+ <h4
+ className="spacer-bottom"
+ >
+ onboarding.analysis.build_wrapper.header.linux
+ </h4>
+ <p
+ className="spacer-bottom markdown"
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "onboarding.analysis.build_wrapper.text.linux",
+ }
+ }
+ />
+ <p>
+ <a
+ className="button"
+ download="build-wrapper-linux-x86.zip"
+ href="/static/cpp/build-wrapper-linux-x86.zip"
+ target="_blank"
+ >
+ download_verb
+ </a>
+ </p>
+</div>
+`;
+
+exports[`renders correctly 3`] = `
+<div>
+ <h4
+ className="spacer-bottom"
+ >
+ onboarding.analysis.build_wrapper.header.mac
+ </h4>
+ <p
+ className="spacer-bottom markdown"
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "onboarding.analysis.build_wrapper.text.mac",
+ }
+ }
+ />
+ <p>
+ <a
+ className="button"
+ download="build-wrapper-macosx-x86.zip"
+ href="/static/cpp/build-wrapper-macosx-x86.zip"
+ target="_blank"
+ >
+ download_verb
+ </a>
+ </p>
+</div>
+`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+<div>
+ <SQScanner
+ os="win"
+ />
+ <BuildWrapper
+ className="huge-spacer-top"
+ os="win"
+ />
+ <h4
+ className="huge-spacer-top spacer-bottom"
+ >
+ onboarding.analysis.sq_scanner.execute
+ </h4>
+ <InstanceMessage
+ message="onboarding.analysis.sq_scanner.execute.text"
+ />
+ <CodeSnippet
+ snippet="build-wrapper-win-x86-64.exe --out-dir bw-output make clean all"
+ />
+ <CodeSnippet
+ isOneLine={true}
+ snippet={
+ Array [
+ "sonar-scanner.bat",
+ "-Dsonar.projectKey=projectKey",
+ undefined,
+ "-Dsonar.sources=.",
+ "-Dsonar.cfamily.build-wrapper-output=bw-output",
+ "-Dsonar.host.url=host",
+ "-Dsonar.login=token",
+ ]
+ }
+ />
+ <p
+ className="big-spacer-top markdown"
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "onboarding.analysis.sq_scanner.docs",
+ }
+ }
+ />
+</div>
+`;
+
+exports[`renders correctly 2`] = `
+<div>
+ <SQScanner
+ os="linux"
+ />
+ <BuildWrapper
+ className="huge-spacer-top"
+ os="linux"
+ />
+ <h4
+ className="huge-spacer-top spacer-bottom"
+ >
+ onboarding.analysis.sq_scanner.execute
+ </h4>
+ <InstanceMessage
+ message="onboarding.analysis.sq_scanner.execute.text"
+ />
+ <CodeSnippet
+ snippet="build-wrapper-linux-x86-64 --out-dir bw-output make clean all"
+ />
+ <CodeSnippet
+ isOneLine={false}
+ snippet={
+ Array [
+ "sonar-scanner",
+ "-Dsonar.projectKey=projectKey",
+ undefined,
+ "-Dsonar.sources=.",
+ "-Dsonar.cfamily.build-wrapper-output=bw-output",
+ "-Dsonar.host.url=host",
+ "-Dsonar.login=token",
+ ]
+ }
+ />
+ <p
+ className="big-spacer-top markdown"
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "onboarding.analysis.sq_scanner.docs",
+ }
+ }
+ />
+</div>
+`;
+
+exports[`renders correctly 3`] = `
+<div>
+ <SQScanner
+ os="linux"
+ />
+ <BuildWrapper
+ className="huge-spacer-top"
+ os="linux"
+ />
+ <h4
+ className="huge-spacer-top spacer-bottom"
+ >
+ onboarding.analysis.sq_scanner.execute
+ </h4>
+ <InstanceMessage
+ message="onboarding.analysis.sq_scanner.execute.text"
+ />
+ <CodeSnippet
+ isOneLine={true}
+ snippet="build-wrapper-linux-x86-64 --out-dir bw-output make clean all"
+ />
+ <CodeSnippet
+ isOneLine={false}
+ snippet={
+ Array [
+ "sonar-scanner",
+ "-Dsonar.projectKey=projectKey",
+ "-Dsonar.organization=organization",
+ "-Dsonar.sources=.",
+ "-Dsonar.cfamily.build-wrapper-output=bw-output",
+ "-Dsonar.host.url=host",
+ "-Dsonar.login=token",
+ ]
+ }
+ />
+ <p
+ className="big-spacer-top markdown"
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "onboarding.analysis.sq_scanner.docs",
+ }
+ }
+ />
+</div>
+`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+<div>
+ <MSBuildScanner />
+ <h4
+ className="huge-spacer-top spacer-bottom"
+ >
+ onboarding.analysis.msbuild.execute
+ </h4>
+ <InstanceMessage
+ message="onboarding.analysis.msbuild.execute.text"
+ />
+ <CodeSnippet
+ isOneLine={true}
+ snippet={
+ Array [
+ "SonarScanner.MSBuild.exe begin",
+ "/k:\\"projectKey\\"",
+ undefined,
+ "/d:sonar.host.url=\\"host\\"",
+ "/d:sonar.login=\\"token\\"",
+ ]
+ }
+ />
+ <CodeSnippet
+ isOneLine={false}
+ snippet="MsBuild.exe /t:Rebuild"
+ />
+ <CodeSnippet
+ snippet={
+ Array [
+ "SonarScanner.MSBuild.exe end",
+ "/d:sonar.login=\\"token\\"",
+ ]
+ }
+ />
+ <p
+ className="big-spacer-top markdown"
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "onboarding.analysis.msbuild.docs",
+ }
+ }
+ />
+</div>
+`;
+
+exports[`renders correctly 2`] = `
+<div>
+ <MSBuildScanner />
+ <h4
+ className="huge-spacer-top spacer-bottom"
+ >
+ onboarding.analysis.msbuild.execute
+ </h4>
+ <InstanceMessage
+ message="onboarding.analysis.msbuild.execute.text"
+ />
+ <CodeSnippet
+ isOneLine={true}
+ snippet={
+ Array [
+ "SonarScanner.MSBuild.exe begin",
+ "/k:\\"projectKey\\"",
+ "/d:sonar.organization=\\"organization\\"",
+ "/d:sonar.host.url=\\"host\\"",
+ "/d:sonar.login=\\"token\\"",
+ ]
+ }
+ />
+ <CodeSnippet
+ isOneLine={false}
+ snippet="MsBuild.exe /t:Rebuild"
+ />
+ <CodeSnippet
+ isOneLine={true}
+ snippet={
+ Array [
+ "SonarScanner.MSBuild.exe end",
+ "/d:sonar.login=\\"token\\"",
+ ]
+ }
+ />
+ <p
+ className="big-spacer-top markdown"
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "onboarding.analysis.msbuild.docs",
+ }
+ }
+ />
+</div>
+`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+<div>
+ <h4
+ className="spacer-bottom"
+ >
+ onboarding.analysis.java.gradle.header
+ </h4>
+ <InstanceMessage
+ message="onboarding.analysis.java.gradle.text.1"
+ />
+ <CodeSnippet
+ snippet="plugins {
+ id \\"org.sonarqube\\" version \\"2.6\\"
+}"
+ />
+ <p
+ className="spacer-top spacer-bottom markdown"
+ >
+ onboarding.analysis.java.gradle.text.2
+ </p>
+ <CodeSnippet
+ snippet={
+ Array [
+ "./gradlew sonarqube",
+ undefined,
+ "-Dsonar.host.url=host",
+ "-Dsonar.login=token",
+ ]
+ }
+ />
+ <p
+ className="big-spacer-top markdown"
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "onboarding.analysis.java.gradle.docs",
+ }
+ }
+ />
+ <p
+ className="big-spacer-top markdown"
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "onboarding.analysis.browse_url_after_analysis",
+ }
+ }
+ />
+</div>
+`;
+
+exports[`renders correctly 2`] = `
+<div>
+ <h4
+ className="spacer-bottom"
+ >
+ onboarding.analysis.java.gradle.header
+ </h4>
+ <InstanceMessage
+ message="onboarding.analysis.java.gradle.text.1"
+ />
+ <CodeSnippet
+ snippet="plugins {
+ id \\"org.sonarqube\\" version \\"2.6\\"
+}"
+ />
+ <p
+ className="spacer-top spacer-bottom markdown"
+ >
+ onboarding.analysis.java.gradle.text.2
+ </p>
+ <CodeSnippet
+ snippet={
+ Array [
+ "./gradlew sonarqube",
+ "-Dsonar.organization=organization",
+ "-Dsonar.host.url=host",
+ "-Dsonar.login=token",
+ ]
+ }
+ />
+ <p
+ className="big-spacer-top markdown"
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "onboarding.analysis.java.gradle.docs",
+ }
+ }
+ />
+ <p
+ className="big-spacer-top markdown"
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "onboarding.analysis.auto_refresh_after_analysis",
+ }
+ }
+ />
+</div>
+`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+<div>
+ <h4
+ className="spacer-bottom"
+ >
+ onboarding.analysis.java.maven.header
+ </h4>
+ <p
+ className="spacer-bottom markdown"
+ >
+ <InstanceMessage
+ message="onboarding.analysis.java.maven.text"
+ />
+ </p>
+ <CodeSnippet
+ snippet={
+ Array [
+ "mvn sonar:sonar",
+ undefined,
+ "-Dsonar.host.url=host",
+ "-Dsonar.login=token",
+ ]
+ }
+ />
+ <p
+ className="big-spacer-top markdown"
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "onboarding.analysis.java.maven.docs",
+ }
+ }
+ />
+ <p
+ className="big-spacer-top markdown"
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "onboarding.analysis.browse_url_after_analysis",
+ }
+ }
+ />
+</div>
+`;
+
+exports[`renders correctly 2`] = `
+<div>
+ <h4
+ className="spacer-bottom"
+ >
+ onboarding.analysis.java.maven.header
+ </h4>
+ <p
+ className="spacer-bottom markdown"
+ >
+ <InstanceMessage
+ message="onboarding.analysis.java.maven.text"
+ />
+ </p>
+ <CodeSnippet
+ snippet={
+ Array [
+ "mvn sonar:sonar",
+ "-Dsonar.organization=organization",
+ "-Dsonar.host.url=host",
+ "-Dsonar.login=token",
+ ]
+ }
+ />
+ <p
+ className="big-spacer-top markdown"
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "onboarding.analysis.java.maven.docs",
+ }
+ }
+ />
+ <p
+ className="big-spacer-top markdown"
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "onboarding.analysis.auto_refresh_after_analysis",
+ }
+ }
+ />
+</div>
+`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+<div>
+ <h4
+ className="spacer-bottom"
+ >
+ onboarding.analysis.msbuild.header
+ </h4>
+ <p
+ className="spacer-bottom markdown"
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "onboarding.analysis.msbuild.text",
+ }
+ }
+ />
+ <p>
+ <a
+ className="button"
+ href="http://redirect.sonarsource.com/doc/install-configure-scanner-msbuild.html"
+ rel="noopener noreferrer"
+ target="_blank"
+ >
+ download_verb
+ </a>
+ </p>
+</div>
+`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+<div>
+ <MSBuildScanner />
+ <BuildWrapper
+ className="huge-spacer-top"
+ os="win"
+ />
+ <h4
+ className="huge-spacer-top spacer-bottom"
+ >
+ onboarding.analysis.msbuild.execute
+ </h4>
+ <InstanceMessage
+ message="onboarding.analysis.msbuild.execute.text"
+ />
+ <CodeSnippet
+ isOneLine={true}
+ snippet={
+ Array [
+ "SonarQube.Scanner.MSBuild.exe begin",
+ "/k:\\"projectKey\\"",
+ undefined,
+ "/d:sonar.cfamily.build-wrapper-output=bw-output",
+ "/d:sonar.host.url=\\"host\\"",
+ "/d:sonar.login=\\"token\\"",
+ ]
+ }
+ />
+ <CodeSnippet
+ snippet="build-wrapper-win-x86-64.exe --out-dir bw-output MsBuild.exe /t:Rebuild"
+ />
+ <CodeSnippet
+ snippet={
+ Array [
+ "SonarQube.Scanner.MSBuild.exe end",
+ "/d:sonar.login=\\"token\\"",
+ ]
+ }
+ />
+ <p
+ className="big-spacer-top markdown"
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "onboarding.analysis.msbuild.docs",
+ }
+ }
+ />
+</div>
+`;
+
+exports[`renders correctly 2`] = `
+<div>
+ <MSBuildScanner />
+ <BuildWrapper
+ className="huge-spacer-top"
+ os="win"
+ />
+ <h4
+ className="huge-spacer-top spacer-bottom"
+ >
+ onboarding.analysis.msbuild.execute
+ </h4>
+ <InstanceMessage
+ message="onboarding.analysis.msbuild.execute.text"
+ />
+ <CodeSnippet
+ isOneLine={true}
+ snippet={
+ Array [
+ "SonarQube.Scanner.MSBuild.exe begin",
+ "/k:\\"projectKey\\"",
+ "/d:sonar.organization=\\"organization\\"",
+ "/d:sonar.cfamily.build-wrapper-output=bw-output",
+ "/d:sonar.host.url=\\"host\\"",
+ "/d:sonar.login=\\"token\\"",
+ ]
+ }
+ />
+ <CodeSnippet
+ isOneLine={true}
+ snippet="build-wrapper-win-x86-64.exe --out-dir bw-output MsBuild.exe /t:Rebuild"
+ />
+ <CodeSnippet
+ isOneLine={true}
+ snippet={
+ Array [
+ "SonarQube.Scanner.MSBuild.exe end",
+ "/d:sonar.login=\\"token\\"",
+ ]
+ }
+ />
+ <p
+ className="big-spacer-top markdown"
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "onboarding.analysis.msbuild.docs",
+ }
+ }
+ />
+</div>
+`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+<div>
+ <SQScanner
+ os="win"
+ />
+ <h4
+ className="huge-spacer-top spacer-bottom"
+ >
+ onboarding.analysis.sq_scanner.execute
+ </h4>
+ <InstanceMessage
+ message="onboarding.analysis.sq_scanner.execute.text"
+ />
+ <CodeSnippet
+ isOneLine={true}
+ snippet={
+ Array [
+ "sonar-scanner.bat",
+ "-Dsonar.projectKey=projectKey",
+ undefined,
+ "-Dsonar.sources=.",
+ "-Dsonar.host.url=host",
+ "-Dsonar.login=token",
+ ]
+ }
+ />
+ <p
+ className="big-spacer-top markdown"
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "onboarding.analysis.sq_scanner.docs",
+ }
+ }
+ />
+</div>
+`;
+
+exports[`renders correctly 2`] = `
+<div>
+ <SQScanner
+ os="linux"
+ />
+ <h4
+ className="huge-spacer-top spacer-bottom"
+ >
+ onboarding.analysis.sq_scanner.execute
+ </h4>
+ <InstanceMessage
+ message="onboarding.analysis.sq_scanner.execute.text"
+ />
+ <CodeSnippet
+ isOneLine={false}
+ snippet={
+ Array [
+ "sonar-scanner",
+ "-Dsonar.projectKey=projectKey",
+ undefined,
+ "-Dsonar.sources=.",
+ "-Dsonar.host.url=host",
+ "-Dsonar.login=token",
+ ]
+ }
+ />
+ <p
+ className="big-spacer-top markdown"
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "onboarding.analysis.sq_scanner.docs",
+ }
+ }
+ />
+</div>
+`;
+
+exports[`renders correctly 3`] = `
+<div>
+ <SQScanner
+ os="linux"
+ />
+ <h4
+ className="huge-spacer-top spacer-bottom"
+ >
+ onboarding.analysis.sq_scanner.execute
+ </h4>
+ <InstanceMessage
+ message="onboarding.analysis.sq_scanner.execute.text"
+ />
+ <CodeSnippet
+ isOneLine={false}
+ snippet={
+ Array [
+ "sonar-scanner",
+ "-Dsonar.projectKey=projectKey",
+ "-Dsonar.organization=organization",
+ "-Dsonar.sources=.",
+ "-Dsonar.host.url=host",
+ "-Dsonar.login=token",
+ ]
+ }
+ />
+ <p
+ className="big-spacer-top markdown"
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "onboarding.analysis.sq_scanner.docs",
+ }
+ }
+ />
+</div>
+`;
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+<div>
+ <h4
+ className="spacer-bottom"
+ >
+ onboarding.analysis.sq_scanner.header.win
+ </h4>
+ <p
+ className="spacer-bottom markdown"
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "onboarding.analysis.sq_scanner.text.win",
+ }
+ }
+ />
+ <p>
+ <a
+ className="button"
+ href="http://redirect.sonarsource.com/doc/install-configure-scanner.html"
+ rel="noopener noreferrer"
+ target="_blank"
+ >
+ download_verb
+ </a>
+ </p>
+</div>
+`;
+
+exports[`renders correctly 2`] = `
+<div>
+ <h4
+ className="spacer-bottom"
+ >
+ onboarding.analysis.sq_scanner.header.linux
+ </h4>
+ <p
+ className="spacer-bottom markdown"
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "onboarding.analysis.sq_scanner.text.linux",
+ }
+ }
+ />
+ <p>
+ <a
+ className="button"
+ href="http://redirect.sonarsource.com/doc/install-configure-scanner.html"
+ rel="noopener noreferrer"
+ target="_blank"
+ >
+ download_verb
+ </a>
+ </p>
+</div>
+`;
+
+exports[`renders correctly 3`] = `
+<div>
+ <h4
+ className="spacer-bottom"
+ >
+ onboarding.analysis.sq_scanner.header.mac
+ </h4>
+ <p
+ className="spacer-bottom markdown"
+ dangerouslySetInnerHTML={
+ Object {
+ "__html": "onboarding.analysis.sq_scanner.text.mac",
+ }
+ }
+ />
+ <p>
+ <a
+ className="button"
+ href="http://redirect.sonarsource.com/doc/install-configure-scanner.html"
+ rel="noopener noreferrer"
+ target="_blank"
+ >
+ download_verb
+ </a>
+ </p>
+</div>
+`;
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import Checkbox from '../../../components/controls/Checkbox';
-import { AlmRepository, IdentityProvider } from '../../../app/types';
-import { getBaseUrl } from '../../../helpers/urls';
-import { translate } from '../../../helpers/l10n';
-import CheckIcon from '../../../components/icons-components/CheckIcon';
-
-interface Props {
- identityProvider: IdentityProvider;
- repository: AlmRepository;
- selected: boolean;
- toggleRepository: (repository: AlmRepository) => void;
-}
-
-export default class AlmRepositoryItem extends React.PureComponent<Props> {
- handleChange = () => {
- this.props.toggleRepository(this.props.repository);
- };
-
- render() {
- const { identityProvider, repository, selected } = this.props;
- const alreadyImported = Boolean(repository.linkedProjectKey);
- return (
- <Checkbox
- checked={selected || alreadyImported}
- disabled={alreadyImported}
- onCheck={this.handleChange}>
- <img
- alt={identityProvider.name}
- className="spacer-left"
- height={14}
- src={getBaseUrl() + identityProvider.iconPath}
- style={{ filter: alreadyImported ? 'invert(50%)' : 'invert(100%)' }}
- width={14}
- />
- <span className="spacer-left">{this.props.repository.label}</span>
- {alreadyImported && (
- <span className="big-spacer-left">
- <CheckIcon className="little-spacer-right" />
- {translate('onboarding.create_project.already_imported')}
- </span>
- )}
- </Checkbox>
- );
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import AlmRepositoryItem from './AlmRepositoryItem';
-import DeferredSpinner from '../../../components/common/DeferredSpinner';
-import IdentityProviderLink from '../../../components/ui/IdentityProviderLink';
-import { getIdentityProviders } from '../../../api/users';
-import { getRepositories, provisionProject } from '../../../api/alm-integration';
-import { IdentityProvider, LoggedInUser, AlmRepository } from '../../../app/types';
-import { ProjectBase } from '../../../api/components';
-import { SubmitButton } from '../../../components/ui/buttons';
-import { translateWithParameters, translate } from '../../../helpers/l10n';
-
-interface Props {
- currentUser: LoggedInUser;
- onProjectCreate: (project: ProjectBase[]) => void;
-}
-
-interface State {
- identityProviders: IdentityProvider[];
- installationUrl?: string;
- installed?: boolean;
- loading: boolean;
- repositories: AlmRepository[];
- selectedRepositories: { [key: string]: AlmRepository | undefined };
- submitting: boolean;
-}
-
-export default class AutoProjectCreate extends React.PureComponent<Props, State> {
- mounted = false;
- state: State = {
- identityProviders: [],
- loading: true,
- repositories: [],
- selectedRepositories: {},
- submitting: false
- };
-
- componentDidMount() {
- this.mounted = true;
- Promise.all([this.fetchIdentityProviders(), this.fetchRepositories()]).then(
- this.stopLoading,
- this.stopLoading
- );
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- fetchIdentityProviders = () => {
- return getIdentityProviders().then(
- ({ identityProviders }) => {
- if (this.mounted) {
- this.setState({ identityProviders });
- }
- },
- () => {
- return Promise.resolve();
- }
- );
- };
-
- fetchRepositories = () => {
- return getRepositories().then(({ almIntegration, repositories }) => {
- if (this.mounted) {
- this.setState({ ...almIntegration, repositories });
- }
- });
- };
-
- handleFormSubmit = (event: React.FormEvent<HTMLFormElement>) => {
- event.preventDefault();
-
- if (this.isValid()) {
- const { selectedRepositories } = this.state;
- this.setState({ submitting: true });
- provisionProject({
- repositories: Object.keys(selectedRepositories).filter(key =>
- Boolean(selectedRepositories[key])
- )
- }).then(
- ({ project }) => this.props.onProjectCreate([project]),
- () => {
- if (this.mounted) {
- this.setState({ submitting: false });
- this.reloadRepositories();
- }
- }
- );
- }
- };
-
- isValid = () => {
- return this.state.repositories.some(repo =>
- Boolean(this.state.selectedRepositories[repo.installationKey])
- );
- };
-
- reloadRepositories = () => {
- this.setState({ loading: true });
- this.fetchRepositories().then(this.stopLoading, this.stopLoading);
- };
-
- stopLoading = () => {
- if (this.mounted) {
- this.setState({ loading: false });
- }
- };
-
- toggleRepository = (repository: AlmRepository) => {
- this.setState(({ selectedRepositories }) => ({
- selectedRepositories: {
- ...selectedRepositories,
- [repository.installationKey]: selectedRepositories[repository.installationKey]
- ? undefined
- : repository
- }
- }));
- };
-
- render() {
- if (this.state.loading) {
- return <DeferredSpinner />;
- }
-
- const { currentUser } = this.props;
- const identityProvider = this.state.identityProviders.find(
- identityProvider => identityProvider.key === currentUser.externalProvider
- );
-
- if (!identityProvider) {
- return null;
- }
-
- const { selectedRepositories, submitting } = this.state;
-
- return (
- <>
- <p className="alert alert-info width-60 big-spacer-bottom">
- {translateWithParameters(
- 'onboarding.create_project.beta_feature_x',
- identityProvider.name
- )}
- </p>
- {this.state.installed ? (
- <form onSubmit={this.handleFormSubmit}>
- <ul>
- {this.state.repositories.map(repo => (
- <li className="big-spacer-bottom" key={repo.installationKey}>
- <AlmRepositoryItem
- identityProvider={identityProvider}
- repository={repo}
- selected={Boolean(selectedRepositories[repo.installationKey])}
- toggleRepository={this.toggleRepository}
- />
- </li>
- ))}
- </ul>
- <SubmitButton disabled={!this.isValid() || submitting}>
- {translate('onboarding.create_project.create_project')}
- </SubmitButton>
- <DeferredSpinner className="spacer-left" loading={submitting} />
- </form>
- ) : (
- <div>
- <p className="spacer-bottom">
- {translateWithParameters(
- 'onboarding.create_project.install_app_x',
- identityProvider.name
- )}
- </p>
- <IdentityProviderLink
- className="display-inline-block"
- identityProvider={identityProvider}
- small={true}
- url={this.state.installationUrl}>
- {translateWithParameters(
- 'onboarding.create_project.install_app_x.button',
- identityProvider.name
- )}
- </IdentityProviderLink>
- </div>
- )}
- </>
- );
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import * as classNames from 'classnames';
-import * as PropTypes from 'prop-types';
-import { connect } from 'react-redux';
-import Helmet from 'react-helmet';
-import AutoProjectCreate from './AutoProjectCreate';
-import ManualProjectCreate from './ManualProjectCreate';
-import handleRequiredAuthentication from '../../../app/utils/handleRequiredAuthentication';
-import { getCurrentUser } from '../../../store/rootReducer';
-import { skipOnboarding } from '../../../store/users/actions';
-import { CurrentUser, isLoggedIn } from '../../../app/types';
-import { translate } from '../../../helpers/l10n';
-import { ProjectBase } from '../../../api/components';
-import { getProjectUrl, getOrganizationUrl } from '../../../helpers/urls';
-import '../../../app/styles/sonarcloud.css';
-import '../styles.css';
-
-interface OwnProps {
- onFinishOnboarding: () => void;
-}
-
-interface StateProps {
- currentUser: CurrentUser;
-}
-
-interface DispatchProps {
- skipOnboarding: () => void;
-}
-
-enum Tabs {
- AUTO,
- MANUAL
-}
-
-type Props = OwnProps & StateProps & DispatchProps;
-
-interface State {
- activeTab: Tabs;
-}
-
-export class CreateProjectOnboarding extends React.PureComponent<Props, State> {
- mounted = false;
- static contextTypes = {
- router: PropTypes.object
- };
-
- constructor(props: Props) {
- super(props);
- this.state = { activeTab: this.shouldDisplayTabs(props) ? Tabs.AUTO : Tabs.MANUAL };
- }
-
- componentDidMount() {
- this.mounted = true;
- if (!isLoggedIn(this.props.currentUser)) {
- handleRequiredAuthentication();
- }
- document.body.classList.add('white-page');
- document.documentElement.classList.add('white-page');
- }
-
- componentWillUnmount() {
- this.mounted = false;
- document.body.classList.remove('white-page');
- document.documentElement.classList.remove('white-page');
- }
-
- handleProjectCreate = (projects: Pick<ProjectBase, 'key'>[], organization?: string) => {
- if (projects.length > 1 && organization) {
- this.context.router.push(getOrganizationUrl(organization) + '/projects');
- } else if (projects.length === 1) {
- this.context.router.push(getProjectUrl(projects[0].key));
- }
- };
-
- shouldDisplayTabs = ({ currentUser } = this.props) => {
- return (
- isLoggedIn(currentUser) &&
- ['bitbucket', 'github'].includes(currentUser.externalProvider || '')
- );
- };
-
- showAuto = (event: React.MouseEvent<HTMLAnchorElement>) => {
- event.preventDefault();
- this.setState({ activeTab: Tabs.AUTO });
- };
-
- showManual = (event: React.MouseEvent<HTMLAnchorElement>) => {
- event.preventDefault();
- this.setState({ activeTab: Tabs.MANUAL });
- };
-
- render() {
- const { currentUser } = this.props;
- if (!isLoggedIn(currentUser)) {
- return null;
- }
-
- const { activeTab } = this.state;
- const header = translate('onboarding.create_project.header');
- return (
- <>
- <Helmet title={header} titleTemplate="%s" />
- <div className="sonarcloud page page-limited">
- <div className="page-header">
- <h1 className="page-title">{header}</h1>
- </div>
-
- {this.shouldDisplayTabs() && (
- <ul className="flex-tabs">
- <li>
- <a
- className={classNames('js-auto', { selected: activeTab === Tabs.AUTO })}
- href="#"
- onClick={this.showAuto}>
- {translate('onboarding.create_project.select_repositories')}
- <span
- className={classNames(
- 'rounded alert alert-small spacer-left display-inline-block',
- {
- 'alert-info': activeTab === Tabs.AUTO,
- 'alert-muted': activeTab !== Tabs.AUTO
- }
- )}>
- {translate('beta')}
- </span>
- </a>
- </li>
- <li>
- <a
- className={classNames('js-manual', { selected: activeTab === Tabs.MANUAL })}
- href="#"
- onClick={this.showManual}>
- {translate('onboarding.create_project.create_manually')}
- </a>
- </li>
- </ul>
- )}
-
- {activeTab === Tabs.AUTO ? (
- <AutoProjectCreate
- currentUser={currentUser}
- onProjectCreate={this.handleProjectCreate}
- />
- ) : (
- <ManualProjectCreate
- currentUser={currentUser}
- onProjectCreate={this.handleProjectCreate}
- />
- )}
- </div>
- </>
- );
- }
-}
-
-const mapStateToProps = (state: any): StateProps => {
- return {
- currentUser: getCurrentUser(state)
- };
-};
-
-const mapDispatchToProps: DispatchProps = { skipOnboarding };
-
-export default connect<StateProps, DispatchProps, OwnProps>(mapStateToProps, mapDispatchToProps)(
- CreateProjectOnboarding
-);
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { sortBy } from 'lodash';
-import { connect } from 'react-redux';
-import CreateOrganizationForm from '../../account/organizations/CreateOrganizationForm';
-import Select from '../../../components/controls/Select';
-import { Button, SubmitButton } from '../../../components/ui/buttons';
-import { LoggedInUser, Organization } from '../../../app/types';
-import { fetchMyOrganizations } from '../../account/organizations/actions';
-import { getMyOrganizations } from '../../../store/rootReducer';
-import { translate } from '../../../helpers/l10n';
-import { createProject, ProjectBase } from '../../../api/components';
-import DeferredSpinner from '../../../components/common/DeferredSpinner';
-
-interface StateProps {
- userOrganizations: Organization[];
-}
-
-interface DispatchProps {
- fetchMyOrganizations: () => Promise<void>;
-}
-
-interface OwnProps {
- currentUser: LoggedInUser;
- onProjectCreate: (project: ProjectBase[]) => void;
-}
-
-type Props = OwnProps & StateProps & DispatchProps;
-
-interface State {
- createOrganizationModal: boolean;
- projectName: string;
- projectKey: string;
- selectedOrganization: string;
- submitting: boolean;
-}
-
-export class ManualProjectCreate extends React.PureComponent<Props, State> {
- mounted = false;
-
- constructor(props: Props) {
- super(props);
- this.state = {
- createOrganizationModal: false,
- projectName: '',
- projectKey: '',
- selectedOrganization:
- props.userOrganizations.length <= 1 ? props.userOrganizations[0].key : '',
- submitting: false
- };
- }
-
- componentDidMount() {
- this.mounted = true;
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- closeCreateOrganization = () => {
- this.setState({ createOrganizationModal: false });
- };
-
- handleFormSubmit = (event: React.FormEvent<HTMLFormElement>) => {
- event.preventDefault();
-
- if (this.isValid()) {
- const { projectKey, projectName, selectedOrganization } = this.state;
- this.setState({ submitting: true });
- createProject({
- project: projectKey,
- name: projectName,
- organization: selectedOrganization
- }).then(
- ({ project }) => this.props.onProjectCreate([project]),
- () => {
- if (this.mounted) {
- this.setState({ submitting: false });
- }
- }
- );
- }
- };
-
- handleOrganizationSelect = ({ value }: { value: string }) => {
- this.setState({ selectedOrganization: value });
- };
-
- handleProjectNameChange = (event: React.ChangeEvent<HTMLInputElement>) => {
- this.setState({ projectName: event.currentTarget.value });
- };
-
- handleProjectKeyChange = (event: React.ChangeEvent<HTMLInputElement>) => {
- this.setState({ projectKey: event.currentTarget.value });
- };
-
- isValid = () => {
- const { projectKey, projectName, selectedOrganization } = this.state;
- return Boolean(projectKey && projectName && selectedOrganization);
- };
-
- onCreateOrganization = (organization: { key: string }) => {
- this.props.fetchMyOrganizations().then(
- () => {
- this.handleOrganizationSelect({ value: organization.key });
- this.closeCreateOrganization();
- },
- () => {
- this.closeCreateOrganization();
- }
- );
- };
-
- showCreateOrganization = () => {
- this.setState({ createOrganizationModal: true });
- };
-
- render() {
- const { submitting } = this.state;
- return (
- <>
- <form onSubmit={this.handleFormSubmit}>
- <div className="form-field">
- <label htmlFor="select-organization">
- {translate('onboarding.create_project.organization')}
- <em className="mandatory">*</em>
- </label>
- <Select
- autoFocus={true}
- className="input-super-large"
- clearable={false}
- id="select-organization"
- onChange={this.handleOrganizationSelect}
- options={sortBy(this.props.userOrganizations, o => o.name.toLowerCase()).map(
- organization => ({
- label: organization.name,
- value: organization.key
- })
- )}
- required={true}
- value={this.state.selectedOrganization}
- />
- <Button
- className="button-link big-spacer-left js-new-org"
- onClick={this.showCreateOrganization}>
- {translate('onboarding.create_project.create_new_org')}
- </Button>
- </div>
- <div className="form-field">
- <label htmlFor="project-name">
- {translate('onboarding.create_project.project_name')}
- <em className="mandatory">*</em>
- </label>
- <input
- className="input-super-large"
- id="project-name"
- maxLength={400}
- minLength={1}
- onChange={this.handleProjectNameChange}
- required={true}
- type="text"
- value={this.state.projectName}
- />
- </div>
- <div className="form-field">
- <label htmlFor="project-key">
- {translate('onboarding.create_project.project_key')}
- <em className="mandatory">*</em>
- </label>
- <input
- className="input-super-large"
- id="project-key"
- maxLength={400}
- minLength={1}
- onChange={this.handleProjectKeyChange}
- required={true}
- type="text"
- value={this.state.projectKey}
- />
- </div>
- <SubmitButton disabled={!this.isValid() || submitting}>
- {translate('onboarding.create_project.create_project')}
- </SubmitButton>
- <DeferredSpinner className="spacer-left" loading={submitting} />
- </form>
- {this.state.createOrganizationModal && (
- <CreateOrganizationForm
- onClose={this.closeCreateOrganization}
- onCreate={this.onCreateOrganization}
- />
- )}
- </>
- );
- }
-}
-
-const mapDispatchToProps = ({
- fetchMyOrganizations
-} as any) as DispatchProps;
-
-const mapStateToProps = (state: any): StateProps => {
- return {
- userOrganizations: getMyOrganizations(state)
- };
-};
-export default connect<StateProps, DispatchProps, OwnProps>(mapStateToProps, mapDispatchToProps)(
- ManualProjectCreate
-);
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { shallow } from 'enzyme';
-import AlmRepositoryItem from '../AlmRepositoryItem';
-
-const identityProviders = {
- backgroundColor: 'blue',
- iconPath: 'icon/path',
- key: 'foo',
- name: 'Foo Provider'
-};
-
-const repositories = [
- {
- label: 'Cool Project',
- installationKey: 'github/cool',
- linkedProjectKey: 'proj_cool',
- linkedProjectName: 'Proj Cool'
- },
- {
- label: 'Awesome Project',
- installationKey: 'github/awesome'
- }
-];
-
-it('should render correctly', () => {
- expect(getWrapper()).toMatchSnapshot();
-});
-
-it('should render selected', () => {
- expect(getWrapper({ selected: true })).toMatchSnapshot();
-});
-
-it('should render disabled', () => {
- expect(getWrapper({ repository: repositories[0] })).toMatchSnapshot();
-});
-
-function getWrapper(props = {}) {
- return shallow(
- <AlmRepositoryItem
- identityProvider={identityProviders}
- repository={repositories[1]}
- selected={false}
- toggleRepository={jest.fn()}
- {...props}
- />
- );
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { shallow } from 'enzyme';
-import AutoProjectCreate from '../AutoProjectCreate';
-import { getIdentityProviders } from '../../../../api/users';
-import { getRepositories } from '../../../../api/alm-integration';
-import { LoggedInUser } from '../../../../app/types';
-import { waitAndUpdate } from '../../../../helpers/testUtils';
-
-jest.mock('../../../../api/users', () => ({
- getIdentityProviders: jest.fn().mockResolvedValue({
- identityProviders: [
- {
- backgroundColor: 'blue',
- iconPath: 'icon/path',
- key: 'foo',
- name: 'Foo Provider'
- }
- ]
- })
-}));
-
-jest.mock('../../../../api/alm-integration', () => ({
- getRepositories: jest.fn().mockResolvedValue({
- almIntegration: {
- installationUrl: 'https://alm.foo.com/install',
- installed: false
- },
- repositories: []
- }),
- provisionProject: jest.fn().mockResolvedValue({ projects: [] })
-}));
-
-const user: LoggedInUser = { isLoggedIn: true, login: 'foo', name: 'Foo', externalProvider: 'foo' };
-const repositories = [
- {
- label: 'Cool Project',
- installationKey: 'github/cool',
- linkedProjectKey: 'proj_cool',
- linkedProjectName: 'Proj Cool'
- },
- {
- label: 'Awesome Project',
- installationKey: 'github/awesome'
- }
-];
-
-beforeEach(() => {
- (getIdentityProviders as jest.Mock<any>).mockClear();
- (getRepositories as jest.Mock<any>).mockClear();
-});
-
-it('should display the provider app install button', async () => {
- const wrapper = getWrapper();
- expect(wrapper).toMatchSnapshot();
- expect(getIdentityProviders).toHaveBeenCalled();
- expect(getRepositories).toHaveBeenCalled();
-
- await waitAndUpdate(wrapper);
- expect(wrapper).toMatchSnapshot();
-});
-
-it('should display the list of repositories', async () => {
- (getRepositories as jest.Mock<any>).mockResolvedValue({
- almIntegration: {
- installationUrl: 'https://alm.foo.com/install',
- installed: true
- },
- repositories
- });
- const wrapper = getWrapper();
- await waitAndUpdate(wrapper);
- expect(wrapper).toMatchSnapshot();
-});
-
-function getWrapper(props = {}) {
- return shallow(<AutoProjectCreate currentUser={user} onProjectCreate={jest.fn()} {...props} />);
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { shallow } from 'enzyme';
-import { CreateProjectOnboarding } from '../CreateProjectOnboarding';
-import { LoggedInUser } from '../../../../app/types';
-import { click } from '../../../../helpers/testUtils';
-
-const user: LoggedInUser = {
- externalProvider: 'github',
- isLoggedIn: true,
- login: 'foo',
- name: 'Foo'
-};
-
-it('should render correctly', () => {
- expect(getWrapper()).toMatchSnapshot();
-});
-
-it('should render with Manual creation only', () => {
- expect(getWrapper({ currentUser: { ...user, externalProvider: 'vsts' } })).toMatchSnapshot();
-});
-
-it('should switch tabs', () => {
- const wrapper = getWrapper();
- click(wrapper.find('.js-manual'));
- expect(wrapper.find('Connect(ManualProjectCreate)').exists()).toBeTruthy();
- click(wrapper.find('.js-auto'));
- expect(wrapper.find('AutoProjectCreate').exists()).toBeTruthy();
-});
-
-function getWrapper(props = {}) {
- return shallow(
- <CreateProjectOnboarding
- currentUser={user}
- onFinishOnboarding={jest.fn()}
- skipOnboarding={jest.fn()}
- {...props}
- />
- );
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { shallow } from 'enzyme';
-import { ManualProjectCreate } from '../ManualProjectCreate';
-import { change, click, submit, waitAndUpdate } from '../../../../helpers/testUtils';
-import { createProject } from '../../../../api/components';
-
-jest.mock('../../../../api/components', () => ({
- createProject: jest.fn().mockResolvedValue({ project: { key: 'bar', name: 'Bar' } })
-}));
-
-beforeEach(() => {
- (createProject as jest.Mock<any>).mockClear();
-});
-
-it('should render correctly', () => {
- expect(getWrapper()).toMatchSnapshot();
-});
-
-it('should allow to create a new org', async () => {
- const fetchMyOrganizations = jest.fn().mockResolvedValueOnce([]);
- const wrapper = getWrapper({ fetchMyOrganizations });
-
- click(wrapper.find('.js-new-org'));
- const createForm = wrapper.find('Connect(CreateOrganizationForm)');
- expect(createForm.exists()).toBeTruthy();
-
- createForm.prop<Function>('onCreate')({ key: 'baz' });
- expect(fetchMyOrganizations).toHaveBeenCalled();
- await waitAndUpdate(wrapper);
- expect(wrapper.state('selectedOrganization')).toBe('baz');
-});
-
-it('should correctly create a project', async () => {
- const onProjectCreate = jest.fn();
- const wrapper = getWrapper({ onProjectCreate });
- wrapper.find('Select').prop<Function>('onChange')({ value: 'foo' });
- change(wrapper.find('#project-name'), 'Bar');
- expect(wrapper.find('SubmitButton')).toMatchSnapshot();
-
- change(wrapper.find('#project-key'), 'bar');
- expect(wrapper.find('SubmitButton')).toMatchSnapshot();
-
- submit(wrapper.find('form'));
- expect(createProject).toBeCalledWith({ project: 'bar', name: 'Bar', organization: 'foo' });
-
- await waitAndUpdate(wrapper);
- expect(onProjectCreate).toBeCalledWith([{ key: 'bar', name: 'Bar' }]);
-});
-
-function getWrapper(props = {}) {
- return shallow(
- <ManualProjectCreate
- currentUser={{ isLoggedIn: true, login: 'foo', name: 'Foo' }}
- fetchMyOrganizations={jest.fn()}
- onProjectCreate={jest.fn()}
- userOrganizations={[{ key: 'foo', name: 'Foo' }, { key: 'bar', name: 'Bar' }]}
- {...props}
- />
- );
-}
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<Checkbox
- checked={false}
- disabled={false}
- onCheck={[Function]}
- thirdState={false}
->
- <img
- alt="Foo Provider"
- className="spacer-left"
- height={14}
- src="icon/path"
- style={
- Object {
- "filter": "invert(100%)",
- }
- }
- width={14}
- />
- <span
- className="spacer-left"
- >
- Awesome Project
- </span>
-</Checkbox>
-`;
-
-exports[`should render disabled 1`] = `
-<Checkbox
- checked={true}
- disabled={true}
- onCheck={[Function]}
- thirdState={false}
->
- <img
- alt="Foo Provider"
- className="spacer-left"
- height={14}
- src="icon/path"
- style={
- Object {
- "filter": "invert(50%)",
- }
- }
- width={14}
- />
- <span
- className="spacer-left"
- >
- Cool Project
- </span>
- <span
- className="big-spacer-left"
- >
- <CheckIcon
- className="little-spacer-right"
- />
- onboarding.create_project.already_imported
- </span>
-</Checkbox>
-`;
-
-exports[`should render selected 1`] = `
-<Checkbox
- checked={true}
- disabled={false}
- onCheck={[Function]}
- thirdState={false}
->
- <img
- alt="Foo Provider"
- className="spacer-left"
- height={14}
- src="icon/path"
- style={
- Object {
- "filter": "invert(100%)",
- }
- }
- width={14}
- />
- <span
- className="spacer-left"
- >
- Awesome Project
- </span>
-</Checkbox>
-`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should display the list of repositories 1`] = `
-<React.Fragment>
- <p
- className="alert alert-info width-60 big-spacer-bottom"
- >
- onboarding.create_project.beta_feature_x.Foo Provider
- </p>
- <form
- onSubmit={[Function]}
- >
- <ul>
- <li
- className="big-spacer-bottom"
- key="github/cool"
- >
- <AlmRepositoryItem
- identityProvider={
- Object {
- "backgroundColor": "blue",
- "iconPath": "icon/path",
- "key": "foo",
- "name": "Foo Provider",
- }
- }
- repository={
- Object {
- "installationKey": "github/cool",
- "label": "Cool Project",
- "linkedProjectKey": "proj_cool",
- "linkedProjectName": "Proj Cool",
- }
- }
- selected={false}
- toggleRepository={[Function]}
- />
- </li>
- <li
- className="big-spacer-bottom"
- key="github/awesome"
- >
- <AlmRepositoryItem
- identityProvider={
- Object {
- "backgroundColor": "blue",
- "iconPath": "icon/path",
- "key": "foo",
- "name": "Foo Provider",
- }
- }
- repository={
- Object {
- "installationKey": "github/awesome",
- "label": "Awesome Project",
- }
- }
- selected={false}
- toggleRepository={[Function]}
- />
- </li>
- </ul>
- <SubmitButton
- disabled={true}
- >
- onboarding.create_project.create_project
- </SubmitButton>
- <DeferredSpinner
- className="spacer-left"
- loading={false}
- timeout={100}
- />
- </form>
-</React.Fragment>
-`;
-
-exports[`should display the provider app install button 1`] = `
-<DeferredSpinner
- timeout={100}
-/>
-`;
-
-exports[`should display the provider app install button 2`] = `
-<React.Fragment>
- <p
- className="alert alert-info width-60 big-spacer-bottom"
- >
- onboarding.create_project.beta_feature_x.Foo Provider
- </p>
- <div>
- <p
- className="spacer-bottom"
- >
- onboarding.create_project.install_app_x.Foo Provider
- </p>
- <IdentityProviderLink
- className="display-inline-block"
- identityProvider={
- Object {
- "backgroundColor": "blue",
- "iconPath": "icon/path",
- "key": "foo",
- "name": "Foo Provider",
- }
- }
- small={true}
- url="https://alm.foo.com/install"
- >
- onboarding.create_project.install_app_x.button.Foo Provider
- </IdentityProviderLink>
- </div>
-</React.Fragment>
-`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly 1`] = `
-<React.Fragment>
- <HelmetWrapper
- defer={true}
- encodeSpecialCharacters={true}
- title="onboarding.create_project.header"
- titleTemplate="%s"
- />
- <div
- className="sonarcloud page page-limited"
- >
- <div
- className="page-header"
- >
- <h1
- className="page-title"
- >
- onboarding.create_project.header
- </h1>
- </div>
- <ul
- className="flex-tabs"
- >
- <li>
- <a
- className="js-auto selected"
- href="#"
- onClick={[Function]}
- >
- onboarding.create_project.select_repositories
- <span
- className="rounded alert alert-small spacer-left display-inline-block alert-info"
- >
- beta
- </span>
- </a>
- </li>
- <li>
- <a
- className="js-manual"
- href="#"
- onClick={[Function]}
- >
- onboarding.create_project.create_manually
- </a>
- </li>
- </ul>
- <AutoProjectCreate
- currentUser={
- Object {
- "externalProvider": "github",
- "isLoggedIn": true,
- "login": "foo",
- "name": "Foo",
- }
- }
- onProjectCreate={[Function]}
- />
- </div>
-</React.Fragment>
-`;
-
-exports[`should render with Manual creation only 1`] = `
-<React.Fragment>
- <HelmetWrapper
- defer={true}
- encodeSpecialCharacters={true}
- title="onboarding.create_project.header"
- titleTemplate="%s"
- />
- <div
- className="sonarcloud page page-limited"
- >
- <div
- className="page-header"
- >
- <h1
- className="page-title"
- >
- onboarding.create_project.header
- </h1>
- </div>
- <Connect(ManualProjectCreate)
- currentUser={
- Object {
- "externalProvider": "vsts",
- "isLoggedIn": true,
- "login": "foo",
- "name": "Foo",
- }
- }
- onProjectCreate={[Function]}
- />
- </div>
-</React.Fragment>
-`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should correctly create a project 1`] = `
-<SubmitButton
- disabled={true}
->
- onboarding.create_project.create_project
-</SubmitButton>
-`;
-
-exports[`should correctly create a project 2`] = `
-<SubmitButton
- disabled={false}
->
- onboarding.create_project.create_project
-</SubmitButton>
-`;
-
-exports[`should render correctly 1`] = `
-<React.Fragment>
- <form
- onSubmit={[Function]}
- >
- <div
- className="form-field"
- >
- <label
- htmlFor="select-organization"
- >
- onboarding.create_project.organization
- <em
- className="mandatory"
- >
- *
- </em>
- </label>
- <Select
- autoFocus={true}
- className="input-super-large"
- clearable={false}
- id="select-organization"
- onChange={[Function]}
- options={
- Array [
- Object {
- "label": "Bar",
- "value": "bar",
- },
- Object {
- "label": "Foo",
- "value": "foo",
- },
- ]
- }
- required={true}
- value=""
- />
- <Button
- className="button-link big-spacer-left js-new-org"
- onClick={[Function]}
- >
- onboarding.create_project.create_new_org
- </Button>
- </div>
- <div
- className="form-field"
- >
- <label
- htmlFor="project-name"
- >
- onboarding.create_project.project_name
- <em
- className="mandatory"
- >
- *
- </em>
- </label>
- <input
- className="input-super-large"
- id="project-name"
- maxLength={400}
- minLength={1}
- onChange={[Function]}
- required={true}
- type="text"
- value=""
- />
- </div>
- <div
- className="form-field"
- >
- <label
- htmlFor="project-key"
- >
- onboarding.create_project.project_key
- <em
- className="mandatory"
- >
- *
- </em>
- </label>
- <input
- className="input-super-large"
- id="project-key"
- maxLength={400}
- minLength={1}
- onChange={[Function]}
- required={true}
- type="text"
- value=""
- />
- </div>
- <SubmitButton
- disabled={true}
- >
- onboarding.create_project.create_project
- </SubmitButton>
- <DeferredSpinner
- className="spacer-left"
- loading={false}
- timeout={100}
- />
- </form>
-</React.Fragment>
-`;
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { connect } from 'react-redux';
+import handleRequiredAuthentication from '../../../app/utils/handleRequiredAuthentication';
+import Modal from '../../../components/controls/Modal';
+import OnboardingPrivateIcon from '../../../components/icons-components/OnboardingPrivateIcon';
+import OnboardingProjectIcon from '../../../components/icons-components/OnboardingProjectIcon';
+import OnboardingTeamIcon from '../../../components/icons-components/OnboardingTeamIcon';
+import { Button, ResetButtonLink } from '../../../components/ui/buttons';
+import { translate } from '../../../helpers/l10n';
+import { CurrentUser, isLoggedIn } from '../../../app/types';
+import { getCurrentUser } from '../../../store/rootReducer';
+import '../styles.css';
+
+interface OwnProps {
+ onClose: () => void;
+ onOpenOrganizationOnboarding: () => void;
+ onOpenProjectOnboarding: () => void;
+ onOpenTeamOnboarding: () => void;
+}
+
+interface StateProps {
+ currentUser: CurrentUser;
+}
+
+type Props = OwnProps & StateProps;
+
+export class OnboardingModal extends React.PureComponent<Props> {
+ componentDidMount() {
+ if (!isLoggedIn(this.props.currentUser)) {
+ handleRequiredAuthentication();
+ }
+ }
+
+ render() {
+ if (!isLoggedIn(this.props.currentUser)) {
+ return null;
+ }
+
+ const header = translate('onboarding.header');
+ return (
+ <Modal
+ contentLabel={header}
+ medium={true}
+ onRequestClose={this.props.onClose}
+ shouldCloseOnOverlayClick={false}>
+ <div className="modal-simple-head text-center">
+ <h1>{translate('onboarding.header')}</h1>
+ <p className="spacer-top">{translate('onboarding.header.description')}</p>
+ </div>
+ <div className="modal-simple-body text-center onboarding-choices">
+ <Button className="onboarding-choice" onClick={this.props.onOpenProjectOnboarding}>
+ <OnboardingProjectIcon />
+ <span>{translate('onboarding.analyze_public_code')}</span>
+ <p className="note">{translate('onboarding.analyze_public_code.note')}</p>
+ </Button>
+ <Button className="onboarding-choice" onClick={this.props.onOpenOrganizationOnboarding}>
+ <OnboardingPrivateIcon />
+ <span>{translate('onboarding.analyze_private_code')}</span>
+ <p className="note">{translate('onboarding.analyze_private_code.note')}</p>
+ </Button>
+ <Button className="onboarding-choice" onClick={this.props.onOpenTeamOnboarding}>
+ <OnboardingTeamIcon />
+ <span>{translate('onboarding.contribute_existing_project')}</span>
+ <p className="note">{translate('onboarding.contribute_existing_project.note')}</p>
+ </Button>
+ </div>
+ <div className="modal-simple-footer text-center">
+ <ResetButtonLink className="spacer-bottom" onClick={this.props.onClose}>
+ {translate('not_now')}
+ </ResetButtonLink>
+ <p className="note">{translate('onboarding.footer')}</p>
+ </div>
+ </Modal>
+ );
+ }
+}
+
+const mapStateToProps = (state: any): StateProps => ({ currentUser: getCurrentUser(state) });
+
+export default connect<StateProps, {}, OwnProps>(mapStateToProps)(OnboardingModal);
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import * as PropTypes from 'prop-types';
+import { connect } from 'react-redux';
+import OnboardingModal from './OnboardingModal';
+import { skipOnboarding } from '../../../api/users';
+import { skipOnboarding as skipOnboardingAction } from '../../../store/users/actions';
+import CreateOrganizationForm from '../../account/organizations/CreateOrganizationForm';
+import TeamOnboardingModal from '../teamOnboarding/TeamOnboardingModal';
+import { Organization } from '../../../app/types';
+
+interface DispatchProps {
+ skipOnboardingAction: () => void;
+}
+
+enum ModalKey {
+ onboarding,
+ organizationOnboarding,
+ teamOnboarding
+}
+
+interface State {
+ modal?: ModalKey;
+}
+
+export class OnboardingPage extends React.PureComponent<DispatchProps, State> {
+ static contextTypes = {
+ openProjectOnboarding: PropTypes.func.isRequired,
+ router: PropTypes.object.isRequired
+ };
+
+ state: State = { modal: ModalKey.onboarding };
+
+ closeOnboarding = () => {
+ skipOnboarding();
+ this.props.skipOnboardingAction();
+ this.context.router.replace('/');
+ };
+
+ closeOrganizationOnboarding = ({ key }: Pick<Organization, 'key'>) => {
+ this.closeOnboarding();
+ this.context.router.push(`/organizations/${key}`);
+ };
+
+ openOrganizationOnboarding = () => {
+ this.setState({ modal: ModalKey.organizationOnboarding });
+ };
+
+ openTeamOnboarding = () => {
+ this.setState({ modal: ModalKey.teamOnboarding });
+ };
+
+ render() {
+ const { modal } = this.state;
+ return (
+ <>
+ {modal === ModalKey.onboarding && (
+ <OnboardingModal
+ onClose={this.closeOnboarding}
+ onOpenOrganizationOnboarding={this.openOrganizationOnboarding}
+ onOpenProjectOnboarding={this.context.openProjectOnboarding}
+ onOpenTeamOnboarding={this.openTeamOnboarding}
+ />
+ )}
+ {modal === ModalKey.organizationOnboarding && (
+ <CreateOrganizationForm
+ onClose={this.closeOnboarding}
+ onCreate={this.closeOrganizationOnboarding}
+ />
+ )}
+ {modal === ModalKey.teamOnboarding && (
+ <TeamOnboardingModal onFinish={this.closeOnboarding} />
+ )}
+ </>
+ );
+ }
+}
+
+const mapDispatchToProps: DispatchProps = { skipOnboardingAction };
+
+export default connect<{}, DispatchProps>(null, mapDispatchToProps)(OnboardingPage);
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import { OnboardingModal } from '../OnboardingModal';
+import { click } from '../../../../helpers/testUtils';
+
+it('renders correctly', () => {
+ expect(
+ shallow(
+ <OnboardingModal
+ currentUser={{ isLoggedIn: true }}
+ onClose={jest.fn()}
+ onOpenOrganizationOnboarding={jest.fn()}
+ onOpenProjectOnboarding={jest.fn()}
+ onOpenTeamOnboarding={jest.fn()}
+ />
+ )
+ ).toMatchSnapshot();
+});
+
+it('should correctly open the different tutorials', () => {
+ const onClose = jest.fn();
+ const onOpenOrganizationOnboarding = jest.fn();
+ const onOpenProjectOnboarding = jest.fn();
+ const onOpenTeamOnboarding = jest.fn();
+ const push = jest.fn();
+ const wrapper = shallow(
+ <OnboardingModal
+ currentUser={{ isLoggedIn: true }}
+ onClose={onClose}
+ onOpenOrganizationOnboarding={onOpenOrganizationOnboarding}
+ onOpenProjectOnboarding={onOpenProjectOnboarding}
+ onOpenTeamOnboarding={onOpenTeamOnboarding}
+ />,
+ { context: { router: { push } } }
+ );
+
+ click(wrapper.find('ResetButtonLink'));
+ expect(onClose).toHaveBeenCalled();
+
+ wrapper.find('Button').forEach(button => click(button));
+ expect(onOpenOrganizationOnboarding).toHaveBeenCalled();
+ expect(onOpenProjectOnboarding).toHaveBeenCalled();
+ expect(onOpenTeamOnboarding).toHaveBeenCalled();
+});
--- /dev/null
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+<Modal
+ contentLabel="onboarding.header"
+ medium={true}
+ onRequestClose={[MockFunction]}
+ shouldCloseOnOverlayClick={false}
+>
+ <div
+ className="modal-simple-head text-center"
+ >
+ <h1>
+ onboarding.header
+ </h1>
+ <p
+ className="spacer-top"
+ >
+ onboarding.header.description
+ </p>
+ </div>
+ <div
+ className="modal-simple-body text-center onboarding-choices"
+ >
+ <Button
+ className="onboarding-choice"
+ onClick={[MockFunction]}
+ >
+ <OnboardingProjectIcon />
+ <span>
+ onboarding.analyze_public_code
+ </span>
+ <p
+ className="note"
+ >
+ onboarding.analyze_public_code.note
+ </p>
+ </Button>
+ <Button
+ className="onboarding-choice"
+ onClick={[MockFunction]}
+ >
+ <OnboardingPrivateIcon />
+ <span>
+ onboarding.analyze_private_code
+ </span>
+ <p
+ className="note"
+ >
+ onboarding.analyze_private_code.note
+ </p>
+ </Button>
+ <Button
+ className="onboarding-choice"
+ onClick={[MockFunction]}
+ >
+ <OnboardingTeamIcon />
+ <span>
+ onboarding.contribute_existing_project
+ </span>
+ <p
+ className="note"
+ >
+ onboarding.contribute_existing_project.note
+ </p>
+ </Button>
+ </div>
+ <div
+ className="modal-simple-footer text-center"
+ >
+ <ResetButtonLink
+ className="spacer-bottom"
+ onClick={[MockFunction]}
+ >
+ not_now
+ </ResetButtonLink>
+ <p
+ className="note"
+ >
+ onboarding.footer
+ </p>
+ </div>
+</Modal>
+`;
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import Step from './Step';
-import LanguageStep, { Result } from './LanguageStep';
-import JavaMaven from './commands/JavaMaven';
-import JavaGradle from './commands/JavaGradle';
-import DotNet from './commands/DotNet';
-import Msvc from './commands/Msvc';
-import ClangGCC from './commands/ClangGCC';
-import Other from './commands/Other';
-import { translate } from '../../../helpers/l10n';
-import { getHostUrl } from '../../../helpers/urls';
-
-interface Props {
- onFinish: (projectKey?: string) => void;
- onReset: () => void;
- open: boolean;
- organization?: string;
- stepNumber: number;
- token?: string;
-}
-
-interface State {
- result?: Result;
-}
-
-export default class AnalysisStep extends React.PureComponent<Props, State> {
- state: State = {};
-
- handleLanguageSelect = (result?: Result) => {
- this.setState({ result });
- const projectKey = result && result.language !== 'java' ? result.projectKey : undefined;
- this.props.onFinish(projectKey);
- };
-
- handleLanguageReset = () => {
- this.setState({ result: undefined });
- this.props.onReset();
- };
-
- renderForm = () => {
- return (
- <div className="boxed-group-inner">
- <div className="flex-columns">
- <div className="flex-column flex-column-half bordered-right">
- <LanguageStep
- onDone={this.handleLanguageSelect}
- onReset={this.handleLanguageReset}
- organization={this.props.organization}
- />
- </div>
- <div className="flex-column flex-column-half">{this.renderCommand()}</div>
- </div>
- </div>
- );
- };
-
- renderFormattedCommand = (...lines: Array<string>) => (
- // keep this "useless" concatentation for the readability reason
- // eslint-disable-next-line no-useless-concat
- <pre>{lines.join(' ' + '\\' + '\n' + ' ')}</pre>
- );
-
- renderCommand = () => {
- const { result } = this.state;
-
- if (!result) {
- return null;
- }
-
- if (result.language === 'java') {
- return result.javaBuild === 'maven'
- ? this.renderCommandForMaven()
- : this.renderCommandForGradle();
- } else if (result.language === 'dotnet') {
- return this.renderCommandForDotNet();
- } else if (result.language === 'c-family') {
- return result.cFamilyCompiler === 'msvc'
- ? this.renderCommandForMSVC()
- : this.renderCommandForClangGCC();
- } else {
- return this.renderCommandForOther();
- }
- };
-
- renderCommandForMaven = () => {
- const { token } = this.props;
- if (!token) {
- return null;
- }
- return <JavaMaven host={getHostUrl()} organization={this.props.organization} token={token} />;
- };
-
- renderCommandForGradle = () => {
- const { token } = this.props;
- if (!token) {
- return null;
- }
- return <JavaGradle host={getHostUrl()} organization={this.props.organization} token={token} />;
- };
-
- renderCommandForDotNet = () => {
- const { token } = this.props;
- const { result } = this.state;
- if (!result || !result.projectKey || !token) {
- return null;
- }
- return (
- <DotNet
- host={getHostUrl()}
- organization={this.props.organization}
- projectKey={result.projectKey}
- token={token}
- />
- );
- };
-
- renderCommandForMSVC = () => {
- const { token } = this.props;
- const { result } = this.state;
- if (!result || !result.projectKey || !token) {
- return null;
- }
- return (
- <Msvc
- host={getHostUrl()}
- organization={this.props.organization}
- projectKey={result.projectKey}
- token={token}
- />
- );
- };
-
- renderCommandForClangGCC = () => {
- const { token } = this.props;
- const { result } = this.state;
- if (!result || !result.projectKey || !result.os || !token) {
- return null;
- }
- return (
- <ClangGCC
- host={getHostUrl()}
- organization={this.props.organization}
- os={result.os}
- projectKey={result.projectKey}
- token={token}
- />
- );
- };
-
- renderCommandForOther = () => {
- const { token } = this.props;
- const { result } = this.state;
- if (!result || !result.projectKey || !result.os || !token) {
- return null;
- }
- return (
- <Other
- host={getHostUrl()}
- organization={this.props.organization}
- os={result.os}
- projectKey={result.projectKey}
- token={token}
- />
- );
- };
-
- renderResult = () => null;
-
- render() {
- return (
- <Step
- finished={false}
- onOpen={() => {}}
- open={this.props.open}
- renderForm={this.renderForm}
- renderResult={this.renderResult}
- stepNumber={this.props.stepNumber}
- stepTitle={translate('onboarding.analysis.header')}
- />
- );
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import NewProjectForm from './NewProjectForm';
-import RadioToggle from '../../../components/controls/RadioToggle';
-import { translate } from '../../../helpers/l10n';
-import { isSonarCloud } from '../../../helpers/system';
-
-export interface Result {
- language?: string;
- javaBuild?: string;
- cFamilyCompiler?: string;
- os?: string;
- projectKey?: string;
-}
-
-interface Props {
- onDone: (result: Result) => void;
- onReset: () => void;
- organization?: string;
-}
-
-type State = Result;
-
-export default class LanguageStep extends React.PureComponent<Props, State> {
- state: State = {};
-
- isConfigured = () => {
- const { language, javaBuild, cFamilyCompiler, os, projectKey } = this.state;
- const isJavaConfigured = language === 'java' && javaBuild != null;
- const isDotNetConfigured = language === 'dotnet' && projectKey != null;
- const isCFamilyConfigured =
- language === 'c-family' && (cFamilyCompiler === 'msvc' || os != null) && projectKey != null;
- const isOtherConfigured = language === 'other' && projectKey != null;
-
- return isJavaConfigured || isDotNetConfigured || isCFamilyConfigured || isOtherConfigured;
- };
-
- handleChange = () => {
- if (this.isConfigured()) {
- this.props.onDone(this.state);
- } else {
- this.props.onReset();
- }
- };
-
- handleLanguageChange = (language: string) => {
- this.setState({ language }, this.handleChange);
- };
-
- handleJavaBuildChange = (javaBuild: string) => {
- this.setState({ javaBuild }, this.handleChange);
- };
-
- handleCFamilyCompilerChange = (cFamilyCompiler: string) => {
- this.setState({ cFamilyCompiler }, this.handleChange);
- };
-
- handleOSChange = (os: string) => {
- this.setState({ os }, this.handleChange);
- };
-
- handleProjectKeyDone = (projectKey: string) => {
- this.setState({ projectKey }, this.handleChange);
- };
-
- handleProjectKeyDelete = () => {
- this.setState({ projectKey: undefined }, this.handleChange);
- };
-
- renderJavaBuild = () => (
- <div className="big-spacer-top">
- <h4 className="spacer-bottom">{translate('onboarding.language.java.build_technology')}</h4>
- <RadioToggle
- name="java-build"
- onCheck={this.handleJavaBuildChange}
- options={['maven', 'gradle'].map(build => ({
- label: translate('onboarding.language.java.build_technology', build),
- value: build
- }))}
- value={this.state.javaBuild}
- />
- </div>
- );
-
- renderCFamilyCompiler = () => (
- <div className="big-spacer-top">
- <h4 className="spacer-bottom">{translate('onboarding.language.c-family.compiler')}</h4>
- <RadioToggle
- name="c-family-compiler"
- onCheck={this.handleCFamilyCompilerChange}
- options={['msvc', 'clang-gcc'].map(compiler => ({
- label: translate('onboarding.language.c-family.compiler', compiler),
- value: compiler
- }))}
- value={this.state.cFamilyCompiler}
- />
- </div>
- );
-
- renderOS = () => (
- <div className="big-spacer-top">
- <h4 className="spacer-bottom">{translate('onboarding.language.os')}</h4>
- <RadioToggle
- name="os"
- onCheck={this.handleOSChange}
- options={['linux', 'win', 'mac'].map(os => ({
- label: translate('onboarding.language.os', os),
- value: os
- }))}
- value={this.state.os}
- />
- </div>
- );
-
- renderProjectKey = () => (
- <NewProjectForm
- onDelete={this.handleProjectKeyDelete}
- onDone={this.handleProjectKeyDone}
- organization={this.props.organization}
- projectKey={this.state.projectKey}
- />
- );
-
- render() {
- const shouldAskProjectKey =
- this.state.language === 'dotnet' ||
- (this.state.language === 'c-family' &&
- (this.state.cFamilyCompiler === 'msvc' ||
- (this.state.cFamilyCompiler === 'clang-gcc' && this.state.os != null))) ||
- (this.state.language === 'other' && this.state.os !== undefined);
-
- const languages = isSonarCloud()
- ? ['java', 'dotnet', 'c-family', 'other']
- : ['java', 'dotnet', 'other'];
-
- return (
- <div>
- <div>
- <h4 className="spacer-bottom">{translate('onboarding.language')}</h4>
- <RadioToggle
- name="language"
- onCheck={this.handleLanguageChange}
- options={languages.map(language => ({
- label: translate('onboarding.language', language),
- value: language
- }))}
- value={this.state.language}
- />
- </div>
- {this.state.language === 'java' && this.renderJavaBuild()}
- {this.state.language === 'c-family' && this.renderCFamilyCompiler()}
- {((this.state.language === 'c-family' && this.state.cFamilyCompiler === 'clang-gcc') ||
- this.state.language === 'other') &&
- this.renderOS()}
- {shouldAskProjectKey && this.renderProjectKey()}
- </div>
- );
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { debounce } from 'lodash';
-import {
- createOrganization,
- deleteOrganization,
- getOrganization
-} from '../../../api/organizations';
-import AlertErrorIcon from '../../../components/icons-components/AlertErrorIcon';
-import { DeleteButton, SubmitButton } from '../../../components/ui/buttons';
-import { translate } from '../../../helpers/l10n';
-
-interface Props {
- onDelete: () => void;
- onDone: (organization: string) => void;
- organization?: string;
-}
-
-interface State {
- done: boolean;
- loading: boolean;
- organization: string;
- unique: boolean;
-}
-
-export default class NewOrganizationForm extends React.PureComponent<Props, State> {
- mounted = false;
-
- constructor(props: Props) {
- super(props);
- this.state = {
- done: props.organization != null,
- loading: false,
- organization: props.organization || '',
- unique: true
- };
- this.validateOrganization = debounce(this.validateOrganization, 500);
- }
-
- componentDidMount() {
- this.mounted = true;
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- stopLoading = () => {
- if (this.mounted) {
- this.setState({ loading: false });
- }
- };
-
- validateOrganization = (organization: string) => {
- getOrganization(organization).then(
- response => {
- if (this.mounted) {
- this.setState({ unique: response == null });
- }
- },
- () => {}
- );
- };
-
- sanitizeOrganization = (organization: string) =>
- organization
- .toLowerCase()
- .replace(/[^a-z0-9-]/, '')
- .replace(/^-/, '');
-
- handleOrganizationChange = (event: React.ChangeEvent<HTMLInputElement>) => {
- const organization = this.sanitizeOrganization(event.target.value);
- this.setState({ organization });
- this.validateOrganization(organization);
- };
-
- handleOrganizationCreate = (event: React.FormEvent<HTMLFormElement>) => {
- event.preventDefault();
- const { organization } = this.state;
- if (organization) {
- this.setState({ loading: true });
- createOrganization({ key: organization, name: organization }).then(() => {
- if (this.mounted) {
- this.setState({ done: true, loading: false });
- this.props.onDone(organization);
- }
- }, this.stopLoading);
- }
- };
-
- handleOrganizationDelete = () => {
- const { organization } = this.state;
- if (organization) {
- this.setState({ loading: true });
- deleteOrganization(organization).then(() => {
- if (this.mounted) {
- this.setState({ done: false, loading: false, organization: '' });
- this.props.onDelete();
- }
- }, this.stopLoading);
- }
- };
-
- render() {
- const { done, loading, organization, unique } = this.state;
-
- const valid = unique && organization.length >= 2;
-
- return done ? (
- <div>
- <span className="spacer-right text-middle">{organization}</span>
- {loading ? (
- <i className="spinner text-middle" />
- ) : (
- <DeleteButton className="button-small" onClick={this.handleOrganizationDelete} />
- )}
- </div>
- ) : (
- <form onSubmit={this.handleOrganizationCreate}>
- <input
- autoFocus={true}
- className="input-super-large spacer-right text-middle"
- maxLength={32}
- minLength={2}
- onChange={this.handleOrganizationChange}
- placeholder={translate('onboarding.organization.placeholder')}
- required={true}
- type="text"
- value={organization}
- />
- {loading ? (
- <i className="spinner text-middle" />
- ) : (
- <SubmitButton className="text-middle" disabled={!valid}>
- {translate('create')}
- </SubmitButton>
- )}
- {!unique && (
- <span className="big-spacer-left text-danger text-middle">
- <AlertErrorIcon className="little-spacer-right text-text-top" />
- {translate('this_name_is_already_taken')}
- </span>
- )}
- <div className="note spacer-top abs-width-300">
- {translate('onboarding.organization.key_requirement')}
- </div>
- </form>
- );
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { createProject, deleteProject } from '../../../api/components';
-import { DeleteButton, SubmitButton } from '../../../components/ui/buttons';
-import { translate } from '../../../helpers/l10n';
-
-interface Props {
- onDelete: () => void;
- onDone: (projectKey: string) => void;
- organization?: string;
- projectKey?: string;
-}
-
-interface State {
- done: boolean;
- loading: boolean;
- projectKey: string;
-}
-
-export default class NewProjectForm extends React.PureComponent<Props, State> {
- mounted = false;
-
- constructor(props: Props) {
- super(props);
- this.state = {
- done: props.projectKey != null,
- loading: false,
- projectKey: props.projectKey || ''
- };
- }
-
- componentDidMount() {
- this.mounted = true;
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- stopLoading = () => {
- if (this.mounted) {
- this.setState({ loading: false });
- }
- };
-
- sanitizeProjectKey = (projectKey: string) => projectKey.replace(/[^-_a-zA-Z0-9.:]/, '');
-
- handleProjectKeyChange = (event: React.ChangeEvent<HTMLInputElement>) => {
- this.setState({ projectKey: this.sanitizeProjectKey(event.target.value) });
- };
-
- handleProjectCreate = (event: React.FormEvent<HTMLFormElement>) => {
- event.preventDefault();
- const { projectKey } = this.state;
- const data: {
- name: string;
- project: string;
- organization?: string;
- } = {
- name: projectKey,
- project: projectKey
- };
- if (this.props.organization) {
- data.organization = this.props.organization;
- }
- this.setState({ loading: true });
- createProject(data).then(() => {
- if (this.mounted) {
- this.setState({ done: true, loading: false });
- this.props.onDone(projectKey);
- }
- }, this.stopLoading);
- };
-
- handleProjectDelete = () => {
- const { projectKey } = this.state;
- this.setState({ loading: true });
- deleteProject(projectKey).then(() => {
- if (this.mounted) {
- this.setState({ done: false, loading: false, projectKey: '' });
- this.props.onDelete();
- }
- }, this.stopLoading);
- };
-
- render() {
- const { done, loading, projectKey } = this.state;
-
- const valid = projectKey.length > 0;
-
- const form = done ? (
- <div>
- <span className="spacer-right text-middle">{projectKey}</span>
- {loading ? (
- <i className="spinner text-middle" />
- ) : (
- <DeleteButton className="button-small text-middle" onClick={this.handleProjectDelete} />
- )}
- </div>
- ) : (
- <form onSubmit={this.handleProjectCreate}>
- <input
- autoFocus={true}
- className="input-large spacer-right text-middle"
- maxLength={400}
- minLength={1}
- onChange={this.handleProjectKeyChange}
- required={true}
- type="text"
- value={projectKey}
- />
- {loading ? (
- <i className="spinner text-middle" />
- ) : (
- <SubmitButton className="text-middle" disabled={!valid}>
- {translate('Done')}
- </SubmitButton>
- )}
- <div className="note spacer-top abs-width-300">
- {translate('onboarding.project_key_requirement')}
- </div>
- </form>
- );
-
- return (
- <div className="big-spacer-top">
- <h4 className="spacer-bottom">{translate('onboarding.language.project_key')}</h4>
- {form}
- </div>
- );
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import * as classNames from 'classnames';
-import { sortBy } from 'lodash';
-import Step from './Step';
-import NewOrganizationForm from './NewOrganizationForm';
-import DocTooltip from '../../../components/docs/DocTooltip';
-import AlertSuccessIcon from '../../../components/icons-components/AlertSuccessIcon';
-import { getOrganizations } from '../../../api/organizations';
-import Select from '../../../components/controls/Select';
-import { translate } from '../../../helpers/l10n';
-import { Button } from '../../../components/ui/buttons';
-
-interface Props {
- currentUser: { login: string; isLoggedIn: boolean };
- finished: boolean;
- onOpen: () => void;
- onContinue: (organization: string) => void;
- open: boolean;
- stepNumber: number;
-}
-
-interface State {
- loading: boolean;
- newOrganization?: string;
- existingOrganization?: string;
- existingOrganizations: Array<string>;
- personalOrganization?: string;
- selection: 'personal' | 'existing' | 'new';
-}
-
-export default class OrganizationStep extends React.PureComponent<Props, State> {
- mounted = false;
- state: State = {
- loading: true,
- existingOrganizations: [],
- selection: 'personal'
- };
-
- componentDidMount() {
- this.mounted = true;
- this.fetchOrganizations();
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- fetchOrganizations = () => {
- getOrganizations({ member: true }).then(
- ({ organizations }) => {
- if (this.mounted) {
- const organizationKeys = organizations.filter(o => o.isAdmin).map(o => o.key);
- // best guess: if there is only one organization, then it is personal
- // otherwise, we can't guess, let's display them all as just "existing organizations"
- const personalOrganization =
- organizationKeys.length === 1 ? organizationKeys[0] : undefined;
- const existingOrganizations = organizationKeys.length > 1 ? sortBy(organizationKeys) : [];
- const selection = personalOrganization
- ? 'personal'
- : existingOrganizations.length > 0 ? 'existing' : 'new';
- this.setState({
- loading: false,
- existingOrganizations,
- personalOrganization,
- selection
- });
- }
- },
- () => {
- if (this.mounted) {
- this.setState({ loading: false });
- }
- }
- );
- };
-
- getSelectedOrganization = () => {
- switch (this.state.selection) {
- case 'personal':
- return this.state.personalOrganization;
- case 'existing':
- return this.state.existingOrganization;
- case 'new':
- return this.state.newOrganization;
- default:
- return null;
- }
- };
-
- handlePersonalClick = (event: React.MouseEvent<HTMLAnchorElement>) => {
- event.preventDefault();
- this.setState({ selection: 'personal' });
- };
-
- handleExistingClick = (event: React.MouseEvent<HTMLAnchorElement>) => {
- event.preventDefault();
- this.setState({ selection: 'existing' });
- };
-
- handleNewClick = (event: React.MouseEvent<HTMLAnchorElement>) => {
- event.preventDefault();
- this.setState({ selection: 'new' });
- };
-
- handleOrganizationCreate = (newOrganization: string) => {
- this.setState({ newOrganization });
- };
-
- handleOrganizationDelete = () => {
- this.setState({ newOrganization: undefined });
- };
-
- handleExistingOrganizationSelect = ({ value }: { value: string }) => {
- this.setState({ existingOrganization: value });
- };
-
- handleContinueClick = () => {
- const organization = this.getSelectedOrganization();
- if (organization) {
- this.props.onContinue(organization);
- }
- };
-
- renderPersonalOrganizationOption = () => (
- <div>
- <a className="link-base-color link-no-underline" href="#" onClick={this.handlePersonalClick}>
- <i
- className={classNames('icon-radio', 'spacer-right', {
- 'is-checked': this.state.selection === 'personal'
- })}
- />
- {translate('onboarding.organization.my_personal_organization')}
- <span className="note spacer-left">{this.state.personalOrganization}</span>
- </a>
- </div>
- );
-
- renderExistingOrganizationOption = () => (
- <div className="big-spacer-top">
- <a
- className="js-existing link-base-color link-no-underline"
- href="#"
- onClick={this.handleExistingClick}>
- <i
- className={classNames('icon-radio', 'spacer-right', {
- 'is-checked': this.state.selection === 'existing'
- })}
- />
- {translate('onboarding.organization.exising_organization')}
- </a>
- {this.state.selection === 'existing' && (
- <div className="big-spacer-top">
- <Select
- className="input-super-large"
- clearable={false}
- onChange={this.handleExistingOrganizationSelect}
- options={this.state.existingOrganizations.map(organization => ({
- label: organization,
- value: organization
- }))}
- value={this.state.existingOrganization}
- />
- </div>
- )}
- </div>
- );
-
- renderNewOrganizationOption = () => (
- <div className="big-spacer-top">
- <a
- className="js-new link-base-color link-no-underline"
- href="#"
- onClick={this.handleNewClick}>
- <i
- className={classNames('icon-radio', 'spacer-right', {
- 'is-checked': this.state.selection === 'new'
- })}
- />
- {translate('onboarding.organization.create_another_organization')}
- </a>
- {this.state.selection === 'new' && (
- <div className="big-spacer-top">
- <NewOrganizationForm
- onDelete={this.handleOrganizationDelete}
- onDone={this.handleOrganizationCreate}
- organization={this.state.newOrganization}
- />
- </div>
- )}
- </div>
- );
-
- renderForm = () => {
- return (
- <div className="boxed-group-inner">
- <div className="big-spacer-bottom width-50">
- {translate('onboarding.organization.text')}
- </div>
-
- {this.state.loading ? (
- <i className="spinner" />
- ) : (
- <div>
- {this.state.personalOrganization && this.renderPersonalOrganizationOption()}
- {this.state.existingOrganizations.length > 0 && this.renderExistingOrganizationOption()}
- {this.renderNewOrganizationOption()}
- </div>
- )}
-
- {this.getSelectedOrganization() != null &&
- !this.state.loading && (
- <div className="big-spacer-top">
- <Button className="js-continue" onClick={this.handleContinueClick}>
- {translate('continue')}
- </Button>
- </div>
- )}
- </div>
- );
- };
-
- renderResult = () => {
- const result = this.getSelectedOrganization();
-
- return result != null ? (
- <div className="boxed-group-actions display-flex-center">
- <AlertSuccessIcon className="spacer-right" />
- <strong>{result}</strong>
- </div>
- ) : null;
- };
-
- render() {
- return (
- <Step
- finished={this.props.finished}
- onOpen={this.props.onOpen}
- open={this.props.open}
- renderForm={this.renderForm}
- renderResult={this.renderResult}
- stepNumber={this.props.stepNumber}
- stepTitle={
- <span>
- {translate('onboarding.organization.header')}
- <DocTooltip
- className="little-spacer-left"
- doc={import(/* webpackMode: "eager" */ 'Docs/tooltips/organizations/organization.md')}
- />
- </span>
- }
- />
- );
- }
-}
import * as PropTypes from 'prop-types';
import Helmet from 'react-helmet';
import { connect } from 'react-redux';
-import TokenStep from './TokenStep';
-import OrganizationStep from './OrganizationStep';
-import AnalysisStep from './AnalysisStep';
import ProjectWatcher from './ProjectWatcher';
+import ProjectAnalysisStep from '../components/ProjectAnalysisStep';
+import OrganizationStep from '../components/OrganizationStep';
+import TokenStep from '../components/TokenStep';
import handleRequiredAuthentication from '../../../app/utils/handleRequiredAuthentication';
import { getCurrentUser, areThereCustomOrganizations } from '../../../store/rootReducer';
import { CurrentUser, isLoggedIn } from '../../../app/types';
stepNumber={stepNumber++}
/>
- <AnalysisStep
+ <ProjectAnalysisStep
onFinish={this.handleFinish}
onReset={this.handleReset}
open={step === 'analysis'}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-/* eslint-disable jsx-a11y/no-static-element-interactions, jsx-a11y/no-noninteractive-tabindex */
-import * as React from 'react';
-import * as classNames from 'classnames';
-
-interface Props {
- finished: boolean;
- onOpen: () => void;
- open: boolean;
- renderForm: () => React.ReactNode;
- renderResult: () => React.ReactNode;
- stepNumber: number;
- stepTitle: React.ReactNode;
-}
-
-export default function Step(props: Props) {
- const className = classNames('boxed-group', 'onboarding-step', {
- 'is-open': props.open,
- 'is-finished': props.finished
- });
-
- const clickable = !props.open && props.finished;
-
- const handleClick = (event: React.MouseEvent<HTMLDivElement>) => {
- event.preventDefault();
- props.onOpen();
- };
-
- return (
- <div
- className={className}
- onClick={clickable ? handleClick : undefined}
- role={clickable ? 'button' : undefined}
- tabIndex={clickable ? 0 : undefined}>
- <div className="onboarding-step-number">{props.stepNumber}</div>
- {!props.open && props.renderResult()}
- <div className="boxed-group-header">
- <h2>{props.stepTitle}</h2>
- </div>
- {props.open ? props.renderForm() : <div className="boxed-group-inner" />}
- </div>
- );
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import * as classNames from 'classnames';
-import Step from './Step';
-import { getTokens, generateToken, revokeToken } from '../../../api/user-tokens';
-import AlertErrorIcon from '../../../components/icons-components/AlertErrorIcon';
-import AlertSuccessIcon from '../../../components/icons-components/AlertSuccessIcon';
-import { DeleteButton, SubmitButton, Button } from '../../../components/ui/buttons';
-import { translate } from '../../../helpers/l10n';
-
-interface Props {
- currentUser: { login: string };
- finished: boolean;
- open: boolean;
- onContinue: (token: string) => void;
- onOpen: () => void;
- stepNumber: number;
-}
-
-interface State {
- canUseExisting: boolean;
- existingToken: string;
- loading: boolean;
- selection: string;
- tokenName?: string;
- token?: string;
-}
-
-export default class TokenStep extends React.PureComponent<Props, State> {
- mounted = false;
-
- state: State = {
- canUseExisting: false,
- existingToken: '',
- loading: false,
- selection: 'generate'
- };
-
- componentDidMount() {
- this.mounted = true;
- getTokens(this.props.currentUser.login).then(
- tokens => {
- if (this.mounted) {
- this.setState({ canUseExisting: tokens.length > 0 });
- }
- },
- () => {}
- );
- }
-
- componentWillUnmount() {
- this.mounted = false;
- }
-
- getToken = () =>
- this.state.selection === 'generate' ? this.state.token : this.state.existingToken;
-
- canContinue = () => {
- const { existingToken, selection, token } = this.state;
- const validExistingToken = existingToken.match(/^[a-z0-9]+$/) != null;
- return (
- (selection === 'generate' && token != null) ||
- (selection === 'use-existing' && existingToken && validExistingToken)
- );
- };
-
- handleTokenNameChange = (event: React.ChangeEvent<HTMLInputElement>) => {
- this.setState({ tokenName: event.target.value });
- };
-
- handleTokenGenerate = (event: React.FormEvent<HTMLFormElement>) => {
- event.preventDefault();
- const { tokenName } = this.state;
- if (tokenName) {
- this.setState({ loading: true });
- generateToken({ name: tokenName }).then(({ token }) => {
- if (this.mounted) {
- this.setState({ loading: false, token });
- }
- }, this.stopLoading);
- }
- };
-
- handleTokenRevoke = () => {
- const { tokenName } = this.state;
- if (tokenName) {
- this.setState({ loading: true });
- revokeToken({ name: tokenName }).then(() => {
- if (this.mounted) {
- this.setState({ loading: false, token: undefined, tokenName: undefined });
- }
- }, this.stopLoading);
- }
- };
-
- handleContinueClick = () => {
- const token = this.getToken();
- if (token) {
- this.props.onContinue(token);
- }
- };
-
- handleGenerateClick = (event: React.MouseEvent<HTMLAnchorElement>) => {
- event.preventDefault();
- this.setState({ selection: 'generate' });
- };
-
- handleUseExistingClick = (event: React.MouseEvent<HTMLAnchorElement>) => {
- event.preventDefault();
- this.setState({ selection: 'use-existing' });
- };
-
- handleExisingTokenChange = (event: React.ChangeEvent<HTMLInputElement>) => {
- this.setState({ existingToken: event.currentTarget.value });
- };
-
- stopLoading = () => {
- if (this.mounted) {
- this.setState({ loading: false });
- }
- };
-
- renderGenerateOption = () => (
- <div>
- {this.state.canUseExisting ? (
- <a
- className="js-new link-base-color link-no-underline"
- href="#"
- onClick={this.handleGenerateClick}>
- <i
- className={classNames('icon-radio', 'spacer-right', {
- 'is-checked': this.state.selection === 'generate'
- })}
- />
- {translate('onboarding.token.generate_token')}
- </a>
- ) : (
- translate('onboarding.token.generate_token')
- )}
- {this.state.selection === 'generate' && (
- <div className="big-spacer-top">
- <form onSubmit={this.handleTokenGenerate}>
- <input
- autoFocus={true}
- className="input-large spacer-right text-middle"
- onChange={this.handleTokenNameChange}
- placeholder={translate('onboarding.token.generate_token.placeholder')}
- required={true}
- type="text"
- value={this.state.tokenName || ''}
- />
- {this.state.loading ? (
- <i className="spinner text-middle" />
- ) : (
- <SubmitButton className="text-middle" disabled={!this.state.tokenName}>
- {translate('onboarding.token.generate')}
- </SubmitButton>
- )}
- </form>
- </div>
- )}
- </div>
- );
-
- renderUseExistingOption = () => {
- const { existingToken } = this.state;
- const validInput = !existingToken || existingToken.match(/^[a-z0-9]+$/) != null;
-
- return (
- <div className="big-spacer-top">
- <a
- className="js-new link-base-color link-no-underline"
- href="#"
- onClick={this.handleUseExistingClick}>
- <i
- className={classNames('icon-radio', 'spacer-right', {
- 'is-checked': this.state.selection === 'use-existing'
- })}
- />
- {translate('onboarding.token.use_existing_token')}
- </a>
- {this.state.selection === 'use-existing' && (
- <div className="big-spacer-top">
- <input
- autoFocus={true}
- className="input-large spacer-right text-middle"
- onChange={this.handleExisingTokenChange}
- placeholder={translate('onboarding.token.use_existing_token.placeholder')}
- required={true}
- type="text"
- value={this.state.existingToken}
- />
- {!validInput && (
- <span className="text-danger">
- <AlertErrorIcon className="little-spacer-right text-text-top" />
- {translate('onboarding.token.invalid_format')}
- </span>
- )}
- </div>
- )}
- </div>
- );
- };
-
- renderForm = () => {
- const { canUseExisting, loading, token, tokenName } = this.state;
-
- return (
- <div className="boxed-group-inner">
- {token != null ? (
- <form onSubmit={this.handleTokenRevoke}>
- <span className="text-middle">
- {tokenName}
- {': '}
- </span>
- <strong className="spacer-right text-middle">{token}</strong>
- {loading ? (
- <i className="spinner text-middle" />
- ) : (
- <DeleteButton className="button-small text-middle" onClick={this.handleTokenRevoke} />
- )}
- </form>
- ) : (
- <div>
- {this.renderGenerateOption()}
- {canUseExisting && this.renderUseExistingOption()}
- </div>
- )}
-
- <div className="note big-spacer-top width-50">{translate('onboarding.token.text')}</div>
-
- {this.canContinue() && (
- <div className="big-spacer-top">
- <Button className="js-continue" onClick={this.handleContinueClick}>
- {translate('continue')}
- </Button>
- </div>
- )}
- </div>
- );
- };
-
- renderResult = () => {
- const { selection, tokenName } = this.state;
- const token = this.getToken();
-
- if (!token) {
- return null;
- }
-
- return (
- <div className="boxed-group-actions display-flex-center">
- <AlertSuccessIcon className="spacer-right" />
- {selection === 'generate' && tokenName && `${tokenName}: `}
- <strong>{token}</strong>
- </div>
- );
- };
-
- render() {
- return (
- <Step
- finished={this.props.finished}
- onOpen={this.props.onOpen}
- open={this.props.open}
- renderForm={this.renderForm}
- renderResult={this.renderResult}
- stepNumber={this.props.stepNumber}
- stepTitle={translate('onboarding.token.header')}
- />
- );
- }
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { shallow } from 'enzyme';
-import LanguageStep from '../LanguageStep';
-import { isSonarCloud } from '../../../../helpers/system';
-
-jest.mock('../../../../helpers/system', () => ({ isSonarCloud: jest.fn() }));
-
-beforeEach(() => {
- (isSonarCloud as jest.Mock<any>).mockImplementation(() => false);
-});
-
-it('selects java', () => {
- const onDone = jest.fn();
- const wrapper = shallow(<LanguageStep onDone={onDone} onReset={jest.fn()} />);
-
- (wrapper.find('RadioToggle').prop('onCheck') as Function)('java');
- wrapper.update();
- expect(wrapper).toMatchSnapshot();
-
- (wrapper
- .find('RadioToggle')
- .at(1)
- .prop('onCheck') as Function)('maven');
- wrapper.update();
- expect(wrapper).toMatchSnapshot();
- expect(onDone).lastCalledWith({ language: 'java', javaBuild: 'maven' });
-
- (wrapper
- .find('RadioToggle')
- .at(1)
- .prop('onCheck') as Function)('gradle');
- wrapper.update();
- expect(wrapper).toMatchSnapshot();
- expect(onDone).lastCalledWith({ language: 'java', javaBuild: 'gradle' });
-});
-
-it('selects c#', () => {
- const onDone = jest.fn();
- const wrapper = shallow(<LanguageStep onDone={onDone} onReset={jest.fn()} />);
-
- (wrapper.find('RadioToggle').prop('onCheck') as Function)('dotnet');
- wrapper.update();
- expect(wrapper).toMatchSnapshot();
-
- (wrapper.find('NewProjectForm').prop('onDone') as Function)('project-foo');
- expect(onDone).lastCalledWith({ language: 'dotnet', projectKey: 'project-foo' });
-});
-
-it('selects c-family', () => {
- (isSonarCloud as jest.Mock<any>).mockImplementation(() => true);
- const onDone = jest.fn();
- const wrapper = shallow(<LanguageStep onDone={onDone} onReset={jest.fn()} />);
-
- (wrapper.find('RadioToggle').prop('onCheck') as Function)('c-family');
- wrapper.update();
- expect(wrapper).toMatchSnapshot();
-
- (wrapper
- .find('RadioToggle')
- .at(1)
- .prop('onCheck') as Function)('msvc');
- wrapper.update();
- expect(wrapper).toMatchSnapshot();
-
- (wrapper.find('NewProjectForm').prop('onDone') as Function)('project-foo');
- expect(onDone).lastCalledWith({
- language: 'c-family',
- cFamilyCompiler: 'msvc',
- projectKey: 'project-foo'
- });
-
- (wrapper
- .find('RadioToggle')
- .at(1)
- .prop('onCheck') as Function)('clang-gcc');
- wrapper.update();
- expect(wrapper).toMatchSnapshot();
-
- (wrapper
- .find('RadioToggle')
- .at(2)
- .prop('onCheck') as Function)('linux');
- wrapper.update();
- expect(wrapper).toMatchSnapshot();
-
- (wrapper.find('NewProjectForm').prop('onDone') as Function)('project-foo');
- expect(onDone).lastCalledWith({
- language: 'c-family',
- cFamilyCompiler: 'clang-gcc',
- os: 'linux',
- projectKey: 'project-foo'
- });
-});
-
-it('selects other', () => {
- const onDone = jest.fn();
- const wrapper = shallow(<LanguageStep onDone={onDone} onReset={jest.fn()} />);
-
- (wrapper.find('RadioToggle').prop('onCheck') as Function)('other');
- wrapper.update();
- expect(wrapper).toMatchSnapshot();
-
- (wrapper
- .find('RadioToggle')
- .at(1)
- .prop('onCheck') as Function)('mac');
- wrapper.update();
- expect(wrapper).toMatchSnapshot();
-
- (wrapper.find('NewProjectForm').prop('onDone') as Function)('project-foo');
- expect(onDone).lastCalledWith({ language: 'other', os: 'mac', projectKey: 'project-foo' });
-});
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { mount } from 'enzyme';
-import NewOrganizationForm from '../NewOrganizationForm';
-import { change, submit, waitAndUpdate } from '../../../../helpers/testUtils';
-
-jest.mock('../../../../api/organizations', () => ({
- createOrganization: () => Promise.resolve(),
- deleteOrganization: () => Promise.resolve(),
- getOrganization: () => Promise.resolve(null)
-}));
-
-jest.mock('../../../../components/icons-components/ClearIcon');
-
-it('creates new organization', async () => {
- const onDone = jest.fn();
- const wrapper = mount(<NewOrganizationForm onDelete={jest.fn()} onDone={onDone} />);
- expect(wrapper).toMatchSnapshot();
- change(wrapper.find('input'), 'foo');
- submit(wrapper.find('form'));
- expect(wrapper).toMatchSnapshot(); // spinner
- await waitAndUpdate(wrapper);
- expect(wrapper).toMatchSnapshot();
- expect(onDone).toBeCalledWith('foo');
-});
-
-it('deletes organization', async () => {
- const onDelete = jest.fn();
- const wrapper = mount(<NewOrganizationForm onDelete={onDelete} onDone={jest.fn()} />);
- wrapper.setState({ done: true, loading: false, organization: 'foo' });
- expect(wrapper).toMatchSnapshot();
- (wrapper.find('DeleteButton').prop('onClick') as Function)();
- wrapper.update();
- expect(wrapper).toMatchSnapshot(); // spinner
- await waitAndUpdate(wrapper);
- expect(wrapper).toMatchSnapshot();
- expect(onDelete).toBeCalled();
-});
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { mount } from 'enzyme';
-import NewProjectForm from '../NewProjectForm';
-import { change, submit, waitAndUpdate } from '../../../../helpers/testUtils';
-
-jest.mock('../../../../api/components', () => ({
- createProject: () => Promise.resolve(),
- deleteProject: () => Promise.resolve()
-}));
-
-jest.mock('../../../../components/icons-components/ClearIcon');
-
-it('creates new project', async () => {
- const onDone = jest.fn();
- const wrapper = mount(<NewProjectForm onDelete={jest.fn()} onDone={onDone} />);
- expect(wrapper).toMatchSnapshot();
- change(wrapper.find('input'), 'foo');
- submit(wrapper.find('form'));
- expect(wrapper).toMatchSnapshot(); // spinner
- await waitAndUpdate(wrapper);
- expect(wrapper).toMatchSnapshot();
- expect(onDone).toBeCalledWith('foo');
-});
-
-it('deletes project', async () => {
- const onDelete = jest.fn();
- const wrapper = mount(<NewProjectForm onDelete={onDelete} onDone={jest.fn()} />);
- wrapper.setState({ done: true, loading: false, projectKey: 'foo' });
- expect(wrapper).toMatchSnapshot();
- (wrapper.find('DeleteButton').prop('onClick') as Function)();
- wrapper.update();
- expect(wrapper).toMatchSnapshot(); // spinner
- await waitAndUpdate(wrapper);
- expect(wrapper).toMatchSnapshot();
- expect(onDelete).toBeCalled();
-});
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { mount } from 'enzyme';
-import OrganizationStep from '../OrganizationStep';
-import { click, waitAndUpdate } from '../../../../helpers/testUtils';
-import { getOrganizations } from '../../../../api/organizations';
-
-jest.mock('../../../../api/organizations', () => ({
- getOrganizations: jest.fn(() =>
- Promise.resolve({
- organizations: [{ isAdmin: true, key: 'user' }, { isAdmin: true, key: 'another' }]
- })
- )
-}));
-
-const currentUser = { isLoggedIn: true, login: 'user' };
-
-beforeEach(() => {
- (getOrganizations as jest.Mock<any>).mockClear();
-});
-
-// FIXME
-// - if `mount` is used, then it's not possible to correctly set the state,
-// because the mocked api call is used
-// - if `shallow` is used, then the continue button is not rendered
-it.skip('works with personal organization', () => {
- const onContinue = jest.fn();
- const wrapper = mount(
- <OrganizationStep
- currentUser={currentUser}
- finished={false}
- onContinue={onContinue}
- onOpen={jest.fn()}
- open={true}
- stepNumber={1}
- />
- );
- click(wrapper.find('.js-continue'));
- expect(onContinue).toBeCalledWith('user');
-});
-
-it('works with existing organization', async () => {
- const onContinue = jest.fn();
- const wrapper = mount(
- <OrganizationStep
- currentUser={currentUser}
- finished={false}
- onContinue={onContinue}
- onOpen={jest.fn()}
- open={true}
- stepNumber={1}
- />
- );
- await waitAndUpdate(wrapper);
- click(wrapper.find('.js-existing'));
- expect(wrapper).toMatchSnapshot();
- (wrapper
- .find('Select')
- .first()
- .prop('onChange') as Function)({ value: 'another' });
- wrapper.update();
- click(wrapper.find('[className="js-continue"]'));
- expect(onContinue).toBeCalledWith('another');
-});
-
-it('works with new organization', async () => {
- const onContinue = jest.fn();
- const wrapper = mount(
- <OrganizationStep
- currentUser={currentUser}
- finished={false}
- onContinue={onContinue}
- onOpen={jest.fn()}
- open={true}
- stepNumber={1}
- />
- );
- await waitAndUpdate(wrapper);
- click(wrapper.find('.js-new'));
- (wrapper.find('NewOrganizationForm').prop('onDone') as Function)('new');
- wrapper.update();
- click(wrapper.find('[className="js-continue"]'));
- expect(onContinue).toBeCalledWith('new');
-});
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { shallow } from 'enzyme';
-import Step from '../Step';
-import { click } from '../../../../helpers/testUtils';
-
-it('renders', () => {
- const wrapper = shallow(
- <Step
- finished={true}
- onOpen={jest.fn()}
- open={true}
- renderForm={() => <div>form</div>}
- renderResult={() => <div>result</div>}
- stepNumber={1}
- stepTitle="First Step"
- />
- );
- expect(wrapper).toMatchSnapshot();
- wrapper.setProps({ open: false });
- expect(wrapper).toMatchSnapshot();
-});
-
-it('re-opens', () => {
- const onOpen = jest.fn();
- const wrapper = shallow(
- <Step
- finished={true}
- onOpen={onOpen}
- open={false}
- renderForm={() => <div>form</div>}
- renderResult={() => <div>result</div>}
- stepNumber={1}
- stepTitle="First Step"
- />
- );
- click(wrapper);
- expect(onOpen).toBeCalled();
-});
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { mount } from 'enzyme';
-import TokenStep from '../TokenStep';
-import { change, click, submit, waitAndUpdate } from '../../../../helpers/testUtils';
-
-jest.mock('../../../../api/user-tokens', () => ({
- getTokens: () => Promise.resolve([{ name: 'foo' }]),
- generateToken: () => Promise.resolve({ token: 'abcd1234' }),
- revokeToken: () => Promise.resolve()
-}));
-
-jest.mock('../../../../components/icons-components/ClearIcon');
-
-const currentUser = { login: 'user' };
-
-it('generates token', async () => {
- const wrapper = mount(
- <TokenStep
- currentUser={currentUser}
- finished={false}
- onContinue={jest.fn()}
- onOpen={jest.fn()}
- open={true}
- stepNumber={1}
- />
- );
- await waitAndUpdate(wrapper);
- expect(wrapper).toMatchSnapshot();
- change(wrapper.find('input'), 'my token');
- submit(wrapper.find('form'));
- expect(wrapper).toMatchSnapshot(); // spinner
- await waitAndUpdate(wrapper);
- expect(wrapper).toMatchSnapshot();
-});
-
-it('revokes token', async () => {
- const wrapper = mount(
- <TokenStep
- currentUser={currentUser}
- finished={false}
- onContinue={jest.fn()}
- onOpen={jest.fn()}
- open={true}
- stepNumber={1}
- />
- );
- await new Promise(setImmediate);
- wrapper.setState({ token: 'abcd1234', tokenName: 'my token' });
- expect(wrapper).toMatchSnapshot();
- (wrapper.find('DeleteButton').prop('onClick') as Function)();
- wrapper.update();
- expect(wrapper).toMatchSnapshot(); // spinner
- await waitAndUpdate(wrapper);
- expect(wrapper).toMatchSnapshot();
-});
-
-it('continues', async () => {
- const onContinue = jest.fn();
- const wrapper = mount(
- <TokenStep
- currentUser={currentUser}
- finished={false}
- onContinue={onContinue}
- onOpen={jest.fn()}
- open={true}
- stepNumber={1}
- />
- );
- await new Promise(setImmediate);
- wrapper.setState({ token: 'abcd1234', tokenName: 'my token' });
- click(wrapper.find('[className="js-continue"]'));
- expect(onContinue).toBeCalledWith('abcd1234');
-});
-
-it('uses existing token', async () => {
- const onContinue = jest.fn();
- const wrapper = mount(
- <TokenStep
- currentUser={currentUser}
- finished={false}
- onContinue={onContinue}
- onOpen={jest.fn()}
- open={true}
- stepNumber={1}
- />
- );
- await new Promise(setImmediate);
- wrapper.setState({ existingToken: 'abcd1234', selection: 'use-existing' });
- click(wrapper.find('[className="js-continue"]'));
- expect(onContinue).toBeCalledWith('abcd1234');
-});
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`selects c# 1`] = `
-<div>
- <div>
- <h4
- className="spacer-bottom"
- >
- onboarding.language
- </h4>
- <RadioToggle
- disabled={false}
- name="language"
- onCheck={[Function]}
- options={
- Array [
- Object {
- "label": "onboarding.language.java",
- "value": "java",
- },
- Object {
- "label": "onboarding.language.dotnet",
- "value": "dotnet",
- },
- Object {
- "label": "onboarding.language.other",
- "value": "other",
- },
- ]
- }
- value="dotnet"
- />
- </div>
- <NewProjectForm
- onDelete={[Function]}
- onDone={[Function]}
- />
-</div>
-`;
-
-exports[`selects c-family 1`] = `
-<div>
- <div>
- <h4
- className="spacer-bottom"
- >
- onboarding.language
- </h4>
- <RadioToggle
- disabled={false}
- name="language"
- onCheck={[Function]}
- options={
- Array [
- Object {
- "label": "onboarding.language.java",
- "value": "java",
- },
- Object {
- "label": "onboarding.language.dotnet",
- "value": "dotnet",
- },
- Object {
- "label": "onboarding.language.c-family",
- "value": "c-family",
- },
- Object {
- "label": "onboarding.language.other",
- "value": "other",
- },
- ]
- }
- value="c-family"
- />
- </div>
- <div
- className="big-spacer-top"
- >
- <h4
- className="spacer-bottom"
- >
- onboarding.language.c-family.compiler
- </h4>
- <RadioToggle
- disabled={false}
- name="c-family-compiler"
- onCheck={[Function]}
- options={
- Array [
- Object {
- "label": "onboarding.language.c-family.compiler.msvc",
- "value": "msvc",
- },
- Object {
- "label": "onboarding.language.c-family.compiler.clang-gcc",
- "value": "clang-gcc",
- },
- ]
- }
- value={null}
- />
- </div>
-</div>
-`;
-
-exports[`selects c-family 2`] = `
-<div>
- <div>
- <h4
- className="spacer-bottom"
- >
- onboarding.language
- </h4>
- <RadioToggle
- disabled={false}
- name="language"
- onCheck={[Function]}
- options={
- Array [
- Object {
- "label": "onboarding.language.java",
- "value": "java",
- },
- Object {
- "label": "onboarding.language.dotnet",
- "value": "dotnet",
- },
- Object {
- "label": "onboarding.language.c-family",
- "value": "c-family",
- },
- Object {
- "label": "onboarding.language.other",
- "value": "other",
- },
- ]
- }
- value="c-family"
- />
- </div>
- <div
- className="big-spacer-top"
- >
- <h4
- className="spacer-bottom"
- >
- onboarding.language.c-family.compiler
- </h4>
- <RadioToggle
- disabled={false}
- name="c-family-compiler"
- onCheck={[Function]}
- options={
- Array [
- Object {
- "label": "onboarding.language.c-family.compiler.msvc",
- "value": "msvc",
- },
- Object {
- "label": "onboarding.language.c-family.compiler.clang-gcc",
- "value": "clang-gcc",
- },
- ]
- }
- value="msvc"
- />
- </div>
- <NewProjectForm
- onDelete={[Function]}
- onDone={[Function]}
- />
-</div>
-`;
-
-exports[`selects c-family 3`] = `
-<div>
- <div>
- <h4
- className="spacer-bottom"
- >
- onboarding.language
- </h4>
- <RadioToggle
- disabled={false}
- name="language"
- onCheck={[Function]}
- options={
- Array [
- Object {
- "label": "onboarding.language.java",
- "value": "java",
- },
- Object {
- "label": "onboarding.language.dotnet",
- "value": "dotnet",
- },
- Object {
- "label": "onboarding.language.c-family",
- "value": "c-family",
- },
- Object {
- "label": "onboarding.language.other",
- "value": "other",
- },
- ]
- }
- value="c-family"
- />
- </div>
- <div
- className="big-spacer-top"
- >
- <h4
- className="spacer-bottom"
- >
- onboarding.language.c-family.compiler
- </h4>
- <RadioToggle
- disabled={false}
- name="c-family-compiler"
- onCheck={[Function]}
- options={
- Array [
- Object {
- "label": "onboarding.language.c-family.compiler.msvc",
- "value": "msvc",
- },
- Object {
- "label": "onboarding.language.c-family.compiler.clang-gcc",
- "value": "clang-gcc",
- },
- ]
- }
- value="clang-gcc"
- />
- </div>
- <div
- className="big-spacer-top"
- >
- <h4
- className="spacer-bottom"
- >
- onboarding.language.os
- </h4>
- <RadioToggle
- disabled={false}
- name="os"
- onCheck={[Function]}
- options={
- Array [
- Object {
- "label": "onboarding.language.os.linux",
- "value": "linux",
- },
- Object {
- "label": "onboarding.language.os.win",
- "value": "win",
- },
- Object {
- "label": "onboarding.language.os.mac",
- "value": "mac",
- },
- ]
- }
- value={null}
- />
- </div>
-</div>
-`;
-
-exports[`selects c-family 4`] = `
-<div>
- <div>
- <h4
- className="spacer-bottom"
- >
- onboarding.language
- </h4>
- <RadioToggle
- disabled={false}
- name="language"
- onCheck={[Function]}
- options={
- Array [
- Object {
- "label": "onboarding.language.java",
- "value": "java",
- },
- Object {
- "label": "onboarding.language.dotnet",
- "value": "dotnet",
- },
- Object {
- "label": "onboarding.language.c-family",
- "value": "c-family",
- },
- Object {
- "label": "onboarding.language.other",
- "value": "other",
- },
- ]
- }
- value="c-family"
- />
- </div>
- <div
- className="big-spacer-top"
- >
- <h4
- className="spacer-bottom"
- >
- onboarding.language.c-family.compiler
- </h4>
- <RadioToggle
- disabled={false}
- name="c-family-compiler"
- onCheck={[Function]}
- options={
- Array [
- Object {
- "label": "onboarding.language.c-family.compiler.msvc",
- "value": "msvc",
- },
- Object {
- "label": "onboarding.language.c-family.compiler.clang-gcc",
- "value": "clang-gcc",
- },
- ]
- }
- value="clang-gcc"
- />
- </div>
- <div
- className="big-spacer-top"
- >
- <h4
- className="spacer-bottom"
- >
- onboarding.language.os
- </h4>
- <RadioToggle
- disabled={false}
- name="os"
- onCheck={[Function]}
- options={
- Array [
- Object {
- "label": "onboarding.language.os.linux",
- "value": "linux",
- },
- Object {
- "label": "onboarding.language.os.win",
- "value": "win",
- },
- Object {
- "label": "onboarding.language.os.mac",
- "value": "mac",
- },
- ]
- }
- value="linux"
- />
- </div>
- <NewProjectForm
- onDelete={[Function]}
- onDone={[Function]}
- projectKey="project-foo"
- />
-</div>
-`;
-
-exports[`selects java 1`] = `
-<div>
- <div>
- <h4
- className="spacer-bottom"
- >
- onboarding.language
- </h4>
- <RadioToggle
- disabled={false}
- name="language"
- onCheck={[Function]}
- options={
- Array [
- Object {
- "label": "onboarding.language.java",
- "value": "java",
- },
- Object {
- "label": "onboarding.language.dotnet",
- "value": "dotnet",
- },
- Object {
- "label": "onboarding.language.other",
- "value": "other",
- },
- ]
- }
- value="java"
- />
- </div>
- <div
- className="big-spacer-top"
- >
- <h4
- className="spacer-bottom"
- >
- onboarding.language.java.build_technology
- </h4>
- <RadioToggle
- disabled={false}
- name="java-build"
- onCheck={[Function]}
- options={
- Array [
- Object {
- "label": "onboarding.language.java.build_technology.maven",
- "value": "maven",
- },
- Object {
- "label": "onboarding.language.java.build_technology.gradle",
- "value": "gradle",
- },
- ]
- }
- value={null}
- />
- </div>
-</div>
-`;
-
-exports[`selects java 2`] = `
-<div>
- <div>
- <h4
- className="spacer-bottom"
- >
- onboarding.language
- </h4>
- <RadioToggle
- disabled={false}
- name="language"
- onCheck={[Function]}
- options={
- Array [
- Object {
- "label": "onboarding.language.java",
- "value": "java",
- },
- Object {
- "label": "onboarding.language.dotnet",
- "value": "dotnet",
- },
- Object {
- "label": "onboarding.language.other",
- "value": "other",
- },
- ]
- }
- value="java"
- />
- </div>
- <div
- className="big-spacer-top"
- >
- <h4
- className="spacer-bottom"
- >
- onboarding.language.java.build_technology
- </h4>
- <RadioToggle
- disabled={false}
- name="java-build"
- onCheck={[Function]}
- options={
- Array [
- Object {
- "label": "onboarding.language.java.build_technology.maven",
- "value": "maven",
- },
- Object {
- "label": "onboarding.language.java.build_technology.gradle",
- "value": "gradle",
- },
- ]
- }
- value="maven"
- />
- </div>
-</div>
-`;
-
-exports[`selects java 3`] = `
-<div>
- <div>
- <h4
- className="spacer-bottom"
- >
- onboarding.language
- </h4>
- <RadioToggle
- disabled={false}
- name="language"
- onCheck={[Function]}
- options={
- Array [
- Object {
- "label": "onboarding.language.java",
- "value": "java",
- },
- Object {
- "label": "onboarding.language.dotnet",
- "value": "dotnet",
- },
- Object {
- "label": "onboarding.language.other",
- "value": "other",
- },
- ]
- }
- value="java"
- />
- </div>
- <div
- className="big-spacer-top"
- >
- <h4
- className="spacer-bottom"
- >
- onboarding.language.java.build_technology
- </h4>
- <RadioToggle
- disabled={false}
- name="java-build"
- onCheck={[Function]}
- options={
- Array [
- Object {
- "label": "onboarding.language.java.build_technology.maven",
- "value": "maven",
- },
- Object {
- "label": "onboarding.language.java.build_technology.gradle",
- "value": "gradle",
- },
- ]
- }
- value="gradle"
- />
- </div>
-</div>
-`;
-
-exports[`selects other 1`] = `
-<div>
- <div>
- <h4
- className="spacer-bottom"
- >
- onboarding.language
- </h4>
- <RadioToggle
- disabled={false}
- name="language"
- onCheck={[Function]}
- options={
- Array [
- Object {
- "label": "onboarding.language.java",
- "value": "java",
- },
- Object {
- "label": "onboarding.language.dotnet",
- "value": "dotnet",
- },
- Object {
- "label": "onboarding.language.other",
- "value": "other",
- },
- ]
- }
- value="other"
- />
- </div>
- <div
- className="big-spacer-top"
- >
- <h4
- className="spacer-bottom"
- >
- onboarding.language.os
- </h4>
- <RadioToggle
- disabled={false}
- name="os"
- onCheck={[Function]}
- options={
- Array [
- Object {
- "label": "onboarding.language.os.linux",
- "value": "linux",
- },
- Object {
- "label": "onboarding.language.os.win",
- "value": "win",
- },
- Object {
- "label": "onboarding.language.os.mac",
- "value": "mac",
- },
- ]
- }
- value={null}
- />
- </div>
-</div>
-`;
-
-exports[`selects other 2`] = `
-<div>
- <div>
- <h4
- className="spacer-bottom"
- >
- onboarding.language
- </h4>
- <RadioToggle
- disabled={false}
- name="language"
- onCheck={[Function]}
- options={
- Array [
- Object {
- "label": "onboarding.language.java",
- "value": "java",
- },
- Object {
- "label": "onboarding.language.dotnet",
- "value": "dotnet",
- },
- Object {
- "label": "onboarding.language.other",
- "value": "other",
- },
- ]
- }
- value="other"
- />
- </div>
- <div
- className="big-spacer-top"
- >
- <h4
- className="spacer-bottom"
- >
- onboarding.language.os
- </h4>
- <RadioToggle
- disabled={false}
- name="os"
- onCheck={[Function]}
- options={
- Array [
- Object {
- "label": "onboarding.language.os.linux",
- "value": "linux",
- },
- Object {
- "label": "onboarding.language.os.win",
- "value": "win",
- },
- Object {
- "label": "onboarding.language.os.mac",
- "value": "mac",
- },
- ]
- }
- value="mac"
- />
- </div>
- <NewProjectForm
- onDelete={[Function]}
- onDone={[Function]}
- />
-</div>
-`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`creates new organization 1`] = `
-<NewOrganizationForm
- onDelete={[MockFunction]}
- onDone={[MockFunction]}
->
- <form
- onSubmit={[Function]}
- >
- <input
- autoFocus={true}
- className="input-super-large spacer-right text-middle"
- maxLength={32}
- minLength={2}
- onChange={[Function]}
- placeholder="onboarding.organization.placeholder"
- required={true}
- type="text"
- value=""
- />
- <SubmitButton
- className="text-middle"
- disabled={true}
- >
- <Button
- className="text-middle"
- disabled={true}
- preventDefault={false}
- type="submit"
- >
- <button
- className="button text-middle"
- disabled={true}
- onClick={[Function]}
- type="submit"
- >
- create
- </button>
- </Button>
- </SubmitButton>
- <div
- className="note spacer-top abs-width-300"
- >
- onboarding.organization.key_requirement
- </div>
- </form>
-</NewOrganizationForm>
-`;
-
-exports[`creates new organization 2`] = `
-<NewOrganizationForm
- onDelete={[MockFunction]}
- onDone={[MockFunction]}
->
- <form
- onSubmit={[Function]}
- >
- <input
- autoFocus={true}
- className="input-super-large spacer-right text-middle"
- maxLength={32}
- minLength={2}
- onChange={[Function]}
- placeholder="onboarding.organization.placeholder"
- required={true}
- type="text"
- value="foo"
- />
- <i
- className="spinner text-middle"
- />
- <div
- className="note spacer-top abs-width-300"
- >
- onboarding.organization.key_requirement
- </div>
- </form>
-</NewOrganizationForm>
-`;
-
-exports[`creates new organization 3`] = `
-<NewOrganizationForm
- onDelete={[MockFunction]}
- onDone={
- [MockFunction] {
- "calls": Array [
- Array [
- "foo",
- ],
- ],
- "results": Array [
- Object {
- "isThrow": false,
- "value": undefined,
- },
- ],
- }
- }
->
- <div>
- <span
- className="spacer-right text-middle"
- >
- foo
- </span>
- <DeleteButton
- className="button-small"
- onClick={[Function]}
- >
- <ButtonIcon
- className="button-small"
- color="#d4333f"
- onClick={[Function]}
- >
- <Button
- className="button-small button-icon"
- onClick={[Function]}
- stopPropagation={true}
- style={
- Object {
- "color": "#d4333f",
- }
- }
- >
- <button
- className="button button-small button-icon"
- onClick={[Function]}
- style={
- Object {
- "color": "#d4333f",
- }
- }
- type="button"
- >
- <ClearIcon />
- </button>
- </Button>
- </ButtonIcon>
- </DeleteButton>
- </div>
-</NewOrganizationForm>
-`;
-
-exports[`deletes organization 1`] = `
-<NewOrganizationForm
- onDelete={[MockFunction]}
- onDone={[MockFunction]}
->
- <div>
- <span
- className="spacer-right text-middle"
- >
- foo
- </span>
- <DeleteButton
- className="button-small"
- onClick={[Function]}
- >
- <ButtonIcon
- className="button-small"
- color="#d4333f"
- onClick={[Function]}
- >
- <Button
- className="button-small button-icon"
- onClick={[Function]}
- stopPropagation={true}
- style={
- Object {
- "color": "#d4333f",
- }
- }
- >
- <button
- className="button button-small button-icon"
- onClick={[Function]}
- style={
- Object {
- "color": "#d4333f",
- }
- }
- type="button"
- >
- <ClearIcon />
- </button>
- </Button>
- </ButtonIcon>
- </DeleteButton>
- </div>
-</NewOrganizationForm>
-`;
-
-exports[`deletes organization 2`] = `
-<NewOrganizationForm
- onDelete={[MockFunction]}
- onDone={[MockFunction]}
->
- <div>
- <span
- className="spacer-right text-middle"
- >
- foo
- </span>
- <i
- className="spinner text-middle"
- />
- </div>
-</NewOrganizationForm>
-`;
-
-exports[`deletes organization 3`] = `
-<NewOrganizationForm
- onDelete={
- [MockFunction] {
- "calls": Array [
- Array [],
- ],
- "results": Array [
- Object {
- "isThrow": false,
- "value": undefined,
- },
- ],
- }
- }
- onDone={[MockFunction]}
->
- <form
- onSubmit={[Function]}
- >
- <input
- autoFocus={true}
- className="input-super-large spacer-right text-middle"
- maxLength={32}
- minLength={2}
- onChange={[Function]}
- placeholder="onboarding.organization.placeholder"
- required={true}
- type="text"
- value=""
- />
- <SubmitButton
- className="text-middle"
- disabled={true}
- >
- <Button
- className="text-middle"
- disabled={true}
- preventDefault={false}
- type="submit"
- >
- <button
- className="button text-middle"
- disabled={true}
- onClick={[Function]}
- type="submit"
- >
- create
- </button>
- </Button>
- </SubmitButton>
- <div
- className="note spacer-top abs-width-300"
- >
- onboarding.organization.key_requirement
- </div>
- </form>
-</NewOrganizationForm>
-`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`creates new project 1`] = `
-<NewProjectForm
- onDelete={[MockFunction]}
- onDone={[MockFunction]}
->
- <div
- className="big-spacer-top"
- >
- <h4
- className="spacer-bottom"
- >
- onboarding.language.project_key
- </h4>
- <form
- onSubmit={[Function]}
- >
- <input
- autoFocus={true}
- className="input-large spacer-right text-middle"
- maxLength={400}
- minLength={1}
- onChange={[Function]}
- required={true}
- type="text"
- value=""
- />
- <SubmitButton
- className="text-middle"
- disabled={true}
- >
- <Button
- className="text-middle"
- disabled={true}
- preventDefault={false}
- type="submit"
- >
- <button
- className="button text-middle"
- disabled={true}
- onClick={[Function]}
- type="submit"
- >
- Done
- </button>
- </Button>
- </SubmitButton>
- <div
- className="note spacer-top abs-width-300"
- >
- onboarding.project_key_requirement
- </div>
- </form>
- </div>
-</NewProjectForm>
-`;
-
-exports[`creates new project 2`] = `
-<NewProjectForm
- onDelete={[MockFunction]}
- onDone={[MockFunction]}
->
- <div
- className="big-spacer-top"
- >
- <h4
- className="spacer-bottom"
- >
- onboarding.language.project_key
- </h4>
- <form
- onSubmit={[Function]}
- >
- <input
- autoFocus={true}
- className="input-large spacer-right text-middle"
- maxLength={400}
- minLength={1}
- onChange={[Function]}
- required={true}
- type="text"
- value="foo"
- />
- <i
- className="spinner text-middle"
- />
- <div
- className="note spacer-top abs-width-300"
- >
- onboarding.project_key_requirement
- </div>
- </form>
- </div>
-</NewProjectForm>
-`;
-
-exports[`creates new project 3`] = `
-<NewProjectForm
- onDelete={[MockFunction]}
- onDone={
- [MockFunction] {
- "calls": Array [
- Array [
- "foo",
- ],
- ],
- "results": Array [
- Object {
- "isThrow": false,
- "value": undefined,
- },
- ],
- }
- }
->
- <div
- className="big-spacer-top"
- >
- <h4
- className="spacer-bottom"
- >
- onboarding.language.project_key
- </h4>
- <div>
- <span
- className="spacer-right text-middle"
- >
- foo
- </span>
- <DeleteButton
- className="button-small text-middle"
- onClick={[Function]}
- >
- <ButtonIcon
- className="button-small text-middle"
- color="#d4333f"
- onClick={[Function]}
- >
- <Button
- className="button-small text-middle button-icon"
- onClick={[Function]}
- stopPropagation={true}
- style={
- Object {
- "color": "#d4333f",
- }
- }
- >
- <button
- className="button button-small text-middle button-icon"
- onClick={[Function]}
- style={
- Object {
- "color": "#d4333f",
- }
- }
- type="button"
- >
- <ClearIcon />
- </button>
- </Button>
- </ButtonIcon>
- </DeleteButton>
- </div>
- </div>
-</NewProjectForm>
-`;
-
-exports[`deletes project 1`] = `
-<NewProjectForm
- onDelete={[MockFunction]}
- onDone={[MockFunction]}
->
- <div
- className="big-spacer-top"
- >
- <h4
- className="spacer-bottom"
- >
- onboarding.language.project_key
- </h4>
- <div>
- <span
- className="spacer-right text-middle"
- >
- foo
- </span>
- <DeleteButton
- className="button-small text-middle"
- onClick={[Function]}
- >
- <ButtonIcon
- className="button-small text-middle"
- color="#d4333f"
- onClick={[Function]}
- >
- <Button
- className="button-small text-middle button-icon"
- onClick={[Function]}
- stopPropagation={true}
- style={
- Object {
- "color": "#d4333f",
- }
- }
- >
- <button
- className="button button-small text-middle button-icon"
- onClick={[Function]}
- style={
- Object {
- "color": "#d4333f",
- }
- }
- type="button"
- >
- <ClearIcon />
- </button>
- </Button>
- </ButtonIcon>
- </DeleteButton>
- </div>
- </div>
-</NewProjectForm>
-`;
-
-exports[`deletes project 2`] = `
-<NewProjectForm
- onDelete={[MockFunction]}
- onDone={[MockFunction]}
->
- <div
- className="big-spacer-top"
- >
- <h4
- className="spacer-bottom"
- >
- onboarding.language.project_key
- </h4>
- <div>
- <span
- className="spacer-right text-middle"
- >
- foo
- </span>
- <i
- className="spinner text-middle"
- />
- </div>
- </div>
-</NewProjectForm>
-`;
-
-exports[`deletes project 3`] = `
-<NewProjectForm
- onDelete={
- [MockFunction] {
- "calls": Array [
- Array [],
- ],
- "results": Array [
- Object {
- "isThrow": false,
- "value": undefined,
- },
- ],
- }
- }
- onDone={[MockFunction]}
->
- <div
- className="big-spacer-top"
- >
- <h4
- className="spacer-bottom"
- >
- onboarding.language.project_key
- </h4>
- <form
- onSubmit={[Function]}
- >
- <input
- autoFocus={true}
- className="input-large spacer-right text-middle"
- maxLength={400}
- minLength={1}
- onChange={[Function]}
- required={true}
- type="text"
- value=""
- />
- <SubmitButton
- className="text-middle"
- disabled={true}
- >
- <Button
- className="text-middle"
- disabled={true}
- preventDefault={false}
- type="submit"
- >
- <button
- className="button text-middle"
- disabled={true}
- onClick={[Function]}
- type="submit"
- >
- Done
- </button>
- </Button>
- </SubmitButton>
- <div
- className="note spacer-top abs-width-300"
- >
- onboarding.project_key_requirement
- </div>
- </form>
- </div>
-</NewProjectForm>
-`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`works with existing organization 1`] = `
-<OrganizationStep
- currentUser={
- Object {
- "isLoggedIn": true,
- "login": "user",
- }
- }
- finished={false}
- onContinue={[MockFunction]}
- onOpen={[MockFunction]}
- open={true}
- stepNumber={1}
->
- <Step
- finished={false}
- onOpen={[MockFunction]}
- open={true}
- renderForm={[Function]}
- renderResult={[Function]}
- stepNumber={1}
- stepTitle={
- <span>
- onboarding.organization.header
- <DocTooltip
- className="little-spacer-left"
- doc={Promise {}}
- />
- </span>
- }
- >
- <div
- className="boxed-group onboarding-step is-open"
- >
- <div
- className="onboarding-step-number"
- >
- 1
- </div>
- <div
- className="boxed-group-header"
- >
- <h2>
- <span>
- onboarding.organization.header
- <DocTooltip
- className="little-spacer-left"
- doc={Promise {}}
- />
- </span>
- </h2>
- </div>
- <div
- className="boxed-group-inner"
- >
- <div
- className="big-spacer-bottom width-50"
- >
- onboarding.organization.text
- </div>
- <div>
- <div
- className="big-spacer-top"
- >
- <a
- className="js-existing link-base-color link-no-underline"
- href="#"
- onClick={[Function]}
- >
- <i
- className="icon-radio spacer-right is-checked"
- />
- onboarding.organization.exising_organization
- </a>
- <div
- className="big-spacer-top"
- >
- <Select
- className="input-super-large"
- clearable={false}
- onChange={[Function]}
- options={
- Array [
- Object {
- "label": "another",
- "value": "another",
- },
- Object {
- "label": "user",
- "value": "user",
- },
- ]
- }
- >
- <LazyLoader
- className="input-super-large"
- clearRenderer={[Function]}
- clearable={false}
- onChange={[Function]}
- options={
- Array [
- Object {
- "label": "another",
- "value": "another",
- },
- Object {
- "label": "user",
- "value": "user",
- },
- ]
- }
- >
- <Select
- arrowRenderer={[Function]}
- autosize={true}
- backspaceRemoves={true}
- backspaceToRemoveMessage="Press backspace to remove {label}"
- className="input-super-large"
- clearAllText="Clear all"
- clearRenderer={[Function]}
- clearValueText="Clear value"
- clearable={false}
- closeOnSelect={true}
- deleteRemoves={true}
- delimiter=","
- disabled={false}
- escapeClearsValue={true}
- filterOptions={[Function]}
- ignoreAccents={true}
- ignoreCase={true}
- inputProps={Object {}}
- isLoading={false}
- joinValues={false}
- labelKey="label"
- matchPos="any"
- matchProp="any"
- menuBuffer={0}
- menuRenderer={[Function]}
- multi={false}
- noResultsText="No results found"
- onBlurResetsInput={true}
- onChange={[Function]}
- onCloseResetsInput={true}
- onSelectResetsInput={true}
- openOnClick={true}
- optionComponent={[Function]}
- options={
- Array [
- Object {
- "label": "another",
- "value": "another",
- },
- Object {
- "label": "user",
- "value": "user",
- },
- ]
- }
- pageSize={5}
- placeholder="Select..."
- removeSelected={true}
- required={false}
- rtl={false}
- scrollMenuIntoView={true}
- searchable={true}
- simpleValue={false}
- tabSelectsValue={true}
- trimFilter={true}
- valueComponent={[Function]}
- valueKey="value"
- >
- <div
- className="Select input-super-large is-searchable Select--single"
- >
- <div
- className="Select-control"
- onKeyDown={[Function]}
- onMouseDown={[Function]}
- onTouchEnd={[Function]}
- onTouchMove={[Function]}
- onTouchStart={[Function]}
- >
- <span
- className="Select-multi-value-wrapper"
- id="react-select-2--value"
- >
- <div
- className="Select-placeholder"
- >
- Select...
- </div>
- <AutosizeInput
- aria-activedescendant="react-select-2--value"
- aria-expanded="false"
- aria-haspopup="false"
- aria-owns=""
- className="Select-input"
- injectStyles={true}
- minWidth="5"
- onBlur={[Function]}
- onChange={[Function]}
- onFocus={[Function]}
- required={false}
- role="combobox"
- value=""
- >
- <div
- className="Select-input"
- style={
- Object {
- "display": "inline-block",
- }
- }
- >
- <input
- aria-activedescendant="react-select-2--value"
- aria-expanded="false"
- aria-haspopup="false"
- aria-owns=""
- onBlur={[Function]}
- onChange={[Function]}
- onFocus={[Function]}
- required={false}
- role="combobox"
- style={
- Object {
- "boxSizing": "content-box",
- "width": "5px",
- }
- }
- value=""
- />
- <div
- style={
- Object {
- "height": 0,
- "left": 0,
- "overflow": "scroll",
- "position": "absolute",
- "top": 0,
- "visibility": "hidden",
- "whiteSpace": "pre",
- }
- }
- />
- </div>
- </AutosizeInput>
- </span>
- <span
- className="Select-arrow-zone"
- onMouseDown={[Function]}
- >
- <span
- className="Select-arrow"
- onMouseDown={[Function]}
- />
- </span>
- </div>
- </div>
- </Select>
- </LazyLoader>
- </Select>
- </div>
- </div>
- <div
- className="big-spacer-top"
- >
- <a
- className="js-new link-base-color link-no-underline"
- href="#"
- onClick={[Function]}
- >
- <i
- className="icon-radio spacer-right"
- />
- onboarding.organization.create_another_organization
- </a>
- </div>
- </div>
- </div>
- </div>
- </Step>
-</OrganizationStep>
-`;
open={true}
stepNumber={1}
/>
- <AnalysisStep
+ <ProjectAnalysisStep
onFinish={[Function]}
onReset={[Function]}
open={false}
open={false}
stepNumber={1}
/>
- <AnalysisStep
+ <ProjectAnalysisStep
onFinish={[Function]}
onReset={[Function]}
open={true}
open={false}
stepNumber={2}
/>
- <AnalysisStep
+ <ProjectAnalysisStep
onFinish={[Function]}
onReset={[Function]}
open={false}
open={true}
stepNumber={2}
/>
- <AnalysisStep
+ <ProjectAnalysisStep
onFinish={[Function]}
onReset={[Function]}
open={false}
open={false}
stepNumber={2}
/>
- <AnalysisStep
+ <ProjectAnalysisStep
onFinish={[Function]}
onReset={[Function]}
open={true}
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`renders 1`] = `
-<div
- className="boxed-group onboarding-step is-open is-finished"
->
- <div
- className="onboarding-step-number"
- >
- 1
- </div>
- <div
- className="boxed-group-header"
- >
- <h2>
- First Step
- </h2>
- </div>
- <div>
- form
- </div>
-</div>
-`;
-
-exports[`renders 2`] = `
-<div
- className="boxed-group onboarding-step is-finished"
- onClick={[Function]}
- role="button"
- tabIndex={0}
->
- <div
- className="onboarding-step-number"
- >
- 1
- </div>
- <div>
- result
- </div>
- <div
- className="boxed-group-header"
- >
- <h2>
- First Step
- </h2>
- </div>
- <div
- className="boxed-group-inner"
- />
-</div>
-`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`generates token 1`] = `
-<TokenStep
- currentUser={
- Object {
- "login": "user",
- }
- }
- finished={false}
- onContinue={[MockFunction]}
- onOpen={[MockFunction]}
- open={true}
- stepNumber={1}
->
- <Step
- finished={false}
- onOpen={[MockFunction]}
- open={true}
- renderForm={[Function]}
- renderResult={[Function]}
- stepNumber={1}
- stepTitle="onboarding.token.header"
- >
- <div
- className="boxed-group onboarding-step is-open"
- >
- <div
- className="onboarding-step-number"
- >
- 1
- </div>
- <div
- className="boxed-group-header"
- >
- <h2>
- onboarding.token.header
- </h2>
- </div>
- <div
- className="boxed-group-inner"
- >
- <div>
- <div>
- <a
- className="js-new link-base-color link-no-underline"
- href="#"
- onClick={[Function]}
- >
- <i
- className="icon-radio spacer-right is-checked"
- />
- onboarding.token.generate_token
- </a>
- <div
- className="big-spacer-top"
- >
- <form
- onSubmit={[Function]}
- >
- <input
- autoFocus={true}
- className="input-large spacer-right text-middle"
- onChange={[Function]}
- placeholder="onboarding.token.generate_token.placeholder"
- required={true}
- type="text"
- value=""
- />
- <SubmitButton
- className="text-middle"
- disabled={true}
- >
- <Button
- className="text-middle"
- disabled={true}
- preventDefault={false}
- type="submit"
- >
- <button
- className="button text-middle"
- disabled={true}
- onClick={[Function]}
- type="submit"
- >
- onboarding.token.generate
- </button>
- </Button>
- </SubmitButton>
- </form>
- </div>
- </div>
- <div
- className="big-spacer-top"
- >
- <a
- className="js-new link-base-color link-no-underline"
- href="#"
- onClick={[Function]}
- >
- <i
- className="icon-radio spacer-right"
- />
- onboarding.token.use_existing_token
- </a>
- </div>
- </div>
- <div
- className="note big-spacer-top width-50"
- >
- onboarding.token.text
- </div>
- </div>
- </div>
- </Step>
-</TokenStep>
-`;
-
-exports[`generates token 2`] = `
-<TokenStep
- currentUser={
- Object {
- "login": "user",
- }
- }
- finished={false}
- onContinue={[MockFunction]}
- onOpen={[MockFunction]}
- open={true}
- stepNumber={1}
->
- <Step
- finished={false}
- onOpen={[MockFunction]}
- open={true}
- renderForm={[Function]}
- renderResult={[Function]}
- stepNumber={1}
- stepTitle="onboarding.token.header"
- >
- <div
- className="boxed-group onboarding-step is-open"
- >
- <div
- className="onboarding-step-number"
- >
- 1
- </div>
- <div
- className="boxed-group-header"
- >
- <h2>
- onboarding.token.header
- </h2>
- </div>
- <div
- className="boxed-group-inner"
- >
- <div>
- <div>
- <a
- className="js-new link-base-color link-no-underline"
- href="#"
- onClick={[Function]}
- >
- <i
- className="icon-radio spacer-right is-checked"
- />
- onboarding.token.generate_token
- </a>
- <div
- className="big-spacer-top"
- >
- <form
- onSubmit={[Function]}
- >
- <input
- autoFocus={true}
- className="input-large spacer-right text-middle"
- onChange={[Function]}
- placeholder="onboarding.token.generate_token.placeholder"
- required={true}
- type="text"
- value="my token"
- />
- <i
- className="spinner text-middle"
- />
- </form>
- </div>
- </div>
- <div
- className="big-spacer-top"
- >
- <a
- className="js-new link-base-color link-no-underline"
- href="#"
- onClick={[Function]}
- >
- <i
- className="icon-radio spacer-right"
- />
- onboarding.token.use_existing_token
- </a>
- </div>
- </div>
- <div
- className="note big-spacer-top width-50"
- >
- onboarding.token.text
- </div>
- </div>
- </div>
- </Step>
-</TokenStep>
-`;
-
-exports[`generates token 3`] = `
-<TokenStep
- currentUser={
- Object {
- "login": "user",
- }
- }
- finished={false}
- onContinue={[MockFunction]}
- onOpen={[MockFunction]}
- open={true}
- stepNumber={1}
->
- <Step
- finished={false}
- onOpen={[MockFunction]}
- open={true}
- renderForm={[Function]}
- renderResult={[Function]}
- stepNumber={1}
- stepTitle="onboarding.token.header"
- >
- <div
- className="boxed-group onboarding-step is-open"
- >
- <div
- className="onboarding-step-number"
- >
- 1
- </div>
- <div
- className="boxed-group-header"
- >
- <h2>
- onboarding.token.header
- </h2>
- </div>
- <div
- className="boxed-group-inner"
- >
- <form
- onSubmit={[Function]}
- >
- <span
- className="text-middle"
- >
- my token
- :
- </span>
- <strong
- className="spacer-right text-middle"
- >
- abcd1234
- </strong>
- <DeleteButton
- className="button-small text-middle"
- onClick={[Function]}
- >
- <ButtonIcon
- className="button-small text-middle"
- color="#d4333f"
- onClick={[Function]}
- >
- <Button
- className="button-small text-middle button-icon"
- onClick={[Function]}
- stopPropagation={true}
- style={
- Object {
- "color": "#d4333f",
- }
- }
- >
- <button
- className="button button-small text-middle button-icon"
- onClick={[Function]}
- style={
- Object {
- "color": "#d4333f",
- }
- }
- type="button"
- >
- <ClearIcon />
- </button>
- </Button>
- </ButtonIcon>
- </DeleteButton>
- </form>
- <div
- className="note big-spacer-top width-50"
- >
- onboarding.token.text
- </div>
- <div
- className="big-spacer-top"
- >
- <Button
- className="js-continue"
- onClick={[Function]}
- >
- <button
- className="button js-continue"
- onClick={[Function]}
- type="button"
- >
- continue
- </button>
- </Button>
- </div>
- </div>
- </div>
- </Step>
-</TokenStep>
-`;
-
-exports[`revokes token 1`] = `
-<TokenStep
- currentUser={
- Object {
- "login": "user",
- }
- }
- finished={false}
- onContinue={[MockFunction]}
- onOpen={[MockFunction]}
- open={true}
- stepNumber={1}
->
- <Step
- finished={false}
- onOpen={[MockFunction]}
- open={true}
- renderForm={[Function]}
- renderResult={[Function]}
- stepNumber={1}
- stepTitle="onboarding.token.header"
- >
- <div
- className="boxed-group onboarding-step is-open"
- >
- <div
- className="onboarding-step-number"
- >
- 1
- </div>
- <div
- className="boxed-group-header"
- >
- <h2>
- onboarding.token.header
- </h2>
- </div>
- <div
- className="boxed-group-inner"
- >
- <form
- onSubmit={[Function]}
- >
- <span
- className="text-middle"
- >
- my token
- :
- </span>
- <strong
- className="spacer-right text-middle"
- >
- abcd1234
- </strong>
- <DeleteButton
- className="button-small text-middle"
- onClick={[Function]}
- >
- <ButtonIcon
- className="button-small text-middle"
- color="#d4333f"
- onClick={[Function]}
- >
- <Button
- className="button-small text-middle button-icon"
- onClick={[Function]}
- stopPropagation={true}
- style={
- Object {
- "color": "#d4333f",
- }
- }
- >
- <button
- className="button button-small text-middle button-icon"
- onClick={[Function]}
- style={
- Object {
- "color": "#d4333f",
- }
- }
- type="button"
- >
- <ClearIcon />
- </button>
- </Button>
- </ButtonIcon>
- </DeleteButton>
- </form>
- <div
- className="note big-spacer-top width-50"
- >
- onboarding.token.text
- </div>
- <div
- className="big-spacer-top"
- >
- <Button
- className="js-continue"
- onClick={[Function]}
- >
- <button
- className="button js-continue"
- onClick={[Function]}
- type="button"
- >
- continue
- </button>
- </Button>
- </div>
- </div>
- </div>
- </Step>
-</TokenStep>
-`;
-
-exports[`revokes token 2`] = `
-<TokenStep
- currentUser={
- Object {
- "login": "user",
- }
- }
- finished={false}
- onContinue={[MockFunction]}
- onOpen={[MockFunction]}
- open={true}
- stepNumber={1}
->
- <Step
- finished={false}
- onOpen={[MockFunction]}
- open={true}
- renderForm={[Function]}
- renderResult={[Function]}
- stepNumber={1}
- stepTitle="onboarding.token.header"
- >
- <div
- className="boxed-group onboarding-step is-open"
- >
- <div
- className="onboarding-step-number"
- >
- 1
- </div>
- <div
- className="boxed-group-header"
- >
- <h2>
- onboarding.token.header
- </h2>
- </div>
- <div
- className="boxed-group-inner"
- >
- <form
- onSubmit={[Function]}
- >
- <span
- className="text-middle"
- >
- my token
- :
- </span>
- <strong
- className="spacer-right text-middle"
- >
- abcd1234
- </strong>
- <i
- className="spinner text-middle"
- />
- </form>
- <div
- className="note big-spacer-top width-50"
- >
- onboarding.token.text
- </div>
- <div
- className="big-spacer-top"
- >
- <Button
- className="js-continue"
- onClick={[Function]}
- >
- <button
- className="button js-continue"
- onClick={[Function]}
- type="button"
- >
- continue
- </button>
- </Button>
- </div>
- </div>
- </div>
- </Step>
-</TokenStep>
-`;
-
-exports[`revokes token 3`] = `
-<TokenStep
- currentUser={
- Object {
- "login": "user",
- }
- }
- finished={false}
- onContinue={[MockFunction]}
- onOpen={[MockFunction]}
- open={true}
- stepNumber={1}
->
- <Step
- finished={false}
- onOpen={[MockFunction]}
- open={true}
- renderForm={[Function]}
- renderResult={[Function]}
- stepNumber={1}
- stepTitle="onboarding.token.header"
- >
- <div
- className="boxed-group onboarding-step is-open"
- >
- <div
- className="onboarding-step-number"
- >
- 1
- </div>
- <div
- className="boxed-group-header"
- >
- <h2>
- onboarding.token.header
- </h2>
- </div>
- <div
- className="boxed-group-inner"
- >
- <div>
- <div>
- <a
- className="js-new link-base-color link-no-underline"
- href="#"
- onClick={[Function]}
- >
- <i
- className="icon-radio spacer-right is-checked"
- />
- onboarding.token.generate_token
- </a>
- <div
- className="big-spacer-top"
- >
- <form
- onSubmit={[Function]}
- >
- <input
- autoFocus={true}
- className="input-large spacer-right text-middle"
- onChange={[Function]}
- placeholder="onboarding.token.generate_token.placeholder"
- required={true}
- type="text"
- value=""
- />
- <SubmitButton
- className="text-middle"
- disabled={true}
- >
- <Button
- className="text-middle"
- disabled={true}
- preventDefault={false}
- type="submit"
- >
- <button
- className="button text-middle"
- disabled={true}
- onClick={[Function]}
- type="submit"
- >
- onboarding.token.generate
- </button>
- </Button>
- </SubmitButton>
- </form>
- </div>
- </div>
- <div
- className="big-spacer-top"
- >
- <a
- className="js-new link-base-color link-no-underline"
- href="#"
- onClick={[Function]}
- >
- <i
- className="icon-radio spacer-right"
- />
- onboarding.token.use_existing_token
- </a>
- </div>
- </div>
- <div
- className="note big-spacer-top width-50"
- >
- onboarding.token.text
- </div>
- </div>
- </div>
- </Step>
-</TokenStep>
-`;
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { translate } from '../../../../helpers/l10n';
-import { getBaseUrl } from '../../../../helpers/urls';
-
-interface Props {
- className?: string;
- os: string;
-}
-
-const filenames: { [key: string]: string } = {
- win: 'build-wrapper-win-x86.zip',
- linux: 'build-wrapper-linux-x86.zip',
- mac: 'build-wrapper-macosx-x86.zip'
-};
-
-export default function BuildWrapper(props: Props) {
- return (
- <div className={props.className}>
- <h4 className="spacer-bottom">
- {translate('onboarding.analysis.build_wrapper.header', props.os)}
- </h4>
- <p
- className="spacer-bottom markdown"
- dangerouslySetInnerHTML={{
- __html: translate('onboarding.analysis.build_wrapper.text', props.os)
- }}
- />
- <p>
- <a
- className="button"
- download={filenames[props.os]}
- href={`${getBaseUrl()}/static/cpp/${filenames[props.os]}`}
- target="_blank">
- {translate('download_verb')}
- </a>
- </p>
- </div>
- );
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import SQScanner from './SQScanner';
-import BuildWrapper from './BuildWrapper';
-import CodeSnippet from '../../../../components/common/CodeSnippet';
-import InstanceMessage from '../../../../components/common/InstanceMessage';
-import { translate } from '../../../../helpers/l10n';
-
-interface Props {
- host: string;
- os: string;
- organization?: string;
- projectKey: string;
- token: string;
-}
-
-const executables: { [key: string]: string } = {
- linux: 'build-wrapper-linux-x86-64',
- win: 'build-wrapper-win-x86-64.exe',
- mac: 'build-wrapper-macosx-x86'
-};
-
-export default function ClangGCC(props: Props) {
- const command1 = `${executables[props.os]} --out-dir bw-output make clean all`;
-
- const command2 = [
- props.os === 'win' ? 'sonar-scanner.bat' : 'sonar-scanner',
- `-Dsonar.projectKey=${props.projectKey}`,
- props.organization && `-Dsonar.organization=${props.organization}`,
- '-Dsonar.sources=.',
- '-Dsonar.cfamily.build-wrapper-output=bw-output',
- `-Dsonar.host.url=${props.host}`,
- `-Dsonar.login=${props.token}`
- ];
-
- return (
- <div>
- <SQScanner os={props.os} />
- <BuildWrapper className="huge-spacer-top" os={props.os} />
-
- <h4 className="huge-spacer-top spacer-bottom">
- {translate('onboarding.analysis.sq_scanner.execute')}
- </h4>
- <InstanceMessage message={translate('onboarding.analysis.sq_scanner.execute.text')}>
- {transformedMessage => (
- <p
- className="spacer-bottom markdown"
- dangerouslySetInnerHTML={{ __html: transformedMessage }}
- />
- )}
- </InstanceMessage>
- <CodeSnippet isOneLine={true} snippet={command1} />
- <CodeSnippet isOneLine={props.os === 'win'} snippet={command2} />
- <p
- className="big-spacer-top markdown"
- dangerouslySetInnerHTML={{ __html: translate('onboarding.analysis.sq_scanner.docs') }}
- />
- </div>
- );
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import MSBuildScanner from './MSBuildScanner';
-import CodeSnippet from '../../../../components/common/CodeSnippet';
-import InstanceMessage from '../../../../components/common/InstanceMessage';
-import { translate } from '../../../../helpers/l10n';
-
-interface Props {
- host: string;
- organization?: string;
- projectKey: string;
- token: string;
-}
-
-export default function DotNet(props: Props) {
- const command1 = [
- 'SonarScanner.MSBuild.exe begin',
- `/k:"${props.projectKey}"`,
- props.organization && `/d:sonar.organization="${props.organization}"`,
- `/d:sonar.host.url="${props.host}"`,
- `/d:sonar.login="${props.token}"`
- ];
-
- const command2 = 'MsBuild.exe /t:Rebuild';
-
- const command3 = ['SonarScanner.MSBuild.exe end', `/d:sonar.login="${props.token}"`];
-
- return (
- <div>
- <MSBuildScanner />
-
- <h4 className="huge-spacer-top spacer-bottom">
- {translate('onboarding.analysis.msbuild.execute')}
- </h4>
- <InstanceMessage message={translate('onboarding.analysis.msbuild.execute.text')}>
- {transformedMessage => (
- <p
- className="spacer-bottom markdown"
- dangerouslySetInnerHTML={{ __html: transformedMessage }}
- />
- )}
- </InstanceMessage>
- <CodeSnippet isOneLine={true} snippet={command1} />
- <CodeSnippet isOneLine={true} snippet={command2} />
- <CodeSnippet isOneLine={true} snippet={command3} />
- <p
- className="big-spacer-top markdown"
- dangerouslySetInnerHTML={{ __html: translate('onboarding.analysis.msbuild.docs') }}
- />
- </div>
- );
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import CodeSnippet from '../../../../components/common/CodeSnippet';
-import InstanceMessage from '../../../../components/common/InstanceMessage';
-import { translate } from '../../../../helpers/l10n';
-
-interface Props {
- host: string;
- organization?: string;
- token: string;
-}
-
-export default function JavaGradle(props: Props) {
- const config = 'plugins {\n id "org.sonarqube" version "2.6"\n}';
-
- const command = [
- './gradlew sonarqube',
- props.organization && `-Dsonar.organization=${props.organization}`,
- `-Dsonar.host.url=${props.host}`,
- `-Dsonar.login=${props.token}`
- ];
-
- return (
- <div>
- <h4 className="spacer-bottom">{translate('onboarding.analysis.java.gradle.header')}</h4>
- <InstanceMessage message={translate('onboarding.analysis.java.gradle.text.1')}>
- {transformedMessage => (
- <p
- className="spacer-bottom markdown"
- dangerouslySetInnerHTML={{ __html: transformedMessage }}
- />
- )}
- </InstanceMessage>
- <CodeSnippet snippet={config} />
- <p className="spacer-top spacer-bottom markdown">
- {translate('onboarding.analysis.java.gradle.text.2')}
- </p>
- <CodeSnippet snippet={command} />
- <p
- className="big-spacer-top markdown"
- dangerouslySetInnerHTML={{ __html: translate('onboarding.analysis.java.gradle.docs') }}
- />
- <p
- className="big-spacer-top markdown"
- dangerouslySetInnerHTML={{
- __html: translate('onboarding.analysis.browse_url_after_analysis')
- }}
- />
- </div>
- );
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import CodeSnippet from '../../../../components/common/CodeSnippet';
-import InstanceMessage from '../../../../components/common/InstanceMessage';
-import { translate } from '../../../../helpers/l10n';
-
-interface Props {
- host: string;
- organization?: string;
- token: string;
-}
-
-export default function JavaMaven(props: Props) {
- const command = [
- 'mvn sonar:sonar',
- props.organization && `-Dsonar.organization=${props.organization}`,
- `-Dsonar.host.url=${props.host}`,
- `-Dsonar.login=${props.token}`
- ];
-
- return (
- <div>
- <h4 className="spacer-bottom">{translate('onboarding.analysis.java.maven.header')}</h4>
- <p className="spacer-bottom markdown">
- <InstanceMessage message={translate('onboarding.analysis.java.maven.text')} />
- </p>
- <CodeSnippet snippet={command} />
- <p
- className="big-spacer-top markdown"
- dangerouslySetInnerHTML={{ __html: translate('onboarding.analysis.java.maven.docs') }}
- />
- <p
- className="big-spacer-top markdown"
- dangerouslySetInnerHTML={{
- __html: translate('onboarding.analysis.browse_url_after_analysis')
- }}
- />
- </div>
- );
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { translate } from '../../../../helpers/l10n';
-
-interface Props {
- className?: string;
-}
-
-export default function MSBuildScanner(props: Props) {
- return (
- <div className={props.className}>
- <h4 className="spacer-bottom">{translate('onboarding.analysis.msbuild.header')}</h4>
- <p
- className="spacer-bottom markdown"
- dangerouslySetInnerHTML={{ __html: translate('onboarding.analysis.msbuild.text') }}
- />
- <p>
- <a
- className="button"
- href="http://redirect.sonarsource.com/doc/install-configure-scanner-msbuild.html"
- rel="noopener noreferrer"
- target="_blank">
- {translate('download_verb')}
- </a>
- </p>
- </div>
- );
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import MSBuildScanner from './MSBuildScanner';
-import BuildWrapper from './BuildWrapper';
-import CodeSnippet from '../../../../components/common/CodeSnippet';
-import InstanceMessage from '../../../../components/common/InstanceMessage';
-import { translate } from '../../../../helpers/l10n';
-
-interface Props {
- host: string;
- organization?: string;
- projectKey: string;
- token: string;
-}
-
-export default function Msvc(props: Props) {
- const command1 = [
- 'SonarQube.Scanner.MSBuild.exe begin',
- `/k:"${props.projectKey}"`,
- props.organization && `/d:sonar.organization="${props.organization}"`,
- '/d:sonar.cfamily.build-wrapper-output=bw-output',
- `/d:sonar.host.url="${props.host}"`,
- `/d:sonar.login="${props.token}"`
- ];
-
- const command2 = 'build-wrapper-win-x86-64.exe --out-dir bw-output MsBuild.exe /t:Rebuild';
-
- const command3 = ['SonarQube.Scanner.MSBuild.exe end', `/d:sonar.login="${props.token}"`];
-
- return (
- <div>
- <MSBuildScanner />
- <BuildWrapper className="huge-spacer-top" os="win" />
-
- <h4 className="huge-spacer-top spacer-bottom">
- {translate('onboarding.analysis.msbuild.execute')}
- </h4>
- <InstanceMessage message={translate('onboarding.analysis.msbuild.execute.text')}>
- {transformedMessage => (
- <p
- className="spacer-bottom markdown"
- dangerouslySetInnerHTML={{ __html: transformedMessage }}
- />
- )}
- </InstanceMessage>
- <CodeSnippet isOneLine={true} snippet={command1} />
- <CodeSnippet isOneLine={true} snippet={command2} />
- <CodeSnippet isOneLine={true} snippet={command3} />
- <p
- className="big-spacer-top markdown"
- dangerouslySetInnerHTML={{ __html: translate('onboarding.analysis.msbuild.docs') }}
- />
- </div>
- );
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import SQScanner from './SQScanner';
-import CodeSnippet from '../../../../components/common/CodeSnippet';
-import InstanceMessage from '../../../../components/common/InstanceMessage';
-import { translate } from '../../../../helpers/l10n';
-
-interface Props {
- host: string;
- organization?: string;
- os: string;
- projectKey: string;
- token: string;
-}
-
-export default function Other(props: Props) {
- const command = [
- props.os === 'win' ? 'sonar-scanner.bat' : 'sonar-scanner',
- `-Dsonar.projectKey=${props.projectKey}`,
- props.organization && `-Dsonar.organization=${props.organization}`,
- '-Dsonar.sources=.',
- `-Dsonar.host.url=${props.host}`,
- `-Dsonar.login=${props.token}`
- ];
-
- return (
- <div>
- <SQScanner os={props.os} />
-
- <h4 className="huge-spacer-top spacer-bottom">
- {translate('onboarding.analysis.sq_scanner.execute')}
- </h4>
- <InstanceMessage message={translate('onboarding.analysis.sq_scanner.execute.text')}>
- {transformedMessage => (
- <p
- className="spacer-bottom markdown"
- dangerouslySetInnerHTML={{ __html: transformedMessage }}
- />
- )}
- </InstanceMessage>
- <CodeSnippet isOneLine={props.os === 'win'} snippet={command} />
- <p
- className="big-spacer-top markdown"
- dangerouslySetInnerHTML={{ __html: translate('onboarding.analysis.sq_scanner.docs') }}
- />
- </div>
- );
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { translate } from '../../../../helpers/l10n';
-
-interface Props {
- className?: string;
- os: string;
-}
-
-export default function SQScanner(props: Props) {
- return (
- <div className={props.className}>
- <h4 className="spacer-bottom">
- {translate('onboarding.analysis.sq_scanner.header', props.os)}
- </h4>
- <p
- className="spacer-bottom markdown"
- dangerouslySetInnerHTML={{
- __html: translate('onboarding.analysis.sq_scanner.text', props.os)
- }}
- />
- <p>
- <a
- className="button"
- href="http://redirect.sonarsource.com/doc/install-configure-scanner.html"
- rel="noopener noreferrer"
- target="_blank">
- {translate('download_verb')}
- </a>
- </p>
- </div>
- );
-}
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import { shallow } from 'enzyme';
-import BuildWrapper from '../BuildWrapper';
-
-it('renders correctly', () => {
- expect(shallow(<BuildWrapper os="win" />)).toMatchSnapshot();
- expect(shallow(<BuildWrapper os="linux" />)).toMatchSnapshot();
- expect(shallow(<BuildWrapper os="mac" />)).toMatchSnapshot();
-});
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { shallow } from 'enzyme';
-import ClangGCC from '../ClangGCC';
-
-it('renders correctly', () => {
- expect(
- shallow(<ClangGCC host="host" os="win" projectKey="projectKey" token="token" />)
- ).toMatchSnapshot();
-
- expect(
- shallow(<ClangGCC host="host" os="linux" projectKey="projectKey" token="token" />)
- ).toMatchSnapshot();
-
- expect(
- shallow(
- <ClangGCC
- host="host"
- organization="organization"
- os="linux"
- projectKey="projectKey"
- token="token"
- />
- )
- ).toMatchSnapshot();
-});
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { shallow } from 'enzyme';
-import DotNet from '../DotNet';
-
-it('renders correctly', () => {
- expect(shallow(<DotNet host="host" projectKey="projectKey" token="token" />)).toMatchSnapshot();
- expect(
- shallow(
- <DotNet host="host" organization="organization" projectKey="projectKey" token="token" />
- )
- ).toMatchSnapshot();
-});
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { shallow } from 'enzyme';
-import JavaGradle from '../JavaGradle';
-
-it('renders correctly', () => {
- expect(shallow(<JavaGradle host="host" token="token" />)).toMatchSnapshot();
- expect(
- shallow(<JavaGradle host="host" organization="organization" token="token" />)
- ).toMatchSnapshot();
-});
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { shallow } from 'enzyme';
-import JavaMaven from '../JavaMaven';
-
-it('renders correctly', () => {
- expect(shallow(<JavaMaven host="host" token="token" />)).toMatchSnapshot();
- expect(
- shallow(<JavaMaven host="host" organization="organization" token="token" />)
- ).toMatchSnapshot();
-});
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { shallow } from 'enzyme';
-import MSBuildScanner from '../MSBuildScanner';
-
-it('renders correctly', () => {
- expect(shallow(<MSBuildScanner />)).toMatchSnapshot();
-});
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { shallow } from 'enzyme';
-import Msvc from '../Msvc';
-
-it('renders correctly', () => {
- expect(shallow(<Msvc host="host" projectKey="projectKey" token="token" />)).toMatchSnapshot();
- expect(
- shallow(<Msvc host="host" organization="organization" projectKey="projectKey" token="token" />)
- ).toMatchSnapshot();
-});
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { shallow } from 'enzyme';
-import Other from '../Other';
-
-it('renders correctly', () => {
- expect(
- shallow(<Other host="host" os="win" projectKey="projectKey" token="token" />)
- ).toMatchSnapshot();
-
- expect(
- shallow(<Other host="host" os="linux" projectKey="projectKey" token="token" />)
- ).toMatchSnapshot();
-
- expect(
- shallow(
- <Other
- host="host"
- organization="organization"
- os="linux"
- projectKey="projectKey"
- token="token"
- />
- )
- ).toMatchSnapshot();
-});
+++ /dev/null
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-import * as React from 'react';
-import { shallow } from 'enzyme';
-import SQScanner from '../SQScanner';
-
-it('renders correctly', () => {
- expect(shallow(<SQScanner os="win" />)).toMatchSnapshot();
- expect(shallow(<SQScanner os="linux" />)).toMatchSnapshot();
- expect(shallow(<SQScanner os="mac" />)).toMatchSnapshot();
-});
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`renders correctly 1`] = `
-<div>
- <h4
- className="spacer-bottom"
- >
- onboarding.analysis.build_wrapper.header.win
- </h4>
- <p
- className="spacer-bottom markdown"
- dangerouslySetInnerHTML={
- Object {
- "__html": "onboarding.analysis.build_wrapper.text.win",
- }
- }
- />
- <p>
- <a
- className="button"
- download="build-wrapper-win-x86.zip"
- href="/static/cpp/build-wrapper-win-x86.zip"
- target="_blank"
- >
- download_verb
- </a>
- </p>
-</div>
-`;
-
-exports[`renders correctly 2`] = `
-<div>
- <h4
- className="spacer-bottom"
- >
- onboarding.analysis.build_wrapper.header.linux
- </h4>
- <p
- className="spacer-bottom markdown"
- dangerouslySetInnerHTML={
- Object {
- "__html": "onboarding.analysis.build_wrapper.text.linux",
- }
- }
- />
- <p>
- <a
- className="button"
- download="build-wrapper-linux-x86.zip"
- href="/static/cpp/build-wrapper-linux-x86.zip"
- target="_blank"
- >
- download_verb
- </a>
- </p>
-</div>
-`;
-
-exports[`renders correctly 3`] = `
-<div>
- <h4
- className="spacer-bottom"
- >
- onboarding.analysis.build_wrapper.header.mac
- </h4>
- <p
- className="spacer-bottom markdown"
- dangerouslySetInnerHTML={
- Object {
- "__html": "onboarding.analysis.build_wrapper.text.mac",
- }
- }
- />
- <p>
- <a
- className="button"
- download="build-wrapper-macosx-x86.zip"
- href="/static/cpp/build-wrapper-macosx-x86.zip"
- target="_blank"
- >
- download_verb
- </a>
- </p>
-</div>
-`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`renders correctly 1`] = `
-<div>
- <SQScanner
- os="win"
- />
- <BuildWrapper
- className="huge-spacer-top"
- os="win"
- />
- <h4
- className="huge-spacer-top spacer-bottom"
- >
- onboarding.analysis.sq_scanner.execute
- </h4>
- <InstanceMessage
- message="onboarding.analysis.sq_scanner.execute.text"
- />
- <CodeSnippet
- isOneLine={true}
- snippet="build-wrapper-win-x86-64.exe --out-dir bw-output make clean all"
- />
- <CodeSnippet
- isOneLine={true}
- snippet={
- Array [
- "sonar-scanner.bat",
- "-Dsonar.projectKey=projectKey",
- undefined,
- "-Dsonar.sources=.",
- "-Dsonar.cfamily.build-wrapper-output=bw-output",
- "-Dsonar.host.url=host",
- "-Dsonar.login=token",
- ]
- }
- />
- <p
- className="big-spacer-top markdown"
- dangerouslySetInnerHTML={
- Object {
- "__html": "onboarding.analysis.sq_scanner.docs",
- }
- }
- />
-</div>
-`;
-
-exports[`renders correctly 2`] = `
-<div>
- <SQScanner
- os="linux"
- />
- <BuildWrapper
- className="huge-spacer-top"
- os="linux"
- />
- <h4
- className="huge-spacer-top spacer-bottom"
- >
- onboarding.analysis.sq_scanner.execute
- </h4>
- <InstanceMessage
- message="onboarding.analysis.sq_scanner.execute.text"
- />
- <CodeSnippet
- isOneLine={true}
- snippet="build-wrapper-linux-x86-64 --out-dir bw-output make clean all"
- />
- <CodeSnippet
- isOneLine={false}
- snippet={
- Array [
- "sonar-scanner",
- "-Dsonar.projectKey=projectKey",
- undefined,
- "-Dsonar.sources=.",
- "-Dsonar.cfamily.build-wrapper-output=bw-output",
- "-Dsonar.host.url=host",
- "-Dsonar.login=token",
- ]
- }
- />
- <p
- className="big-spacer-top markdown"
- dangerouslySetInnerHTML={
- Object {
- "__html": "onboarding.analysis.sq_scanner.docs",
- }
- }
- />
-</div>
-`;
-
-exports[`renders correctly 3`] = `
-<div>
- <SQScanner
- os="linux"
- />
- <BuildWrapper
- className="huge-spacer-top"
- os="linux"
- />
- <h4
- className="huge-spacer-top spacer-bottom"
- >
- onboarding.analysis.sq_scanner.execute
- </h4>
- <InstanceMessage
- message="onboarding.analysis.sq_scanner.execute.text"
- />
- <CodeSnippet
- isOneLine={true}
- snippet="build-wrapper-linux-x86-64 --out-dir bw-output make clean all"
- />
- <CodeSnippet
- isOneLine={false}
- snippet={
- Array [
- "sonar-scanner",
- "-Dsonar.projectKey=projectKey",
- "-Dsonar.organization=organization",
- "-Dsonar.sources=.",
- "-Dsonar.cfamily.build-wrapper-output=bw-output",
- "-Dsonar.host.url=host",
- "-Dsonar.login=token",
- ]
- }
- />
- <p
- className="big-spacer-top markdown"
- dangerouslySetInnerHTML={
- Object {
- "__html": "onboarding.analysis.sq_scanner.docs",
- }
- }
- />
-</div>
-`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`renders correctly 1`] = `
-<div>
- <MSBuildScanner />
- <h4
- className="huge-spacer-top spacer-bottom"
- >
- onboarding.analysis.msbuild.execute
- </h4>
- <InstanceMessage
- message="onboarding.analysis.msbuild.execute.text"
- />
- <CodeSnippet
- isOneLine={true}
- snippet={
- Array [
- "SonarScanner.MSBuild.exe begin",
- "/k:\\"projectKey\\"",
- undefined,
- "/d:sonar.host.url=\\"host\\"",
- "/d:sonar.login=\\"token\\"",
- ]
- }
- />
- <CodeSnippet
- isOneLine={true}
- snippet="MsBuild.exe /t:Rebuild"
- />
- <CodeSnippet
- isOneLine={true}
- snippet={
- Array [
- "SonarScanner.MSBuild.exe end",
- "/d:sonar.login=\\"token\\"",
- ]
- }
- />
- <p
- className="big-spacer-top markdown"
- dangerouslySetInnerHTML={
- Object {
- "__html": "onboarding.analysis.msbuild.docs",
- }
- }
- />
-</div>
-`;
-
-exports[`renders correctly 2`] = `
-<div>
- <MSBuildScanner />
- <h4
- className="huge-spacer-top spacer-bottom"
- >
- onboarding.analysis.msbuild.execute
- </h4>
- <InstanceMessage
- message="onboarding.analysis.msbuild.execute.text"
- />
- <CodeSnippet
- isOneLine={true}
- snippet={
- Array [
- "SonarScanner.MSBuild.exe begin",
- "/k:\\"projectKey\\"",
- "/d:sonar.organization=\\"organization\\"",
- "/d:sonar.host.url=\\"host\\"",
- "/d:sonar.login=\\"token\\"",
- ]
- }
- />
- <CodeSnippet
- isOneLine={true}
- snippet="MsBuild.exe /t:Rebuild"
- />
- <CodeSnippet
- isOneLine={true}
- snippet={
- Array [
- "SonarScanner.MSBuild.exe end",
- "/d:sonar.login=\\"token\\"",
- ]
- }
- />
- <p
- className="big-spacer-top markdown"
- dangerouslySetInnerHTML={
- Object {
- "__html": "onboarding.analysis.msbuild.docs",
- }
- }
- />
-</div>
-`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`renders correctly 1`] = `
-<div>
- <h4
- className="spacer-bottom"
- >
- onboarding.analysis.java.gradle.header
- </h4>
- <InstanceMessage
- message="onboarding.analysis.java.gradle.text.1"
- />
- <CodeSnippet
- snippet="plugins {
- id \\"org.sonarqube\\" version \\"2.6\\"
-}"
- />
- <p
- className="spacer-top spacer-bottom markdown"
- >
- onboarding.analysis.java.gradle.text.2
- </p>
- <CodeSnippet
- snippet={
- Array [
- "./gradlew sonarqube",
- undefined,
- "-Dsonar.host.url=host",
- "-Dsonar.login=token",
- ]
- }
- />
- <p
- className="big-spacer-top markdown"
- dangerouslySetInnerHTML={
- Object {
- "__html": "onboarding.analysis.java.gradle.docs",
- }
- }
- />
- <p
- className="big-spacer-top markdown"
- dangerouslySetInnerHTML={
- Object {
- "__html": "onboarding.analysis.browse_url_after_analysis",
- }
- }
- />
-</div>
-`;
-
-exports[`renders correctly 2`] = `
-<div>
- <h4
- className="spacer-bottom"
- >
- onboarding.analysis.java.gradle.header
- </h4>
- <InstanceMessage
- message="onboarding.analysis.java.gradle.text.1"
- />
- <CodeSnippet
- snippet="plugins {
- id \\"org.sonarqube\\" version \\"2.6\\"
-}"
- />
- <p
- className="spacer-top spacer-bottom markdown"
- >
- onboarding.analysis.java.gradle.text.2
- </p>
- <CodeSnippet
- snippet={
- Array [
- "./gradlew sonarqube",
- "-Dsonar.organization=organization",
- "-Dsonar.host.url=host",
- "-Dsonar.login=token",
- ]
- }
- />
- <p
- className="big-spacer-top markdown"
- dangerouslySetInnerHTML={
- Object {
- "__html": "onboarding.analysis.java.gradle.docs",
- }
- }
- />
- <p
- className="big-spacer-top markdown"
- dangerouslySetInnerHTML={
- Object {
- "__html": "onboarding.analysis.browse_url_after_analysis",
- }
- }
- />
-</div>
-`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`renders correctly 1`] = `
-<div>
- <h4
- className="spacer-bottom"
- >
- onboarding.analysis.java.maven.header
- </h4>
- <p
- className="spacer-bottom markdown"
- >
- <InstanceMessage
- message="onboarding.analysis.java.maven.text"
- />
- </p>
- <CodeSnippet
- snippet={
- Array [
- "mvn sonar:sonar",
- undefined,
- "-Dsonar.host.url=host",
- "-Dsonar.login=token",
- ]
- }
- />
- <p
- className="big-spacer-top markdown"
- dangerouslySetInnerHTML={
- Object {
- "__html": "onboarding.analysis.java.maven.docs",
- }
- }
- />
- <p
- className="big-spacer-top markdown"
- dangerouslySetInnerHTML={
- Object {
- "__html": "onboarding.analysis.browse_url_after_analysis",
- }
- }
- />
-</div>
-`;
-
-exports[`renders correctly 2`] = `
-<div>
- <h4
- className="spacer-bottom"
- >
- onboarding.analysis.java.maven.header
- </h4>
- <p
- className="spacer-bottom markdown"
- >
- <InstanceMessage
- message="onboarding.analysis.java.maven.text"
- />
- </p>
- <CodeSnippet
- snippet={
- Array [
- "mvn sonar:sonar",
- "-Dsonar.organization=organization",
- "-Dsonar.host.url=host",
- "-Dsonar.login=token",
- ]
- }
- />
- <p
- className="big-spacer-top markdown"
- dangerouslySetInnerHTML={
- Object {
- "__html": "onboarding.analysis.java.maven.docs",
- }
- }
- />
- <p
- className="big-spacer-top markdown"
- dangerouslySetInnerHTML={
- Object {
- "__html": "onboarding.analysis.browse_url_after_analysis",
- }
- }
- />
-</div>
-`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`renders correctly 1`] = `
-<div>
- <h4
- className="spacer-bottom"
- >
- onboarding.analysis.msbuild.header
- </h4>
- <p
- className="spacer-bottom markdown"
- dangerouslySetInnerHTML={
- Object {
- "__html": "onboarding.analysis.msbuild.text",
- }
- }
- />
- <p>
- <a
- className="button"
- href="http://redirect.sonarsource.com/doc/install-configure-scanner-msbuild.html"
- rel="noopener noreferrer"
- target="_blank"
- >
- download_verb
- </a>
- </p>
-</div>
-`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`renders correctly 1`] = `
-<div>
- <MSBuildScanner />
- <BuildWrapper
- className="huge-spacer-top"
- os="win"
- />
- <h4
- className="huge-spacer-top spacer-bottom"
- >
- onboarding.analysis.msbuild.execute
- </h4>
- <InstanceMessage
- message="onboarding.analysis.msbuild.execute.text"
- />
- <CodeSnippet
- isOneLine={true}
- snippet={
- Array [
- "SonarQube.Scanner.MSBuild.exe begin",
- "/k:\\"projectKey\\"",
- undefined,
- "/d:sonar.cfamily.build-wrapper-output=bw-output",
- "/d:sonar.host.url=\\"host\\"",
- "/d:sonar.login=\\"token\\"",
- ]
- }
- />
- <CodeSnippet
- isOneLine={true}
- snippet="build-wrapper-win-x86-64.exe --out-dir bw-output MsBuild.exe /t:Rebuild"
- />
- <CodeSnippet
- isOneLine={true}
- snippet={
- Array [
- "SonarQube.Scanner.MSBuild.exe end",
- "/d:sonar.login=\\"token\\"",
- ]
- }
- />
- <p
- className="big-spacer-top markdown"
- dangerouslySetInnerHTML={
- Object {
- "__html": "onboarding.analysis.msbuild.docs",
- }
- }
- />
-</div>
-`;
-
-exports[`renders correctly 2`] = `
-<div>
- <MSBuildScanner />
- <BuildWrapper
- className="huge-spacer-top"
- os="win"
- />
- <h4
- className="huge-spacer-top spacer-bottom"
- >
- onboarding.analysis.msbuild.execute
- </h4>
- <InstanceMessage
- message="onboarding.analysis.msbuild.execute.text"
- />
- <CodeSnippet
- isOneLine={true}
- snippet={
- Array [
- "SonarQube.Scanner.MSBuild.exe begin",
- "/k:\\"projectKey\\"",
- "/d:sonar.organization=\\"organization\\"",
- "/d:sonar.cfamily.build-wrapper-output=bw-output",
- "/d:sonar.host.url=\\"host\\"",
- "/d:sonar.login=\\"token\\"",
- ]
- }
- />
- <CodeSnippet
- isOneLine={true}
- snippet="build-wrapper-win-x86-64.exe --out-dir bw-output MsBuild.exe /t:Rebuild"
- />
- <CodeSnippet
- isOneLine={true}
- snippet={
- Array [
- "SonarQube.Scanner.MSBuild.exe end",
- "/d:sonar.login=\\"token\\"",
- ]
- }
- />
- <p
- className="big-spacer-top markdown"
- dangerouslySetInnerHTML={
- Object {
- "__html": "onboarding.analysis.msbuild.docs",
- }
- }
- />
-</div>
-`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`renders correctly 1`] = `
-<div>
- <SQScanner
- os="win"
- />
- <h4
- className="huge-spacer-top spacer-bottom"
- >
- onboarding.analysis.sq_scanner.execute
- </h4>
- <InstanceMessage
- message="onboarding.analysis.sq_scanner.execute.text"
- />
- <CodeSnippet
- isOneLine={true}
- snippet={
- Array [
- "sonar-scanner.bat",
- "-Dsonar.projectKey=projectKey",
- undefined,
- "-Dsonar.sources=.",
- "-Dsonar.host.url=host",
- "-Dsonar.login=token",
- ]
- }
- />
- <p
- className="big-spacer-top markdown"
- dangerouslySetInnerHTML={
- Object {
- "__html": "onboarding.analysis.sq_scanner.docs",
- }
- }
- />
-</div>
-`;
-
-exports[`renders correctly 2`] = `
-<div>
- <SQScanner
- os="linux"
- />
- <h4
- className="huge-spacer-top spacer-bottom"
- >
- onboarding.analysis.sq_scanner.execute
- </h4>
- <InstanceMessage
- message="onboarding.analysis.sq_scanner.execute.text"
- />
- <CodeSnippet
- isOneLine={false}
- snippet={
- Array [
- "sonar-scanner",
- "-Dsonar.projectKey=projectKey",
- undefined,
- "-Dsonar.sources=.",
- "-Dsonar.host.url=host",
- "-Dsonar.login=token",
- ]
- }
- />
- <p
- className="big-spacer-top markdown"
- dangerouslySetInnerHTML={
- Object {
- "__html": "onboarding.analysis.sq_scanner.docs",
- }
- }
- />
-</div>
-`;
-
-exports[`renders correctly 3`] = `
-<div>
- <SQScanner
- os="linux"
- />
- <h4
- className="huge-spacer-top spacer-bottom"
- >
- onboarding.analysis.sq_scanner.execute
- </h4>
- <InstanceMessage
- message="onboarding.analysis.sq_scanner.execute.text"
- />
- <CodeSnippet
- isOneLine={false}
- snippet={
- Array [
- "sonar-scanner",
- "-Dsonar.projectKey=projectKey",
- "-Dsonar.organization=organization",
- "-Dsonar.sources=.",
- "-Dsonar.host.url=host",
- "-Dsonar.login=token",
- ]
- }
- />
- <p
- className="big-spacer-top markdown"
- dangerouslySetInnerHTML={
- Object {
- "__html": "onboarding.analysis.sq_scanner.docs",
- }
- }
- />
-</div>
-`;
+++ /dev/null
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`renders correctly 1`] = `
-<div>
- <h4
- className="spacer-bottom"
- >
- onboarding.analysis.sq_scanner.header.win
- </h4>
- <p
- className="spacer-bottom markdown"
- dangerouslySetInnerHTML={
- Object {
- "__html": "onboarding.analysis.sq_scanner.text.win",
- }
- }
- />
- <p>
- <a
- className="button"
- href="http://redirect.sonarsource.com/doc/install-configure-scanner.html"
- rel="noopener noreferrer"
- target="_blank"
- >
- download_verb
- </a>
- </p>
-</div>
-`;
-
-exports[`renders correctly 2`] = `
-<div>
- <h4
- className="spacer-bottom"
- >
- onboarding.analysis.sq_scanner.header.linux
- </h4>
- <p
- className="spacer-bottom markdown"
- dangerouslySetInnerHTML={
- Object {
- "__html": "onboarding.analysis.sq_scanner.text.linux",
- }
- }
- />
- <p>
- <a
- className="button"
- href="http://redirect.sonarsource.com/doc/install-configure-scanner.html"
- rel="noopener noreferrer"
- target="_blank"
- >
- download_verb
- </a>
- </p>
-</div>
-`;
-
-exports[`renders correctly 3`] = `
-<div>
- <h4
- className="spacer-bottom"
- >
- onboarding.analysis.sq_scanner.header.mac
- </h4>
- <p
- className="spacer-bottom markdown"
- dangerouslySetInnerHTML={
- Object {
- "__html": "onboarding.analysis.sq_scanner.text.mac",
- }
- }
- />
- <p>
- <a
- className="button"
- href="http://redirect.sonarsource.com/doc/install-configure-scanner.html"
- rel="noopener noreferrer"
- target="_blank"
- >
- download_verb
- </a>
- </p>
-</div>
-`;
component: lazyLoad(
() =>
isSonarCloud()
- ? import('./createProjectOnboarding/CreateProjectOnboarding')
+ ? import('./onboarding/OnboardingPage')
: import('./projectOnboarding/ProjectOnboardingPage')
)
}
.onboarding-choices {
display: flex;
justify-content: space-around;
- padding-top: 44px;
- padding-bottom: 44px;
+ padding: 44px 0;
background-color: var(--barBackgroundColor);
}
--- /dev/null
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+export interface LanguageConfig {
+ language?: string;
+ javaBuild?: string;
+ cFamilyCompiler?: string;
+ os?: string;
+ projectKey?: string;
+}
+
+export function isLanguageConfigured(config?: LanguageConfig) {
+ if (!config) {
+ return false;
+ }
+ const { language, javaBuild, cFamilyCompiler, os, projectKey } = config;
+ const isJavaConfigured = language === 'java' && javaBuild != null;
+ const isDotNetConfigured = language === 'dotnet' && projectKey != null;
+ const isCFamilyConfigured =
+ language === 'c-family' && (cFamilyCompiler === 'msvc' || os != null) && projectKey != null;
+ const isOtherConfigured = language === 'other' && projectKey != null;
+
+ return isJavaConfigured || isDotNetConfigured || isCFamilyConfigured || isOtherConfigured;
+}
size
}: IconProps) {
return (
- <Icon className={className} size={size || 64} viewBox="">
+ <Icon className={className} size={size || 64} viewBox="0 0 64 64">
<g fill="none" stroke={fill} strokeWidth="2">
<path d="M2 59h60V13H2zm0-46h60V5H2zm3-4h2m2 0h2m2 0h2m2 0h42" />
<path d="M59 34h-6l-2-4h-6l-2 5h-6l-2 2h-6l-2-4h-6l-2 5h-6l-2 4H5m1 14v-9m4 9v-6m4 6V43m4 13V45m4 11V42m4 14V39m4 17V41m4 15V46m4 10V40m4 16V44m4 12V37m4 19V38m4 18V43m4 13V39m-3-18h-2m-2 0h-2m-2 0h-2M9 29h14M9 33h7m17-12h8m-14 4h8m-8-4h4m-21 4h12v-4H10z" />
size
}: IconProps) {
return (
- <Icon className={className} size={size || 64} viewBox="">
+ <Icon className={className} size={size || 64} viewBox="0 0 64 64">
<g fill="none" fillRule="evenodd" stroke={fill} strokeWidth="2">
<path d="M2 59h60V13H2zm0-46h60V5H2zm3-4h2m2 0h2m2 0h2m2 0h42" />
<path d="M59 34h-6l-2-4h-6l-2 5h-6l-2 2h-6l-2-4h-6l-2 5h-6l-2 4H5m1 14v-9m4 9v-6m4 6V43m4 13V45m4 11V42m4 14V39m4 17V41m4 15V46m4 10V40m4 16V44m4 12V37m4 19V38m4 18V43m4 13V39m-3-18h-2m-2 0h-2m-2 0h-2M9 29h14M9 33h7m17-12h8m-14 4h8m-8-4h4m-21 4h12v-4H10z" />
export default function OnboardingTeamIcon({ className, fill = 'currentColor', size }: IconProps) {
return (
- <Icon className={className} size={size || 64} viewBox="">
+ <Icon className={className} size={size || 64} viewBox="0 0 64 64">
<g fill="none" fillRule="evenodd" stroke={fill} strokeWidth="2">
<path d="M32 9v5M11.5195 43.0898l7.48-4.091m33.481-18.0994l-7.48 4.1m-33.481-4.1l7.48 4.1M45 38.999l7.48 4.101M32 50v5m15-23c0 8.284-6.715 15-15 15s-15-6.716-15-15c0-8.285 6.715-15 15-15s15 6.715 15 15z" />
<path d="M40 38c0 1.656-3.58 2-8 2s-8-.344-8-2m16 0v-3l-5-3-1-1m-10 7v-3l5-3 1-1m6-4c0 2.2-1.8 4-4 4s-4-1.8-4-4v-1c0-2.2 1.8-4 4-4s4 1.8 4 4v1zm-.0098-21.71c7.18 1.069 13.439 4.96 17.609 10.51m-17.609 42.91c7.18-1.07 13.439-4.96 17.609-10.51M6.6299 41.25c-1.06-2.88-1.63-6-1.63-9.25s.57-6.37 1.63-9.25m3.7705-6.9502c4.17-5.55 10.43-9.44 17.609-10.51m-17.609 42.9104c4.17 5.55 10.43 9.439 17.609 10.51M57.3701 22.75c1.06 2.88 1.63 6 1.63 9.25s-.57 6.37-1.63 9.25" />
transition: all 0.2s ease;
}
+.dropdown .button-link {
+ border-bottom: none;
+}
+
.button-link:hover {
background: transparent;
color: var(--blue);
* @returns {string}
*/
function filterContent(content) {
- const { isSonarCloud } = require('../helpers/system');
+ const { isSonarCloud } = require('./system');
const contentWithoutStatic = cutConditionalContent(content, 'static');
return isSonarCloud()
? cutConditionalContent(contentWithoutStatic, 'sonarqube')
return `${getBaseUrl()}${path.pathname}?${stringify(omitBy(path.query, isNil))}`;
}
-export function getSonarCloudUrlAsString(location: Location) {
- return 'https://sonarcloud.io' + getPathUrlAsString(location);
-}
-
export function getProjectUrl(project: string, branch?: string): Location {
return { pathname: '/dashboard', query: { id: project, branch } };
}
#------------------------------------------------------------------------------
provisioning.create_new_project=Create new project
provisioning.no_analysis=No analysis has been performed since creation. The only available section is the configuration.
-provisioning.no_analysis.delete=Either you should retry analysis or simply {0}.
+provisioning.no_analysis.delete=Either you should retry analysis or simply {link}.
provisioning.no_analysis.delete_project=delete the project
-provisioning.no_analysis_on_main_branch={branch} has not been analyzed yet.
+provisioning.no_analysis_on_main_branch="{branchName}" branch has not been analyzed yet.
+provisioning.no_analysis_on_main_branch.bad_configuration="{branchName}" branch has not been analyzed yet and you have multiple branches already. It looks like it is not your {branchType}, check your configuration.
provisioning.only_provisioned=Only Provisioned
provisioning.only_provisioned.tooltip=Provisioned projects are projects that have been created, but have not been analyzed yet.
onboarding.project.header=Analyze a project
onboarding.project.header.description=Want to quickly analyze a first project? Follow these {0} easy steps.
+onboarding.project_analysis.header=Analyze your project
+onboarding.project_analysis.description=We initialized your project on SonarCloud, now it's up to you to launch analyses!
+onboarding.project_analysis.commands_for_analysis=Bellow are the commands to use to do an analysis.
+onboarding.project_analysis.guide_to_integrate_piplines=follow the guide to integrating with Pipelines
+onboarding.project_analysis.guide_to_integrate_travis=follow the guide to integrating with Travis CI
+onboarding.project_analysis.guide_to_integrate_vsts=follow the guide to integrating with VSTS
+onboarding.project_analysis.simply_link=Simply {link}.
+onboarding.project_analysis.suggestions.bitbucket=If you are using Bitbucket Cloud Pipelines, the SonarCloud App makes it easier to run these commands with your CI process.
+onboarding.project_analysis.suggestions.github=If you are using Travis CI, the SonarCloud Travis Add-on makes it easier to run these commands with your CI process.
+
onboarding.create_project.header=Create project(s)
onboarding.create_project.already_imported=Repository already imported
-onboarding.create_project.beta_feature_x=This feature is being beta tested. We offer to create projects from your {0} repositories only for public personal projects on your personal SonarCloud organization. For other kind of projects please create them maually.
+onboarding.create_project.beta_feature_x=This feature is being beta tested. We offer to create projects from your {0} repositories only for public personal projects on your personal SonarCloud organization. For other kind of projects please create them manually.
onboarding.create_project.create_manually=Create manually
onboarding.create_project.create_new_org=I want to create another organization
-onboarding.create_project.create_project=Create project
-onboarding.create_project.create_projects=Create projects
onboarding.create_project.install_app_x=We need you to install the Sonarcloud {0} application in order to select which repositories you want to analyze.
onboarding.create_project.install_app_x.button=Install SonarCloud {0} application
onboarding.create_project.organization=Organization
onboarding.project_key_requirement=Allowed characters are alphanumeric, '-', '_', '.' and ':', with at least one non-digit. 400 characters max.
onboarding.analysis.header=Run analysis on your project
+onboarding.analysis.auto_refresh_after_analysis=Once the analysis is completed, this page will automatically refresh and you will be able to browse the analysis results.
onboarding.analysis.browse_url_after_analysis=Once the analysis is completed, you will be able to browse your project at the URL displayed at the end of the logs.
onboarding.language=What is your project's main language?
+onboarding.language.header=Which primary language are you using?
onboarding.language.java=Java
onboarding.language.java.build_technology=You are developing primarily in Java: what is your build technology?
onboarding.language.java.build_technology.maven=Maven