From: Grégoire Aubert Date: Thu, 26 Jul 2018 09:44:57 +0000 (+0200) Subject: SONAR-11029 Move the tutorial inside provisioned projects dashboard X-Git-Tag: 7.5~620 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=4f5f81d6c146d6cc873239258343141e9631c9b6;p=sonarqube.git SONAR-11029 Move the tutorial inside provisioned projects dashboard * Move/Rename files of tutorials folder * SONAR-11049 Update tutorial UI and move it inside the project dashboard * SONAR-11050 Update tutorial to skip now useless steps * Remove unused style * SONAR-11030 Make dashboard tutorial work with already known project key * Better manage error messages when no analysis and analyzed branches * SONAR-11052 Refresh project status as long as there is no analysis * SONAR-11051 Add infos suggestions depending on the ALM of the project * Do no display tutorial when there is analyses in the pipe --- diff --git a/server/sonar-docs/src/templates/page.css b/server/sonar-docs/src/templates/page.css index 73515b1460d..3b7180f4baf 100644 --- a/server/sonar-docs/src/templates/page.css +++ b/server/sonar-docs/src/templates/page.css @@ -24,7 +24,7 @@ .alert-info { border-color: #bce8f1; background-color: #d9edf7; - color: #31708f; + color: #666666; } .alert-success { diff --git a/server/sonar-web/src/main/js/app/components/ComponentContainer.tsx b/server/sonar-web/src/main/js/app/components/ComponentContainer.tsx index 82d4b81197e..176a21d06ac 100644 --- a/server/sonar-web/src/main/js/app/components/ComponentContainer.tsx +++ b/server/sonar-web/src/main/js/app/components/ComponentContainer.tsx @@ -176,7 +176,12 @@ export class ComponentContainer extends React.PureComponent { 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), diff --git a/server/sonar-web/src/main/js/app/components/StartupModal.tsx b/server/sonar-web/src/main/js/app/components/StartupModal.tsx index 8a7e7e2f444..b85885bbcd0 100644 --- a/server/sonar-web/src/main/js/app/components/StartupModal.tsx +++ b/server/sonar-web/src/main/js/app/components/StartupModal.tsx @@ -35,7 +35,7 @@ import { lazyLoad } from '../../components/lazyLoad'; 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' @@ -135,7 +135,7 @@ export class StartupModal extends React.PureComponent { 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 }); } @@ -189,7 +189,7 @@ export class StartupModal extends React.PureComponent { {this.props.children} {modal === ModalKey.license && } {modal === ModalKey.onboarding && ( - ({ - 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 @@ -90,14 +88,12 @@ it('changes component', () => { }); it("loads branches for module's project", async () => { - (getComponentNavigation as jest.Mock).mockImplementationOnce(() => - Promise.resolve({ - breadcrumbs: [ - { key: 'projectKey', name: 'project', qualifier: 'TRK' }, - { key: 'moduleKey', name: 'module', qualifier: 'BRC' } - ] - }) - ); + (getComponentNavigation as jest.Mock).mockResolvedValueOnce({ + breadcrumbs: [ + { key: 'projectKey', name: 'project', qualifier: 'TRK' }, + { key: 'moduleKey', name: 'module', qualifier: 'BRC' } + ] + }); mount( @@ -149,9 +145,7 @@ it('updates branches on change', () => { }); it('loads organization', async () => { - (getComponentData as jest.Mock).mockImplementationOnce(() => - Promise.resolve({ organization: 'org' }) - ); + (getComponentData as jest.Mock).mockResolvedValueOnce({ organization: 'org' }); const fetchOrganizations = jest.fn(); mount( @@ -166,9 +160,7 @@ it('loads organization', async () => { }); it('fetches status', async () => { - (getComponentData as jest.Mock).mockImplementationOnce(() => - Promise.resolve({ organization: 'org' }) - ); + (getComponentData as jest.Mock).mockResolvedValueOnce({ organization: 'org' }); mount( diff --git a/server/sonar-web/src/main/js/app/styles/components/alerts.css b/server/sonar-web/src/main/js/app/styles/components/alerts.css index b965dced2d6..97457fe8dd6 100644 --- a/server/sonar-web/src/main/js/app/styles/components/alerts.css +++ b/server/sonar-web/src/main/js/app/styles/components/alerts.css @@ -51,7 +51,7 @@ .alert-info { border-color: #bce8f1; background-color: #d9edf7; - color: #31708f; + color: #666666; } .alert-success { diff --git a/server/sonar-web/src/main/js/app/styles/components/boxed-group.css b/server/sonar-web/src/main/js/app/styles/components/boxed-group.css index e77b22430da..5a79c7f70e8 100644 --- a/server/sonar-web/src/main/js/app/styles/components/boxed-group.css +++ b/server/sonar-web/src/main/js/app/styles/components/boxed-group.css @@ -18,7 +18,7 @@ * 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; diff --git a/server/sonar-web/src/main/js/app/styles/components/page.css b/server/sonar-web/src/main/js/app/styles/components/page.css index c493b82d22c..a18b282cc45 100644 --- a/server/sonar-web/src/main/js/app/styles/components/page.css +++ b/server/sonar-web/src/main/js/app/styles/components/page.css @@ -187,7 +187,6 @@ } .page-sidebar-fixed { - width: 30%; min-width: 300px; flex-shrink: 0; padding-left: 40px; @@ -228,17 +227,6 @@ } } -.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; diff --git a/server/sonar-web/src/main/js/app/styles/init/misc.css b/server/sonar-web/src/main/js/app/styles/init/misc.css index c0f7bd23abb..11bbc4bb9f7 100644 --- a/server/sonar-web/src/main/js/app/styles/init/misc.css +++ b/server/sonar-web/src/main/js/app/styles/init/misc.css @@ -293,6 +293,11 @@ td.big-spacer-top { flex-direction: row; } +.display-flex-column { + display: flex !important; + flex-direction: column; +} + .display-flex-center { display: flex !important; align-items: center; diff --git a/server/sonar-web/src/main/js/app/styles/sonarcloud.css b/server/sonar-web/src/main/js/app/styles/sonarcloud.css index 66a4f2f0ba8..aa5ab408659 100644 --- a/server/sonar-web/src/main/js/app/styles/sonarcloud.css +++ b/server/sonar-web/src/main/js/app/styles/sonarcloud.css @@ -37,19 +37,22 @@ 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; } diff --git a/server/sonar-web/src/main/js/app/types.ts b/server/sonar-web/src/main/js/app/types.ts index ea3be59fc5c..4b55b604c22 100644 --- a/server/sonar-web/src/main/js/app/types.ts +++ b/server/sonar-web/src/main/js/app/types.ts @@ -61,6 +61,8 @@ export interface Breadcrumb { } export interface Component extends LightComponent { + almId?: string; + almRepoUrl?: string; analysisDate?: string; breadcrumbs: Breadcrumb[]; configuration?: ComponentConfiguration; diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/FacetsList.tsx b/server/sonar-web/src/main/js/apps/coding-rules/components/FacetsList.tsx index 9eb8edb79ed..2540d76707c 100644 --- a/server/sonar-web/src/main/js/apps/coding-rules/components/FacetsList.tsx +++ b/server/sonar-web/src/main/js/apps/coding-rules/components/FacetsList.tsx @@ -57,7 +57,7 @@ export default function FacetsList(props: Props) { props.selectedProfile === undefined || !props.query.activation; return ( -
+ <> )} -
+ ); } diff --git a/server/sonar-web/src/main/js/apps/component-measures/sidebar/Sidebar.js b/server/sonar-web/src/main/js/apps/component-measures/sidebar/Sidebar.js index 4b8edc255c3..183875dc425 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/sidebar/Sidebar.js +++ b/server/sonar-web/src/main/js/apps/component-measures/sidebar/Sidebar.js @@ -77,7 +77,7 @@ export default class Sidebar extends React.PureComponent { render() { return ( -
+
+
{ (this.props.organization && this.props.organization.key); return ( -
+ <> { stats={facets.authors} /> )} -
+ ); } } diff --git a/server/sonar-web/src/main/js/apps/overview/components/App.tsx b/server/sonar-web/src/main/js/apps/overview/components/App.tsx index d54ea53f10b..68c8238c23c 100644 --- a/server/sonar-web/src/main/js/apps/overview/components/App.tsx +++ b/server/sonar-web/src/main/js/apps/overview/components/App.tsx @@ -19,11 +19,21 @@ */ 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; @@ -67,22 +77,43 @@ export default class App extends React.PureComponent { return null; } - if (!component.analysisDate) { - return ( - 1} - showWarning={!this.props.isPending && !this.props.isInProgress} - /> - ); - } - return ( - + <> + {isSonarCloud() && ( + + + + )} + + + {!component.analysisDate && + (isSonarCloud() ? ( + + ) : ( + + ))} + {component.analysisDate && ( + + )} + ); } } diff --git a/server/sonar-web/src/main/js/apps/overview/components/EmptyOverview.tsx b/server/sonar-web/src/main/js/apps/overview/components/EmptyOverview.tsx index 9beed6e65b5..69c3d81ae27 100644 --- a/server/sonar-web/src/main/js/apps/overview/components/EmptyOverview.tsx +++ b/server/sonar-web/src/main/js/apps/overview/components/EmptyOverview.tsx @@ -21,30 +21,39 @@ import * as React from 'react'; 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 (
{showWarning && (
- {hasBranches ? ( + {hasBranches && isBranch(branchLike) ? ( + branchName: branchLike.name, + branchType: ( +
{translate('branches.main_branch')}
) @@ -57,13 +66,19 @@ export default function EmptyOverview({ component, hasBranches, showWarning }: P {!hasBranches && (
- {head} - - {translate('provisioning.no_analysis.delete_project')} - - {tail} + + {translate('provisioning.no_analysis.delete_project')} + + ) + }} + />
)}
diff --git a/server/sonar-web/src/main/js/apps/overview/components/OverviewApp.tsx b/server/sonar-web/src/main/js/apps/overview/components/OverviewApp.tsx index 402725bdc71..dcf365a6615 100644 --- a/server/sonar-web/src/main/js/apps/overview/components/OverviewApp.tsx +++ b/server/sonar-web/src/main/js/apps/overview/components/OverviewApp.tsx @@ -20,16 +20,14 @@ 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'; @@ -52,8 +50,6 @@ import { fetchMetrics } from '../../../store/rootActions'; 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 { @@ -246,14 +242,6 @@ export class OverviewApp extends React.PureComponent { return (
- - - {isSonarCloud() && ( - - - - )} - {this.renderMain()}
diff --git a/server/sonar-web/src/main/js/apps/overview/components/SonarCloudEmptyOverview.tsx b/server/sonar-web/src/main/js/apps/overview/components/SonarCloudEmptyOverview.tsx new file mode 100644 index 00000000000..53dace6236e --- /dev/null +++ b/server/sonar-web/src/main/js/apps/overview/components/SonarCloudEmptyOverview.tsx @@ -0,0 +1,126 @@ +/* + * 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 ( +
+
+
+ {isLoggedIn(currentUser) && isMainBranch(branchLike) ? ( + <> + {hasBranches && ( + + )} + {!hasBranches && + !hasAnalyses && } + + ) : ( + + )} +
+ +
+ +
+
+
+ ); +} + +export function WarningMessage({ + branchLike, + message +}: { + branchLike?: BranchLike; + message: string; +}) { + if (!isBranch(branchLike)) { + return null; + } + return ( +
+ {translate('branches.main_branch')}
+ ) + }} + /> +
+ ); +} + +const mapStateToProps = (state: any) => ({ + currentUser: getCurrentUser(state) +}); + +export default connect(mapStateToProps)(SonarCloudEmptyOverview); diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/App-test.tsx b/server/sonar-web/src/main/js/apps/overview/components/__tests__/App-test.tsx index ac84c986293..73eb99d9350 100644 --- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/App-test.tsx +++ b/server/sonar-web/src/main/js/apps/overview/components/__tests__/App-test.tsx @@ -20,9 +20,10 @@ 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', @@ -34,13 +35,34 @@ const component = { version: '0.0.1' }; +beforeEach(() => { + (isSonarCloud as jest.Mock).mockClear(); + (isSonarCloud as jest.Mock).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).mockReturnValue(true); + expect( + getWrapper({ component: { key: 'foo' } }) + .find('Connect(SonarCloudEmptyOverview)') + .exists() + ).toBeTruthy(); }); it('redirects on Code page for files', () => { diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/EmptyOverview-test.tsx b/server/sonar-web/src/main/js/apps/overview/components/__tests__/EmptyOverview-test.tsx index c2468df3638..6fd204472ab 100644 --- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/EmptyOverview-test.tsx +++ b/server/sonar-web/src/main/js/apps/overview/components/__tests__/EmptyOverview-test.tsx @@ -20,17 +20,41 @@ 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()).toMatchSnapshot(); + expect( + shallow() + ).toMatchSnapshot(); }); it('does not render warning', () => { - expect(shallow()).toMatchSnapshot(); + expect( + shallow() + ).toMatchSnapshot(); }); it('should render another message when there are branches', () => { expect( - shallow() + shallow( + + ) + ).toMatchSnapshot(); + expect( + shallow( + + ) ).toMatchSnapshot(); }); diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/SonarCloudEmptyOverview-test.tsx b/server/sonar-web/src/main/js/apps/overview/components/__tests__/SonarCloudEmptyOverview-test.tsx new file mode 100644 index 00000000000..278fca079d1 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/overview/components/__tests__/SonarCloudEmptyOverview-test.tsx @@ -0,0 +1,117 @@ +/* + * 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( + + ) + ).toMatchSnapshot(); +}); + +it('should render another message when there are branches', () => { + expect( + shallow( + + ) + ).toMatchSnapshot(); + expect( + shallow( + + ) + ).toMatchSnapshot(); +}); + +it('should not render the tutorial', () => { + expect( + shallow( + + ) + ).toMatchSnapshot(); +}); + +it('should render warning message', () => { + expect(shallow()).toMatchSnapshot(); +}); + +it('should not render warning message', () => { + expect( + shallow( + + ) + .find('FormattedMessage') + .exists() + ).toBeFalsy(); +}); diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/Timeline-test.js b/server/sonar-web/src/main/js/apps/overview/components/__tests__/Timeline-test.js deleted file mode 100644 index 0d9a0fdc23b..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/Timeline-test.js +++ /dev/null @@ -1,51 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import 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()).toMatchSnapshot(); -}); - -it('should render correctly with a "before" range', () => { - expect(shallow()).toMatchSnapshot(); -}); - -it('should have a correct domain with strings or numbers', () => { - const date = parseDate('2017-05-08T00:00:00.000Z'); - const wrapper = shallow(); - 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]); -}); diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/EmptyOverview-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/EmptyOverview-test.tsx.snap index 4d8cdf63248..cede657480c 100644 --- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/EmptyOverview-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/EmptyOverview-test.tsx.snap @@ -30,22 +30,29 @@ exports[`renders 1`] = `
- + provisioning.no_analysis.delete_project + , } } - > - provisioning.no_analysis.delete_project - - ovisioning.no_analysis.delete + />
@@ -74,8 +81,46 @@ exports[`should render another message when there are branches 1`] = ` id="provisioning.no_analysis_on_main_branch" values={ Object { - "branch":
+ branches.main_branch +
, + } + } + /> +
+
+
+

+ key +

+ + abcd + +
+
+`; + +exports[`should render another message when there are branches 2`] = ` +
+
+
+ branches.main_branch
, diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/SonarCloudEmptyOverview-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/SonarCloudEmptyOverview-test.tsx.snap new file mode 100644 index 00000000000..1dd9c747b5a --- /dev/null +++ b/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/SonarCloudEmptyOverview-test.tsx.snap @@ -0,0 +1,229 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders correctly 1`] = ` +
+
+
+ + + +
+
+ +
+
+
+`; + +exports[`should not render the tutorial 1`] = ` +
+
+
+ +
+
+ +
+
+
+`; + +exports[`should render another message when there are branches 1`] = ` +
+
+
+ + + +
+
+ +
+
+
+`; + +exports[`should render another message when there are branches 2`] = ` +
+
+
+ + + +
+
+ +
+
+
+`; + +exports[`should render warning message 1`] = ` +
+ + branches.main_branch +
, + } + } + /> +
+`; diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/Timeline-test.js.snap b/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/Timeline-test.js.snap deleted file mode 100644 index 3c01c85264d..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/Timeline-test.js.snap +++ /dev/null @@ -1,71 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly with a "before" range 1`] = ` - -`; - -exports[`should render correctly with an "after" range 1`] = ` - -`; diff --git a/server/sonar-web/src/main/js/apps/overview/meta/MetaContainer.tsx b/server/sonar-web/src/main/js/apps/overview/meta/MetaContainer.tsx index 3e7749343a5..64a0a9e4ea6 100644 --- a/server/sonar-web/src/main/js/apps/overview/meta/MetaContainer.tsx +++ b/server/sonar-web/src/main/js/apps/overview/meta/MetaContainer.tsx @@ -58,8 +58,8 @@ interface OwnProps { branchLike?: BranchLike; component: Component; history?: History; - measures: MeasureEnhanced[]; - metrics: { [key: string]: Metric }; + measures?: MeasureEnhanced[]; + metrics?: { [key: string]: Metric }; onComponentChange: (changes: {}) => void; } @@ -106,7 +106,7 @@ export class Meta extends React.PureComponent { 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'; @@ -131,16 +131,20 @@ export class Meta extends React.PureComponent { {isProject && ( )} - + {measures && ( + + )}
- + {metrics && ( + + )} {this.renderQualityInfos()} @@ -152,7 +156,8 @@ export class Meta extends React.PureComponent {
{!isPrivate && - (isProject || isApp) && ( + (isProject || isApp) && + metrics && ( void; +} + +export default class AlmRepositoryItem extends React.PureComponent { + handleChange = () => { + this.props.toggleRepository(this.props.repository); + }; + + render() { + const { identityProvider, repository, selected } = this.props; + const alreadyImported = Boolean(repository.linkedProjectKey); + return ( + + {identityProvider.name} + {this.props.repository.label} + {alreadyImported && ( + + + {translate('onboarding.create_project.already_imported')} + + )} + + ); + } +} diff --git a/server/sonar-web/src/main/js/apps/projects/create/AutoProjectCreate.tsx b/server/sonar-web/src/main/js/apps/projects/create/AutoProjectCreate.tsx new file mode 100644 index 00000000000..078a54d13de --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projects/create/AutoProjectCreate.tsx @@ -0,0 +1,205 @@ +/* + * 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 { + 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) => { + 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 ; + } + + 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 ( + <> +

+ {translateWithParameters( + 'onboarding.create_project.beta_feature_x', + identityProvider.name + )} +

+ {this.state.installed ? ( +
+
    + {this.state.repositories.map(repo => ( +
  • + +
  • + ))} +
+ + {translate('onboarding.create_project.create_project')} + + + + ) : ( +
+

+ {translateWithParameters( + 'onboarding.create_project.install_app_x', + identityProvider.name + )} +

+ + {translateWithParameters( + 'onboarding.create_project.install_app_x.button', + identityProvider.name + )} + +
+ )} + + ); + } +} diff --git a/server/sonar-web/src/main/js/apps/projects/create/CreateProjectPage.tsx b/server/sonar-web/src/main/js/apps/projects/create/CreateProjectPage.tsx new file mode 100644 index 00000000000..63224ebacec --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projects/create/CreateProjectPage.tsx @@ -0,0 +1,184 @@ +/* + * 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; +} + +interface StateProps { + currentUser: CurrentUser; +} + +interface DispatchProps { + skipOnboarding: () => void; +} + +type Props = OwnProps & StateProps & DispatchProps; + +export class CreateProjectPage extends React.PureComponent { + 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[], 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) => { + event.preventDefault(); + this.updateQuery({ manual: false }); + }; + + showManual = (event: React.MouseEvent) => { + event.preventDefault(); + this.updateQuery({ manual: true }); + }; + + updateQuery = (changes: Partial) => { + 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 ( + <> + +
+
+

{header}

+
+ + {this.canAutoCreate() && ( + + )} + + {displayManual || !this.canAutoCreate() ? ( + + ) : ( + + )} +
+ + ); + } +} + +const mapStateToProps = (state: any): StateProps => { + return { + currentUser: getCurrentUser(state) + }; +}; + +const mapDispatchToProps: DispatchProps = { skipOnboarding }; + +export default connect(mapStateToProps, mapDispatchToProps)( + CreateProjectPage +); diff --git a/server/sonar-web/src/main/js/apps/projects/create/ManualProjectCreate.tsx b/server/sonar-web/src/main/js/apps/projects/create/ManualProjectCreate.tsx new file mode 100644 index 00000000000..041b09bdd4d --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projects/create/ManualProjectCreate.tsx @@ -0,0 +1,227 @@ +/* + * 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; +} + +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 { + 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) => { + 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) => { + this.setState({ projectName: event.currentTarget.value }); + }; + + handleProjectKeyChange = (event: React.ChangeEvent) => { + 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 ( + <> +
+
+ + +
+
+ + +
+ + {translate('onboarding.create_project.create_project')} + + + + {this.state.createOrganizationModal && ( + + )} + + ); + } +} + +const mapDispatchToProps = ({ + fetchMyOrganizations +} as any) as DispatchProps; + +const mapStateToProps = (state: any): StateProps => { + return { + userOrganizations: getMyOrganizations(state) + }; +}; +export default connect(mapStateToProps, mapDispatchToProps)( + ManualProjectCreate +); diff --git a/server/sonar-web/src/main/js/apps/projects/create/__tests__/AlmRepositoryItem-test.tsx b/server/sonar-web/src/main/js/apps/projects/create/__tests__/AlmRepositoryItem-test.tsx new file mode 100644 index 00000000000..72b25cb2815 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projects/create/__tests__/AlmRepositoryItem-test.tsx @@ -0,0 +1,66 @@ +/* + * 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( + + ); +} diff --git a/server/sonar-web/src/main/js/apps/projects/create/__tests__/AutoProjectCreate-test.tsx b/server/sonar-web/src/main/js/apps/projects/create/__tests__/AutoProjectCreate-test.tsx new file mode 100644 index 00000000000..bfe95430578 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projects/create/__tests__/AutoProjectCreate-test.tsx @@ -0,0 +1,96 @@ +/* + * 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).mockClear(); + (getRepositories as jest.Mock).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).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(); +} diff --git a/server/sonar-web/src/main/js/apps/projects/create/__tests__/CreateProjectPage-test.tsx b/server/sonar-web/src/main/js/apps/projects/create/__tests__/CreateProjectPage-test.tsx new file mode 100644 index 00000000000..6f995afd252 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projects/create/__tests__/CreateProjectPage-test.tsx @@ -0,0 +1,66 @@ +/* + * 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( + + ); +} diff --git a/server/sonar-web/src/main/js/apps/projects/create/__tests__/ManualProjectCreate-test.tsx b/server/sonar-web/src/main/js/apps/projects/create/__tests__/ManualProjectCreate-test.tsx new file mode 100644 index 00000000000..b79b4e4ae35 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projects/create/__tests__/ManualProjectCreate-test.tsx @@ -0,0 +1,79 @@ +/* + * 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).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('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('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( + + ); +} diff --git a/server/sonar-web/src/main/js/apps/projects/create/__tests__/__snapshots__/AlmRepositoryItem-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/create/__tests__/__snapshots__/AlmRepositoryItem-test.tsx.snap new file mode 100644 index 00000000000..ad71bfc6e60 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projects/create/__tests__/__snapshots__/AlmRepositoryItem-test.tsx.snap @@ -0,0 +1,90 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should render correctly 1`] = ` + + Foo Provider + + Awesome Project + + +`; + +exports[`should render disabled 1`] = ` + + Foo Provider + + Cool Project + + + + onboarding.create_project.already_imported + + +`; + +exports[`should render selected 1`] = ` + + Foo Provider + + Awesome Project + + +`; diff --git a/server/sonar-web/src/main/js/apps/projects/create/__tests__/__snapshots__/AutoProjectCreate-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/create/__tests__/__snapshots__/AutoProjectCreate-test.tsx.snap new file mode 100644 index 00000000000..6d6c0398864 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projects/create/__tests__/__snapshots__/AutoProjectCreate-test.tsx.snap @@ -0,0 +1,113 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should display the list of repositories 1`] = ` + +

+ onboarding.create_project.beta_feature_x.Foo Provider +

+
+
    +
  • + +
  • +
  • + +
  • +
+ + onboarding.create_project.create_project + + + +
+`; + +exports[`should display the provider app install button 1`] = ` + +`; + +exports[`should display the provider app install button 2`] = ` + +

+ onboarding.create_project.beta_feature_x.Foo Provider +

+
+

+ onboarding.create_project.install_app_x.Foo Provider +

+ + onboarding.create_project.install_app_x.button.Foo Provider + +
+
+`; diff --git a/server/sonar-web/src/main/js/apps/projects/create/__tests__/__snapshots__/CreateProjectPage-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/create/__tests__/__snapshots__/CreateProjectPage-test.tsx.snap new file mode 100644 index 00000000000..1880a16ba4c --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projects/create/__tests__/__snapshots__/CreateProjectPage-test.tsx.snap @@ -0,0 +1,98 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should render correctly 1`] = ` + + + + +`; + +exports[`should render with Manual creation only 1`] = ` + + +
+
+

+ onboarding.create_project.header +

+
+ +
+
+`; diff --git a/server/sonar-web/src/main/js/apps/projects/create/__tests__/__snapshots__/ManualProjectCreate-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/create/__tests__/__snapshots__/ManualProjectCreate-test.tsx.snap new file mode 100644 index 00000000000..fafb751c9bb --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projects/create/__tests__/__snapshots__/ManualProjectCreate-test.tsx.snap @@ -0,0 +1,125 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should correctly create a project 1`] = ` + + onboarding.create_project.create_project + +`; + +exports[`should correctly create a project 2`] = ` + + onboarding.create_project.create_project + +`; + +exports[`should render correctly 1`] = ` + +
+
+ + +
+
+ + +
+ + onboarding.create_project.create_project + + + +
+`; diff --git a/server/sonar-web/src/main/js/apps/projects/create/utils.ts b/server/sonar-web/src/main/js/apps/projects/create/utils.ts new file mode 100644 index 00000000000..f3528d0a633 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/projects/create/utils.ts @@ -0,0 +1,42 @@ +/* + * 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) + }) +); diff --git a/server/sonar-web/src/main/js/apps/projects/routes.ts b/server/sonar-web/src/main/js/apps/projects/routes.ts index 873d933ce07..061627c206a 100644 --- a/server/sonar-web/src/main/js/apps/projects/routes.ts +++ b/server/sonar-web/src/main/js/apps/projects/routes.ts @@ -22,6 +22,8 @@ import DefaultPageSelectorContainer from './components/DefaultPageSelectorContai 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 } }, @@ -32,7 +34,11 @@ const routes = [ replace('/projects'); } }, - { path: 'favorite', component: FavoriteProjectsContainer } -]; + { path: 'favorite', component: FavoriteProjectsContainer }, + isSonarCloud() && { + path: 'create', + component: lazyLoad(() => import('./create/CreateProjectPage')) + } +].filter(Boolean); export default routes; diff --git a/server/sonar-web/src/main/js/apps/tutorials/Onboarding.tsx b/server/sonar-web/src/main/js/apps/tutorials/Onboarding.tsx deleted file mode 100644 index 6f19ade590d..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/Onboarding.tsx +++ /dev/null @@ -1,99 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * 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 { - componentDidMount() { - if (!isLoggedIn(this.props.currentUser)) { - handleRequiredAuthentication(); - } - } - - render() { - if (!isLoggedIn(this.props.currentUser)) { - return null; - } - - const header = translate('onboarding.header'); - return ( - -
-

{translate('onboarding.header')}

-

{translate('onboarding.header.description')}

-
-
- - - -
-
- - {translate('not_now')} - -

{translate('onboarding.footer')}

-
-
- ); - } -} - -const mapStateToProps = (state: any): StateProps => ({ currentUser: getCurrentUser(state) }); - -export default connect(mapStateToProps)(Onboarding); diff --git a/server/sonar-web/src/main/js/apps/tutorials/__tests__/Onboarding-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/__tests__/Onboarding-test.tsx deleted file mode 100644 index 9bab36759a5..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/__tests__/Onboarding-test.tsx +++ /dev/null @@ -1,63 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import { shallow } from 'enzyme'; -import { Onboarding } from '../Onboarding'; -import { click } from '../../../helpers/testUtils'; - -it('renders correctly', () => { - expect( - shallow( - - ) - ).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( - , - { 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(); -}); diff --git a/server/sonar-web/src/main/js/apps/tutorials/__tests__/__snapshots__/Onboarding-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/__tests__/__snapshots__/Onboarding-test.tsx.snap deleted file mode 100644 index 18b2f16f846..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/__tests__/__snapshots__/Onboarding-test.tsx.snap +++ /dev/null @@ -1,84 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`renders correctly 1`] = ` - -
-

- onboarding.header -

-

- onboarding.header.description -

-
-
- - - -
-
- - not_now - -

- onboarding.footer -

-
-
-`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/AnalyzeTutorial.tsx b/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/AnalyzeTutorial.tsx new file mode 100644 index 00000000000..7ed7513f6f4 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/AnalyzeTutorial.tsx @@ -0,0 +1,94 @@ +/* + * 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 { + 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 ( + <> +
+

{translate('onboarding.project_analysis.header')}

+

{translate('onboarding.project_analysis.description')}

+
+ + + + {showTutorial && ( + <> + + + + + )} + + ); + } +} diff --git a/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/AnalyzeTutorialSuggestion.tsx b/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/AnalyzeTutorialSuggestion.tsx new file mode 100644 index 00000000000..a93c73b94c8 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/AnalyzeTutorialSuggestion.tsx @@ -0,0 +1,88 @@ +/* + * 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 ( +
+

{translate('onboarding.project_analysis.commands_for_analysis')}

+

{translate('onboarding.project_analysis.suggestions.bitbucket')}

+ + {translate('onboarding.project_analysis.guide_to_integrate_piplines')} + + ) + }} + /> +
+ ); + } else if (almId === 'github') { + return ( +
+

{translate('onboarding.project_analysis.commands_for_analysis')}

+

{translate('onboarding.project_analysis.suggestions.github')}

+ + {translate('onboarding.project_analysis.guide_to_integrate_travis')} + + ) + }} + /> +
+ ); + } else if (almId === 'microsoft') { + return ( +

+ + {translate('onboarding.project_analysis.guide_to_integrate_vsts')} + + ) + }} + /> +

+ ); + } + return null; +} diff --git a/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/__tests__/AnalyzeTutorial-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/__tests__/AnalyzeTutorial-test.tsx new file mode 100644 index 00000000000..39f0233081f --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/__tests__/AnalyzeTutorial-test.tsx @@ -0,0 +1,47 @@ +/* + * 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(); +} diff --git a/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/__tests__/AnalyzeTutorialSuggestion-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/__tests__/AnalyzeTutorialSuggestion-test.tsx new file mode 100644 index 00000000000..bc4a6d7b55b --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/__tests__/AnalyzeTutorialSuggestion-test.tsx @@ -0,0 +1,38 @@ +/* + * 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().type()).toBeNull(); +}); + +it('renders bitbucket suggestions correctly', () => { + expect(shallow()).toMatchSnapshot(); +}); + +it('renders github suggestions correctly', () => { + expect(shallow()).toMatchSnapshot(); +}); + +it('renders vsts suggestions correctly', () => { + expect(shallow()).toMatchSnapshot(); +}); diff --git a/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/__tests__/__snapshots__/AnalyzeTutorial-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/__tests__/__snapshots__/AnalyzeTutorial-test.tsx.snap new file mode 100644 index 00000000000..af09b977a36 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/__tests__/__snapshots__/AnalyzeTutorial-test.tsx.snap @@ -0,0 +1,54 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders correctly 1`] = ` + +
+

+ onboarding.project_analysis.header +

+

+ onboarding.project_analysis.description +

+
+ + + + + +
+`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/__tests__/__snapshots__/AnalyzeTutorialSuggestion-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/__tests__/__snapshots__/AnalyzeTutorialSuggestion-test.tsx.snap new file mode 100644 index 00000000000..b682fbd8ed0 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/__tests__/__snapshots__/AnalyzeTutorialSuggestion-test.tsx.snap @@ -0,0 +1,78 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders bitbucket suggestions correctly 1`] = ` +
+

+ onboarding.project_analysis.commands_for_analysis +

+

+ onboarding.project_analysis.suggestions.bitbucket +

+ + onboarding.project_analysis.guide_to_integrate_piplines + , + } + } + /> +
+`; + +exports[`renders github suggestions correctly 1`] = ` +
+

+ onboarding.project_analysis.commands_for_analysis + +

+

+ onboarding.project_analysis.suggestions.github +

+ + onboarding.project_analysis.guide_to_integrate_travis + , + } + } + /> +
+`; + +exports[`renders vsts suggestions correctly 1`] = ` +

+ + onboarding.project_analysis.guide_to_integrate_vsts + , + } + } + /> +

+`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/LanguageForm.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/LanguageForm.tsx new file mode 100644 index 00000000000..8762501b301 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/LanguageForm.tsx @@ -0,0 +1,175 @@ +/* + * 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 { + 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 = () => ( +
+

{translate('onboarding.language.java.build_technology')}

+ ({ + label: translate('onboarding.language.java.build_technology', build), + value: build + }))} + value={this.state.javaBuild} + /> +
+ ); + + renderCFamilyCompiler = () => ( +
+

{translate('onboarding.language.c-family.compiler')}

+ ({ + label: translate('onboarding.language.c-family.compiler', compiler), + value: compiler + }))} + value={this.state.cFamilyCompiler} + /> +
+ ); + + renderOS = () => ( +
+

{translate('onboarding.language.os')}

+ ({ + label: translate('onboarding.language.os', os), + value: os + }))} + value={this.state.os} + /> +
+ ); + + 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 ( + + ); + }; + + render() { + const { cFamilyCompiler, language } = this.state; + const languages = isSonarCloud() + ? ['java', 'dotnet', 'c-family', 'other'] + : ['java', 'dotnet', 'other']; + + return ( + <> +
+

{translate('onboarding.language')}

+ ({ + label: translate('onboarding.language', language), + value: language + }))} + value={language} + /> +
+ {language === 'java' && this.renderJavaBuild()} + {language === 'c-family' && this.renderCFamilyCompiler()} + {((language === 'c-family' && cFamilyCompiler === 'clang-gcc') || language === 'other') && + this.renderOS()} + {this.renderProjectKey()} + + ); + } +} diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/NewOrganizationForm.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/NewOrganizationForm.tsx new file mode 100644 index 00000000000..5244898544d --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/NewOrganizationForm.tsx @@ -0,0 +1,168 @@ +/* + * 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 { + 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) => { + const organization = this.sanitizeOrganization(event.target.value); + this.setState({ organization }); + this.validateOrganization(organization); + }; + + handleOrganizationCreate = (event: React.FormEvent) => { + 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 ? ( +
+ {organization} + {loading ? ( + + ) : ( + + )} +
+ ) : ( +
+ + {loading ? ( + + ) : ( + + {translate('create')} + + )} + {!unique && ( + + + {translate('this_name_is_already_taken')} + + )} +
+ {translate('onboarding.organization.key_requirement')} +
+ + ); + } +} diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/NewProjectForm.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/NewProjectForm.tsx new file mode 100644 index 00000000000..f09b4d152bf --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/NewProjectForm.tsx @@ -0,0 +1,150 @@ +/* + * 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 { + 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) => { + this.setState({ projectKey: this.sanitizeProjectKey(event.target.value) }); + }; + + handleProjectCreate = (event: React.FormEvent) => { + 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 ? ( +
+ {projectKey} + {loading ? ( + + ) : ( + + )} +
+ ) : ( +
+ + {loading ? ( + + ) : ( + + {translate('Done')} + + )} +
+ {translate('onboarding.project_key_requirement')} +
+ + ); + + return ( +
+

{translate('onboarding.language.project_key')}

+ {form} +
+ ); + } +} diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/OrganizationStep.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/OrganizationStep.tsx new file mode 100644 index 00000000000..934965c7559 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/OrganizationStep.tsx @@ -0,0 +1,273 @@ +/* + * 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; + personalOrganization?: string; + selection: 'personal' | 'existing' | 'new'; +} + +export default class OrganizationStep extends React.PureComponent { + 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) => { + event.preventDefault(); + this.setState({ selection: 'personal' }); + }; + + handleExistingClick = (event: React.MouseEvent) => { + event.preventDefault(); + this.setState({ selection: 'existing' }); + }; + + handleNewClick = (event: React.MouseEvent) => { + 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 = () => ( + + ); + + renderExistingOrganizationOption = () => ( +
+ + + {translate('onboarding.organization.exising_organization')} + + {this.state.selection === 'existing' && ( +
+ + {this.state.loading ? ( + + ) : ( + + {translate('onboarding.token.generate')} + + )} + +
+ )} +
+ ); + + renderUseExistingOption = () => { + const { existingToken } = this.state; + const validInput = !existingToken || existingToken.match(/^[a-z0-9]+$/) != null; + + return ( +
+ + + {translate('onboarding.token.use_existing_token')} + + {this.state.selection === 'use-existing' && ( +
+ + {!validInput && ( + + + {translate('onboarding.token.invalid_format')} + + )} +
+ )} +
+ ); + }; + + renderForm = () => { + const { canUseExisting, loading, token, tokenName } = this.state; + + return ( +
+ {token != null ? ( +
+ + {tokenName} + {': '} + + {token} + {loading ? ( + + ) : ( + + )} + + ) : ( +
+ {this.renderGenerateOption()} + {canUseExisting && this.renderUseExistingOption()} +
+ )} + +
{translate('onboarding.token.text')}
+ + {this.canContinue() && ( +
+ +
+ )} +
+ ); + }; + + renderResult = () => { + const { selection, tokenName } = this.state; + const token = this.getToken(); + + if (!token) { + return null; + } + + return ( +
+ + {selection === 'generate' && tokenName && `${tokenName}: `} + {token} +
+ ); + }; + + render() { + return ( + + ); + } +} diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/LanguageForm-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/LanguageForm-test.tsx new file mode 100644 index 00000000000..f767450c0ac --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/LanguageForm-test.tsx @@ -0,0 +1,131 @@ +/* + * 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).mockImplementation(() => false); +}); + +it('selects java', () => { + const onDone = jest.fn(); + const wrapper = shallow(); + + (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(); + + (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).mockImplementation(() => true); + const onDone = jest.fn(); + const wrapper = shallow(); + + (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(); + + (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' }); +}); diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/NewOrganizationForm-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/NewOrganizationForm-test.tsx new file mode 100644 index 00000000000..bb16f901167 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/NewOrganizationForm-test.tsx @@ -0,0 +1,56 @@ +/* + * 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(); + 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(); + 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(); +}); diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/NewProjectForm-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/NewProjectForm-test.tsx new file mode 100644 index 00000000000..2c8c18cace4 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/NewProjectForm-test.tsx @@ -0,0 +1,55 @@ +/* + * 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(); + 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(); + 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(); +}); diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/OrganizationStep-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/OrganizationStep-test.tsx new file mode 100644 index 00000000000..b2192a0bce7 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/OrganizationStep-test.tsx @@ -0,0 +1,102 @@ +/* + * 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).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( + + ); + click(wrapper.find('.js-continue')); + expect(onContinue).toBeCalledWith('user'); +}); + +it('works with existing organization', async () => { + const onContinue = jest.fn(); + const wrapper = mount( + + ); + 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( + + ); + 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'); +}); diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/Step-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/Step-test.tsx new file mode 100644 index 00000000000..8a9664f71c8 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/Step-test.tsx @@ -0,0 +1,57 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import * as React from 'react'; +import { shallow } from 'enzyme'; +import Step from '../Step'; +import { click } from '../../../../helpers/testUtils'; + +it('renders', () => { + const wrapper = shallow( +
form
} + renderResult={() =>
result
} + 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( +
form
} + renderResult={() =>
result
} + stepNumber={1} + stepTitle="First Step" + /> + ); + click(wrapper); + expect(onOpen).toBeCalled(); +}); diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/TokenStep-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/TokenStep-test.tsx new file mode 100644 index 00000000000..25b5f0c7462 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/TokenStep-test.tsx @@ -0,0 +1,110 @@ +/* + * 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( + + ); + 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( + + ); + 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( + + ); + 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( + + ); + await new Promise(setImmediate); + wrapper.setState({ existingToken: 'abcd1234', selection: 'use-existing' }); + click(wrapper.find('[className="js-continue"]')); + expect(onContinue).toBeCalledWith('abcd1234'); +}); diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/__snapshots__/LanguageForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/__snapshots__/LanguageForm-test.tsx.snap new file mode 100644 index 00000000000..c653180e332 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/__snapshots__/LanguageForm-test.tsx.snap @@ -0,0 +1,687 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`selects c# 1`] = ` + +
+

+ onboarding.language +

+ +
+ +
+`; + +exports[`selects c-family 1`] = ` + +
+

+ onboarding.language +

+ +
+
+

+ onboarding.language.c-family.compiler +

+ +
+
+`; + +exports[`selects c-family 2`] = ` + +
+

+ onboarding.language +

+ +
+
+

+ onboarding.language.c-family.compiler +

+ +
+ +
+`; + +exports[`selects c-family 3`] = ` + +
+

+ onboarding.language +

+ +
+
+

+ onboarding.language.c-family.compiler +

+ +
+
+

+ onboarding.language.os +

+ +
+
+`; + +exports[`selects c-family 4`] = ` + +
+

+ onboarding.language +

+ +
+
+

+ onboarding.language.c-family.compiler +

+ +
+
+

+ onboarding.language.os +

+ +
+ +
+`; + +exports[`selects java 1`] = ` + +
+

+ onboarding.language +

+ +
+
+

+ onboarding.language.java.build_technology +

+ +
+
+`; + +exports[`selects java 2`] = ` + +
+

+ onboarding.language +

+ +
+
+

+ onboarding.language.java.build_technology +

+ +
+
+`; + +exports[`selects java 3`] = ` + +
+

+ onboarding.language +

+ +
+
+

+ onboarding.language.java.build_technology +

+ +
+
+`; + +exports[`selects other 1`] = ` + +
+

+ onboarding.language +

+ +
+
+

+ onboarding.language.os +

+ +
+
+`; + +exports[`selects other 2`] = ` + +
+

+ onboarding.language +

+ +
+
+

+ onboarding.language.os +

+ +
+ +
+`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/__snapshots__/NewOrganizationForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/__snapshots__/NewOrganizationForm-test.tsx.snap new file mode 100644 index 00000000000..eae8fcdb833 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/__snapshots__/NewOrganizationForm-test.tsx.snap @@ -0,0 +1,270 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`creates new organization 1`] = ` + +
+ + + + + +
+ onboarding.organization.key_requirement +
+
+
+`; + +exports[`creates new organization 2`] = ` + +
+ + +
+ onboarding.organization.key_requirement +
+ +
+`; + +exports[`creates new organization 3`] = ` + +
+ + foo + + + + + + + +
+
+`; + +exports[`deletes organization 1`] = ` + +
+ + foo + + + + + + + +
+
+`; + +exports[`deletes organization 2`] = ` + +
+ + foo + + +
+
+`; + +exports[`deletes organization 3`] = ` + +
+ + + + + +
+ onboarding.organization.key_requirement +
+
+
+`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/__snapshots__/NewProjectForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/__snapshots__/NewProjectForm-test.tsx.snap new file mode 100644 index 00000000000..f6722a21bf6 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/__snapshots__/NewProjectForm-test.tsx.snap @@ -0,0 +1,321 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`creates new project 1`] = ` + +
+

+ onboarding.language.project_key +

+
+ + + + + +
+ onboarding.project_key_requirement +
+
+
+
+`; + +exports[`creates new project 2`] = ` + +
+

+ onboarding.language.project_key +

+
+ + +
+ onboarding.project_key_requirement +
+ +
+
+`; + +exports[`creates new project 3`] = ` + +
+

+ onboarding.language.project_key +

+
+ + foo + + + + + + + +
+
+
+`; + +exports[`deletes project 1`] = ` + +
+

+ onboarding.language.project_key +

+
+ + foo + + + + + + + +
+
+
+`; + +exports[`deletes project 2`] = ` + +
+

+ onboarding.language.project_key +

+
+ + foo + + +
+
+
+`; + +exports[`deletes project 3`] = ` + +
+

+ onboarding.language.project_key +

+
+ + + + + +
+ onboarding.project_key_requirement +
+
+
+
+`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/__snapshots__/OrganizationStep-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/__snapshots__/OrganizationStep-test.tsx.snap new file mode 100644 index 00000000000..8ece74c899f --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/__snapshots__/OrganizationStep-test.tsx.snap @@ -0,0 +1,286 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`works with existing organization 1`] = ` + + + onboarding.organization.header + + + } + > +
+
+ 1 +
+
+

+ + onboarding.organization.header + + +

+
+
+
+ onboarding.organization.text +
+
+ +
+
+ + +`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/__snapshots__/Step-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/__snapshots__/Step-test.tsx.snap new file mode 100644 index 00000000000..4667ca7ae8a --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/__snapshots__/Step-test.tsx.snap @@ -0,0 +1,51 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders 1`] = ` +
+
+ 1 +
+
+

+ First Step +

+
+
+ form +
+
+`; + +exports[`renders 2`] = ` +
+
+ 1 +
+
+ result +
+
+

+ First Step +

+
+
+
+`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/__snapshots__/TokenStep-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/__snapshots__/TokenStep-test.tsx.snap new file mode 100644 index 00000000000..54847972e8c --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/__snapshots__/TokenStep-test.tsx.snap @@ -0,0 +1,649 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`generates token 1`] = ` + + +
+
+ 1 +
+
+

+ onboarding.token.header +

+
+
+
+
+ + + onboarding.token.generate_token + +
+
+ + + + + +
+
+
+ +
+
+ onboarding.token.text +
+
+
+
+
+`; + +exports[`generates token 2`] = ` + + +
+
+ 1 +
+
+

+ onboarding.token.header +

+
+
+ +
+ onboarding.token.text +
+
+
+
+
+`; + +exports[`generates token 3`] = ` + + +
+
+ 1 +
+
+

+ onboarding.token.header +

+
+
+
+ + my token + : + + + abcd1234 + + + + + + + +
+
+ onboarding.token.text +
+
+ + +
+
+
+
+
+`; + +exports[`revokes token 1`] = ` + + +
+
+ 1 +
+
+

+ onboarding.token.header +

+
+
+
+ + my token + : + + + abcd1234 + + + + + + + +
+
+ onboarding.token.text +
+
+ + +
+
+
+
+
+`; + +exports[`revokes token 2`] = ` + + +
+
+ 1 +
+
+

+ onboarding.token.header +

+
+
+
+ + my token + : + + + abcd1234 + + + +
+ onboarding.token.text +
+
+ + +
+
+
+
+
+`; + +exports[`revokes token 3`] = ` + + +
+
+ 1 +
+
+

+ onboarding.token.header +

+
+
+
+
+ + + onboarding.token.generate_token + +
+
+ + + + + +
+
+
+ +
+
+ onboarding.token.text +
+
+
+
+
+`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/commands/AnalysisCommand.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/AnalysisCommand.tsx new file mode 100644 index 00000000000..3bcdb9bdbdb --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/AnalysisCommand.tsx @@ -0,0 +1,146 @@ +/* + * 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 { + getProjectKey = ({ component, languageConfig } = this.props) => { + return (component && component.key) || languageConfig.projectKey; + }; + + renderCommandForMaven = () => { + const { token } = this.props; + if (!token) { + return null; + } + return ; + }; + + renderCommandForGradle = () => { + const { token } = this.props; + if (!token) { + return null; + } + return ; + }; + + renderCommandForDotNet = () => { + const { small, token } = this.props; + const projectKey = this.getProjectKey(); + if (!projectKey || !token) { + return null; + } + return ( + + ); + }; + + renderCommandForMSVC = () => { + const { small, token } = this.props; + const projectKey = this.getProjectKey(); + if (!projectKey || !token) { + return null; + } + return ( + + ); + }; + + renderCommandForClangGCC = () => { + const { languageConfig, small, token } = this.props; + const projectKey = this.getProjectKey(); + if (!languageConfig || !projectKey || !languageConfig.os || !token) { + return null; + } + return ( + + ); + }; + + renderCommandForOther = () => { + const { languageConfig, token } = this.props; + const projectKey = this.getProjectKey(); + if (!languageConfig || !projectKey || !languageConfig.os || !token) { + return null; + } + return ( + + ); + }; + + 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(); + } + } +} diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/commands/BuildWrapper.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/BuildWrapper.tsx new file mode 100644 index 00000000000..ed03adbf911 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/BuildWrapper.tsx @@ -0,0 +1,58 @@ +/* + * 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 ( +
+

+ {translate('onboarding.analysis.build_wrapper.header', props.os)} +

+

+

+ + {translate('download_verb')} + +

+
+ ); +} diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/commands/ClangGCC.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/ClangGCC.tsx new file mode 100644 index 00000000000..0afc9783def --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/ClangGCC.tsx @@ -0,0 +1,79 @@ +/* + * 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 ( +
+ + + +

+ {translate('onboarding.analysis.sq_scanner.execute')} +

+ + {transformedMessage => ( +

+ )} + + + +

+

+ ); +} diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/commands/DotNet.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/DotNet.tsx new file mode 100644 index 00000000000..12de244aaf8 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/DotNet.tsx @@ -0,0 +1,71 @@ +/* + * 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 ( +
+ + +

+ {translate('onboarding.analysis.msbuild.execute')} +

+ + {transformedMessage => ( +

+ )} + + + + +

+

+ ); +} diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/commands/JavaGradle.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/JavaGradle.tsx new file mode 100644 index 00000000000..fa95c27bf5e --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/JavaGradle.tsx @@ -0,0 +1,71 @@ +/* + * 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 ( +
+

{translate('onboarding.analysis.java.gradle.header')}

+ + {transformedMessage => ( +

+ )} + + +

+ {translate('onboarding.analysis.java.gradle.text.2')} +

+ +

+

+

+ ); +} diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/commands/JavaMaven.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/JavaMaven.tsx new file mode 100644 index 00000000000..8ade1b432bd --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/JavaMaven.tsx @@ -0,0 +1,60 @@ +/* + * 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 ( +
+

{translate('onboarding.analysis.java.maven.header')}

+

+ +

+ +

+

+

+ ); +} diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/commands/MSBuildScanner.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/MSBuildScanner.tsx new file mode 100644 index 00000000000..65c4005af86 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/MSBuildScanner.tsx @@ -0,0 +1,47 @@ +/* + * 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 ( +
+

{translate('onboarding.analysis.msbuild.header')}

+

+

+ + {translate('download_verb')} + +

+
+ ); +} diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/commands/Msvc.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/Msvc.tsx new file mode 100644 index 00000000000..838da876e26 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/Msvc.tsx @@ -0,0 +1,74 @@ +/* + * 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 ( +
+ + + +

+ {translate('onboarding.analysis.msbuild.execute')} +

+ + {transformedMessage => ( +

+ )} + + + + +

+

+ ); +} diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/commands/Other.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/Other.tsx new file mode 100644 index 00000000000..3d0b3b2a718 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/Other.tsx @@ -0,0 +1,66 @@ +/* + * 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 ( +
+ + +

+ {translate('onboarding.analysis.sq_scanner.execute')} +

+ + {transformedMessage => ( +

+ )} + + +

+

+ ); +} diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/commands/SQScanner.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/SQScanner.tsx new file mode 100644 index 00000000000..78b90f851bc --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/SQScanner.tsx @@ -0,0 +1,52 @@ +/* + * 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 ( +
+

+ {translate('onboarding.analysis.sq_scanner.header', props.os)} +

+

+

+ + {translate('download_verb')} + +

+
+ ); +} diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/AnalysisCommand-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/AnalysisCommand-test.tsx new file mode 100644 index 00000000000..3dc16151384 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/AnalysisCommand-test.tsx @@ -0,0 +1,71 @@ +/* + * 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(); +} diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/BuildWrapper-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/BuildWrapper-test.tsx new file mode 100644 index 00000000000..b19e334793b --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/BuildWrapper-test.tsx @@ -0,0 +1,28 @@ +/* + * 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()).toMatchSnapshot(); + expect(shallow()).toMatchSnapshot(); + expect(shallow()).toMatchSnapshot(); +}); diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/ClangGCC-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/ClangGCC-test.tsx new file mode 100644 index 00000000000..8ffa75c7217 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/ClangGCC-test.tsx @@ -0,0 +1,46 @@ +/* + * 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() + ).toMatchSnapshot(); + + expect( + shallow() + ).toMatchSnapshot(); + + expect( + shallow( + + ) + ).toMatchSnapshot(); +}); diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/DotNet-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/DotNet-test.tsx new file mode 100644 index 00000000000..e95302cb59a --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/DotNet-test.tsx @@ -0,0 +1,38 @@ +/* + * 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()).toMatchSnapshot(); + expect( + shallow( + + ) + ).toMatchSnapshot(); +}); diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/JavaGradle-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/JavaGradle-test.tsx new file mode 100644 index 00000000000..f0d130a248d --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/JavaGradle-test.tsx @@ -0,0 +1,30 @@ +/* + * 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()).toMatchSnapshot(); + expect( + shallow() + ).toMatchSnapshot(); +}); diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/JavaMaven-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/JavaMaven-test.tsx new file mode 100644 index 00000000000..dbda16ca13e --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/JavaMaven-test.tsx @@ -0,0 +1,30 @@ +/* + * 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()).toMatchSnapshot(); + expect( + shallow() + ).toMatchSnapshot(); +}); diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/MSBuildScanner-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/MSBuildScanner-test.tsx new file mode 100644 index 00000000000..e5411341d10 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/MSBuildScanner-test.tsx @@ -0,0 +1,27 @@ +/* + * 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()).toMatchSnapshot(); +}); diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/Msvc-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/Msvc-test.tsx new file mode 100644 index 00000000000..68ee47b0de3 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/Msvc-test.tsx @@ -0,0 +1,38 @@ +/* + * 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()).toMatchSnapshot(); + expect( + shallow( + + ) + ).toMatchSnapshot(); +}); diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/Other-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/Other-test.tsx new file mode 100644 index 00000000000..16cc44ae69f --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/Other-test.tsx @@ -0,0 +1,45 @@ +/* + * 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() + ).toMatchSnapshot(); + + expect( + shallow() + ).toMatchSnapshot(); + + expect( + shallow( + + ) + ).toMatchSnapshot(); +}); diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/SQScanner-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/SQScanner-test.tsx new file mode 100644 index 00000000000..2be4e546bb3 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/SQScanner-test.tsx @@ -0,0 +1,29 @@ +/* + * 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()).toMatchSnapshot(); + expect(shallow()).toMatchSnapshot(); + expect(shallow()).toMatchSnapshot(); +}); diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/AnalysisCommand-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/AnalysisCommand-test.tsx.snap new file mode 100644 index 00000000000..f6a09725d51 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/AnalysisCommand-test.tsx.snap @@ -0,0 +1,49 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`display c# command 1`] = ` + +`; + +exports[`display c-family command 1`] = ` + +`; + +exports[`display c-family command 2`] = ` + +`; + +exports[`display java command 1`] = ` + +`; + +exports[`display java command 2`] = ` + +`; + +exports[`display others command 1`] = ` + +`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/BuildWrapper-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/BuildWrapper-test.tsx.snap new file mode 100644 index 00000000000..07e8eb45f0a --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/BuildWrapper-test.tsx.snap @@ -0,0 +1,85 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders correctly 1`] = ` +
+

+ onboarding.analysis.build_wrapper.header.win +

+

+

+ + download_verb + +

+
+`; + +exports[`renders correctly 2`] = ` +
+

+ onboarding.analysis.build_wrapper.header.linux +

+

+

+ + download_verb + +

+
+`; + +exports[`renders correctly 3`] = ` +
+

+ onboarding.analysis.build_wrapper.header.mac +

+

+

+ + download_verb + +

+
+`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/ClangGCC-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/ClangGCC-test.tsx.snap new file mode 100644 index 00000000000..642935280e5 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/ClangGCC-test.tsx.snap @@ -0,0 +1,137 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders correctly 1`] = ` +
+ + +

+ onboarding.analysis.sq_scanner.execute +

+ + + +

+

+`; + +exports[`renders correctly 2`] = ` +
+ + +

+ onboarding.analysis.sq_scanner.execute +

+ + + +

+

+`; + +exports[`renders correctly 3`] = ` +
+ + +

+ onboarding.analysis.sq_scanner.execute +

+ + + +

+

+`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/DotNet-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/DotNet-test.tsx.snap new file mode 100644 index 00000000000..7f0e70d7242 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/DotNet-test.tsx.snap @@ -0,0 +1,94 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders correctly 1`] = ` +
+ +

+ onboarding.analysis.msbuild.execute +

+ + + + +

+

+`; + +exports[`renders correctly 2`] = ` +
+ +

+ onboarding.analysis.msbuild.execute +

+ + + + +

+

+`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/JavaGradle-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/JavaGradle-test.tsx.snap new file mode 100644 index 00000000000..c5ff1eb813c --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/JavaGradle-test.tsx.snap @@ -0,0 +1,99 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders correctly 1`] = ` +
+

+ onboarding.analysis.java.gradle.header +

+ + +

+ onboarding.analysis.java.gradle.text.2 +

+ +

+

+

+`; + +exports[`renders correctly 2`] = ` +
+

+ onboarding.analysis.java.gradle.header +

+ + +

+ onboarding.analysis.java.gradle.text.2 +

+ +

+

+

+`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/JavaMaven-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/JavaMaven-test.tsx.snap new file mode 100644 index 00000000000..7993a392397 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/JavaMaven-test.tsx.snap @@ -0,0 +1,87 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders correctly 1`] = ` +
+

+ onboarding.analysis.java.maven.header +

+

+ +

+ +

+

+

+`; + +exports[`renders correctly 2`] = ` +
+

+ onboarding.analysis.java.maven.header +

+

+ +

+ +

+

+

+`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/MSBuildScanner-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/MSBuildScanner-test.tsx.snap new file mode 100644 index 00000000000..740e26ed12b --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/MSBuildScanner-test.tsx.snap @@ -0,0 +1,29 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders correctly 1`] = ` +
+

+ onboarding.analysis.msbuild.header +

+

+

+ + download_verb + +

+
+`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/Msvc-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/Msvc-test.tsx.snap new file mode 100644 index 00000000000..accb581024c --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/Msvc-test.tsx.snap @@ -0,0 +1,103 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders correctly 1`] = ` +
+ + +

+ onboarding.analysis.msbuild.execute +

+ + + + +

+

+`; + +exports[`renders correctly 2`] = ` +
+ + +

+ onboarding.analysis.msbuild.execute +

+ + + + +

+

+`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/Other-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/Other-test.tsx.snap new file mode 100644 index 00000000000..73aba357dca --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/Other-test.tsx.snap @@ -0,0 +1,112 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders correctly 1`] = ` +
+ +

+ onboarding.analysis.sq_scanner.execute +

+ + +

+

+`; + +exports[`renders correctly 2`] = ` +
+ +

+ onboarding.analysis.sq_scanner.execute +

+ + +

+

+`; + +exports[`renders correctly 3`] = ` +
+ +

+ onboarding.analysis.sq_scanner.execute +

+ + +

+

+`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/SQScanner-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/SQScanner-test.tsx.snap new file mode 100644 index 00000000000..cf6a8de4ce3 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/SQScanner-test.tsx.snap @@ -0,0 +1,85 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders correctly 1`] = ` +
+

+ onboarding.analysis.sq_scanner.header.win +

+

+

+ + download_verb + +

+
+`; + +exports[`renders correctly 2`] = ` +
+

+ onboarding.analysis.sq_scanner.header.linux +

+

+

+ + download_verb + +

+
+`; + +exports[`renders correctly 3`] = ` +
+

+ onboarding.analysis.sq_scanner.header.mac +

+

+

+ + download_verb + +

+
+`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/AlmRepositoryItem.tsx b/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/AlmRepositoryItem.tsx deleted file mode 100644 index 8e21b7111ae..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/AlmRepositoryItem.tsx +++ /dev/null @@ -1,65 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * 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 { - handleChange = () => { - this.props.toggleRepository(this.props.repository); - }; - - render() { - const { identityProvider, repository, selected } = this.props; - const alreadyImported = Boolean(repository.linkedProjectKey); - return ( - - {identityProvider.name} - {this.props.repository.label} - {alreadyImported && ( - - - {translate('onboarding.create_project.already_imported')} - - )} - - ); - } -} diff --git a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/AutoProjectCreate.tsx b/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/AutoProjectCreate.tsx deleted file mode 100644 index 078a54d13de..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/AutoProjectCreate.tsx +++ /dev/null @@ -1,205 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * 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 { - 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) => { - 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 ; - } - - 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 ( - <> -

- {translateWithParameters( - 'onboarding.create_project.beta_feature_x', - identityProvider.name - )} -

- {this.state.installed ? ( -
-
    - {this.state.repositories.map(repo => ( -
  • - -
  • - ))} -
- - {translate('onboarding.create_project.create_project')} - - - - ) : ( -
-

- {translateWithParameters( - 'onboarding.create_project.install_app_x', - identityProvider.name - )} -

- - {translateWithParameters( - 'onboarding.create_project.install_app_x.button', - identityProvider.name - )} - -
- )} - - ); - } -} diff --git a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/CreateProjectOnboarding.tsx b/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/CreateProjectOnboarding.tsx deleted file mode 100644 index 17bae7689e7..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/CreateProjectOnboarding.tsx +++ /dev/null @@ -1,185 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * 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 { - 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[], 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) => { - event.preventDefault(); - this.setState({ activeTab: Tabs.AUTO }); - }; - - showManual = (event: React.MouseEvent) => { - 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 ( - <> - -
-
-

{header}

-
- - {this.shouldDisplayTabs() && ( - - )} - - {activeTab === Tabs.AUTO ? ( - - ) : ( - - )} -
- - ); - } -} - -const mapStateToProps = (state: any): StateProps => { - return { - currentUser: getCurrentUser(state) - }; -}; - -const mapDispatchToProps: DispatchProps = { skipOnboarding }; - -export default connect(mapStateToProps, mapDispatchToProps)( - CreateProjectOnboarding -); diff --git a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/ManualProjectCreate.tsx b/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/ManualProjectCreate.tsx deleted file mode 100644 index 59d615583c7..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/ManualProjectCreate.tsx +++ /dev/null @@ -1,227 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * 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; -} - -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 { - 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) => { - 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) => { - this.setState({ projectName: event.currentTarget.value }); - }; - - handleProjectKeyChange = (event: React.ChangeEvent) => { - 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 ( - <> -
-
- - -
-
- - -
- - {translate('onboarding.create_project.create_project')} - - - - {this.state.createOrganizationModal && ( - - )} - - ); - } -} - -const mapDispatchToProps = ({ - fetchMyOrganizations -} as any) as DispatchProps; - -const mapStateToProps = (state: any): StateProps => { - return { - userOrganizations: getMyOrganizations(state) - }; -}; -export default connect(mapStateToProps, mapDispatchToProps)( - ManualProjectCreate -); diff --git a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/AlmRepositoryItem-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/AlmRepositoryItem-test.tsx deleted file mode 100644 index 72b25cb2815..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/AlmRepositoryItem-test.tsx +++ /dev/null @@ -1,66 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * 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( - - ); -} diff --git a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/AutoProjectCreate-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/AutoProjectCreate-test.tsx deleted file mode 100644 index bfe95430578..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/AutoProjectCreate-test.tsx +++ /dev/null @@ -1,96 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * 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).mockClear(); - (getRepositories as jest.Mock).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).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(); -} diff --git a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/CreateProjectOnboarding-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/CreateProjectOnboarding-test.tsx deleted file mode 100644 index f7cfa3ce8da..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/CreateProjectOnboarding-test.tsx +++ /dev/null @@ -1,58 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * 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( - - ); -} diff --git a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/ManualProjectCreate-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/ManualProjectCreate-test.tsx deleted file mode 100644 index b79b4e4ae35..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/ManualProjectCreate-test.tsx +++ /dev/null @@ -1,79 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * 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).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('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('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( - - ); -} diff --git a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/__snapshots__/AlmRepositoryItem-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/__snapshots__/AlmRepositoryItem-test.tsx.snap deleted file mode 100644 index ad71bfc6e60..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/__snapshots__/AlmRepositoryItem-test.tsx.snap +++ /dev/null @@ -1,90 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly 1`] = ` - - Foo Provider - - Awesome Project - - -`; - -exports[`should render disabled 1`] = ` - - Foo Provider - - Cool Project - - - - onboarding.create_project.already_imported - - -`; - -exports[`should render selected 1`] = ` - - Foo Provider - - Awesome Project - - -`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/__snapshots__/AutoProjectCreate-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/__snapshots__/AutoProjectCreate-test.tsx.snap deleted file mode 100644 index 6d6c0398864..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/__snapshots__/AutoProjectCreate-test.tsx.snap +++ /dev/null @@ -1,113 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should display the list of repositories 1`] = ` - -

- onboarding.create_project.beta_feature_x.Foo Provider -

-
-
    -
  • - -
  • -
  • - -
  • -
- - onboarding.create_project.create_project - - - -
-`; - -exports[`should display the provider app install button 1`] = ` - -`; - -exports[`should display the provider app install button 2`] = ` - -

- onboarding.create_project.beta_feature_x.Foo Provider -

-
-

- onboarding.create_project.install_app_x.Foo Provider -

- - onboarding.create_project.install_app_x.button.Foo Provider - -
-
-`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/__snapshots__/CreateProjectOnboarding-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/__snapshots__/CreateProjectOnboarding-test.tsx.snap deleted file mode 100644 index 1920eb22a54..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/__snapshots__/CreateProjectOnboarding-test.tsx.snap +++ /dev/null @@ -1,98 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly 1`] = ` - - - - -`; - -exports[`should render with Manual creation only 1`] = ` - - -
-
-

- onboarding.create_project.header -

-
- -
-
-`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/__snapshots__/ManualProjectCreate-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/__snapshots__/ManualProjectCreate-test.tsx.snap deleted file mode 100644 index fafb751c9bb..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/__snapshots__/ManualProjectCreate-test.tsx.snap +++ /dev/null @@ -1,125 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should correctly create a project 1`] = ` - - onboarding.create_project.create_project - -`; - -exports[`should correctly create a project 2`] = ` - - onboarding.create_project.create_project - -`; - -exports[`should render correctly 1`] = ` - -
-
- - -
-
- - -
- - onboarding.create_project.create_project - - - -
-`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/OnboardingModal.tsx b/server/sonar-web/src/main/js/apps/tutorials/onboarding/OnboardingModal.tsx new file mode 100644 index 00000000000..b8006ff3758 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/OnboardingModal.tsx @@ -0,0 +1,99 @@ +/* + * 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 { + componentDidMount() { + if (!isLoggedIn(this.props.currentUser)) { + handleRequiredAuthentication(); + } + } + + render() { + if (!isLoggedIn(this.props.currentUser)) { + return null; + } + + const header = translate('onboarding.header'); + return ( + +
+

{translate('onboarding.header')}

+

{translate('onboarding.header.description')}

+
+
+ + + +
+
+ + {translate('not_now')} + +

{translate('onboarding.footer')}

+
+
+ ); + } +} + +const mapStateToProps = (state: any): StateProps => ({ currentUser: getCurrentUser(state) }); + +export default connect(mapStateToProps)(OnboardingModal); diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/OnboardingPage.tsx b/server/sonar-web/src/main/js/apps/tutorials/onboarding/OnboardingPage.tsx new file mode 100644 index 00000000000..d69e98ae561 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/OnboardingPage.tsx @@ -0,0 +1,99 @@ +/* + * 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 { + 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) => { + 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 && ( + + )} + {modal === ModalKey.organizationOnboarding && ( + + )} + {modal === ModalKey.teamOnboarding && ( + + )} + + ); + } +} + +const mapDispatchToProps: DispatchProps = { skipOnboardingAction }; + +export default connect<{}, DispatchProps>(null, mapDispatchToProps)(OnboardingPage); diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/OnboardingModal-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/OnboardingModal-test.tsx new file mode 100644 index 00000000000..76c801faaf8 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/OnboardingModal-test.tsx @@ -0,0 +1,63 @@ +/* + * 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( + + ) + ).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( + , + { 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(); +}); diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/OnboardingModal-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/OnboardingModal-test.tsx.snap new file mode 100644 index 00000000000..18b2f16f846 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/OnboardingModal-test.tsx.snap @@ -0,0 +1,84 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders correctly 1`] = ` + +
+

+ onboarding.header +

+

+ onboarding.header.description +

+
+
+ + + +
+
+ + not_now + +

+ onboarding.footer +

+
+
+`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/AnalysisStep.tsx b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/AnalysisStep.tsx deleted file mode 100644 index a91ff541119..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/AnalysisStep.tsx +++ /dev/null @@ -1,201 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * 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 { - 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 ( -
-
-
- -
-
{this.renderCommand()}
-
-
- ); - }; - - renderFormattedCommand = (...lines: Array) => ( - // keep this "useless" concatentation for the readability reason - // eslint-disable-next-line no-useless-concat -
{lines.join(' ' + '\\' + '\n' + '  ')}
- ); - - 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 ; - }; - - renderCommandForGradle = () => { - const { token } = this.props; - if (!token) { - return null; - } - return ; - }; - - renderCommandForDotNet = () => { - const { token } = this.props; - const { result } = this.state; - if (!result || !result.projectKey || !token) { - return null; - } - return ( - - ); - }; - - renderCommandForMSVC = () => { - const { token } = this.props; - const { result } = this.state; - if (!result || !result.projectKey || !token) { - return null; - } - return ( - - ); - }; - - renderCommandForClangGCC = () => { - const { token } = this.props; - const { result } = this.state; - if (!result || !result.projectKey || !result.os || !token) { - return null; - } - return ( - - ); - }; - - renderCommandForOther = () => { - const { token } = this.props; - const { result } = this.state; - if (!result || !result.projectKey || !result.os || !token) { - return null; - } - return ( - - ); - }; - - renderResult = () => null; - - render() { - return ( - {}} - open={this.props.open} - renderForm={this.renderForm} - renderResult={this.renderResult} - stepNumber={this.props.stepNumber} - stepTitle={translate('onboarding.analysis.header')} - /> - ); - } -} diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/LanguageStep.tsx b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/LanguageStep.tsx deleted file mode 100644 index 25b7544ddcc..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/LanguageStep.tsx +++ /dev/null @@ -1,178 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -import * 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 { - 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 = () => ( -
-

{translate('onboarding.language.java.build_technology')}

- ({ - label: translate('onboarding.language.java.build_technology', build), - value: build - }))} - value={this.state.javaBuild} - /> -
- ); - - renderCFamilyCompiler = () => ( -
-

{translate('onboarding.language.c-family.compiler')}

- ({ - label: translate('onboarding.language.c-family.compiler', compiler), - value: compiler - }))} - value={this.state.cFamilyCompiler} - /> -
- ); - - renderOS = () => ( -
-

{translate('onboarding.language.os')}

- ({ - label: translate('onboarding.language.os', os), - value: os - }))} - value={this.state.os} - /> -
- ); - - renderProjectKey = () => ( - - ); - - 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 ( -
-
-

{translate('onboarding.language')}

- ({ - label: translate('onboarding.language', language), - value: language - }))} - value={this.state.language} - /> -
- {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()} -
- ); - } -} diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/NewOrganizationForm.tsx b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/NewOrganizationForm.tsx deleted file mode 100644 index 5244898544d..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/NewOrganizationForm.tsx +++ /dev/null @@ -1,168 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * 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 { - 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) => { - const organization = this.sanitizeOrganization(event.target.value); - this.setState({ organization }); - this.validateOrganization(organization); - }; - - handleOrganizationCreate = (event: React.FormEvent) => { - 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 ? ( -
- {organization} - {loading ? ( - - ) : ( - - )} -
- ) : ( -
- - {loading ? ( - - ) : ( - - {translate('create')} - - )} - {!unique && ( - - - {translate('this_name_is_already_taken')} - - )} -
- {translate('onboarding.organization.key_requirement')} -
- - ); - } -} diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/NewProjectForm.tsx b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/NewProjectForm.tsx deleted file mode 100644 index f09b4d152bf..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/NewProjectForm.tsx +++ /dev/null @@ -1,150 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * 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 { - 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) => { - this.setState({ projectKey: this.sanitizeProjectKey(event.target.value) }); - }; - - handleProjectCreate = (event: React.FormEvent) => { - 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 ? ( -
- {projectKey} - {loading ? ( - - ) : ( - - )} -
- ) : ( -
- - {loading ? ( - - ) : ( - - {translate('Done')} - - )} -
- {translate('onboarding.project_key_requirement')} -
- - ); - - return ( -
-

{translate('onboarding.language.project_key')}

- {form} -
- ); - } -} diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/OrganizationStep.tsx b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/OrganizationStep.tsx deleted file mode 100644 index 934965c7559..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/OrganizationStep.tsx +++ /dev/null @@ -1,273 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * 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; - personalOrganization?: string; - selection: 'personal' | 'existing' | 'new'; -} - -export default class OrganizationStep extends React.PureComponent { - 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) => { - event.preventDefault(); - this.setState({ selection: 'personal' }); - }; - - handleExistingClick = (event: React.MouseEvent) => { - event.preventDefault(); - this.setState({ selection: 'existing' }); - }; - - handleNewClick = (event: React.MouseEvent) => { - 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 = () => ( - - ); - - renderExistingOrganizationOption = () => ( -
- - - {translate('onboarding.organization.exising_organization')} - - {this.state.selection === 'existing' && ( -
- - {this.state.loading ? ( - - ) : ( - - {translate('onboarding.token.generate')} - - )} - -
- )} -
- ); - - renderUseExistingOption = () => { - const { existingToken } = this.state; - const validInput = !existingToken || existingToken.match(/^[a-z0-9]+$/) != null; - - return ( -
- - - {translate('onboarding.token.use_existing_token')} - - {this.state.selection === 'use-existing' && ( -
- - {!validInput && ( - - - {translate('onboarding.token.invalid_format')} - - )} -
- )} -
- ); - }; - - renderForm = () => { - const { canUseExisting, loading, token, tokenName } = this.state; - - return ( -
- {token != null ? ( -
- - {tokenName} - {': '} - - {token} - {loading ? ( - - ) : ( - - )} - - ) : ( -
- {this.renderGenerateOption()} - {canUseExisting && this.renderUseExistingOption()} -
- )} - -
{translate('onboarding.token.text')}
- - {this.canContinue() && ( -
- -
- )} -
- ); - }; - - renderResult = () => { - const { selection, tokenName } = this.state; - const token = this.getToken(); - - if (!token) { - return null; - } - - return ( -
- - {selection === 'generate' && tokenName && `${tokenName}: `} - {token} -
- ); - }; - - render() { - return ( - - ); - } -} diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/LanguageStep-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/LanguageStep-test.tsx deleted file mode 100644 index 629044f2c4c..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/LanguageStep-test.tsx +++ /dev/null @@ -1,131 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * 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).mockImplementation(() => false); -}); - -it('selects java', () => { - const onDone = jest.fn(); - const wrapper = shallow(); - - (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(); - - (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).mockImplementation(() => true); - const onDone = jest.fn(); - const wrapper = shallow(); - - (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(); - - (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' }); -}); diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/NewOrganizationForm-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/NewOrganizationForm-test.tsx deleted file mode 100644 index bb16f901167..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/NewOrganizationForm-test.tsx +++ /dev/null @@ -1,56 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * 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(); - 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(); - 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(); -}); diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/NewProjectForm-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/NewProjectForm-test.tsx deleted file mode 100644 index 2c8c18cace4..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/NewProjectForm-test.tsx +++ /dev/null @@ -1,55 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * 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(); - 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(); - 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(); -}); diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/OrganizationStep-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/OrganizationStep-test.tsx deleted file mode 100644 index b2192a0bce7..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/OrganizationStep-test.tsx +++ /dev/null @@ -1,102 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * 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).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( - - ); - click(wrapper.find('.js-continue')); - expect(onContinue).toBeCalledWith('user'); -}); - -it('works with existing organization', async () => { - const onContinue = jest.fn(); - const wrapper = mount( - - ); - 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( - - ); - 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'); -}); diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/Step-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/Step-test.tsx deleted file mode 100644 index 8a9664f71c8..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/Step-test.tsx +++ /dev/null @@ -1,57 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import { shallow } from 'enzyme'; -import Step from '../Step'; -import { click } from '../../../../helpers/testUtils'; - -it('renders', () => { - const wrapper = shallow( -
form
} - renderResult={() =>
result
} - 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( -
form
} - renderResult={() =>
result
} - stepNumber={1} - stepTitle="First Step" - /> - ); - click(wrapper); - expect(onOpen).toBeCalled(); -}); diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/TokenStep-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/TokenStep-test.tsx deleted file mode 100644 index 25b5f0c7462..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/TokenStep-test.tsx +++ /dev/null @@ -1,110 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * 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( - - ); - 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( - - ); - 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( - - ); - 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( - - ); - await new Promise(setImmediate); - wrapper.setState({ existingToken: 'abcd1234', selection: 'use-existing' }); - click(wrapper.find('[className="js-continue"]')); - expect(onContinue).toBeCalledWith('abcd1234'); -}); diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/LanguageStep-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/LanguageStep-test.tsx.snap deleted file mode 100644 index 8e82d384b3f..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/LanguageStep-test.tsx.snap +++ /dev/null @@ -1,687 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`selects c# 1`] = ` -
-
-

- onboarding.language -

- -
- -
-`; - -exports[`selects c-family 1`] = ` -
-
-

- onboarding.language -

- -
-
-

- onboarding.language.c-family.compiler -

- -
-
-`; - -exports[`selects c-family 2`] = ` -
-
-

- onboarding.language -

- -
-
-

- onboarding.language.c-family.compiler -

- -
- -
-`; - -exports[`selects c-family 3`] = ` -
-
-

- onboarding.language -

- -
-
-

- onboarding.language.c-family.compiler -

- -
-
-

- onboarding.language.os -

- -
-
-`; - -exports[`selects c-family 4`] = ` -
-
-

- onboarding.language -

- -
-
-

- onboarding.language.c-family.compiler -

- -
-
-

- onboarding.language.os -

- -
- -
-`; - -exports[`selects java 1`] = ` -
-
-

- onboarding.language -

- -
-
-

- onboarding.language.java.build_technology -

- -
-
-`; - -exports[`selects java 2`] = ` -
-
-

- onboarding.language -

- -
-
-

- onboarding.language.java.build_technology -

- -
-
-`; - -exports[`selects java 3`] = ` -
-
-

- onboarding.language -

- -
-
-

- onboarding.language.java.build_technology -

- -
-
-`; - -exports[`selects other 1`] = ` -
-
-

- onboarding.language -

- -
-
-

- onboarding.language.os -

- -
-
-`; - -exports[`selects other 2`] = ` -
-
-

- onboarding.language -

- -
-
-

- onboarding.language.os -

- -
- -
-`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/NewOrganizationForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/NewOrganizationForm-test.tsx.snap deleted file mode 100644 index eae8fcdb833..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/NewOrganizationForm-test.tsx.snap +++ /dev/null @@ -1,270 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`creates new organization 1`] = ` - -
- - - - - -
- onboarding.organization.key_requirement -
-
-
-`; - -exports[`creates new organization 2`] = ` - -
- - -
- onboarding.organization.key_requirement -
- -
-`; - -exports[`creates new organization 3`] = ` - -
- - foo - - - - - - - -
-
-`; - -exports[`deletes organization 1`] = ` - -
- - foo - - - - - - - -
-
-`; - -exports[`deletes organization 2`] = ` - -
- - foo - - -
-
-`; - -exports[`deletes organization 3`] = ` - -
- - - - - -
- onboarding.organization.key_requirement -
-
-
-`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/NewProjectForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/NewProjectForm-test.tsx.snap deleted file mode 100644 index f6722a21bf6..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/NewProjectForm-test.tsx.snap +++ /dev/null @@ -1,321 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`creates new project 1`] = ` - -
-

- onboarding.language.project_key -

-
- - - - - -
- onboarding.project_key_requirement -
-
-
-
-`; - -exports[`creates new project 2`] = ` - -
-

- onboarding.language.project_key -

-
- - -
- onboarding.project_key_requirement -
- -
-
-`; - -exports[`creates new project 3`] = ` - -
-

- onboarding.language.project_key -

-
- - foo - - - - - - - -
-
-
-`; - -exports[`deletes project 1`] = ` - -
-

- onboarding.language.project_key -

-
- - foo - - - - - - - -
-
-
-`; - -exports[`deletes project 2`] = ` - -
-

- onboarding.language.project_key -

-
- - foo - - -
-
-
-`; - -exports[`deletes project 3`] = ` - -
-

- onboarding.language.project_key -

-
- - - - - -
- onboarding.project_key_requirement -
-
-
-
-`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/OrganizationStep-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/OrganizationStep-test.tsx.snap deleted file mode 100644 index 8ece74c899f..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/OrganizationStep-test.tsx.snap +++ /dev/null @@ -1,286 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`works with existing organization 1`] = ` - - - onboarding.organization.header - - - } - > -
-
- 1 -
-
-

- - onboarding.organization.header - - -

-
-
-
- onboarding.organization.text -
-
- -
-
- - -`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/ProjectOnboarding-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/ProjectOnboarding-test.tsx.snap index 0c5b93e108a..655ed26af50 100644 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/ProjectOnboarding-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/ProjectOnboarding-test.tsx.snap @@ -36,7 +36,7 @@ exports[`guides for on-premise 1`] = ` open={true} stepNumber={1} /> - - - - - -
- 1 -
-
-

- First Step -

-
-
- form -
-
-`; - -exports[`renders 2`] = ` -
-
- 1 -
-
- result -
-
-

- First Step -

-
-
-
-`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/TokenStep-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/TokenStep-test.tsx.snap deleted file mode 100644 index 54847972e8c..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/TokenStep-test.tsx.snap +++ /dev/null @@ -1,649 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`generates token 1`] = ` - - -
-
- 1 -
-
-

- onboarding.token.header -

-
-
-
-
- - - onboarding.token.generate_token - -
-
- - - - - -
-
-
- -
-
- onboarding.token.text -
-
-
-
-
-`; - -exports[`generates token 2`] = ` - - -
-
- 1 -
-
-

- onboarding.token.header -

-
-
- -
- onboarding.token.text -
-
-
-
-
-`; - -exports[`generates token 3`] = ` - - -
-
- 1 -
-
-

- onboarding.token.header -

-
-
-
- - my token - : - - - abcd1234 - - - - - - - -
-
- onboarding.token.text -
-
- - -
-
-
-
-
-`; - -exports[`revokes token 1`] = ` - - -
-
- 1 -
-
-

- onboarding.token.header -

-
-
-
- - my token - : - - - abcd1234 - - - - - - - -
-
- onboarding.token.text -
-
- - -
-
-
-
-
-`; - -exports[`revokes token 2`] = ` - - -
-
- 1 -
-
-

- onboarding.token.header -

-
-
-
- - my token - : - - - abcd1234 - - - -
- onboarding.token.text -
-
- - -
-
-
-
-
-`; - -exports[`revokes token 3`] = ` - - -
-
- 1 -
-
-

- onboarding.token.header -

-
-
-
-
- - - onboarding.token.generate_token - -
-
- - - - - -
-
-
- -
-
- onboarding.token.text -
-
-
-
-
-`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/BuildWrapper.tsx b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/BuildWrapper.tsx deleted file mode 100644 index ed03adbf911..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/BuildWrapper.tsx +++ /dev/null @@ -1,58 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * 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 ( -
-

- {translate('onboarding.analysis.build_wrapper.header', props.os)} -

-

-

- - {translate('download_verb')} - -

-
- ); -} diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/ClangGCC.tsx b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/ClangGCC.tsx deleted file mode 100644 index 6ebe42a3ca9..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/ClangGCC.tsx +++ /dev/null @@ -1,78 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * 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 ( -
- - - -

- {translate('onboarding.analysis.sq_scanner.execute')} -

- - {transformedMessage => ( -

- )} - - - -

-

- ); -} diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/DotNet.tsx b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/DotNet.tsx deleted file mode 100644 index 6dc321dbb42..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/DotNet.tsx +++ /dev/null @@ -1,70 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * 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 ( -
- - -

- {translate('onboarding.analysis.msbuild.execute')} -

- - {transformedMessage => ( -

- )} - - - - -

-

- ); -} diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/JavaGradle.tsx b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/JavaGradle.tsx deleted file mode 100644 index 02da9fd1a2a..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/JavaGradle.tsx +++ /dev/null @@ -1,69 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * 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 ( -
-

{translate('onboarding.analysis.java.gradle.header')}

- - {transformedMessage => ( -

- )} - - -

- {translate('onboarding.analysis.java.gradle.text.2')} -

- -

-

-

- ); -} diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/JavaMaven.tsx b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/JavaMaven.tsx deleted file mode 100644 index 5663b1f2911..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/JavaMaven.tsx +++ /dev/null @@ -1,58 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * 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 ( -
-

{translate('onboarding.analysis.java.maven.header')}

-

- -

- -

-

-

- ); -} diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/MSBuildScanner.tsx b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/MSBuildScanner.tsx deleted file mode 100644 index 65c4005af86..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/MSBuildScanner.tsx +++ /dev/null @@ -1,47 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -import * as React from 'react'; -import { translate } from '../../../../helpers/l10n'; - -interface Props { - className?: string; -} - -export default function MSBuildScanner(props: Props) { - return ( -
-

{translate('onboarding.analysis.msbuild.header')}

-

-

- - {translate('download_verb')} - -

-
- ); -} diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/Msvc.tsx b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/Msvc.tsx deleted file mode 100644 index cf6120a3b31..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/Msvc.tsx +++ /dev/null @@ -1,73 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * 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 ( -
- - - -

- {translate('onboarding.analysis.msbuild.execute')} -

- - {transformedMessage => ( -

- )} - - - - -

-

- ); -} diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/Other.tsx b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/Other.tsx deleted file mode 100644 index 3d0b3b2a718..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/Other.tsx +++ /dev/null @@ -1,66 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * 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 ( -
- - -

- {translate('onboarding.analysis.sq_scanner.execute')} -

- - {transformedMessage => ( -

- )} - - -

-

- ); -} diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/SQScanner.tsx b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/SQScanner.tsx deleted file mode 100644 index 78b90f851bc..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/SQScanner.tsx +++ /dev/null @@ -1,52 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -import * as React from 'react'; -import { translate } from '../../../../helpers/l10n'; - -interface Props { - className?: string; - os: string; -} - -export default function SQScanner(props: Props) { - return ( -
-

- {translate('onboarding.analysis.sq_scanner.header', props.os)} -

-

-

- - {translate('download_verb')} - -

-
- ); -} diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/BuildWrapper-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/BuildWrapper-test.tsx deleted file mode 100644 index b19e334793b..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/BuildWrapper-test.tsx +++ /dev/null @@ -1,28 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import * as React from 'react'; -import { shallow } from 'enzyme'; -import BuildWrapper from '../BuildWrapper'; - -it('renders correctly', () => { - expect(shallow()).toMatchSnapshot(); - expect(shallow()).toMatchSnapshot(); - expect(shallow()).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/ClangGCC-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/ClangGCC-test.tsx deleted file mode 100644 index a6f7c4f550a..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/ClangGCC-test.tsx +++ /dev/null @@ -1,45 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -import * as React from 'react'; -import { shallow } from 'enzyme'; -import ClangGCC from '../ClangGCC'; - -it('renders correctly', () => { - expect( - shallow() - ).toMatchSnapshot(); - - expect( - shallow() - ).toMatchSnapshot(); - - expect( - shallow( - - ) - ).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/DotNet-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/DotNet-test.tsx deleted file mode 100644 index 91ecab828b2..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/DotNet-test.tsx +++ /dev/null @@ -1,32 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -import * as React from 'react'; -import { shallow } from 'enzyme'; -import DotNet from '../DotNet'; - -it('renders correctly', () => { - expect(shallow()).toMatchSnapshot(); - expect( - shallow( - - ) - ).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/JavaGradle-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/JavaGradle-test.tsx deleted file mode 100644 index f0d130a248d..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/JavaGradle-test.tsx +++ /dev/null @@ -1,30 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -import * as React from 'react'; -import { shallow } from 'enzyme'; -import JavaGradle from '../JavaGradle'; - -it('renders correctly', () => { - expect(shallow()).toMatchSnapshot(); - expect( - shallow() - ).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/JavaMaven-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/JavaMaven-test.tsx deleted file mode 100644 index dbda16ca13e..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/JavaMaven-test.tsx +++ /dev/null @@ -1,30 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -import * as React from 'react'; -import { shallow } from 'enzyme'; -import JavaMaven from '../JavaMaven'; - -it('renders correctly', () => { - expect(shallow()).toMatchSnapshot(); - expect( - shallow() - ).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/MSBuildScanner-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/MSBuildScanner-test.tsx deleted file mode 100644 index e5411341d10..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/MSBuildScanner-test.tsx +++ /dev/null @@ -1,27 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -import * as React from 'react'; -import { shallow } from 'enzyme'; -import MSBuildScanner from '../MSBuildScanner'; - -it('renders correctly', () => { - expect(shallow()).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/Msvc-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/Msvc-test.tsx deleted file mode 100644 index 78470bbd2e6..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/Msvc-test.tsx +++ /dev/null @@ -1,30 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -import * as React from 'react'; -import { shallow } from 'enzyme'; -import Msvc from '../Msvc'; - -it('renders correctly', () => { - expect(shallow()).toMatchSnapshot(); - expect( - shallow() - ).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/Other-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/Other-test.tsx deleted file mode 100644 index 16cc44ae69f..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/Other-test.tsx +++ /dev/null @@ -1,45 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -import * as React from 'react'; -import { shallow } from 'enzyme'; -import Other from '../Other'; - -it('renders correctly', () => { - expect( - shallow() - ).toMatchSnapshot(); - - expect( - shallow() - ).toMatchSnapshot(); - - expect( - shallow( - - ) - ).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/SQScanner-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/SQScanner-test.tsx deleted file mode 100644 index 2be4e546bb3..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/SQScanner-test.tsx +++ /dev/null @@ -1,29 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -import * as React from 'react'; -import { shallow } from 'enzyme'; -import SQScanner from '../SQScanner'; - -it('renders correctly', () => { - expect(shallow()).toMatchSnapshot(); - expect(shallow()).toMatchSnapshot(); - expect(shallow()).toMatchSnapshot(); -}); diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/BuildWrapper-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/BuildWrapper-test.tsx.snap deleted file mode 100644 index 07e8eb45f0a..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/BuildWrapper-test.tsx.snap +++ /dev/null @@ -1,85 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`renders correctly 1`] = ` -
-

- onboarding.analysis.build_wrapper.header.win -

-

-

- - download_verb - -

-
-`; - -exports[`renders correctly 2`] = ` -
-

- onboarding.analysis.build_wrapper.header.linux -

-

-

- - download_verb - -

-
-`; - -exports[`renders correctly 3`] = ` -
-

- onboarding.analysis.build_wrapper.header.mac -

-

-

- - download_verb - -

-
-`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/ClangGCC-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/ClangGCC-test.tsx.snap deleted file mode 100644 index cdffd4c2061..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/ClangGCC-test.tsx.snap +++ /dev/null @@ -1,139 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`renders correctly 1`] = ` -
- - -

- onboarding.analysis.sq_scanner.execute -

- - - -

-

-`; - -exports[`renders correctly 2`] = ` -
- - -

- onboarding.analysis.sq_scanner.execute -

- - - -

-

-`; - -exports[`renders correctly 3`] = ` -
- - -

- onboarding.analysis.sq_scanner.execute -

- - - -

-

-`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/DotNet-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/DotNet-test.tsx.snap deleted file mode 100644 index e072eef9d83..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/DotNet-test.tsx.snap +++ /dev/null @@ -1,95 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`renders correctly 1`] = ` -
- -

- onboarding.analysis.msbuild.execute -

- - - - -

-

-`; - -exports[`renders correctly 2`] = ` -
- -

- onboarding.analysis.msbuild.execute -

- - - - -

-

-`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/JavaGradle-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/JavaGradle-test.tsx.snap deleted file mode 100644 index 401137a9234..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/JavaGradle-test.tsx.snap +++ /dev/null @@ -1,99 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`renders correctly 1`] = ` -
-

- onboarding.analysis.java.gradle.header -

- - -

- onboarding.analysis.java.gradle.text.2 -

- -

-

-

-`; - -exports[`renders correctly 2`] = ` -
-

- onboarding.analysis.java.gradle.header -

- - -

- onboarding.analysis.java.gradle.text.2 -

- -

-

-

-`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/JavaMaven-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/JavaMaven-test.tsx.snap deleted file mode 100644 index d4462b957c6..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/JavaMaven-test.tsx.snap +++ /dev/null @@ -1,87 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`renders correctly 1`] = ` -
-

- onboarding.analysis.java.maven.header -

-

- -

- -

-

-

-`; - -exports[`renders correctly 2`] = ` -
-

- onboarding.analysis.java.maven.header -

-

- -

- -

-

-

-`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/MSBuildScanner-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/MSBuildScanner-test.tsx.snap deleted file mode 100644 index 740e26ed12b..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/MSBuildScanner-test.tsx.snap +++ /dev/null @@ -1,29 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`renders correctly 1`] = ` -
-

- onboarding.analysis.msbuild.header -

-

-

- - download_verb - -

-
-`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/Msvc-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/Msvc-test.tsx.snap deleted file mode 100644 index 2240a13995c..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/Msvc-test.tsx.snap +++ /dev/null @@ -1,105 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`renders correctly 1`] = ` -
- - -

- onboarding.analysis.msbuild.execute -

- - - - -

-

-`; - -exports[`renders correctly 2`] = ` -
- - -

- onboarding.analysis.msbuild.execute -

- - - - -

-

-`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/Other-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/Other-test.tsx.snap deleted file mode 100644 index 73aba357dca..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/Other-test.tsx.snap +++ /dev/null @@ -1,112 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`renders correctly 1`] = ` -
- -

- onboarding.analysis.sq_scanner.execute -

- - -

-

-`; - -exports[`renders correctly 2`] = ` -
- -

- onboarding.analysis.sq_scanner.execute -

- - -

-

-`; - -exports[`renders correctly 3`] = ` -
- -

- onboarding.analysis.sq_scanner.execute -

- - -

-

-`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/SQScanner-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/SQScanner-test.tsx.snap deleted file mode 100644 index cf6a8de4ce3..00000000000 --- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/SQScanner-test.tsx.snap +++ /dev/null @@ -1,85 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`renders correctly 1`] = ` -
-

- onboarding.analysis.sq_scanner.header.win -

-

-

- - download_verb - -

-
-`; - -exports[`renders correctly 2`] = ` -
-

- onboarding.analysis.sq_scanner.header.linux -

-

-

- - download_verb - -

-
-`; - -exports[`renders correctly 3`] = ` -
-

- onboarding.analysis.sq_scanner.header.mac -

-

-

- - download_verb - -

-
-`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/routes.ts b/server/sonar-web/src/main/js/apps/tutorials/routes.ts index 5c8f9c88641..94c25460e0a 100644 --- a/server/sonar-web/src/main/js/apps/tutorials/routes.ts +++ b/server/sonar-web/src/main/js/apps/tutorials/routes.ts @@ -26,7 +26,7 @@ const routes = [ component: lazyLoad( () => isSonarCloud() - ? import('./createProjectOnboarding/CreateProjectOnboarding') + ? import('./onboarding/OnboardingPage') : import('./projectOnboarding/ProjectOnboardingPage') ) } diff --git a/server/sonar-web/src/main/js/apps/tutorials/styles.css b/server/sonar-web/src/main/js/apps/tutorials/styles.css index 798fce21bcc..da2571a369d 100644 --- a/server/sonar-web/src/main/js/apps/tutorials/styles.css +++ b/server/sonar-web/src/main/js/apps/tutorials/styles.css @@ -58,8 +58,7 @@ .onboarding-choices { display: flex; justify-content: space-around; - padding-top: 44px; - padding-bottom: 44px; + padding: 44px 0; background-color: var(--barBackgroundColor); } diff --git a/server/sonar-web/src/main/js/apps/tutorials/utils.ts b/server/sonar-web/src/main/js/apps/tutorials/utils.ts new file mode 100644 index 00000000000..f84785ef61d --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/utils.ts @@ -0,0 +1,40 @@ +/* + * 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; +} diff --git a/server/sonar-web/src/main/js/components/icons-components/OnboardingPrivateIcon.tsx b/server/sonar-web/src/main/js/components/icons-components/OnboardingPrivateIcon.tsx index 3592d9b0be0..7542f09a3aa 100644 --- a/server/sonar-web/src/main/js/components/icons-components/OnboardingPrivateIcon.tsx +++ b/server/sonar-web/src/main/js/components/icons-components/OnboardingPrivateIcon.tsx @@ -26,7 +26,7 @@ export default function OnboardingPrivateIcon({ size }: IconProps) { return ( - + diff --git a/server/sonar-web/src/main/js/components/icons-components/OnboardingProjectIcon.tsx b/server/sonar-web/src/main/js/components/icons-components/OnboardingProjectIcon.tsx index d2090eed867..d97972db6e7 100644 --- a/server/sonar-web/src/main/js/components/icons-components/OnboardingProjectIcon.tsx +++ b/server/sonar-web/src/main/js/components/icons-components/OnboardingProjectIcon.tsx @@ -26,7 +26,7 @@ export default function OnboardingProjectIcon({ size }: IconProps) { return ( - + diff --git a/server/sonar-web/src/main/js/components/icons-components/OnboardingTeamIcon.tsx b/server/sonar-web/src/main/js/components/icons-components/OnboardingTeamIcon.tsx index 6ce74838a0d..023067e74a8 100644 --- a/server/sonar-web/src/main/js/components/icons-components/OnboardingTeamIcon.tsx +++ b/server/sonar-web/src/main/js/components/icons-components/OnboardingTeamIcon.tsx @@ -22,7 +22,7 @@ import Icon, { IconProps } from './Icon'; export default function OnboardingTeamIcon({ className, fill = 'currentColor', size }: IconProps) { return ( - + diff --git a/server/sonar-web/src/main/js/components/ui/buttons.css b/server/sonar-web/src/main/js/components/ui/buttons.css index cc24ba79baf..032c0255117 100644 --- a/server/sonar-web/src/main/js/components/ui/buttons.css +++ b/server/sonar-web/src/main/js/components/ui/buttons.css @@ -130,6 +130,10 @@ transition: all 0.2s ease; } +.dropdown .button-link { + border-bottom: none; +} + .button-link:hover { background: transparent; color: var(--blue); diff --git a/server/sonar-web/src/main/js/helpers/markdown.js b/server/sonar-web/src/main/js/helpers/markdown.js index 7f1c21325df..633c3450289 100644 --- a/server/sonar-web/src/main/js/helpers/markdown.js +++ b/server/sonar-web/src/main/js/helpers/markdown.js @@ -72,7 +72,7 @@ function parseFrontMatter(lines) { * @returns {string} */ function filterContent(content) { - const { isSonarCloud } = require('../helpers/system'); + const { isSonarCloud } = require('./system'); const contentWithoutStatic = cutConditionalContent(content, 'static'); return isSonarCloud() ? cutConditionalContent(contentWithoutStatic, 'sonarqube') diff --git a/server/sonar-web/src/main/js/helpers/urls.ts b/server/sonar-web/src/main/js/helpers/urls.ts index 4d17bde0b09..9d3959260bf 100644 --- a/server/sonar-web/src/main/js/helpers/urls.ts +++ b/server/sonar-web/src/main/js/helpers/urls.ts @@ -49,10 +49,6 @@ export function getPathUrlAsString(path: Location): string { 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 } }; } diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties index 2265fcc9f90..a2e9ef14fc6 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -1496,9 +1496,10 @@ my_account.create_new_organization=Create new organization #------------------------------------------------------------------------------ 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. @@ -2659,13 +2660,21 @@ onboarding.footer=Don't worry you can do all of this later. Just click the "+" i 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 @@ -2706,9 +2715,11 @@ onboarding.organization.key_requirement=2 to 32 characters. All chars must be lo 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