From fbc932a882b6dec72900f5242d0cead7ff03e4b2 Mon Sep 17 00:00:00 2001 From: Stas Vilchik Date: Mon, 12 Jun 2017 03:50:27 -0700 Subject: UI: SONAR-9355 Create onboarding tutorial (#2137) --- .../src/main/js/apps/account/tokens-view.js | 16 +- .../js/apps/projects-admin/CreateProjectForm.js | 3 +- .../src/main/js/apps/settings/components/App.js | 6 +- .../js/apps/settings/components/CategoriesList.js | 2 +- .../sonar-web/src/main/js/apps/settings/styles.css | 53 -- .../js/apps/tutorials/onboarding/AnalysisStep.js | 181 ++++++ .../js/apps/tutorials/onboarding/LanguageStep.js | 188 ++++++ .../tutorials/onboarding/NewOrganizationForm.js | 157 +++++ .../js/apps/tutorials/onboarding/NewProjectForm.js | 145 +++++ .../js/apps/tutorials/onboarding/Onboarding.js | 109 ++++ .../tutorials/onboarding/OnboardingContainer.js | 39 ++ .../apps/tutorials/onboarding/OrganizationStep.js | 240 +++++++ .../js/apps/tutorials/onboarding/ProjectKeyStep.js | 145 +++++ .../src/main/js/apps/tutorials/onboarding/Step.js | 47 ++ .../main/js/apps/tutorials/onboarding/TokenStep.js | 180 ++++++ .../onboarding/__tests__/LanguageStep-test.js | 106 ++++ .../__tests__/NewOrganizationForm-test.js | 56 ++ .../onboarding/__tests__/NewProjectForm-test.js | 55 ++ .../onboarding/__tests__/OrganizationStep-test.js | 63 ++ .../onboarding/__tests__/ProjectKeyStep-test.js | 55 ++ .../tutorials/onboarding/__tests__/Step-test.js | 38 ++ .../onboarding/__tests__/TokenStep-test.js | 55 ++ .../__snapshots__/LanguageStep-test.js.snap | 687 +++++++++++++++++++++ .../__snapshots__/NewOrganizationForm-test.js.snap | 168 +++++ .../__snapshots__/NewProjectForm-test.js.snap | 219 +++++++ .../__snapshots__/ProjectKeyStep-test.js.snap | 219 +++++++ .../__tests__/__snapshots__/Step-test.js.snap | 48 ++ .../__tests__/__snapshots__/TokenStep-test.js.snap | 383 ++++++++++++ .../tutorials/onboarding/commands/BuildWrapper.js | 58 ++ .../apps/tutorials/onboarding/commands/ClangGCC.js | 76 +++ .../apps/tutorials/onboarding/commands/Command.js | 89 +++ .../apps/tutorials/onboarding/commands/DotNet.js | 68 ++ .../tutorials/onboarding/commands/JavaGradle.js | 59 ++ .../tutorials/onboarding/commands/JavaMaven.js | 50 ++ .../onboarding/commands/MSBuildScanner.js | 46 ++ .../js/apps/tutorials/onboarding/commands/Msvc.js | 71 +++ .../js/apps/tutorials/onboarding/commands/Other.js | 64 ++ .../tutorials/onboarding/commands/SQScanner.js | 51 ++ .../commands/__tests__/BuildWrapper-test.js | 29 + .../onboarding/commands/__tests__/ClangGCC-test.js | 45 ++ .../onboarding/commands/__tests__/Command-test.js | 27 + .../onboarding/commands/__tests__/DotNet-test.js | 32 + .../commands/__tests__/JavaGradle-test.js | 30 + .../commands/__tests__/JavaMaven-test.js | 30 + .../commands/__tests__/MSBuildScanner-test.js | 27 + .../onboarding/commands/__tests__/Msvc-test.js | 30 + .../onboarding/commands/__tests__/Other-test.js | 45 ++ .../commands/__tests__/SQScanner-test.js | 29 + .../__snapshots__/BuildWrapper-test.js.snap | 85 +++ .../__tests__/__snapshots__/ClangGCC-test.js.snap | 148 +++++ .../__tests__/__snapshots__/Command-test.js.snap | 18 + .../__tests__/__snapshots__/DotNet-test.js.snap | 99 +++ .../__snapshots__/JavaGradle-test.js.snap | 93 +++ .../__tests__/__snapshots__/JavaMaven-test.js.snap | 67 ++ .../__snapshots__/MSBuildScanner-test.js.snap | 28 + .../__tests__/__snapshots__/Msvc-test.js.snap | 109 ++++ .../__tests__/__snapshots__/Other-test.js.snap | 124 ++++ .../__tests__/__snapshots__/SQScanner-test.js.snap | 82 +++ .../main/js/apps/tutorials/onboarding/styles.css | 59 ++ .../sonar-web/src/main/js/apps/tutorials/routes.js | 31 + .../src/main/js/apps/users/tokens-view.js | 16 +- 61 files changed, 5499 insertions(+), 79 deletions(-) create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/AnalysisStep.js create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/LanguageStep.js create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/NewOrganizationForm.js create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/NewProjectForm.js create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/Onboarding.js create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/OnboardingContainer.js create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/OrganizationStep.js create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/ProjectKeyStep.js create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/Step.js create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/TokenStep.js create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/LanguageStep-test.js create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/NewOrganizationForm-test.js create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/NewProjectForm-test.js create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/OrganizationStep-test.js create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/ProjectKeyStep-test.js create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/Step-test.js create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/TokenStep-test.js create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/LanguageStep-test.js.snap create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/NewOrganizationForm-test.js.snap create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/NewProjectForm-test.js.snap create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/ProjectKeyStep-test.js.snap create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/Step-test.js.snap create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/TokenStep-test.js.snap create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/BuildWrapper.js create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/ClangGCC.js create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/Command.js create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/DotNet.js create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/JavaGradle.js create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/JavaMaven.js create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/MSBuildScanner.js create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/Msvc.js create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/Other.js create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/SQScanner.js create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/BuildWrapper-test.js create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/ClangGCC-test.js create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/Command-test.js create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/DotNet-test.js create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/JavaGradle-test.js create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/JavaMaven-test.js create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/MSBuildScanner-test.js create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/Msvc-test.js create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/Other-test.js create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/SQScanner-test.js create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/BuildWrapper-test.js.snap create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/ClangGCC-test.js.snap create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/Command-test.js.snap create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/DotNet-test.js.snap create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/JavaGradle-test.js.snap create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/JavaMaven-test.js.snap create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/MSBuildScanner-test.js.snap create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/Msvc-test.js.snap create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/Other-test.js.snap create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/SQScanner-test.js.snap create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/styles.css create mode 100644 server/sonar-web/src/main/js/apps/tutorials/routes.js (limited to 'server/sonar-web/src/main/js/apps') diff --git a/server/sonar-web/src/main/js/apps/account/tokens-view.js b/server/sonar-web/src/main/js/apps/account/tokens-view.js index 62c6f8f9143..29ef6f5f9cd 100644 --- a/server/sonar-web/src/main/js/apps/account/tokens-view.js +++ b/server/sonar-web/src/main/js/apps/account/tokens-view.js @@ -52,17 +52,13 @@ export default Marionette.ItemView.extend({ this.errors = []; this.newToken = null; const tokenName = this.$('.js-generate-token-form input').val(); - generateToken(this.model.id, tokenName) - .then(response => { + generateToken(tokenName, this.model.id).then( + response => { this.newToken = response; this.requestTokens(); - }) - .catch(error => { - error.response.json().then(response => { - this.errors = response.errors; - this.render(); - }); - }); + }, + () => {} + ); }, onRevokeTokenFormSubmit(e) { @@ -71,7 +67,7 @@ export default Marionette.ItemView.extend({ const token = this.tokens.find(token => token.name === `${tokenName}`); if (token) { if (token.deleting) { - revokeToken(this.model.id, tokenName).then(this.requestTokens.bind(this)); + revokeToken(tokenName, this.model.id).then(this.requestTokens.bind(this), () => {}); } else { token.deleting = true; this.render(); diff --git a/server/sonar-web/src/main/js/apps/projects-admin/CreateProjectForm.js b/server/sonar-web/src/main/js/apps/projects-admin/CreateProjectForm.js index acc503123ed..0266656aa8d 100644 --- a/server/sonar-web/src/main/js/apps/projects-admin/CreateProjectForm.js +++ b/server/sonar-web/src/main/js/apps/projects-admin/CreateProjectForm.js @@ -103,10 +103,9 @@ export default class CreateProjectForm extends React.PureComponent { this.props.onProjectCreated(); } }, - error => { + () => { if (this.mounted) { this.setState({ loading: false }); - this.props.onRequestFail(error); } } ); diff --git a/server/sonar-web/src/main/js/apps/settings/components/App.js b/server/sonar-web/src/main/js/apps/settings/components/App.js index d357cff1fbc..9d45c3749e7 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/App.js +++ b/server/sonar-web/src/main/js/apps/settings/components/App.js @@ -83,15 +83,15 @@ class App extends React.PureComponent { -
-
+
+
-
+
{selectedCategory === 'exclusions' && } diff --git a/server/sonar-web/src/main/js/apps/settings/components/CategoriesList.js b/server/sonar-web/src/main/js/apps/settings/components/CategoriesList.js index 3ad92ee2b96..676f5511174 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/CategoriesList.js +++ b/server/sonar-web/src/main/js/apps/settings/components/CategoriesList.js @@ -70,7 +70,7 @@ export default class CategoriesList extends React.PureComponent { const sortedCategories = sortBy(categoriesWithName, category => category.name.toLowerCase()); return ( -
    +
      {sortedCategories.map(category => (
    • {this.renderLink(category)} diff --git a/server/sonar-web/src/main/js/apps/settings/styles.css b/server/sonar-web/src/main/js/apps/settings/styles.css index a529c5c5c5f..4d188e811dc 100644 --- a/server/sonar-web/src/main/js/apps/settings/styles.css +++ b/server/sonar-web/src/main/js/apps/settings/styles.css @@ -1,60 +1,7 @@ .settings-layout { - display: flex; - justify-content: space-between; - align-items: stretch; margin-bottom: 60px; } -.settings-main { - position: relative; - z-index: 2; - flex-grow: 1; - padding: 15px 20px; - border: 1px solid #e6e6e6; - box-sizing: border-box; - background-color: #fff; -} - -.settings-side { - position: relative; - z-index: 3; - width: 160px; - flex-shrink: 0; - padding: 10px 0; - box-sizing: border-box; - transform: translateX(1px); -} - -.settings-menu {} - -.settings-menu > li { - margin-bottom: 4px; -} - -.settings-menu > li > a { - display: block; - padding: 10px 10px; - line-height: 1.5; - border-top-left-radius: 3px; - border-bottom-left-radius: 3px; - border: 1px solid #e6e6e6; - border-right: none; - overflow: hidden; - text-overflow: ellipsis; - transition: color 0.3s ease, background-color 0.3s ease; -} - -.settings-menu > li > a:hover, -.settings-menu > li > a:focus, -.settings-menu > li > a.active { - background-color: #fff; -} - -.settings-menu > li > a.active { - color: #444; - cursor: default; -} - .settings-definitions-list > li + li { margin-top: 30px; } diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/AnalysisStep.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/AnalysisStep.js new file mode 100644 index 00000000000..78db84e6ef9 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/AnalysisStep.js @@ -0,0 +1,181 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +// @flow +import React from 'react'; +import Step from './Step'; +import LanguageStep from './LanguageStep'; +import type { 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'; + +type Props = {| + open: boolean, + organization?: string, + sonarCloud: boolean, + stepNumber: number, + token: string +|}; + +type State = { + result?: Result +}; + +export default class AnalysisStep extends React.PureComponent { + props: Props; + state: State = {}; + + handleLanguageSelect = (result?: Result) => { + this.setState({ result }); + }; + + handleLanguageReset = () => { + this.setState({ result: undefined }); + }; + + getHost = () => window.location.origin + window.baseUrl; + + renderForm = () => { + return ( +
      +
      +
      + +
      +
      + {this.renderCommand()} +
      +
      +
      + ); + }; + + renderFormattedCommand = (...lines: Array) => ( +
      {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 = () => ( + + ); + + renderCommandForGradle = () => ( + + ); + + renderCommandForDotNet = () => { + return ( + + ); + }; + + renderCommandForMSVC = () => { + return ( + + ); + }; + + renderCommandForClangGCC = () => ( + + ); + + renderCommandForOther = () => ( + + ); + + renderResult = () => null; + + render() { + return ( + + ); + } +} diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/LanguageStep.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/LanguageStep.js new file mode 100644 index 00000000000..44bfb4ed766 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/LanguageStep.js @@ -0,0 +1,188 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +// @flow +import React from 'react'; +import NewProjectForm from './NewProjectForm'; +import RadioToggle from '../../../components/controls/RadioToggle'; +import { translate } from '../../../helpers/l10n'; + +type Props = {| + onDone: (result: Result) => void, + onReset: () => void, + organization?: string, + sonarCloud: boolean +|}; + +type State = { + language?: string, + javaBuild?: string, + cFamilyCompiler?: string, + os?: string, + projectKey?: string +}; + +export type Result = State; + +export default class LanguageStep extends React.PureComponent { + props: Props; + + static defaultProps = { sonarCloud: false }; + + 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 = this.props.sonarCloud + ? ['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/onboarding/NewOrganizationForm.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/NewOrganizationForm.js new file mode 100644 index 00000000000..16a7c54d526 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/NewOrganizationForm.js @@ -0,0 +1,157 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +// @flow +import React from 'react'; +import { debounce } from 'lodash'; +import { + createOrganization, + deleteOrganization, + getOrganization +} from '../../../api/organizations'; +import { translate } from '../../../helpers/l10n'; + +type Props = {| + onDelete: () => void, + onDone: (organization: string) => void, + organization?: string +|}; + +type State = { + done: boolean, + loading: boolean, + organization: string, + unique: boolean +}; + +export default class NewOrganizationForm extends React.PureComponent { + mounted: boolean; + props: Props; + state: State; + + 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: { target: HTMLInputElement }) => { + const organization = this.sanitizeOrganization(event.target.value); + this.setState({ organization }); + this.validateOrganization(organization); + }; + + handleOrganizationCreate = (event: Event) => { + 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 = (event: Event) => { + event.preventDefault(); + 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 + ? + : } + {!unique && + + + {translate('this_name_is_already_taken')} + } +
      + {translate('onboarding.organization.key_requirement')} +
      + ; + } +} diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/NewProjectForm.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/NewProjectForm.js new file mode 100644 index 00000000000..2bf64f8fe5a --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/NewProjectForm.js @@ -0,0 +1,145 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +// @flow +import React from 'react'; +import { createProject, deleteProject } from '../../../api/components'; +import { translate } from '../../../helpers/l10n'; + +type Props = {| + onDelete: () => void, + onDone: (projectKey: string) => void, + organization?: string, + projectKey?: string +|}; + +type State = { + done: boolean, + loading: boolean, + projectKey: string +}; + +export default class NewProjectForm extends React.PureComponent { + mounted: boolean; + props: Props; + state: State; + + 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: { target: HTMLInputElement }) => { + this.setState({ projectKey: this.sanitizeProjectKey(event.target.value) }); + }; + + handleProjectCreate = (event: Event) => { + event.preventDefault(); + const { projectKey } = this.state; + const data: { [string]: 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 = (event: Event) => { + event.preventDefault(); + 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('onboarding.project_key_requirement')} +
      + ; + + return ( +
      +

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

      + {form} +
      + ); + } +} diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/Onboarding.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/Onboarding.js new file mode 100644 index 00000000000..0382a33e0d6 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/Onboarding.js @@ -0,0 +1,109 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +// @flow +import React from 'react'; +import TokenStep from './TokenStep'; +import OrganizationStep from './OrganizationStep'; +import AnalysisStep from './AnalysisStep'; +import { translate } from '../../../helpers/l10n'; +import handleRequiredAuthentication from '../../../app/utils/handleRequiredAuthentication'; +import './styles.css'; + +type Props = { + currentUser: { login: string, isLoggedIn: boolean }, + organizationsEnabled: boolean, + sonarCloud: boolean +}; + +type State = { + organization?: string, + step: string, + token?: string +}; + +export default class Onboarding extends React.PureComponent { + props: Props; + state: State; + + constructor(props: Props) { + super(props); + this.state = { step: props.organizationsEnabled ? 'organization' : 'token' }; + } + + componentDidMount() { + if (!this.props.currentUser.isLoggedIn) { + handleRequiredAuthentication(); + } + } + + handleTokenDone = (token: string) => { + this.setState({ step: 'analysis', token }); + }; + + handleOrganizationDone = (organization: string) => { + this.setState({ organization, step: 'token' }); + }; + + render() { + if (!this.props.currentUser.isLoggedIn) { + return null; + } + + const { organizationsEnabled, sonarCloud } = this.props; + const { step, token } = this.state; + + let stepNumber = 1; + + return ( +
      +
      +

      + {translate(sonarCloud ? 'onboarding.header.sonarcloud' : 'onboarding.header')} +

      +
      + {translate('onboarding.header.description')} +
      +
      + + {organizationsEnabled && + } + + + + +
      + ); + } +} diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/OnboardingContainer.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/OnboardingContainer.js new file mode 100644 index 00000000000..a7eecc2e9e4 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/OnboardingContainer.js @@ -0,0 +1,39 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +// @flow +import { connect } from 'react-redux'; +import Onboarding from './Onboarding'; +import { + getCurrentUser, + areThereCustomOrganizations, + getSettingValue +} from '../../../store/rootReducer'; + +const mapStateToProps = state => { + const sonarCloudSetting = getSettingValue(state, 'sonar.lf.sonarqube.com.enabled'); + + return { + currentUser: getCurrentUser(state), + organizationsEnabled: areThereCustomOrganizations(state), + sonarCloud: sonarCloudSetting != null && sonarCloudSetting.value === 'true' + }; +}; + +export default connect(mapStateToProps)(Onboarding); diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/OrganizationStep.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/OrganizationStep.js new file mode 100644 index 00000000000..325e8e8ac56 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/OrganizationStep.js @@ -0,0 +1,240 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +// @flow +import React from 'react'; +import Select from 'react-select'; +import classNames from 'classnames'; +import { sortBy } from 'lodash'; +import Step from './Step'; +import NewOrganizationForm from './NewOrganizationForm'; +import { getMyOrganizations } from '../../../api/organizations'; +import { translate } from '../../../helpers/l10n'; + +type Props = { + currentUser: { login: string, isLoggedIn: boolean }, + open: boolean, + onContinue: (organization: string) => void +}; + +type State = { + loading: boolean, + newOrganization?: string, + existingOrganization?: string, + existingOrganizations: Array, + selection: 'personal' | 'existing' | 'new' +}; + +export default class OrganizationStep extends React.PureComponent { + mounted: boolean; + props: Props; + state: State = { + loading: true, + existingOrganizations: [], + selection: 'personal' + }; + + componentDidMount() { + this.mounted = true; + this.fetchOrganizations(); + } + + componentWillUnmount() { + this.mounted = false; + } + + fetchOrganizations = () => { + getMyOrganizations().then( + organizations => { + if (this.mounted) { + this.setState({ + loading: false, + existingOrganizations: sortBy( + organizations.filter(organization => organization !== this.props.currentUser.login) + ) + }); + } + }, + () => { + if (this.mounted) { + this.setState({ loading: false }); + } + } + ); + }; + + getSelectedOrganization = () => { + switch (this.state.selection) { + case 'personal': + return this.props.currentUser.login; + case 'existing': + return this.state.existingOrganization; + case 'new': + return this.state.newOrganization; + default: + return null; + } + }; + + handlePersonalClick = (event: Event) => { + event.preventDefault(); + this.setState({ selection: 'personal' }); + }; + + handleExistingClick = (event: Event) => { + event.preventDefault(); + this.setState({ selection: 'existing' }); + }; + + handleNewClick = (event: Event) => { + 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 = (event: Event) => { + event.preventDefault(); + const organization = this.getSelectedOrganization(); + if (organization) { + this.props.onContinue(organization); + } + }; + + renderPersonalOrganizationOption = () => ( + + ); + + renderExistingOrganizationOption = () => ( +
      + + + {translate('onboarding.organization.exising_organization')} + + {this.state.selection === 'existing' && +
      + + {loading + ? + : } +
      + {translate('onboarding.project_key_requirement')} +
      + ; + + return ( +
      +

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

      + {form} +
      + ); + } +} diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/Step.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/Step.js new file mode 100644 index 00000000000..763cef635df --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/Step.js @@ -0,0 +1,47 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +// @flow +import React from 'react'; +import classNames from 'classnames'; + +type Props = { + open: boolean, + renderForm: () => React.Element<*>, + renderResult: () => ?React.Element<*>, + stepNumber: number, + stepTitle: string +}; + +export default function Step(props: Props) { + const className = classNames('boxed-group', 'onboarding-step', { + 'onboarding-step-open': props.open + }); + + return ( +
      +
      {props.stepNumber}
      + {!props.open && props.renderResult()} +
      +

      {props.stepTitle}

      +
      + {props.open ? props.renderForm() :
      } +
      + ); +} diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/TokenStep.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/TokenStep.js new file mode 100644 index 00000000000..9a171f7bc77 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/TokenStep.js @@ -0,0 +1,180 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +// @flow +import React from 'react'; +import Step from './Step'; +import { generateToken, revokeToken } from '../../../api/user-tokens'; +import { translate } from '../../../helpers/l10n'; + +type Props = { + open: boolean, + onContinue: (token: string) => void, + stepNumber: number +}; + +type State = { + loading: boolean, + tokenName?: string, + token?: string +}; + +export default class TokenStep extends React.PureComponent { + mounted: boolean; + props: Props; + + static defaultProps = { + stepNumber: 1 + }; + + state: State = { + loading: false + }; + + componentDidMount() { + this.mounted = true; + } + + componentWillUnmount() { + this.mounted = false; + } + + handleTokenNameChange = (event: { target: HTMLInputElement }) => { + this.setState({ tokenName: event.target.value }); + }; + + handleTokenGenerate = (event: Event) => { + event.preventDefault(); + const { tokenName } = this.state; + if (tokenName) { + this.setState({ loading: true }); + generateToken(tokenName).then( + ({ token }) => { + if (this.mounted) { + this.setState({ loading: false, token }); + } + }, + () => { + if (this.mounted) { + this.setState({ loading: false }); + } + } + ); + } + }; + + handleTokenRevoke = (event: Event) => { + event.preventDefault(); + const { tokenName } = this.state; + if (tokenName) { + this.setState({ loading: true }); + revokeToken(tokenName).then( + () => { + if (this.mounted) { + this.setState({ loading: false, token: undefined, tokenName: undefined }); + } + }, + () => { + if (this.mounted) { + this.setState({ loading: false }); + } + } + ); + } + }; + + handleContinueClick = (event: Event) => { + event.preventDefault(); + if (this.state.token) { + this.props.onContinue(this.state.token); + } + }; + + renderForm = () => { + const { loading, token, tokenName } = this.state; + + return ( +
      +
      + {translate('onboarding.token.text')} +
      + + {token != null + ?
      + {tokenName}{': '} + {token} + {loading + ? + : } + + :
      + + {loading + ? + : } + } + + {token != null && +
      + +
      } +
      + ); + }; + + renderResult = () => { + const { token, tokenName } = this.state; + + if (!token) { + return null; + } + + return ( +
      + + {tokenName}{': '} + {token} +
      + ); + }; + + render() { + return ( + + ); + } +} diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/LanguageStep-test.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/LanguageStep-test.js new file mode 100644 index 00000000000..414b0dba7fe --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/LanguageStep-test.js @@ -0,0 +1,106 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +// @flow +import React from 'react'; +import { shallow } from 'enzyme'; +import LanguageStep from '../LanguageStep'; + +it('selects java', () => { + const onDone = jest.fn(); + const wrapper = shallow(); + + wrapper.find('RadioToggle').prop('onCheck')('java'); + wrapper.update(); + expect(wrapper).toMatchSnapshot(); + + wrapper.find('RadioToggle').at(1).prop('onCheck')('maven'); + wrapper.update(); + expect(wrapper).toMatchSnapshot(); + expect(onDone).lastCalledWith({ language: 'java', javaBuild: 'maven' }); + + wrapper.find('RadioToggle').at(1).prop('onCheck')('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')('dotnet'); + wrapper.update(); + expect(wrapper).toMatchSnapshot(); + + wrapper.find('NewProjectForm').prop('onDone')('project-foo'); + expect(onDone).lastCalledWith({ language: 'dotnet', projectKey: 'project-foo' }); +}); + +it('selects c-family', () => { + const onDone = jest.fn(); + const wrapper = shallow(); + + wrapper.find('RadioToggle').prop('onCheck')('c-family'); + wrapper.update(); + expect(wrapper).toMatchSnapshot(); + + wrapper.find('RadioToggle').at(1).prop('onCheck')('msvc'); + wrapper.update(); + expect(wrapper).toMatchSnapshot(); + + wrapper.find('NewProjectForm').prop('onDone')('project-foo'); + expect(onDone).lastCalledWith({ + language: 'c-family', + cFamilyCompiler: 'msvc', + projectKey: 'project-foo' + }); + + wrapper.find('RadioToggle').at(1).prop('onCheck')('clang-gcc'); + wrapper.update(); + expect(wrapper).toMatchSnapshot(); + + wrapper.find('RadioToggle').at(2).prop('onCheck')('linux'); + wrapper.update(); + expect(wrapper).toMatchSnapshot(); + + wrapper.find('NewProjectForm').prop('onDone')('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')('other'); + wrapper.update(); + expect(wrapper).toMatchSnapshot(); + + wrapper.find('RadioToggle').at(1).prop('onCheck')('mac'); + wrapper.update(); + expect(wrapper).toMatchSnapshot(); + + wrapper.find('NewProjectForm').prop('onDone')('project-foo'); + expect(onDone).lastCalledWith({ language: 'other', os: 'mac', projectKey: 'project-foo' }); +}); diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/NewOrganizationForm-test.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/NewOrganizationForm-test.js new file mode 100644 index 00000000000..79a5542b3ee --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/NewOrganizationForm-test.js @@ -0,0 +1,56 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +// @flow +import React from 'react'; +import { mount } from 'enzyme'; +import NewOrganizationForm from '../NewOrganizationForm'; +import { change, doAsync, submit } from '../../../../helpers/testUtils'; + +jest.mock('../../../../api/organizations', () => ({ + createOrganization: () => Promise.resolve(), + deleteOrganization: () => Promise.resolve(), + getOrganization: () => Promise.resolve(null) +})); + +it('creates new organization', () => { + const onDone = jest.fn(); + const wrapper = mount(); + expect(wrapper).toMatchSnapshot(); + change(wrapper.find('input'), 'foo'); + submit(wrapper.find('form')); + expect(wrapper).toMatchSnapshot(); // spinner + return doAsync(() => { + expect(wrapper).toMatchSnapshot(); + expect(onDone).toBeCalledWith('foo'); + }); +}); + +it('deletes organization', () => { + const onDelete = jest.fn(); + const wrapper = mount(); + wrapper.setState({ done: true, loading: false, organization: 'foo' }); + expect(wrapper).toMatchSnapshot(); + submit(wrapper.find('form')); + expect(wrapper).toMatchSnapshot(); // spinner + return doAsync(() => { + expect(wrapper).toMatchSnapshot(); + expect(onDelete).toBeCalled(); + }); +}); diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/NewProjectForm-test.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/NewProjectForm-test.js new file mode 100644 index 00000000000..7b05724cbe7 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/NewProjectForm-test.js @@ -0,0 +1,55 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +// @flow +import React from 'react'; +import { mount } from 'enzyme'; +import NewProjectForm from '../NewProjectForm'; +import { change, doAsync, submit } from '../../../../helpers/testUtils'; + +jest.mock('../../../../api/components', () => ({ + createProject: () => Promise.resolve(), + deleteProject: () => Promise.resolve() +})); + +it('creates new project', () => { + const onDone = jest.fn(); + const wrapper = mount(); + expect(wrapper).toMatchSnapshot(); + change(wrapper.find('input'), 'foo'); + submit(wrapper.find('form')); + expect(wrapper).toMatchSnapshot(); // spinner + return doAsync(() => { + expect(wrapper).toMatchSnapshot(); + expect(onDone).toBeCalledWith('foo'); + }); +}); + +it('deletes project', () => { + const onDelete = jest.fn(); + const wrapper = mount(); + wrapper.setState({ done: true, loading: false, projectKey: 'foo' }); + expect(wrapper).toMatchSnapshot(); + submit(wrapper.find('form')); + expect(wrapper).toMatchSnapshot(); // spinner + return doAsync(() => { + expect(wrapper).toMatchSnapshot(); + expect(onDelete).toBeCalled(); + }); +}); diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/OrganizationStep-test.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/OrganizationStep-test.js new file mode 100644 index 00000000000..9352556f5d1 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/OrganizationStep-test.js @@ -0,0 +1,63 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +// @flow +import React from 'react'; +import { mount } from 'enzyme'; +import OrganizationStep from '../OrganizationStep'; +import { click, doAsync } from '../../../../helpers/testUtils'; + +jest.mock('../../../../api/organizations', () => ({ + getMyOrganizations: () => Promise.resolve(['user', 'another']) +})); + +const currentUser = { isLoggedIn: true, login: 'user' }; + +it('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', () => { + const onContinue = jest.fn(); + const wrapper = mount( + + ); + return doAsync(() => { + click(wrapper.find('.js-existing')); + wrapper.find('Select').prop('onChange')({ value: 'another' }); + click(wrapper.find('.js-continue')); + expect(onContinue).toBeCalledWith('another'); + }); +}); + +it('works with new organization', () => { + const onContinue = jest.fn(); + const wrapper = mount( + + ); + click(wrapper.find('.js-new')); + wrapper.find('NewOrganizationForm').prop('onDone')('new'); + click(wrapper.find('.js-continue')); + expect(onContinue).toBeCalledWith('new'); +}); diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/ProjectKeyStep-test.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/ProjectKeyStep-test.js new file mode 100644 index 00000000000..2af50f6a3b5 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/ProjectKeyStep-test.js @@ -0,0 +1,55 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +// @flow +import React from 'react'; +import { mount } from 'enzyme'; +import ProjectKeyStep from '../ProjectKeyStep'; +import { change, doAsync, submit } from '../../../../helpers/testUtils'; + +jest.mock('../../../../api/components', () => ({ + createProject: () => Promise.resolve(), + deleteProject: () => Promise.resolve() +})); + +it('creates new project', () => { + const onDone = jest.fn(); + const wrapper = mount(); + expect(wrapper).toMatchSnapshot(); + change(wrapper.find('input'), 'foo'); + submit(wrapper.find('form')); + expect(wrapper).toMatchSnapshot(); // spinner + return doAsync(() => { + expect(wrapper).toMatchSnapshot(); + expect(onDone).toBeCalledWith('foo'); + }); +}); + +it('deletes project', () => { + const onDelete = jest.fn(); + const wrapper = mount(); + wrapper.setState({ done: true, loading: false, projectKey: 'foo' }); + expect(wrapper).toMatchSnapshot(); + submit(wrapper.find('form')); + expect(wrapper).toMatchSnapshot(); // spinner + return doAsync(() => { + expect(wrapper).toMatchSnapshot(); + expect(onDelete).toBeCalled(); + }); +}); diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/Step-test.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/Step-test.js new file mode 100644 index 00000000000..89d7a3b7ba4 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/Step-test.js @@ -0,0 +1,38 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +// @flow +import React from 'react'; +import { shallow } from 'enzyme'; +import Step from '../Step'; + +it('renders', () => { + const wrapper = shallow( +
      form
      } + renderResult={() =>
      result
      } + stepNumber={1} + stepTitle="First Step" + /> + ); + expect(wrapper).toMatchSnapshot(); + wrapper.setProps({ open: false }); + expect(wrapper).toMatchSnapshot(); +}); diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/TokenStep-test.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/TokenStep-test.js new file mode 100644 index 00000000000..9498fc27ada --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/TokenStep-test.js @@ -0,0 +1,55 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +// @flow +import React from 'react'; +import { mount } from 'enzyme'; +import TokenStep from '../TokenStep'; +import { change, click, doAsync, submit } from '../../../../helpers/testUtils'; + +jest.mock('../../../../api/user-tokens', () => ({ + generateToken: () => Promise.resolve({ token: 'abcd1234' }), + revokeToken: () => Promise.resolve() +})); + +it('generates token', () => { + const wrapper = mount(); + expect(wrapper).toMatchSnapshot(); + change(wrapper.find('input'), 'my token'); + submit(wrapper.find('form')); + expect(wrapper).toMatchSnapshot(); // spinner + return doAsync(() => expect(wrapper).toMatchSnapshot()); +}); + +it('revokes token', () => { + const wrapper = mount(); + wrapper.setState({ token: 'abcd1234', tokenName: 'my token' }); + expect(wrapper).toMatchSnapshot(); + submit(wrapper.find('form')); + expect(wrapper).toMatchSnapshot(); // spinner + return doAsync(() => expect(wrapper).toMatchSnapshot()); +}); + +it('continues', () => { + const onContinue = jest.fn(); + const wrapper = mount(); + wrapper.setState({ token: 'abcd1234', tokenName: 'my token' }); + click(wrapper.find('.js-continue')); + expect(onContinue).toBeCalledWith('abcd1234'); +}); diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/LanguageStep-test.js.snap b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/LanguageStep-test.js.snap new file mode 100644 index 00000000000..8e82d384b3f --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/LanguageStep-test.js.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/onboarding/__tests__/__snapshots__/NewOrganizationForm-test.js.snap b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/NewOrganizationForm-test.js.snap new file mode 100644 index 00000000000..c5f05454644 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/NewOrganizationForm-test.js.snap @@ -0,0 +1,168 @@ +// 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/onboarding/__tests__/__snapshots__/NewProjectForm-test.js.snap b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/NewProjectForm-test.js.snap new file mode 100644 index 00000000000..50ef33521cc --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/NewProjectForm-test.js.snap @@ -0,0 +1,219 @@ +// 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/onboarding/__tests__/__snapshots__/ProjectKeyStep-test.js.snap b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/ProjectKeyStep-test.js.snap new file mode 100644 index 00000000000..cbfbf1da7ca --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/ProjectKeyStep-test.js.snap @@ -0,0 +1,219 @@ +// 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/onboarding/__tests__/__snapshots__/Step-test.js.snap b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/Step-test.js.snap new file mode 100644 index 00000000000..1df068a503c --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/Step-test.js.snap @@ -0,0 +1,48 @@ +// 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/onboarding/__tests__/__snapshots__/TokenStep-test.js.snap b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/TokenStep-test.js.snap new file mode 100644 index 00000000000..73ae3896df4 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/TokenStep-test.js.snap @@ -0,0 +1,383 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`generates token 1`] = ` + + +
      +
      + 1 +
      +
      +

      + onboarding.token.header +

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

      + onboarding.token.header +

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

      + onboarding.token.header +

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

      + onboarding.token.header +

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

      + onboarding.token.header +

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

      + onboarding.token.header +

      +
      +
      +
      + onboarding.token.text +
      +
      + + +
      +
      +
      +
      +
      +`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/BuildWrapper.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/BuildWrapper.js new file mode 100644 index 00000000000..3b0624e4629 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/BuildWrapper.js @@ -0,0 +1,58 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +// @flow +import React from 'react'; +import { translate } from '../../../../helpers/l10n'; + +type Props = { + className?: string, + os: string +}; + +const filenames = { + linux: 'build-wrapper-win-x86.zip', + win: '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/onboarding/commands/ClangGCC.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/ClangGCC.js new file mode 100644 index 00000000000..7940263931c --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/ClangGCC.js @@ -0,0 +1,76 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +// @flow +import React from 'react'; +import Command from './Command'; +import SQScanner from './SQScanner'; +import BuildWrapper from './BuildWrapper'; +import { translate } from '../../../../helpers/l10n'; + +type Props = { + host: string, + os: string, + organization?: string, + projectKey: string, + token: string +}; + +const executables = { + 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')} +

      +

      + + +

      +

      + ); +} diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/Command.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/Command.js new file mode 100644 index 00000000000..ec9f980083d --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/Command.js @@ -0,0 +1,89 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +// @flow +import React from 'react'; +import Clipboard from 'clipboard'; +import Tooltip from '../../../../components/controls/Tooltip'; +import { translate } from '../../../../helpers/l10n'; + +type Props = { + command: string | Array +}; + +type State = { + tooltipShown: boolean +}; + +const s = ' \\' + '\n '; + +export default class Command extends React.PureComponent { + clipboard: Object; + copyButton: HTMLButtonElement; + mounted: boolean; + props: Props; + state: State = { tooltipShown: false }; + + componentDidMount() { + this.mounted = true; + this.clipboard = new Clipboard(this.copyButton); + this.clipboard.on('success', this.showTooltip); + } + + componentWillUnmount() { + this.mounted = false; + this.clipboard.destroy(); + } + + showTooltip = () => { + if (this.mounted) { + this.setState({ tooltipShown: true }); + setTimeout(this.hideTooltip, 1000); + } + }; + + hideTooltip = () => { + if (this.mounted) { + this.setState({ tooltipShown: false }); + } + }; + + render() { + const { command } = this.props; + const commandArray = Array.isArray(command) ? command.filter(line => line != null) : [command]; + const finalCommand = commandArray.join(s); + + const button = ( + + ); + + return ( +
      +
      {finalCommand}
      + {this.state.tooltipShown + ? + {button} + + : button} +
      + ); + } +} diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/DotNet.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/DotNet.js new file mode 100644 index 00000000000..8885458953b --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/DotNet.js @@ -0,0 +1,68 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +// @flow +import React from 'react'; +import Command from './Command'; +import MSBuildScanner from './MSBuildScanner'; +import { translate } from '../../../../helpers/l10n'; + +type Props = {| + host: string, + organization?: string, + projectKey: string, + token: string +|}; + +export default function DotNet(props: Props) { + const command1 = [ + 'SonarQube.Scanner.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 = ['SonarQube.Scanner.MSBuild.exe end', `/d:"sonar.login=${props.token}"`]; + + return ( +
      + + +

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

      +

      + + + +

      +

      + ); +} diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/JavaGradle.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/JavaGradle.js new file mode 100644 index 00000000000..3f89a2bb241 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/JavaGradle.js @@ -0,0 +1,59 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +// @flow +import React from 'react'; +import Command from './Command'; +import { translate } from '../../../../helpers/l10n'; + +type Props = {| + host: string, + organization?: string, + token: string +|}; + +export default function JavaGradle(props: Props) { + const config = 'plugins {\n id "org.sonarqube" version "2.2"\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')}

      +

      + +

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

      + +

      +

      + ); +} diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/JavaMaven.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/JavaMaven.js new file mode 100644 index 00000000000..6317b1bac2e --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/JavaMaven.js @@ -0,0 +1,50 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +// @flow +import React from 'react'; +import Command from './Command'; +import { translate } from '../../../../helpers/l10n'; + +type 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')}

      +

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

      + +

      +

      + ); +} diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/MSBuildScanner.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/MSBuildScanner.js new file mode 100644 index 00000000000..3be38395ca9 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/MSBuildScanner.js @@ -0,0 +1,46 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +// @flow +import React from 'react'; +import { translate } from '../../../../helpers/l10n'; + +type 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/onboarding/commands/Msvc.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/Msvc.js new file mode 100644 index 00000000000..00fba90474a --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/Msvc.js @@ -0,0 +1,71 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +// @flow +import React from 'react'; +import Command from './Command'; +import MSBuildScanner from './MSBuildScanner'; +import BuildWrapper from './BuildWrapper'; +import { translate } from '../../../../helpers/l10n'; + +type 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')} +

      +

      + + + +

      +

      + ); +} diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/Other.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/Other.js new file mode 100644 index 00000000000..534be2f8584 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/Other.js @@ -0,0 +1,64 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +// @flow +import React from 'react'; +import Command from './Command'; +import SQScanner from './SQScanner'; +import { translate } from '../../../../helpers/l10n'; + +type 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')} +

      +

      + +

      +

      + ); +} diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/SQScanner.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/SQScanner.js new file mode 100644 index 00000000000..d36c6379259 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/SQScanner.js @@ -0,0 +1,51 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +// @flow +import React from 'react'; +import { translate } from '../../../../helpers/l10n'; + +type 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/onboarding/commands/__tests__/BuildWrapper-test.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/BuildWrapper-test.js new file mode 100644 index 00000000000..2135abc7606 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/BuildWrapper-test.js @@ -0,0 +1,29 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +// @flow +import 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/onboarding/commands/__tests__/ClangGCC-test.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/ClangGCC-test.js new file mode 100644 index 00000000000..16c458660b8 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/ClangGCC-test.js @@ -0,0 +1,45 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +// @flow +import 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/onboarding/commands/__tests__/Command-test.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/Command-test.js new file mode 100644 index 00000000000..19ee425c791 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/Command-test.js @@ -0,0 +1,27 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +// @flow +import React from 'react'; +import { shallow } from 'enzyme'; +import Command from '../Command'; + +it('renders correctly', () => { + expect(shallow()).toMatchSnapshot(); +}); diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/DotNet-test.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/DotNet-test.js new file mode 100644 index 00000000000..f1e320e2b3f --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/DotNet-test.js @@ -0,0 +1,32 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +// @flow +import 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/onboarding/commands/__tests__/JavaGradle-test.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/JavaGradle-test.js new file mode 100644 index 00000000000..ef326ddc8c9 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/JavaGradle-test.js @@ -0,0 +1,30 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +// @flow +import 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/onboarding/commands/__tests__/JavaMaven-test.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/JavaMaven-test.js new file mode 100644 index 00000000000..bb24f89e611 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/JavaMaven-test.js @@ -0,0 +1,30 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +// @flow +import 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/onboarding/commands/__tests__/MSBuildScanner-test.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/MSBuildScanner-test.js new file mode 100644 index 00000000000..e2c22bc157e --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/MSBuildScanner-test.js @@ -0,0 +1,27 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +// @flow +import 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/onboarding/commands/__tests__/Msvc-test.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/Msvc-test.js new file mode 100644 index 00000000000..28bfa947aa6 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/Msvc-test.js @@ -0,0 +1,30 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +// @flow +import 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/onboarding/commands/__tests__/Other-test.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/Other-test.js new file mode 100644 index 00000000000..0eda78f2f94 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/Other-test.js @@ -0,0 +1,45 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +// @flow +import 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/onboarding/commands/__tests__/SQScanner-test.js b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/SQScanner-test.js new file mode 100644 index 00000000000..3b2881377ad --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/SQScanner-test.js @@ -0,0 +1,29 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +// @flow +import 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/onboarding/commands/__tests__/__snapshots__/BuildWrapper-test.js.snap b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/BuildWrapper-test.js.snap new file mode 100644 index 00000000000..4a1e0c3944c --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/BuildWrapper-test.js.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/onboarding/commands/__tests__/__snapshots__/ClangGCC-test.js.snap b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/ClangGCC-test.js.snap new file mode 100644 index 00000000000..1ec053c4083 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/ClangGCC-test.js.snap @@ -0,0 +1,148 @@ +// 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/onboarding/commands/__tests__/__snapshots__/Command-test.js.snap b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/Command-test.js.snap new file mode 100644 index 00000000000..9ce1c887f5f --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/Command-test.js.snap @@ -0,0 +1,18 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders correctly 1`] = ` +
      +
      +    foo
      +    bar
      +  
      + +
      +`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/DotNet-test.js.snap b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/DotNet-test.js.snap new file mode 100644 index 00000000000..3672a2f4c8d --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/DotNet-test.js.snap @@ -0,0 +1,99 @@ +// 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/onboarding/commands/__tests__/__snapshots__/JavaGradle-test.js.snap b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/JavaGradle-test.js.snap new file mode 100644 index 00000000000..df6bf9db47f --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/JavaGradle-test.js.snap @@ -0,0 +1,93 @@ +// 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/onboarding/commands/__tests__/__snapshots__/JavaMaven-test.js.snap b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/JavaMaven-test.js.snap new file mode 100644 index 00000000000..3cd4796988b --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/JavaMaven-test.js.snap @@ -0,0 +1,67 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders correctly 1`] = ` +
      +

      + onboarding.analysis.java.maven.header +

      +

      + onboarding.analysis.java.maven.text +

      + +

      +

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

      + onboarding.analysis.java.maven.header +

      +

      + onboarding.analysis.java.maven.text +

      + +

      +

      +`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/MSBuildScanner-test.js.snap b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/MSBuildScanner-test.js.snap new file mode 100644 index 00000000000..c7f156bc53f --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/MSBuildScanner-test.js.snap @@ -0,0 +1,28 @@ +// 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/onboarding/commands/__tests__/__snapshots__/Msvc-test.js.snap b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/Msvc-test.js.snap new file mode 100644 index 00000000000..c2f54b40496 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/Msvc-test.js.snap @@ -0,0 +1,109 @@ +// 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/onboarding/commands/__tests__/__snapshots__/Other-test.js.snap b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/Other-test.js.snap new file mode 100644 index 00000000000..699ff84d414 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/Other-test.js.snap @@ -0,0 +1,124 @@ +// 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/onboarding/commands/__tests__/__snapshots__/SQScanner-test.js.snap b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/SQScanner-test.js.snap new file mode 100644 index 00000000000..bcdac075ce4 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/commands/__tests__/__snapshots__/SQScanner-test.js.snap @@ -0,0 +1,82 @@ +// 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/onboarding/styles.css b/server/sonar-web/src/main/js/apps/tutorials/onboarding/styles.css new file mode 100644 index 00000000000..870da20acde --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/styles.css @@ -0,0 +1,59 @@ +.onboarding-step { + position: relative; + padding-left: 34px; +} + +.onboarding-step .boxed-group-actions { + height: 24px; + line-height: 24px; +} + +.onboarding-step-number { + position: absolute; + top: 15px; + left: 15px; + width: 24px; + height: 24px; + line-height: 24px; + border-radius: 24px; + background-color: #cdcdcd; + color: #fff; + font-size: 14px; + text-align: center; +} + +.onboarding-step-open .onboarding-step-number { + background-color: #236a97; +} + +.onboarding-command { + position: relative; + margin: 8px 0; +} + +.onboarding-command pre { + padding: 15px; + border-radius: 2px; + background: #404040; + color: #f0f0f0; + overflow: auto; +} + +.onboarding-command button { + position: absolute; + top: 15px; + right: 15px; + height: 20px; + line-height: 18px; + border: 1px solid #fff; + color: #fff; + font-size: 11px; + font-weight: normal; +} + +.onboarding-command button:hover, +.onboarding-command button:focus, +.onboarding-command button:active { + background-color: #fff; + color: #404040; +} diff --git a/server/sonar-web/src/main/js/apps/tutorials/routes.js b/server/sonar-web/src/main/js/apps/tutorials/routes.js new file mode 100644 index 00000000000..3a7111d0ae0 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/routes.js @@ -0,0 +1,31 @@ +/* + * SonarQube + * Copyright (C) 2009-2017 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. + */ +const routes = [ + { + path: 'onboarding', + getComponent(_, callback) { + require.ensure([], require => { + callback(null, require('./onboarding/OnboardingContainer').default); + }); + } + } +]; + +export default routes; diff --git a/server/sonar-web/src/main/js/apps/users/tokens-view.js b/server/sonar-web/src/main/js/apps/users/tokens-view.js index 01fa9a6636e..01889e1d848 100644 --- a/server/sonar-web/src/main/js/apps/users/tokens-view.js +++ b/server/sonar-web/src/main/js/apps/users/tokens-view.js @@ -54,17 +54,13 @@ export default Modal.extend({ this.errors = []; this.newToken = null; const tokenName = this.$('.js-generate-token-form input').val(); - generateToken(this.model.id, tokenName) - .then(response => { + generateToken(tokenName, this.model.id).then( + response => { this.newToken = response; this.requestTokens(); - }) - .catch(error => { - error.response.json().then(response => { - this.errors = response.errors; - this.render(); - }); - }); + }, + () => {} + ); }, onRevokeTokenFormSubmit(e) { @@ -73,7 +69,7 @@ export default Modal.extend({ const token = this.tokens.find(t => t.name === `${tokenName}`); if (token) { if (token.deleting) { - revokeToken(this.model.id, tokenName).then(this.requestTokens.bind(this)); + revokeToken(tokenName, this.model.id).then(this.requestTokens.bind(this), () => {}); } else { token.deleting = true; this.render(); -- cgit v1.2.3