aboutsummaryrefslogtreecommitdiffstats
path: root/server/sonar-web/src/main
diff options
context:
space:
mode:
authorGrégoire Aubert <gregoire.aubert@sonarsource.com>2018-07-26 11:44:57 +0200
committerSonarTech <sonartech@sonarsource.com>2018-08-10 20:21:30 +0200
commit4f5f81d6c146d6cc873239258343141e9631c9b6 (patch)
treecbfc4686ececf2c9308ad3f5ece645c5fc0945cd /server/sonar-web/src/main
parent75f56b1e0ce0d59f9bdb039b41563c1994488775 (diff)
downloadsonarqube-4f5f81d6c146d6cc873239258343141e9631c9b6.tar.gz
sonarqube-4f5f81d6c146d6cc873239258343141e9631c9b6.zip
SONAR-11029 Move the tutorial inside provisioned projects dashboard
* Move/Rename files of tutorials folder * SONAR-11049 Update tutorial UI and move it inside the project dashboard * SONAR-11050 Update tutorial to skip now useless steps * Remove unused style * SONAR-11030 Make dashboard tutorial work with already known project key * Better manage error messages when no analysis and analyzed branches * SONAR-11052 Refresh project status as long as there is no analysis * SONAR-11051 Add infos suggestions depending on the ALM of the project * Do no display tutorial when there is analyses in the pipe
Diffstat (limited to 'server/sonar-web/src/main')
-rw-r--r--server/sonar-web/src/main/js/app/components/ComponentContainer.tsx7
-rw-r--r--server/sonar-web/src/main/js/app/components/StartupModal.tsx6
-rw-r--r--server/sonar-web/src/main/js/app/components/__tests__/ComponentContainer-test.tsx40
-rw-r--r--server/sonar-web/src/main/js/app/styles/components/alerts.css2
-rw-r--r--server/sonar-web/src/main/js/app/styles/components/boxed-group.css2
-rw-r--r--server/sonar-web/src/main/js/app/styles/components/page.css12
-rw-r--r--server/sonar-web/src/main/js/app/styles/init/misc.css5
-rw-r--r--server/sonar-web/src/main/js/app/styles/sonarcloud.css9
-rw-r--r--server/sonar-web/src/main/js/app/types.ts2
-rw-r--r--server/sonar-web/src/main/js/apps/coding-rules/components/FacetsList.tsx4
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/sidebar/Sidebar.js2
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/Sidebar-test.js.snap4
-rw-r--r--server/sonar-web/src/main/js/apps/issues/sidebar/Sidebar.tsx4
-rw-r--r--server/sonar-web/src/main/js/apps/overview/components/App.tsx65
-rw-r--r--server/sonar-web/src/main/js/apps/overview/components/EmptyOverview.tsx49
-rw-r--r--server/sonar-web/src/main/js/apps/overview/components/OverviewApp.tsx14
-rw-r--r--server/sonar-web/src/main/js/apps/overview/components/SonarCloudEmptyOverview.tsx126
-rw-r--r--server/sonar-web/src/main/js/apps/overview/components/__tests__/App-test.tsx32
-rw-r--r--server/sonar-web/src/main/js/apps/overview/components/__tests__/EmptyOverview-test.tsx30
-rw-r--r--server/sonar-web/src/main/js/apps/overview/components/__tests__/SonarCloudEmptyOverview-test.tsx117
-rw-r--r--server/sonar-web/src/main/js/apps/overview/components/__tests__/Timeline-test.js51
-rw-r--r--server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/EmptyOverview-test.tsx.snap75
-rw-r--r--server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/SonarCloudEmptyOverview-test.tsx.snap229
-rw-r--r--server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/Timeline-test.js.snap71
-rw-r--r--server/sonar-web/src/main/js/apps/overview/meta/MetaContainer.tsx29
-rw-r--r--server/sonar-web/src/main/js/apps/overview/styles.css1
-rw-r--r--server/sonar-web/src/main/js/apps/projects/create/AlmRepositoryItem.tsx (renamed from server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/AlmRepositoryItem.tsx)0
-rw-r--r--server/sonar-web/src/main/js/apps/projects/create/AutoProjectCreate.tsx (renamed from server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/AutoProjectCreate.tsx)0
-rw-r--r--server/sonar-web/src/main/js/apps/projects/create/CreateProjectPage.tsx (renamed from server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/CreateProjectOnboarding.tsx)63
-rw-r--r--server/sonar-web/src/main/js/apps/projects/create/ManualProjectCreate.tsx (renamed from server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/ManualProjectCreate.tsx)2
-rw-r--r--server/sonar-web/src/main/js/apps/projects/create/__tests__/AlmRepositoryItem-test.tsx (renamed from server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/AlmRepositoryItem-test.tsx)0
-rw-r--r--server/sonar-web/src/main/js/apps/projects/create/__tests__/AutoProjectCreate-test.tsx (renamed from server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/AutoProjectCreate-test.tsx)0
-rw-r--r--server/sonar-web/src/main/js/apps/projects/create/__tests__/CreateProjectPage-test.tsx (renamed from server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/CreateProjectOnboarding-test.tsx)16
-rw-r--r--server/sonar-web/src/main/js/apps/projects/create/__tests__/ManualProjectCreate-test.tsx (renamed from server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/ManualProjectCreate-test.tsx)0
-rw-r--r--server/sonar-web/src/main/js/apps/projects/create/__tests__/__snapshots__/AlmRepositoryItem-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/__snapshots__/AlmRepositoryItem-test.tsx.snap)0
-rw-r--r--server/sonar-web/src/main/js/apps/projects/create/__tests__/__snapshots__/AutoProjectCreate-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/__snapshots__/AutoProjectCreate-test.tsx.snap)0
-rw-r--r--server/sonar-web/src/main/js/apps/projects/create/__tests__/__snapshots__/CreateProjectPage-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/__snapshots__/CreateProjectOnboarding-test.tsx.snap)2
-rw-r--r--server/sonar-web/src/main/js/apps/projects/create/__tests__/__snapshots__/ManualProjectCreate-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/__snapshots__/ManualProjectCreate-test.tsx.snap)0
-rw-r--r--server/sonar-web/src/main/js/apps/projects/create/utils.ts42
-rw-r--r--server/sonar-web/src/main/js/apps/projects/routes.ts10
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/analyzeProject/AnalyzeTutorial.tsx94
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/analyzeProject/AnalyzeTutorialSuggestion.tsx88
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/analyzeProject/__tests__/AnalyzeTutorial-test.tsx47
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/analyzeProject/__tests__/AnalyzeTutorialSuggestion-test.tsx38
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/analyzeProject/__tests__/__snapshots__/AnalyzeTutorial-test.tsx.snap54
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/analyzeProject/__tests__/__snapshots__/AnalyzeTutorialSuggestion-test.tsx.snap78
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/LanguageForm.tsx (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/LanguageStep.tsx)91
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/NewOrganizationForm.tsx (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/NewOrganizationForm.tsx)0
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/NewProjectForm.tsx (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/NewProjectForm.tsx)0
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/OrganizationStep.tsx (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/OrganizationStep.tsx)0
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/ProjectAnalysisStep.tsx120
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/Step.tsx (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/Step.tsx)0
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/TokenStep.tsx (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/TokenStep.tsx)0
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/__tests__/LanguageForm-test.tsx (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/LanguageStep-test.tsx)10
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/__tests__/NewOrganizationForm-test.tsx (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/NewOrganizationForm-test.tsx)0
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/__tests__/NewProjectForm-test.tsx (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/NewProjectForm-test.tsx)0
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/__tests__/OrganizationStep-test.tsx (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/OrganizationStep-test.tsx)0
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/__tests__/Step-test.tsx (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/Step-test.tsx)0
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/__tests__/TokenStep-test.tsx (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/TokenStep-test.tsx)0
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/__tests__/__snapshots__/LanguageForm-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/LanguageStep-test.tsx.snap)40
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/__tests__/__snapshots__/NewOrganizationForm-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/NewOrganizationForm-test.tsx.snap)0
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/__tests__/__snapshots__/NewProjectForm-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/NewProjectForm-test.tsx.snap)0
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/__tests__/__snapshots__/OrganizationStep-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/OrganizationStep-test.tsx.snap)0
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/__tests__/__snapshots__/Step-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/Step-test.tsx.snap)0
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/__tests__/__snapshots__/TokenStep-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/TokenStep-test.tsx.snap)0
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/commands/AnalysisCommand.tsx146
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/commands/BuildWrapper.tsx (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/BuildWrapper.tsx)0
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/commands/ClangGCC.tsx (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/ClangGCC.tsx)3
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/commands/DotNet.tsx (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/DotNet.tsx)5
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/commands/JavaGradle.tsx (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/JavaGradle.tsx)4
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/commands/JavaMaven.tsx (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/JavaMaven.tsx)4
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/commands/MSBuildScanner.tsx (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/MSBuildScanner.tsx)0
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/commands/Msvc.tsx (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/Msvc.tsx)5
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/commands/Other.tsx (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/Other.tsx)0
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/commands/SQScanner.tsx (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/SQScanner.tsx)0
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/AnalysisCommand-test.tsx71
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/BuildWrapper-test.tsx (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/BuildWrapper-test.tsx)0
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/ClangGCC-test.tsx (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/ClangGCC-test.tsx)1
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/DotNet-test.tsx (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/DotNet-test.tsx)8
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/JavaGradle-test.tsx (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/JavaGradle-test.tsx)0
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/JavaMaven-test.tsx (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/JavaMaven-test.tsx)0
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/MSBuildScanner-test.tsx (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/MSBuildScanner-test.tsx)0
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/Msvc-test.tsx (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/Msvc-test.tsx)10
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/Other-test.tsx (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/Other-test.tsx)0
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/SQScanner-test.tsx (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/SQScanner-test.tsx)0
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/AnalysisCommand-test.tsx.snap49
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/BuildWrapper-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/BuildWrapper-test.tsx.snap)0
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/ClangGCC-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/ClangGCC-test.tsx.snap)2
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/DotNet-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/DotNet-test.tsx.snap)5
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/JavaGradle-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/JavaGradle-test.tsx.snap)2
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/JavaMaven-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/JavaMaven-test.tsx.snap)2
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/MSBuildScanner-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/MSBuildScanner-test.tsx.snap)0
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/Msvc-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/Msvc-test.tsx.snap)2
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/Other-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/Other-test.tsx.snap)0
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/SQScanner-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/SQScanner-test.tsx.snap)0
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/onboarding/OnboardingModal.tsx (renamed from server/sonar-web/src/main/js/apps/tutorials/Onboarding.tsx)24
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/onboarding/OnboardingPage.tsx99
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/OnboardingModal-test.tsx (renamed from server/sonar-web/src/main/js/apps/tutorials/__tests__/Onboarding-test.tsx)8
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/OnboardingModal-test.tsx.snap (renamed from server/sonar-web/src/main/js/apps/tutorials/__tests__/__snapshots__/Onboarding-test.tsx.snap)0
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/AnalysisStep.tsx201
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/ProjectOnboarding.tsx8
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/ProjectOnboarding-test.tsx.snap10
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/routes.ts2
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/styles.css3
-rw-r--r--server/sonar-web/src/main/js/apps/tutorials/utils.ts40
-rw-r--r--server/sonar-web/src/main/js/components/icons-components/OnboardingPrivateIcon.tsx2
-rw-r--r--server/sonar-web/src/main/js/components/icons-components/OnboardingProjectIcon.tsx2
-rw-r--r--server/sonar-web/src/main/js/components/icons-components/OnboardingTeamIcon.tsx2
-rw-r--r--server/sonar-web/src/main/js/components/ui/buttons.css4
-rw-r--r--server/sonar-web/src/main/js/helpers/markdown.js2
-rw-r--r--server/sonar-web/src/main/js/helpers/urls.ts4
111 files changed, 1889 insertions, 624 deletions
diff --git a/server/sonar-web/src/main/js/app/components/ComponentContainer.tsx b/server/sonar-web/src/main/js/app/components/ComponentContainer.tsx
index 82d4b81197e..176a21d06ac 100644
--- a/server/sonar-web/src/main/js/app/components/ComponentContainer.tsx
+++ b/server/sonar-web/src/main/js/app/components/ComponentContainer.tsx
@@ -176,7 +176,12 @@ export class ComponentContainer extends React.PureComponent<Props, State> {
differenceBy(newTasksInProgress, tasksInProgress, 'id').length > 0);
shouldFetchComponent = Boolean(currentTaskChanged || progressChanged);
- if (!shouldFetchComponent && component && newTasksInProgress.length > 0) {
+ if (
+ !shouldFetchComponent &&
+ component &&
+ (newTasksInProgress.length > 0 || !component.analysisDate)
+ ) {
+ // Refresh the status as long as there is tasks in progress or no analysis
window.clearTimeout(this.watchStatusTimer);
this.watchStatusTimer = window.setTimeout(
() => this.fetchStatus(component),
diff --git a/server/sonar-web/src/main/js/app/components/StartupModal.tsx b/server/sonar-web/src/main/js/app/components/StartupModal.tsx
index 8a7e7e2f444..b85885bbcd0 100644
--- a/server/sonar-web/src/main/js/app/components/StartupModal.tsx
+++ b/server/sonar-web/src/main/js/app/components/StartupModal.tsx
@@ -35,7 +35,7 @@ import { lazyLoad } from '../../components/lazyLoad';
const CreateOrganizationForm = lazyLoad(() =>
import('../../apps/account/organizations/CreateOrganizationForm')
);
-const Onboarding = lazyLoad(() => import('../../apps/tutorials/Onboarding'));
+const OnboardingModal = lazyLoad(() => import('../../apps/tutorials/onboarding/OnboardingModal'));
const LicensePromptModal = lazyLoad(
() => import('../../apps/marketplace/components/LicensePromptModal'),
'LicensePromptModal'
@@ -135,7 +135,7 @@ export class StartupModal extends React.PureComponent<Props, State> {
openProjectOnboarding = () => {
if (isSonarCloud()) {
this.setState({ automatic: false, modal: undefined });
- this.context.router.push(`/onboarding`);
+ this.context.router.push(`/projects/create`);
} else {
this.setState({ modal: ModalKey.projectOnboarding });
}
@@ -189,7 +189,7 @@ export class StartupModal extends React.PureComponent<Props, State> {
{this.props.children}
{modal === ModalKey.license && <LicensePromptModal onClose={this.closeLicense} />}
{modal === ModalKey.onboarding && (
- <Onboarding
+ <OnboardingModal
onClose={this.closeOnboarding}
onOpenOrganizationOnboarding={this.openOrganizationOnboarding}
onOpenProjectOnboarding={this.openProjectOnboarding}
diff --git a/server/sonar-web/src/main/js/app/components/__tests__/ComponentContainer-test.tsx b/server/sonar-web/src/main/js/app/components/__tests__/ComponentContainer-test.tsx
index 83a4afb2822..e67564559f6 100644
--- a/server/sonar-web/src/main/js/app/components/__tests__/ComponentContainer-test.tsx
+++ b/server/sonar-web/src/main/js/app/components/__tests__/ComponentContainer-test.tsx
@@ -36,25 +36,23 @@ import { STATUSES } from '../../../apps/background-tasks/constants';
import { waitAndUpdate } from '../../../helpers/testUtils';
jest.mock('../../../api/branches', () => ({
- getBranches: jest.fn(() => Promise.resolve([])),
- getPullRequests: jest.fn(() => Promise.resolve([]))
+ getBranches: jest.fn().mockResolvedValue([]),
+ getPullRequests: jest.fn().mockResolvedValue([])
}));
jest.mock('../../../api/ce', () => ({
- getTasksForComponent: jest.fn(() => Promise.resolve({ queue: [] }))
+ getTasksForComponent: jest.fn().mockResolvedValue({ queue: [] })
}));
jest.mock('../../../api/components', () => ({
- getComponentData: jest.fn(() => Promise.resolve({}))
+ getComponentData: jest.fn().mockResolvedValue({ analysisDate: '2018-07-30' })
}));
jest.mock('../../../api/nav', () => ({
- getComponentNavigation: jest.fn(() =>
- Promise.resolve({
- breadcrumbs: [{ key: 'portfolioKey', name: 'portfolio', qualifier: 'VW' }],
- key: 'portfolioKey'
- })
- )
+ getComponentNavigation: jest.fn().mockResolvedValue({
+ breadcrumbs: [{ key: 'portfolioKey', name: 'portfolio', qualifier: 'VW' }],
+ key: 'portfolioKey'
+ })
}));
// mock this, because some of its children are using redux store
@@ -90,14 +88,12 @@ it('changes component', () => {
});
it("loads branches for module's project", async () => {
- (getComponentNavigation as jest.Mock<any>).mockImplementationOnce(() =>
- Promise.resolve({
- breadcrumbs: [
- { key: 'projectKey', name: 'project', qualifier: 'TRK' },
- { key: 'moduleKey', name: 'module', qualifier: 'BRC' }
- ]
- })
- );
+ (getComponentNavigation as jest.Mock<any>).mockResolvedValueOnce({
+ breadcrumbs: [
+ { key: 'projectKey', name: 'project', qualifier: 'TRK' },
+ { key: 'moduleKey', name: 'module', qualifier: 'BRC' }
+ ]
+ });
mount(
<ComponentContainer fetchOrganizations={jest.fn()} location={{ query: { id: 'moduleKey' } }}>
@@ -149,9 +145,7 @@ it('updates branches on change', () => {
});
it('loads organization', async () => {
- (getComponentData as jest.Mock<any>).mockImplementationOnce(() =>
- Promise.resolve({ organization: 'org' })
- );
+ (getComponentData as jest.Mock<any>).mockResolvedValueOnce({ organization: 'org' });
const fetchOrganizations = jest.fn();
mount(
@@ -166,9 +160,7 @@ it('loads organization', async () => {
});
it('fetches status', async () => {
- (getComponentData as jest.Mock<any>).mockImplementationOnce(() =>
- Promise.resolve({ organization: 'org' })
- );
+ (getComponentData as jest.Mock<any>).mockResolvedValueOnce({ organization: 'org' });
mount(
<ComponentContainer fetchOrganizations={jest.fn()} location={{ query: { id: 'foo' } }}>
diff --git a/server/sonar-web/src/main/js/app/styles/components/alerts.css b/server/sonar-web/src/main/js/app/styles/components/alerts.css
index b965dced2d6..97457fe8dd6 100644
--- a/server/sonar-web/src/main/js/app/styles/components/alerts.css
+++ b/server/sonar-web/src/main/js/app/styles/components/alerts.css
@@ -51,7 +51,7 @@
.alert-info {
border-color: #bce8f1;
background-color: #d9edf7;
- color: #31708f;
+ color: #666666;
}
.alert-success {
diff --git a/server/sonar-web/src/main/js/app/styles/components/boxed-group.css b/server/sonar-web/src/main/js/app/styles/components/boxed-group.css
index e77b22430da..5a79c7f70e8 100644
--- a/server/sonar-web/src/main/js/app/styles/components/boxed-group.css
+++ b/server/sonar-web/src/main/js/app/styles/components/boxed-group.css
@@ -18,7 +18,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
.boxed-group {
- margin-bottom: 20px;
+ margin-bottom: calc(2.5 * var(--gridSize));
border: 1px solid var(--barBorderColor);
border-radius: 2px;
background-color: #fff;
diff --git a/server/sonar-web/src/main/js/app/styles/components/page.css b/server/sonar-web/src/main/js/app/styles/components/page.css
index c493b82d22c..a18b282cc45 100644
--- a/server/sonar-web/src/main/js/app/styles/components/page.css
+++ b/server/sonar-web/src/main/js/app/styles/components/page.css
@@ -187,7 +187,6 @@
}
.page-sidebar-fixed {
- width: 30%;
min-width: 300px;
flex-shrink: 0;
padding-left: 40px;
@@ -228,17 +227,6 @@
}
}
-.page-sidebar-sticky .page-sidebar-sticky-inner .search-navigator-facets-list {
- width: 260px;
- margin-left: calc(50vw - 640px + 290px - 260px - 37px);
-}
-
-@media (max-width: 1335px) {
- .page-sidebar-sticky .page-sidebar-sticky-inner .search-navigator-facets-list {
- margin-left: 20px;
- }
-}
-
.layout-page {
display: flex;
align-items: stretch;
diff --git a/server/sonar-web/src/main/js/app/styles/init/misc.css b/server/sonar-web/src/main/js/app/styles/init/misc.css
index c0f7bd23abb..11bbc4bb9f7 100644
--- a/server/sonar-web/src/main/js/app/styles/init/misc.css
+++ b/server/sonar-web/src/main/js/app/styles/init/misc.css
@@ -293,6 +293,11 @@ td.big-spacer-top {
flex-direction: row;
}
+.display-flex-column {
+ display: flex !important;
+ flex-direction: column;
+}
+
.display-flex-center {
display: flex !important;
align-items: center;
diff --git a/server/sonar-web/src/main/js/app/styles/sonarcloud.css b/server/sonar-web/src/main/js/app/styles/sonarcloud.css
index 66a4f2f0ba8..aa5ab408659 100644
--- a/server/sonar-web/src/main/js/app/styles/sonarcloud.css
+++ b/server/sonar-web/src/main/js/app/styles/sonarcloud.css
@@ -37,19 +37,22 @@
display: flex;
clear: left;
margin-bottom: calc(3 * var(--gridSize));
- box-shadow: 0 1px 0 var(--barBorderColor);
+ border-bottom: 1px solid var(--barBorderColor);
+ font-size: var(--mediumFontSize);
}
.sonarcloud .flex-tabs > li > a {
+ position: relative;
display: block;
+ top: 1px;
height: 100%;
width: 100%;
box-sizing: border-box;
color: var(--secondFontColor);
font-weight: 600;
cursor: pointer;
- padding-bottom: var(--gridSize);
- border-bottom: 2px solid transparent;
+ padding-bottom: calc(1.5 * var(--gridSize));
+ border-bottom: 3px solid transparent;
transition: color 0.2s ease;
}
diff --git a/server/sonar-web/src/main/js/app/types.ts b/server/sonar-web/src/main/js/app/types.ts
index ea3be59fc5c..4b55b604c22 100644
--- a/server/sonar-web/src/main/js/app/types.ts
+++ b/server/sonar-web/src/main/js/app/types.ts
@@ -61,6 +61,8 @@ export interface Breadcrumb {
}
export interface Component extends LightComponent {
+ almId?: string;
+ almRepoUrl?: string;
analysisDate?: string;
breadcrumbs: Breadcrumb[];
configuration?: ComponentConfiguration;
diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/FacetsList.tsx b/server/sonar-web/src/main/js/apps/coding-rules/components/FacetsList.tsx
index 9eb8edb79ed..2540d76707c 100644
--- a/server/sonar-web/src/main/js/apps/coding-rules/components/FacetsList.tsx
+++ b/server/sonar-web/src/main/js/apps/coding-rules/components/FacetsList.tsx
@@ -57,7 +57,7 @@ export default function FacetsList(props: Props) {
props.selectedProfile === undefined ||
!props.query.activation;
return (
- <div className="search-navigator-facets-list">
+ <>
<LanguageFacet
onChange={props.onFilterChange}
onToggle={props.onFacetToggle}
@@ -145,6 +145,6 @@ export default function FacetsList(props: Props) {
/>
</>
)}
- </div>
+ </>
);
}
diff --git a/server/sonar-web/src/main/js/apps/component-measures/sidebar/Sidebar.js b/server/sonar-web/src/main/js/apps/component-measures/sidebar/Sidebar.js
index 4b8edc255c3..183875dc425 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/sidebar/Sidebar.js
+++ b/server/sonar-web/src/main/js/apps/component-measures/sidebar/Sidebar.js
@@ -77,7 +77,7 @@ export default class Sidebar extends React.PureComponent {
render() {
return (
- <div className="search-navigator-facets-list">
+ <div>
<ProjectOverviewFacet
onChange={this.changeMetric}
selected={this.props.selectedMetric}
diff --git a/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/Sidebar-test.js.snap b/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/Sidebar-test.js.snap
index 2a3aab950cb..f526bbb3a16 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/Sidebar-test.js.snap
+++ b/server/sonar-web/src/main/js/apps/component-measures/sidebar/__tests__/__snapshots__/Sidebar-test.js.snap
@@ -1,9 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`should display two facets 1`] = `
-<div
- className="search-navigator-facets-list"
->
+<div>
<ProjectOverviewFacet
onChange={[Function]}
selected="duplicated_lines_density"
diff --git a/server/sonar-web/src/main/js/apps/issues/sidebar/Sidebar.tsx b/server/sonar-web/src/main/js/apps/issues/sidebar/Sidebar.tsx
index d888dbbb507..2953934dd4a 100644
--- a/server/sonar-web/src/main/js/apps/issues/sidebar/Sidebar.tsx
+++ b/server/sonar-web/src/main/js/apps/issues/sidebar/Sidebar.tsx
@@ -77,7 +77,7 @@ export default class Sidebar extends React.PureComponent<Props> {
(this.props.organization && this.props.organization.key);
return (
- <div className="search-navigator-facets-list">
+ <>
<TypeFacet
fetching={this.props.loadingFacets.types === true}
loading={this.props.loading}
@@ -256,7 +256,7 @@ export default class Sidebar extends React.PureComponent<Props> {
stats={facets.authors}
/>
)}
- </div>
+ </>
);
}
}
diff --git a/server/sonar-web/src/main/js/apps/overview/components/App.tsx b/server/sonar-web/src/main/js/apps/overview/components/App.tsx
index d54ea53f10b..68c8238c23c 100644
--- a/server/sonar-web/src/main/js/apps/overview/components/App.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/components/App.tsx
@@ -19,11 +19,21 @@
*/
import * as React from 'react';
import * as PropTypes from 'prop-types';
-import OverviewApp from './OverviewApp';
+import { Helmet } from 'react-helmet';
import EmptyOverview from './EmptyOverview';
+import OverviewApp from './OverviewApp';
+import SonarCloudEmptyOverview from './SonarCloudEmptyOverview';
+import Suggestions from '../../../app/components/embed-docs-modal/Suggestions';
import { Component, BranchLike } from '../../../app/types';
import { isShortLivingBranch } from '../../../helpers/branches';
-import { getShortLivingBranchUrl, getCodeUrl } from '../../../helpers/urls';
+import {
+ getShortLivingBranchUrl,
+ getCodeUrl,
+ getProjectUrl,
+ getBaseUrl,
+ getPathUrlAsString
+} from '../../../helpers/urls';
+import { isSonarCloud } from '../../../helpers/system';
interface Props {
branchLike?: BranchLike;
@@ -67,22 +77,43 @@ export default class App extends React.PureComponent<Props> {
return null;
}
- if (!component.analysisDate) {
- return (
- <EmptyOverview
- component={component.key}
- hasBranches={branchLikes.length > 1}
- showWarning={!this.props.isPending && !this.props.isInProgress}
- />
- );
- }
-
return (
- <OverviewApp
- branchLike={branchLike}
- component={component}
- onComponentChange={this.props.onComponentChange}
- />
+ <>
+ {isSonarCloud() && (
+ <Helmet>
+ <link
+ href={getBaseUrl() + getPathUrlAsString(getProjectUrl(component.key))}
+ rel="canonical"
+ />
+ </Helmet>
+ )}
+ <Suggestions suggestions="overview" />
+
+ {!component.analysisDate &&
+ (isSonarCloud() ? (
+ <SonarCloudEmptyOverview
+ branchLike={branchLike}
+ branchLikes={branchLikes}
+ component={component}
+ hasAnalyses={this.props.isPending || this.props.isInProgress}
+ onComponentChange={this.props.onComponentChange}
+ />
+ ) : (
+ <EmptyOverview
+ branchLike={branchLike}
+ branchLikes={branchLikes}
+ component={component.key}
+ showWarning={!this.props.isPending && !this.props.isInProgress}
+ />
+ ))}
+ {component.analysisDate && (
+ <OverviewApp
+ branchLike={branchLike}
+ component={component}
+ onComponentChange={this.props.onComponentChange}
+ />
+ )}
+ </>
);
}
}
diff --git a/server/sonar-web/src/main/js/apps/overview/components/EmptyOverview.tsx b/server/sonar-web/src/main/js/apps/overview/components/EmptyOverview.tsx
index 9beed6e65b5..69c3d81ae27 100644
--- a/server/sonar-web/src/main/js/apps/overview/components/EmptyOverview.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/components/EmptyOverview.tsx
@@ -21,30 +21,39 @@ import * as React from 'react';
import { Link } from 'react-router';
import { FormattedMessage } from 'react-intl';
import { translate } from '../../../helpers/l10n';
+import { BranchLike } from '../../../app/types';
+import { isBranch, isLongLivingBranch } from '../../../helpers/branches';
interface Props {
+ branchLike?: BranchLike;
+ branchLikes: BranchLike[];
component: string;
- hasBranches?: boolean;
showWarning?: boolean;
}
-export default function EmptyOverview({ component, hasBranches, showWarning }: Props) {
- const rawMessage = translate('provisioning.no_analysis.delete');
- const head = rawMessage.substr(0, rawMessage.indexOf('{0}'));
- const tail = rawMessage.substr(rawMessage.indexOf('{0}') + 3);
+export default function EmptyOverview({ branchLike, branchLikes, component, showWarning }: Props) {
+ const hasBranches = branchLikes.length > 1;
+ const hasBadConfig =
+ branchLikes.length > 2 ||
+ (branchLikes.length === 2 && branchLikes.some(branch => isLongLivingBranch(branch)));
+
+ const branchWarnMsg = hasBadConfig
+ ? translate('provisioning.no_analysis_on_main_branch.bad_configuration')
+ : translate('provisioning.no_analysis_on_main_branch');
return (
<div className="page page-limited">
{showWarning && (
<div className="big-spacer-bottom">
<div className="alert alert-warning">
- {hasBranches ? (
+ {hasBranches && isBranch(branchLike) ? (
<FormattedMessage
- defaultMessage={translate('provisioning.no_analysis_on_main_branch')}
- id="provisioning.no_analysis_on_main_branch"
+ defaultMessage={branchWarnMsg}
+ id={branchWarnMsg}
values={{
- branch: (
- <div className="outline-badge text-baseline little-spacer-right">
+ branchName: branchLike.name,
+ branchType: (
+ <div className="outline-badge text-baseline">
{translate('branches.main_branch')}
</div>
)
@@ -57,13 +66,19 @@ export default function EmptyOverview({ component, hasBranches, showWarning }: P
{!hasBranches && (
<div className="big-spacer-top">
- {head}
- <Link
- className="text-danger"
- to={{ pathname: '/project/deletion', query: { id: component } }}>
- {translate('provisioning.no_analysis.delete_project')}
- </Link>
- {tail}
+ <FormattedMessage
+ defaultMessage={translate('provisioning.no_analysis.delete')}
+ id={'provisioning.no_analysis.delete'}
+ values={{
+ link: (
+ <Link
+ className="text-danger"
+ to={{ pathname: '/project/deletion', query: { id: component } }}>
+ {translate('provisioning.no_analysis.delete_project')}
+ </Link>
+ )
+ }}
+ />
</div>
)}
</div>
diff --git a/server/sonar-web/src/main/js/apps/overview/components/OverviewApp.tsx b/server/sonar-web/src/main/js/apps/overview/components/OverviewApp.tsx
index 402725bdc71..dcf365a6615 100644
--- a/server/sonar-web/src/main/js/apps/overview/components/OverviewApp.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/components/OverviewApp.tsx
@@ -20,16 +20,14 @@
import * as React from 'react';
import { uniq } from 'lodash';
import { connect } from 'react-redux';
-import { Helmet } from 'react-helmet';
-import QualityGate from '../qualityGate/QualityGate';
import ApplicationQualityGate from '../qualityGate/ApplicationQualityGate';
import BugsAndVulnerabilities from '../main/BugsAndVulnerabilities';
import CodeSmells from '../main/CodeSmells';
import Coverage from '../main/Coverage';
import Duplications from '../main/Duplications';
import MetaContainer from '../meta/MetaContainer';
+import QualityGate from '../qualityGate/QualityGate';
import throwGlobalError from '../../../app/utils/throwGlobalError';
-import Suggestions from '../../../app/components/embed-docs-modal/Suggestions';
import { getMeasuresAndMeta } from '../../../api/measures';
import { getAllTimeMachineData, History } from '../../../api/time-machine';
import { parseDate } from '../../../helpers/dates';
@@ -52,8 +50,6 @@ import { fetchMetrics } from '../../../store/rootActions';
import { getMetrics } from '../../../store/rootReducer';
import { BranchLike, Component, Metric } from '../../../app/types';
import { translate } from '../../../helpers/l10n';
-import { getProjectUrl, getSonarCloudUrlAsString } from '../../../helpers/urls';
-import { isSonarCloud } from '../../../helpers/system';
import '../styles.css';
interface OwnProps {
@@ -246,14 +242,6 @@ export class OverviewApp extends React.PureComponent<Props, State> {
return (
<div className="page page-limited">
<div className="overview page-with-sidebar">
- <Suggestions suggestions="overview" />
-
- {isSonarCloud() && (
- <Helmet>
- <link href={getSonarCloudUrlAsString(getProjectUrl(component.key))} rel="canonical" />
- </Helmet>
- )}
-
{this.renderMain()}
<div className="overview-sidebar page-sidebar-fixed">
diff --git a/server/sonar-web/src/main/js/apps/overview/components/SonarCloudEmptyOverview.tsx b/server/sonar-web/src/main/js/apps/overview/components/SonarCloudEmptyOverview.tsx
new file mode 100644
index 00000000000..53dace6236e
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/overview/components/SonarCloudEmptyOverview.tsx
@@ -0,0 +1,126 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { connect } from 'react-redux';
+import { FormattedMessage } from 'react-intl';
+import AnalyzeTutorial from '../../tutorials/analyzeProject/AnalyzeTutorial';
+import MetaContainer from '../meta/MetaContainer';
+import { BranchLike, Component, CurrentUser, isLoggedIn } from '../../../app/types';
+import { isLongLivingBranch, isBranch, isMainBranch } from '../../../helpers/branches';
+import { translate } from '../../../helpers/l10n';
+import { getCurrentUser } from '../../../store/rootReducer';
+import '../../../app/styles/sonarcloud.css';
+
+interface OwnProps {
+ branchLike?: BranchLike;
+ branchLikes: BranchLike[];
+ component: Component;
+ hasAnalyses?: boolean;
+ onComponentChange: (changes: {}) => void;
+}
+
+interface StateProps {
+ currentUser: CurrentUser;
+}
+
+type Props = OwnProps & StateProps;
+
+export function SonarCloudEmptyOverview({
+ branchLike,
+ branchLikes,
+ component,
+ currentUser,
+ hasAnalyses,
+ onComponentChange
+}: Props) {
+ const hasBranches = branchLikes.length > 1;
+ const hasBadBranchConfig =
+ branchLikes.length > 2 ||
+ (branchLikes.length === 2 && branchLikes.some(branch => isLongLivingBranch(branch)));
+ return (
+ <div className="page page-limited">
+ <div className="overview page-with-sidebar">
+ <div className="overview-main page-main sonarcloud">
+ {isLoggedIn(currentUser) && isMainBranch(branchLike) ? (
+ <>
+ {hasBranches && (
+ <WarningMessage
+ branchLike={branchLike}
+ message={
+ hasBadBranchConfig
+ ? translate('provisioning.no_analysis_on_main_branch.bad_configuration')
+ : translate('provisioning.no_analysis_on_main_branch')
+ }
+ />
+ )}
+ {!hasBranches &&
+ !hasAnalyses && <AnalyzeTutorial component={component} currentUser={currentUser} />}
+ </>
+ ) : (
+ <WarningMessage
+ branchLike={branchLike}
+ message={translate('provisioning.no_analysis_on_main_branch')}
+ />
+ )}
+ </div>
+
+ <div className="overview-sidebar page-sidebar-fixed">
+ <MetaContainer
+ branchLike={branchLike}
+ component={component}
+ onComponentChange={onComponentChange}
+ />
+ </div>
+ </div>
+ </div>
+ );
+}
+
+export function WarningMessage({
+ branchLike,
+ message
+}: {
+ branchLike?: BranchLike;
+ message: string;
+}) {
+ if (!isBranch(branchLike)) {
+ return null;
+ }
+ return (
+ <div className="alert alert-warning">
+ <FormattedMessage
+ defaultMessage={message}
+ id={message}
+ values={{
+ branchName: branchLike.name,
+ branchType: (
+ <div className="outline-badge text-baseline">{translate('branches.main_branch')}</div>
+ )
+ }}
+ />
+ </div>
+ );
+}
+
+const mapStateToProps = (state: any) => ({
+ currentUser: getCurrentUser(state)
+});
+
+export default connect<StateProps, {}, OwnProps>(mapStateToProps)(SonarCloudEmptyOverview);
diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/App-test.tsx b/server/sonar-web/src/main/js/apps/overview/components/__tests__/App-test.tsx
index ac84c986293..73eb99d9350 100644
--- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/App-test.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/components/__tests__/App-test.tsx
@@ -20,9 +20,10 @@
import * as React from 'react';
import { mount, shallow } from 'enzyme';
import App from '../App';
-import OverviewApp from '../OverviewApp';
-import EmptyOverview from '../EmptyOverview';
import { BranchType, LongLivingBranch } from '../../../../app/types';
+import { isSonarCloud } from '../../../../helpers/system';
+
+jest.mock('../../../../helpers/system', () => ({ isSonarCloud: jest.fn() }));
const component = {
key: 'foo',
@@ -34,13 +35,34 @@ const component = {
version: '0.0.1'
};
+beforeEach(() => {
+ (isSonarCloud as jest.Mock<any>).mockClear();
+ (isSonarCloud as jest.Mock<any>).mockReturnValue(false);
+});
+
it('should render OverviewApp', () => {
- expect(getWrapper().type()).toBe(OverviewApp);
+ expect(
+ getWrapper()
+ .find('Connect(OverviewApp)')
+ .exists()
+ ).toBeTruthy();
});
it('should render EmptyOverview', () => {
- const output = getWrapper({ component: { key: 'foo' } });
- expect(output.type()).toBe(EmptyOverview);
+ expect(
+ getWrapper({ component: { key: 'foo' } })
+ .find('EmptyOverview')
+ .exists()
+ ).toBeTruthy();
+});
+
+it('should render SonarCloudEmptyOverview', () => {
+ (isSonarCloud as jest.Mock<any>).mockReturnValue(true);
+ expect(
+ getWrapper({ component: { key: 'foo' } })
+ .find('Connect(SonarCloudEmptyOverview)')
+ .exists()
+ ).toBeTruthy();
});
it('redirects on Code page for files', () => {
diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/EmptyOverview-test.tsx b/server/sonar-web/src/main/js/apps/overview/components/__tests__/EmptyOverview-test.tsx
index c2468df3638..6fd204472ab 100644
--- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/EmptyOverview-test.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/components/__tests__/EmptyOverview-test.tsx
@@ -20,17 +20,41 @@
import * as React from 'react';
import { shallow } from 'enzyme';
import EmptyOverview from '../EmptyOverview';
+import { BranchType } from '../../../../app/types';
+
+const branch = { isMain: true, name: 'b', type: BranchType.LONG };
it('renders', () => {
- expect(shallow(<EmptyOverview component="abcd" showWarning={true} />)).toMatchSnapshot();
+ expect(
+ shallow(<EmptyOverview branchLikes={[]} component="abcd" showWarning={true} />)
+ ).toMatchSnapshot();
});
it('does not render warning', () => {
- expect(shallow(<EmptyOverview component="abcd" showWarning={false} />)).toMatchSnapshot();
+ expect(
+ shallow(<EmptyOverview branchLikes={[]} component="abcd" showWarning={false} />)
+ ).toMatchSnapshot();
});
it('should render another message when there are branches', () => {
expect(
- shallow(<EmptyOverview component="abcd" hasBranches={true} showWarning={true} />)
+ shallow(
+ <EmptyOverview
+ branchLike={branch}
+ branchLikes={[branch, branch]}
+ component="abcd"
+ showWarning={true}
+ />
+ )
+ ).toMatchSnapshot();
+ expect(
+ shallow(
+ <EmptyOverview
+ branchLike={branch}
+ branchLikes={[branch, branch, branch]}
+ component="abcd"
+ showWarning={true}
+ />
+ )
).toMatchSnapshot();
});
diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/SonarCloudEmptyOverview-test.tsx b/server/sonar-web/src/main/js/apps/overview/components/__tests__/SonarCloudEmptyOverview-test.tsx
new file mode 100644
index 00000000000..278fca079d1
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/overview/components/__tests__/SonarCloudEmptyOverview-test.tsx
@@ -0,0 +1,117 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import { SonarCloudEmptyOverview, WarningMessage } from '../SonarCloudEmptyOverview';
+import { BranchType } from '../../../../app/types';
+
+const branch = { isMain: true, name: 'b', type: BranchType.LONG };
+
+const component = {
+ key: 'foo',
+ analysisDate: '2016-01-01',
+ breadcrumbs: [],
+ name: 'Foo',
+ organization: 'org',
+ qualifier: 'TRK',
+ version: '0.0.1'
+};
+
+const LoggedInUser = {
+ isLoggedIn: true,
+ login: 'luke',
+ name: 'Skywalker'
+};
+
+it('renders correctly', () => {
+ expect(
+ shallow(
+ <SonarCloudEmptyOverview
+ branchLike={branch}
+ branchLikes={[branch]}
+ component={component}
+ currentUser={LoggedInUser}
+ onComponentChange={jest.fn()}
+ />
+ )
+ ).toMatchSnapshot();
+});
+
+it('should render another message when there are branches', () => {
+ expect(
+ shallow(
+ <SonarCloudEmptyOverview
+ branchLike={branch}
+ branchLikes={[branch, branch]}
+ component={component}
+ currentUser={LoggedInUser}
+ onComponentChange={jest.fn()}
+ />
+ )
+ ).toMatchSnapshot();
+ expect(
+ shallow(
+ <SonarCloudEmptyOverview
+ branchLike={branch}
+ branchLikes={[branch, branch, branch]}
+ component={component}
+ currentUser={LoggedInUser}
+ onComponentChange={jest.fn()}
+ />
+ )
+ ).toMatchSnapshot();
+});
+
+it('should not render the tutorial', () => {
+ expect(
+ shallow(
+ <SonarCloudEmptyOverview
+ branchLike={branch}
+ branchLikes={[branch]}
+ component={component}
+ currentUser={LoggedInUser}
+ hasAnalyses={true}
+ onComponentChange={jest.fn()}
+ />
+ )
+ ).toMatchSnapshot();
+});
+
+it('should render warning message', () => {
+ expect(shallow(<WarningMessage branchLike={branch} message="foo" />)).toMatchSnapshot();
+});
+
+it('should not render warning message', () => {
+ expect(
+ shallow(
+ <WarningMessage
+ branchLike={{
+ base: 'foo',
+ branch: 'bar',
+ key: '1',
+ title: 'PR bar'
+ }}
+ message="foo"
+ />
+ )
+ .find('FormattedMessage')
+ .exists()
+ ).toBeFalsy();
+});
diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/Timeline-test.js b/server/sonar-web/src/main/js/apps/overview/components/__tests__/Timeline-test.js
deleted file mode 100644
index 0d9a0fdc23b..00000000000
--- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/Timeline-test.js
+++ /dev/null
@@ -1,51 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import React from 'react';
-import { shallow } from 'enzyme';
-import Timeline from '../Timeline';
-import { parseDate } from '../../../../helpers/dates';
-
-const range = parseDate('2017-05-01T00:00:00.000Z');
-const history = [
- { date: parseDate('2017-04-08T00:00:00.000Z'), value: '29.6' },
- { date: parseDate('2017-04-09T00:00:00.000Z'), value: '170.8' },
- { date: parseDate('2017-05-08T00:00:00.000Z'), value: '360' },
- { date: parseDate('2017-05-09T00:00:00.000Z'), value: '39' }
-];
-
-it('should render correctly with an "after" range', () => {
- expect(shallow(<Timeline after={range} history={history} />)).toMatchSnapshot();
-});
-
-it('should render correctly with a "before" range', () => {
- expect(shallow(<Timeline before={range} history={history} />)).toMatchSnapshot();
-});
-
-it('should have a correct domain with strings or numbers', () => {
- const date = parseDate('2017-05-08T00:00:00.000Z');
- const wrapper = shallow(<Timeline after={range} history={history} />);
- expect(wrapper.find('LineChart').props().domain).toEqual([0, 360]);
-
- wrapper.setProps({ history: [{ date, value: '360.33' }, { date, value: '39.54' }] });
- expect(wrapper.find('LineChart').props().domain).toEqual([0, 360.33]);
-
- wrapper.setProps({ history: [{ date, value: 360 }, { date, value: 39 }] });
- expect(wrapper.find('LineChart').props().domain).toEqual([0, 360]);
-});
diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/EmptyOverview-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/EmptyOverview-test.tsx.snap
index 4d8cdf63248..cede657480c 100644
--- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/EmptyOverview-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/EmptyOverview-test.tsx.snap
@@ -30,22 +30,29 @@ exports[`renders 1`] = `
<div
className="big-spacer-top"
>
- <Link
- className="text-danger"
- onlyActiveOnIndex={false}
- style={Object {}}
- to={
+ <FormattedMessage
+ defaultMessage="provisioning.no_analysis.delete"
+ id="provisioning.no_analysis.delete"
+ values={
Object {
- "pathname": "/project/deletion",
- "query": Object {
- "id": "abcd",
- },
+ "link": <Link
+ className="text-danger"
+ onlyActiveOnIndex={false}
+ style={Object {}}
+ to={
+ Object {
+ "pathname": "/project/deletion",
+ "query": Object {
+ "id": "abcd",
+ },
+ }
+ }
+ >
+ provisioning.no_analysis.delete_project
+ </Link>,
}
}
- >
- provisioning.no_analysis.delete_project
- </Link>
- ovisioning.no_analysis.delete
+ />
</div>
</div>
<div>
@@ -74,8 +81,46 @@ exports[`should render another message when there are branches 1`] = `
id="provisioning.no_analysis_on_main_branch"
values={
Object {
- "branch": <div
- className="outline-badge text-baseline little-spacer-right"
+ "branchName": "b",
+ "branchType": <div
+ className="outline-badge text-baseline"
+ >
+ branches.main_branch
+ </div>,
+ }
+ }
+ />
+ </div>
+ </div>
+ <div>
+ <h4>
+ key
+ </h4>
+ <code>
+ abcd
+ </code>
+ </div>
+</div>
+`;
+
+exports[`should render another message when there are branches 2`] = `
+<div
+ className="page page-limited"
+>
+ <div
+ className="big-spacer-bottom"
+ >
+ <div
+ className="alert alert-warning"
+ >
+ <FormattedMessage
+ defaultMessage="provisioning.no_analysis_on_main_branch.bad_configuration"
+ id="provisioning.no_analysis_on_main_branch.bad_configuration"
+ values={
+ Object {
+ "branchName": "b",
+ "branchType": <div
+ className="outline-badge text-baseline"
>
branches.main_branch
</div>,
diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/SonarCloudEmptyOverview-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/SonarCloudEmptyOverview-test.tsx.snap
new file mode 100644
index 00000000000..1dd9c747b5a
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/SonarCloudEmptyOverview-test.tsx.snap
@@ -0,0 +1,229 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+<div
+ className="page page-limited"
+>
+ <div
+ className="overview page-with-sidebar"
+ >
+ <div
+ className="overview-main page-main sonarcloud"
+ >
+ <React.Fragment>
+ <AnalyzeTutorial
+ component={
+ Object {
+ "analysisDate": "2016-01-01",
+ "breadcrumbs": Array [],
+ "key": "foo",
+ "name": "Foo",
+ "organization": "org",
+ "qualifier": "TRK",
+ "version": "0.0.1",
+ }
+ }
+ currentUser={
+ Object {
+ "isLoggedIn": true,
+ "login": "luke",
+ "name": "Skywalker",
+ }
+ }
+ />
+ </React.Fragment>
+ </div>
+ <div
+ className="overview-sidebar page-sidebar-fixed"
+ >
+ <Connect(Meta)
+ branchLike={
+ Object {
+ "isMain": true,
+ "name": "b",
+ "type": "LONG",
+ }
+ }
+ component={
+ Object {
+ "analysisDate": "2016-01-01",
+ "breadcrumbs": Array [],
+ "key": "foo",
+ "name": "Foo",
+ "organization": "org",
+ "qualifier": "TRK",
+ "version": "0.0.1",
+ }
+ }
+ onComponentChange={[MockFunction]}
+ />
+ </div>
+ </div>
+</div>
+`;
+
+exports[`should not render the tutorial 1`] = `
+<div
+ className="page page-limited"
+>
+ <div
+ className="overview page-with-sidebar"
+ >
+ <div
+ className="overview-main page-main sonarcloud"
+ >
+ <React.Fragment />
+ </div>
+ <div
+ className="overview-sidebar page-sidebar-fixed"
+ >
+ <Connect(Meta)
+ branchLike={
+ Object {
+ "isMain": true,
+ "name": "b",
+ "type": "LONG",
+ }
+ }
+ component={
+ Object {
+ "analysisDate": "2016-01-01",
+ "breadcrumbs": Array [],
+ "key": "foo",
+ "name": "Foo",
+ "organization": "org",
+ "qualifier": "TRK",
+ "version": "0.0.1",
+ }
+ }
+ onComponentChange={[MockFunction]}
+ />
+ </div>
+ </div>
+</div>
+`;
+
+exports[`should render another message when there are branches 1`] = `
+<div
+ className="page page-limited"
+>
+ <div
+ className="overview page-with-sidebar"
+ >
+ <div
+ className="overview-main page-main sonarcloud"
+ >
+ <React.Fragment>
+ <WarningMessage
+ branchLike={
+ Object {
+ "isMain": true,
+ "name": "b",
+ "type": "LONG",
+ }
+ }
+ message="provisioning.no_analysis_on_main_branch"
+ />
+ </React.Fragment>
+ </div>
+ <div
+ className="overview-sidebar page-sidebar-fixed"
+ >
+ <Connect(Meta)
+ branchLike={
+ Object {
+ "isMain": true,
+ "name": "b",
+ "type": "LONG",
+ }
+ }
+ component={
+ Object {
+ "analysisDate": "2016-01-01",
+ "breadcrumbs": Array [],
+ "key": "foo",
+ "name": "Foo",
+ "organization": "org",
+ "qualifier": "TRK",
+ "version": "0.0.1",
+ }
+ }
+ onComponentChange={[MockFunction]}
+ />
+ </div>
+ </div>
+</div>
+`;
+
+exports[`should render another message when there are branches 2`] = `
+<div
+ className="page page-limited"
+>
+ <div
+ className="overview page-with-sidebar"
+ >
+ <div
+ className="overview-main page-main sonarcloud"
+ >
+ <React.Fragment>
+ <WarningMessage
+ branchLike={
+ Object {
+ "isMain": true,
+ "name": "b",
+ "type": "LONG",
+ }
+ }
+ message="provisioning.no_analysis_on_main_branch.bad_configuration"
+ />
+ </React.Fragment>
+ </div>
+ <div
+ className="overview-sidebar page-sidebar-fixed"
+ >
+ <Connect(Meta)
+ branchLike={
+ Object {
+ "isMain": true,
+ "name": "b",
+ "type": "LONG",
+ }
+ }
+ component={
+ Object {
+ "analysisDate": "2016-01-01",
+ "breadcrumbs": Array [],
+ "key": "foo",
+ "name": "Foo",
+ "organization": "org",
+ "qualifier": "TRK",
+ "version": "0.0.1",
+ }
+ }
+ onComponentChange={[MockFunction]}
+ />
+ </div>
+ </div>
+</div>
+`;
+
+exports[`should render warning message 1`] = `
+<div
+ className="alert alert-warning"
+>
+ <FormattedMessage
+ defaultMessage="foo"
+ id="foo"
+ values={
+ Object {
+ "branchName": "b",
+ "branchType": <div
+ className="outline-badge text-baseline"
+ >
+ branches.main_branch
+ </div>,
+ }
+ }
+ />
+</div>
+`;
diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/Timeline-test.js.snap b/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/Timeline-test.js.snap
deleted file mode 100644
index 3c01c85264d..00000000000
--- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/Timeline-test.js.snap
+++ /dev/null
@@ -1,71 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`should render correctly with a "before" range 1`] = `
-<LineChart
- data={
- Array [
- Object {
- "x": 0,
- "y": 29.6,
- },
- Object {
- "x": 1,
- "y": 170.8,
- },
- ]
- }
- displayBackdrop={true}
- displayPoints={false}
- displayVerticalGrid={false}
- domain={
- Array [
- 0,
- 360,
- ]
- }
- height={80}
- padding={
- Array [
- 0,
- 0,
- 0,
- 0,
- ]
- }
-/>
-`;
-
-exports[`should render correctly with an "after" range 1`] = `
-<LineChart
- data={
- Array [
- Object {
- "x": 0,
- "y": 360,
- },
- Object {
- "x": 1,
- "y": 39,
- },
- ]
- }
- displayBackdrop={true}
- displayPoints={false}
- displayVerticalGrid={false}
- domain={
- Array [
- 0,
- 360,
- ]
- }
- height={80}
- padding={
- Array [
- 0,
- 0,
- 0,
- 0,
- ]
- }
-/>
-`;
diff --git a/server/sonar-web/src/main/js/apps/overview/meta/MetaContainer.tsx b/server/sonar-web/src/main/js/apps/overview/meta/MetaContainer.tsx
index 3e7749343a5..64a0a9e4ea6 100644
--- a/server/sonar-web/src/main/js/apps/overview/meta/MetaContainer.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/meta/MetaContainer.tsx
@@ -58,8 +58,8 @@ interface OwnProps {
branchLike?: BranchLike;
component: Component;
history?: History;
- measures: MeasureEnhanced[];
- metrics: { [key: string]: Metric };
+ measures?: MeasureEnhanced[];
+ metrics?: { [key: string]: Metric };
onComponentChange: (changes: {}) => void;
}
@@ -106,7 +106,7 @@ export class Meta extends React.PureComponent<Props> {
render() {
const { organizationsEnabled } = this.context;
- const { branchLike, component, metrics, organization } = this.props;
+ const { branchLike, component, measures, metrics, organization } = this.props;
const { qualifier, description, visibility } = component;
const isProject = qualifier === 'TRK';
@@ -131,16 +131,20 @@ export class Meta extends React.PureComponent<Props> {
{isProject && (
<MetaTags component={component} onComponentChange={this.props.onComponentChange} />
)}
- <MetaSize branchLike={branchLike} component={component} measures={this.props.measures} />
+ {measures && (
+ <MetaSize branchLike={branchLike} component={component} measures={measures} />
+ )}
</div>
- <AnalysesList
- branchLike={branchLike}
- component={component}
- history={this.props.history}
- metrics={metrics}
- qualifier={component.qualifier}
- />
+ {metrics && (
+ <AnalysesList
+ branchLike={branchLike}
+ component={component}
+ history={this.props.history}
+ metrics={metrics}
+ qualifier={component.qualifier}
+ />
+ )}
{this.renderQualityInfos()}
@@ -152,7 +156,8 @@ export class Meta extends React.PureComponent<Props> {
</div>
{!isPrivate &&
- (isProject || isApp) && (
+ (isProject || isApp) &&
+ metrics && (
<BadgesModal
branchLike={branchLike}
metrics={metrics}
diff --git a/server/sonar-web/src/main/js/apps/overview/styles.css b/server/sonar-web/src/main/js/apps/overview/styles.css
index 7f14ac0420a..92ed309cda0 100644
--- a/server/sonar-web/src/main/js/apps/overview/styles.css
+++ b/server/sonar-web/src/main/js/apps/overview/styles.css
@@ -24,6 +24,7 @@
.overview-main {
background-color: var(--barBackgroundColor);
transition: transform 0.5s ease, opacity 0.5s ease;
+ width: calc(100% - 300px);
}
.overview-sidebar {
diff --git a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/AlmRepositoryItem.tsx b/server/sonar-web/src/main/js/apps/projects/create/AlmRepositoryItem.tsx
index 8e21b7111ae..8e21b7111ae 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/AlmRepositoryItem.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/create/AlmRepositoryItem.tsx
diff --git a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/AutoProjectCreate.tsx b/server/sonar-web/src/main/js/apps/projects/create/AutoProjectCreate.tsx
index 078a54d13de..078a54d13de 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/AutoProjectCreate.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/create/AutoProjectCreate.tsx
diff --git a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/CreateProjectOnboarding.tsx b/server/sonar-web/src/main/js/apps/projects/create/CreateProjectPage.tsx
index 17bae7689e7..63224ebacec 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/CreateProjectOnboarding.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/create/CreateProjectPage.tsx
@@ -19,11 +19,13 @@
*/
import * as React from 'react';
import * as classNames from 'classnames';
-import * as PropTypes from 'prop-types';
import { connect } from 'react-redux';
+import { InjectedRouter } from 'react-router';
+import { Location } from 'history';
import Helmet from 'react-helmet';
import AutoProjectCreate from './AutoProjectCreate';
import ManualProjectCreate from './ManualProjectCreate';
+import { serializeQuery, Query, parseQuery } from './utils';
import handleRequiredAuthentication from '../../../app/utils/handleRequiredAuthentication';
import { getCurrentUser } from '../../../store/rootReducer';
import { skipOnboarding } from '../../../store/users/actions';
@@ -32,10 +34,11 @@ import { translate } from '../../../helpers/l10n';
import { ProjectBase } from '../../../api/components';
import { getProjectUrl, getOrganizationUrl } from '../../../helpers/urls';
import '../../../app/styles/sonarcloud.css';
-import '../styles.css';
interface OwnProps {
+ location: Location;
onFinishOnboarding: () => void;
+ router: Pick<InjectedRouter, 'push' | 'replace'>;
}
interface StateProps {
@@ -46,26 +49,16 @@ interface DispatchProps {
skipOnboarding: () => void;
}
-enum Tabs {
- AUTO,
- MANUAL
-}
-
type Props = OwnProps & StateProps & DispatchProps;
-interface State {
- activeTab: Tabs;
-}
-
-export class CreateProjectOnboarding extends React.PureComponent<Props, State> {
+export class CreateProjectPage extends React.PureComponent<Props> {
mounted = false;
- static contextTypes = {
- router: PropTypes.object
- };
constructor(props: Props) {
super(props);
- this.state = { activeTab: this.shouldDisplayTabs(props) ? Tabs.AUTO : Tabs.MANUAL };
+ if (!this.canAutoCreate(props)) {
+ this.updateQuery({ manual: true });
+ }
}
componentDidMount() {
@@ -85,13 +78,13 @@ export class CreateProjectOnboarding extends React.PureComponent<Props, State> {
handleProjectCreate = (projects: Pick<ProjectBase, 'key'>[], organization?: string) => {
if (projects.length > 1 && organization) {
- this.context.router.push(getOrganizationUrl(organization) + '/projects');
+ this.props.router.push(getOrganizationUrl(organization) + '/projects');
} else if (projects.length === 1) {
- this.context.router.push(getProjectUrl(projects[0].key));
+ this.props.router.push(getProjectUrl(projects[0].key));
}
};
- shouldDisplayTabs = ({ currentUser } = this.props) => {
+ canAutoCreate = ({ currentUser } = this.props) => {
return (
isLoggedIn(currentUser) &&
['bitbucket', 'github'].includes(currentUser.externalProvider || '')
@@ -100,12 +93,19 @@ export class CreateProjectOnboarding extends React.PureComponent<Props, State> {
showAuto = (event: React.MouseEvent<HTMLAnchorElement>) => {
event.preventDefault();
- this.setState({ activeTab: Tabs.AUTO });
+ this.updateQuery({ manual: false });
};
showManual = (event: React.MouseEvent<HTMLAnchorElement>) => {
event.preventDefault();
- this.setState({ activeTab: Tabs.MANUAL });
+ this.updateQuery({ manual: true });
+ };
+
+ updateQuery = (changes: Partial<Query>) => {
+ this.props.router.replace({
+ pathname: this.props.location.pathname,
+ query: serializeQuery({ ...parseQuery(this.props.location.query), ...changes })
+ });
};
render() {
@@ -113,8 +113,7 @@ export class CreateProjectOnboarding extends React.PureComponent<Props, State> {
if (!isLoggedIn(currentUser)) {
return null;
}
-
- const { activeTab } = this.state;
+ const displayManual = parseQuery(this.props.location.query).manual;
const header = translate('onboarding.create_project.header');
return (
<>
@@ -124,11 +123,11 @@ export class CreateProjectOnboarding extends React.PureComponent<Props, State> {
<h1 className="page-title">{header}</h1>
</div>
- {this.shouldDisplayTabs() && (
+ {this.canAutoCreate() && (
<ul className="flex-tabs">
<li>
<a
- className={classNames('js-auto', { selected: activeTab === Tabs.AUTO })}
+ className={classNames('js-auto', { selected: !displayManual })}
href="#"
onClick={this.showAuto}>
{translate('onboarding.create_project.select_repositories')}
@@ -136,8 +135,8 @@ export class CreateProjectOnboarding extends React.PureComponent<Props, State> {
className={classNames(
'rounded alert alert-small spacer-left display-inline-block',
{
- 'alert-info': activeTab === Tabs.AUTO,
- 'alert-muted': activeTab !== Tabs.AUTO
+ 'alert-info': !displayManual,
+ 'alert-muted': displayManual
}
)}>
{translate('beta')}
@@ -146,7 +145,7 @@ export class CreateProjectOnboarding extends React.PureComponent<Props, State> {
</li>
<li>
<a
- className={classNames('js-manual', { selected: activeTab === Tabs.MANUAL })}
+ className={classNames('js-manual', { selected: displayManual })}
href="#"
onClick={this.showManual}>
{translate('onboarding.create_project.create_manually')}
@@ -155,13 +154,13 @@ export class CreateProjectOnboarding extends React.PureComponent<Props, State> {
</ul>
)}
- {activeTab === Tabs.AUTO ? (
- <AutoProjectCreate
+ {displayManual || !this.canAutoCreate() ? (
+ <ManualProjectCreate
currentUser={currentUser}
onProjectCreate={this.handleProjectCreate}
/>
) : (
- <ManualProjectCreate
+ <AutoProjectCreate
currentUser={currentUser}
onProjectCreate={this.handleProjectCreate}
/>
@@ -181,5 +180,5 @@ const mapStateToProps = (state: any): StateProps => {
const mapDispatchToProps: DispatchProps = { skipOnboarding };
export default connect<StateProps, DispatchProps, OwnProps>(mapStateToProps, mapDispatchToProps)(
- CreateProjectOnboarding
+ CreateProjectPage
);
diff --git a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/ManualProjectCreate.tsx b/server/sonar-web/src/main/js/apps/projects/create/ManualProjectCreate.tsx
index 59d615583c7..041b09bdd4d 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/ManualProjectCreate.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/create/ManualProjectCreate.tsx
@@ -63,7 +63,7 @@ export class ManualProjectCreate extends React.PureComponent<Props, State> {
projectName: '',
projectKey: '',
selectedOrganization:
- props.userOrganizations.length <= 1 ? props.userOrganizations[0].key : '',
+ props.userOrganizations.length === 1 ? props.userOrganizations[0].key : '',
submitting: false
};
}
diff --git a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/AlmRepositoryItem-test.tsx b/server/sonar-web/src/main/js/apps/projects/create/__tests__/AlmRepositoryItem-test.tsx
index 72b25cb2815..72b25cb2815 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/AlmRepositoryItem-test.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/create/__tests__/AlmRepositoryItem-test.tsx
diff --git a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/AutoProjectCreate-test.tsx b/server/sonar-web/src/main/js/apps/projects/create/__tests__/AutoProjectCreate-test.tsx
index bfe95430578..bfe95430578 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/AutoProjectCreate-test.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/create/__tests__/AutoProjectCreate-test.tsx
diff --git a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/CreateProjectOnboarding-test.tsx b/server/sonar-web/src/main/js/apps/projects/create/__tests__/CreateProjectPage-test.tsx
index f7cfa3ce8da..6f995afd252 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/CreateProjectOnboarding-test.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/create/__tests__/CreateProjectPage-test.tsx
@@ -19,7 +19,8 @@
*/
import * as React from 'react';
import { shallow } from 'enzyme';
-import { CreateProjectOnboarding } from '../CreateProjectOnboarding';
+import { Location } from 'history';
+import { CreateProjectPage } from '../CreateProjectPage';
import { LoggedInUser } from '../../../../app/types';
import { click } from '../../../../helpers/testUtils';
@@ -35,11 +36,16 @@ it('should render correctly', () => {
});
it('should render with Manual creation only', () => {
- expect(getWrapper({ currentUser: { ...user, externalProvider: 'vsts' } })).toMatchSnapshot();
+ expect(getWrapper({ currentUser: { ...user, externalProvider: 'microsoft' } })).toMatchSnapshot();
});
it('should switch tabs', () => {
- const wrapper = getWrapper();
+ const replace = jest.fn();
+ const wrapper = getWrapper({ router: { replace } });
+ replace.mockImplementation(location => {
+ wrapper.setProps({ location }).update();
+ });
+
click(wrapper.find('.js-manual'));
expect(wrapper.find('Connect(ManualProjectCreate)').exists()).toBeTruthy();
click(wrapper.find('.js-auto'));
@@ -48,9 +54,11 @@ it('should switch tabs', () => {
function getWrapper(props = {}) {
return shallow(
- <CreateProjectOnboarding
+ <CreateProjectPage
currentUser={user}
+ location={{ pathname: 'foo', query: { manual: 'false' } } as Location}
onFinishOnboarding={jest.fn()}
+ router={{ push: jest.fn(), replace: jest.fn() }}
skipOnboarding={jest.fn()}
{...props}
/>
diff --git a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/ManualProjectCreate-test.tsx b/server/sonar-web/src/main/js/apps/projects/create/__tests__/ManualProjectCreate-test.tsx
index b79b4e4ae35..b79b4e4ae35 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/ManualProjectCreate-test.tsx
+++ b/server/sonar-web/src/main/js/apps/projects/create/__tests__/ManualProjectCreate-test.tsx
diff --git a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/__snapshots__/AlmRepositoryItem-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/create/__tests__/__snapshots__/AlmRepositoryItem-test.tsx.snap
index ad71bfc6e60..ad71bfc6e60 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/__snapshots__/AlmRepositoryItem-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projects/create/__tests__/__snapshots__/AlmRepositoryItem-test.tsx.snap
diff --git a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/__snapshots__/AutoProjectCreate-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/create/__tests__/__snapshots__/AutoProjectCreate-test.tsx.snap
index 6d6c0398864..6d6c0398864 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/__snapshots__/AutoProjectCreate-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projects/create/__tests__/__snapshots__/AutoProjectCreate-test.tsx.snap
diff --git a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/__snapshots__/CreateProjectOnboarding-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/create/__tests__/__snapshots__/CreateProjectPage-test.tsx.snap
index 1920eb22a54..1880a16ba4c 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/__snapshots__/CreateProjectOnboarding-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projects/create/__tests__/__snapshots__/CreateProjectPage-test.tsx.snap
@@ -85,7 +85,7 @@ exports[`should render with Manual creation only 1`] = `
<Connect(ManualProjectCreate)
currentUser={
Object {
- "externalProvider": "vsts",
+ "externalProvider": "microsoft",
"isLoggedIn": true,
"login": "foo",
"name": "Foo",
diff --git a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/__snapshots__/ManualProjectCreate-test.tsx.snap b/server/sonar-web/src/main/js/apps/projects/create/__tests__/__snapshots__/ManualProjectCreate-test.tsx.snap
index fafb751c9bb..fafb751c9bb 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/__snapshots__/ManualProjectCreate-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/projects/create/__tests__/__snapshots__/ManualProjectCreate-test.tsx.snap
diff --git a/server/sonar-web/src/main/js/apps/projects/create/utils.ts b/server/sonar-web/src/main/js/apps/projects/create/utils.ts
new file mode 100644
index 00000000000..f3528d0a633
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/projects/create/utils.ts
@@ -0,0 +1,42 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import { memoize } from 'lodash';
+import {
+ cleanQuery,
+ RawQuery,
+ parseAsBoolean,
+ serializeOptionalBoolean
+} from '../../../helpers/query';
+
+export interface Query {
+ manual: boolean;
+}
+
+export const parseQuery = memoize((urlQuery: RawQuery): Query => {
+ return {
+ manual: parseAsBoolean(urlQuery['manual'], false)
+ };
+});
+
+export const serializeQuery = memoize((query: Query): RawQuery =>
+ cleanQuery({
+ manual: serializeOptionalBoolean(query.manual || undefined)
+ })
+);
diff --git a/server/sonar-web/src/main/js/apps/projects/routes.ts b/server/sonar-web/src/main/js/apps/projects/routes.ts
index 873d933ce07..061627c206a 100644
--- a/server/sonar-web/src/main/js/apps/projects/routes.ts
+++ b/server/sonar-web/src/main/js/apps/projects/routes.ts
@@ -22,6 +22,8 @@ import DefaultPageSelectorContainer from './components/DefaultPageSelectorContai
import FavoriteProjectsContainer from './components/FavoriteProjectsContainer';
import { PROJECTS_DEFAULT_FILTER, PROJECTS_ALL } from './utils';
import { save } from '../../helpers/storage';
+import { isSonarCloud } from '../../helpers/system';
+import { lazyLoad } from '../../components/lazyLoad';
const routes = [
{ indexRoute: { component: DefaultPageSelectorContainer } },
@@ -32,7 +34,11 @@ const routes = [
replace('/projects');
}
},
- { path: 'favorite', component: FavoriteProjectsContainer }
-];
+ { path: 'favorite', component: FavoriteProjectsContainer },
+ isSonarCloud() && {
+ path: 'create',
+ component: lazyLoad(() => import('./create/CreateProjectPage'))
+ }
+].filter(Boolean);
export default routes;
diff --git a/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/AnalyzeTutorial.tsx b/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/AnalyzeTutorial.tsx
new file mode 100644
index 00000000000..7ed7513f6f4
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/AnalyzeTutorial.tsx
@@ -0,0 +1,94 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import AnalyzeTutorialSuggestion from './AnalyzeTutorialSuggestion';
+import ProjectAnalysisStep from '../components/ProjectAnalysisStep';
+import TokenStep from '../components/TokenStep';
+import { Component, LoggedInUser } from '../../../app/types';
+import { translate } from '../../../helpers/l10n';
+import '../styles.css';
+
+enum Steps {
+ ANALYSIS,
+ TOKEN
+}
+
+interface Props {
+ component: Component;
+ currentUser: LoggedInUser;
+}
+
+interface State {
+ step: Steps;
+ token?: string;
+}
+
+export default class AnalyzeTutorial extends React.PureComponent<Props, State> {
+ state: State = { step: Steps.TOKEN };
+
+ handleTokenDone = (token: string) => {
+ this.setState({ step: Steps.ANALYSIS, token });
+ };
+
+ handleTokenOpen = () => {
+ this.setState({ step: Steps.TOKEN });
+ };
+
+ render() {
+ const { component, currentUser } = this.props;
+ const { step, token } = this.state;
+ let stepNumber = 1;
+
+ const almId = component.almId || currentUser.externalProvider;
+ const showTutorial = almId !== 'microsoft';
+ return (
+ <>
+ <div className="page-header big-spacer-bottom">
+ <h1 className="page-title">{translate('onboarding.project_analysis.header')}</h1>
+ <p className="page-description">{translate('onboarding.project_analysis.description')}</p>
+ </div>
+
+ <AnalyzeTutorialSuggestion almId={almId} />
+
+ {showTutorial && (
+ <>
+ <TokenStep
+ currentUser={currentUser}
+ finished={Boolean(this.state.token)}
+ onContinue={this.handleTokenDone}
+ onOpen={this.handleTokenOpen}
+ open={step === Steps.TOKEN}
+ stepNumber={stepNumber++}
+ />
+
+ <ProjectAnalysisStep
+ component={component}
+ displayRowLayout={true}
+ open={step === Steps.ANALYSIS}
+ organization={component.organization}
+ stepNumber={stepNumber++}
+ token={token}
+ />
+ </>
+ )}
+ </>
+ );
+ }
+}
diff --git a/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/AnalyzeTutorialSuggestion.tsx b/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/AnalyzeTutorialSuggestion.tsx
new file mode 100644
index 00000000000..a93c73b94c8
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/AnalyzeTutorialSuggestion.tsx
@@ -0,0 +1,88 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { FormattedMessage } from 'react-intl';
+import { translate } from '../../../helpers/l10n';
+import { getBaseUrl } from '../../../helpers/urls';
+
+export default function AnalyzeTutorialSuggestion({ almId }: { almId?: string }) {
+ if (almId && almId.startsWith('bitbucket')) {
+ return (
+ <div className="alert alert-info big-spacer-bottom">
+ <p>{translate('onboarding.project_analysis.commands_for_analysis')}</p>
+ <p>{translate('onboarding.project_analysis.suggestions.bitbucket')}</p>
+ <FormattedMessage
+ defaultMessage={translate('onboarding.project_analysis.simply_link')}
+ id={'onboarding.project_analysis.simply_link'}
+ values={{
+ link: (
+ <a
+ href={
+ getBaseUrl() +
+ '/documentation/integrations/bitbucketcloud#analyzing-with-pipelines'
+ }
+ target="_blank">
+ {translate('onboarding.project_analysis.guide_to_integrate_piplines')}
+ </a>
+ )
+ }}
+ />
+ </div>
+ );
+ } else if (almId === 'github') {
+ return (
+ <div className="alert alert-info big-spacer-bottom">
+ <p>{translate('onboarding.project_analysis.commands_for_analysis')} </p>
+ <p>{translate('onboarding.project_analysis.suggestions.github')}</p>
+ <FormattedMessage
+ defaultMessage={translate('onboarding.project_analysis.simply_link')}
+ id={'onboarding.project_analysis.simply_link'}
+ values={{
+ link: (
+ <a
+ href="https://docs.travis-ci.com/user/sonarcloud/"
+ rel="noopener noreferrer"
+ target="_blank">
+ {translate('onboarding.project_analysis.guide_to_integrate_travis')}
+ </a>
+ )
+ }}
+ />
+ </div>
+ );
+ } else if (almId === 'microsoft') {
+ return (
+ <p className="alert alert-info big-spacer-bottom">
+ <FormattedMessage
+ defaultMessage={translate('onboarding.project_analysis.simply_link')}
+ id={'onboarding.project_analysis.simply_link'}
+ values={{
+ link: (
+ <a href={getBaseUrl() + '/documentation/integrations/vsts'} target="_blank">
+ {translate('onboarding.project_analysis.guide_to_integrate_vsts')}
+ </a>
+ )
+ }}
+ />
+ </p>
+ );
+ }
+ return null;
+}
diff --git a/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/__tests__/AnalyzeTutorial-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/__tests__/AnalyzeTutorial-test.tsx
new file mode 100644
index 00000000000..39f0233081f
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/__tests__/AnalyzeTutorial-test.tsx
@@ -0,0 +1,47 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import AnalyzeTutorial from '../AnalyzeTutorial';
+import { LoggedInUser } from '../../../../app/types';
+
+const component = {
+ key: 'foo',
+ analysisDate: '2016-01-01',
+ breadcrumbs: [],
+ name: 'Foo',
+ organization: 'org',
+ qualifier: 'TRK',
+ version: '0.0.1'
+};
+
+const loggedInUser: LoggedInUser = {
+ isLoggedIn: true,
+ login: 'luke',
+ name: 'Skywalker'
+};
+
+it('renders correctly', () => {
+ expect(getWrapper()).toMatchSnapshot();
+});
+
+function getWrapper(props = {}) {
+ return shallow(<AnalyzeTutorial component={component} currentUser={loggedInUser} {...props} />);
+}
diff --git a/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/__tests__/AnalyzeTutorialSuggestion-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/__tests__/AnalyzeTutorialSuggestion-test.tsx
new file mode 100644
index 00000000000..bc4a6d7b55b
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/__tests__/AnalyzeTutorialSuggestion-test.tsx
@@ -0,0 +1,38 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import AnalyzeTutorialSuggestion from '../AnalyzeTutorialSuggestion';
+
+it('should not render', () => {
+ expect(shallow(<AnalyzeTutorialSuggestion almId={undefined} />).type()).toBeNull();
+});
+
+it('renders bitbucket suggestions correctly', () => {
+ expect(shallow(<AnalyzeTutorialSuggestion almId="bitbucket" />)).toMatchSnapshot();
+});
+
+it('renders github suggestions correctly', () => {
+ expect(shallow(<AnalyzeTutorialSuggestion almId="github" />)).toMatchSnapshot();
+});
+
+it('renders vsts suggestions correctly', () => {
+ expect(shallow(<AnalyzeTutorialSuggestion almId="microsoft" />)).toMatchSnapshot();
+});
diff --git a/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/__tests__/__snapshots__/AnalyzeTutorial-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/__tests__/__snapshots__/AnalyzeTutorial-test.tsx.snap
new file mode 100644
index 00000000000..af09b977a36
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/__tests__/__snapshots__/AnalyzeTutorial-test.tsx.snap
@@ -0,0 +1,54 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders correctly 1`] = `
+<React.Fragment>
+ <div
+ className="page-header big-spacer-bottom"
+ >
+ <h1
+ className="page-title"
+ >
+ onboarding.project_analysis.header
+ </h1>
+ <p
+ className="page-description"
+ >
+ onboarding.project_analysis.description
+ </p>
+ </div>
+ <AnalyzeTutorialSuggestion />
+ <React.Fragment>
+ <TokenStep
+ currentUser={
+ Object {
+ "isLoggedIn": true,
+ "login": "luke",
+ "name": "Skywalker",
+ }
+ }
+ finished={false}
+ onContinue={[Function]}
+ onOpen={[Function]}
+ open={true}
+ stepNumber={1}
+ />
+ <ProjectAnalysisStep
+ component={
+ Object {
+ "analysisDate": "2016-01-01",
+ "breadcrumbs": Array [],
+ "key": "foo",
+ "name": "Foo",
+ "organization": "org",
+ "qualifier": "TRK",
+ "version": "0.0.1",
+ }
+ }
+ displayRowLayout={true}
+ open={false}
+ organization="org"
+ stepNumber={2}
+ />
+ </React.Fragment>
+</React.Fragment>
+`;
diff --git a/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/__tests__/__snapshots__/AnalyzeTutorialSuggestion-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/__tests__/__snapshots__/AnalyzeTutorialSuggestion-test.tsx.snap
new file mode 100644
index 00000000000..b682fbd8ed0
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/__tests__/__snapshots__/AnalyzeTutorialSuggestion-test.tsx.snap
@@ -0,0 +1,78 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`renders bitbucket suggestions correctly 1`] = `
+<div
+ className="alert alert-info big-spacer-bottom"
+>
+ <p>
+ onboarding.project_analysis.commands_for_analysis
+ </p>
+ <p>
+ onboarding.project_analysis.suggestions.bitbucket
+ </p>
+ <FormattedMessage
+ defaultMessage="onboarding.project_analysis.simply_link"
+ id="onboarding.project_analysis.simply_link"
+ values={
+ Object {
+ "link": <a
+ href="/documentation/integrations/bitbucketcloud#analyzing-with-pipelines"
+ target="_blank"
+ >
+ onboarding.project_analysis.guide_to_integrate_piplines
+ </a>,
+ }
+ }
+ />
+</div>
+`;
+
+exports[`renders github suggestions correctly 1`] = `
+<div
+ className="alert alert-info big-spacer-bottom"
+>
+ <p>
+ onboarding.project_analysis.commands_for_analysis
+
+ </p>
+ <p>
+ onboarding.project_analysis.suggestions.github
+ </p>
+ <FormattedMessage
+ defaultMessage="onboarding.project_analysis.simply_link"
+ id="onboarding.project_analysis.simply_link"
+ values={
+ Object {
+ "link": <a
+ href="https://docs.travis-ci.com/user/sonarcloud/"
+ rel="noopener noreferrer"
+ target="_blank"
+ >
+ onboarding.project_analysis.guide_to_integrate_travis
+ </a>,
+ }
+ }
+ />
+</div>
+`;
+
+exports[`renders vsts suggestions correctly 1`] = `
+<p
+ className="alert alert-info big-spacer-bottom"
+>
+ <FormattedMessage
+ defaultMessage="onboarding.project_analysis.simply_link"
+ id="onboarding.project_analysis.simply_link"
+ values={
+ Object {
+ "link": <a
+ href="/documentation/integrations/vsts"
+ target="_blank"
+ >
+ onboarding.project_analysis.guide_to_integrate_vsts
+ </a>,
+ }
+ }
+ />
+</p>
+`;
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/LanguageStep.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/LanguageForm.tsx
index 25b7544ddcc..8762501b301 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/LanguageStep.tsx
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/LanguageForm.tsx
@@ -23,39 +23,30 @@ import NewProjectForm from './NewProjectForm';
import RadioToggle from '../../../components/controls/RadioToggle';
import { translate } from '../../../helpers/l10n';
import { isSonarCloud } from '../../../helpers/system';
-
-export interface Result {
- language?: string;
- javaBuild?: string;
- cFamilyCompiler?: string;
- os?: string;
- projectKey?: string;
-}
+import { Component } from '../../../app/types';
+import { isLanguageConfigured, LanguageConfig } from '../utils';
interface Props {
- onDone: (result: Result) => void;
+ component?: Component;
+ config?: LanguageConfig;
+ onDone: (config: LanguageConfig) => void;
onReset: () => void;
organization?: string;
}
-type State = Result;
-
-export default class LanguageStep extends React.PureComponent<Props, State> {
- state: State = {};
-
- isConfigured = () => {
- const { language, javaBuild, cFamilyCompiler, os, projectKey } = this.state;
- const isJavaConfigured = language === 'java' && javaBuild != null;
- const isDotNetConfigured = language === 'dotnet' && projectKey != null;
- const isCFamilyConfigured =
- language === 'c-family' && (cFamilyCompiler === 'msvc' || os != null) && projectKey != null;
- const isOtherConfigured = language === 'other' && projectKey != null;
+type State = LanguageConfig;
- return isJavaConfigured || isDotNetConfigured || isCFamilyConfigured || isOtherConfigured;
- };
+export default class LanguageForm extends React.PureComponent<Props, State> {
+ constructor(props: Props) {
+ super(props);
+ this.state = {
+ ...(this.props.config || {}),
+ projectKey: props.component ? props.component.key : undefined
+ };
+ }
handleChange = () => {
- if (this.isConfigured()) {
+ if (isLanguageConfigured(this.state)) {
this.props.onDone(this.state);
} else {
this.props.onReset();
@@ -131,29 +122,36 @@ export default class LanguageStep extends React.PureComponent<Props, State> {
</div>
);
- renderProjectKey = () => (
- <NewProjectForm
- onDelete={this.handleProjectKeyDelete}
- onDone={this.handleProjectKeyDone}
- organization={this.props.organization}
- projectKey={this.state.projectKey}
- />
- );
+ renderProjectKey = () => {
+ const { cFamilyCompiler, language, os } = this.state;
+ const needProjectKey =
+ language === 'dotnet' ||
+ (language === 'c-family' &&
+ (cFamilyCompiler === 'msvc' || (cFamilyCompiler === 'clang-gcc' && os !== undefined))) ||
+ (language === 'other' && os !== undefined);
- 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);
+ if (!needProjectKey || this.props.component) {
+ return null;
+ }
+ return (
+ <NewProjectForm
+ onDelete={this.handleProjectKeyDelete}
+ onDone={this.handleProjectKeyDone}
+ organization={this.props.organization}
+ projectKey={this.state.projectKey}
+ />
+ );
+ };
+
+ render() {
+ const { cFamilyCompiler, language } = this.state;
const languages = isSonarCloud()
? ['java', 'dotnet', 'c-family', 'other']
: ['java', 'dotnet', 'other'];
return (
- <div>
+ <>
<div>
<h4 className="spacer-bottom">{translate('onboarding.language')}</h4>
<RadioToggle
@@ -163,16 +161,15 @@ export default class LanguageStep extends React.PureComponent<Props, State> {
label: translate('onboarding.language', language),
value: language
}))}
- value={this.state.language}
+ value={language}
/>
</div>
- {this.state.language === 'java' && this.renderJavaBuild()}
- {this.state.language === 'c-family' && this.renderCFamilyCompiler()}
- {((this.state.language === 'c-family' && this.state.cFamilyCompiler === 'clang-gcc') ||
- this.state.language === 'other') &&
+ {language === 'java' && this.renderJavaBuild()}
+ {language === 'c-family' && this.renderCFamilyCompiler()}
+ {((language === 'c-family' && cFamilyCompiler === 'clang-gcc') || language === 'other') &&
this.renderOS()}
- {shouldAskProjectKey && this.renderProjectKey()}
- </div>
+ {this.renderProjectKey()}
+ </>
);
}
}
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/NewOrganizationForm.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/NewOrganizationForm.tsx
index 5244898544d..5244898544d 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/NewOrganizationForm.tsx
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/NewOrganizationForm.tsx
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/NewProjectForm.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/NewProjectForm.tsx
index f09b4d152bf..f09b4d152bf 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/NewProjectForm.tsx
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/NewProjectForm.tsx
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/OrganizationStep.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/OrganizationStep.tsx
index 934965c7559..934965c7559 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/OrganizationStep.tsx
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/OrganizationStep.tsx
diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/ProjectAnalysisStep.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/ProjectAnalysisStep.tsx
new file mode 100644
index 00000000000..3a924f2415e
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/ProjectAnalysisStep.tsx
@@ -0,0 +1,120 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import Step from './Step';
+import LanguageForm from './LanguageForm';
+import AnalysisCommand from './commands/AnalysisCommand';
+import { translate } from '../../../helpers/l10n';
+import { Component } from '../../../app/types';
+import { LanguageConfig } from '../utils';
+
+interface Props {
+ component?: Component;
+ displayRowLayout?: boolean;
+ onFinish?: (projectKey?: string) => void;
+ onReset?: () => void;
+ open: boolean;
+ organization?: string;
+ stepNumber: number;
+ token?: string;
+}
+
+interface State {
+ config?: LanguageConfig;
+}
+
+export default class ProjectAnalysisStep extends React.PureComponent<Props, State> {
+ state: State = {};
+
+ getProjectKey = ({ config } = this.state, { component } = this.props) => {
+ return (component && component.key) || (config && config.projectKey);
+ };
+
+ handleLanguageSelect = (config: LanguageConfig) => {
+ this.setState({ config });
+ if (this.props.onFinish) {
+ const projectKey = config.language !== 'java' ? this.getProjectKey({ config }) : undefined;
+ this.props.onFinish(projectKey);
+ }
+ };
+
+ handleLanguageReset = () => {
+ this.setState({ config: undefined });
+ if (this.props.onReset) {
+ this.props.onReset();
+ }
+ };
+
+ renderForm = () => {
+ const languageComponent = (
+ <LanguageForm
+ component={this.props.component}
+ onDone={this.handleLanguageSelect}
+ onReset={this.handleLanguageReset}
+ organization={this.props.organization}
+ />
+ );
+ const analysisComponent = this.state.config && (
+ <AnalysisCommand
+ component={this.props.component}
+ languageConfig={this.state.config}
+ organization={this.props.organization}
+ small={true}
+ token={this.props.token}
+ />
+ );
+
+ if (this.props.displayRowLayout) {
+ return (
+ <div className="boxed-group-inner">
+ <div className="display-flex-column">
+ {languageComponent}
+ {analysisComponent && <div className="huge-spacer-top">{analysisComponent}</div>}
+ </div>
+ </div>
+ );
+ }
+
+ return (
+ <div className="boxed-group-inner">
+ <div className="flex-columns">
+ <div className="flex-column flex-column-half bordered-right">{languageComponent}</div>
+ <div className="flex-column flex-column-half">{analysisComponent}</div>
+ </div>
+ </div>
+ );
+ };
+
+ renderResult = () => null;
+
+ render() {
+ return (
+ <Step
+ finished={false}
+ onOpen={() => {}}
+ open={this.props.open}
+ renderForm={this.renderForm}
+ renderResult={this.renderResult}
+ stepNumber={this.props.stepNumber}
+ stepTitle={translate('onboarding.analysis.header')}
+ />
+ );
+ }
+}
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/Step.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/Step.tsx
index 7fda3877528..7fda3877528 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/Step.tsx
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/Step.tsx
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/TokenStep.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/TokenStep.tsx
index e0cd2c5aacc..e0cd2c5aacc 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/TokenStep.tsx
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/TokenStep.tsx
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/LanguageStep-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/LanguageForm-test.tsx
index 629044f2c4c..f767450c0ac 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/LanguageStep-test.tsx
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/LanguageForm-test.tsx
@@ -19,7 +19,7 @@
*/
import * as React from 'react';
import { shallow } from 'enzyme';
-import LanguageStep from '../LanguageStep';
+import LanguageForm from '../LanguageForm';
import { isSonarCloud } from '../../../../helpers/system';
jest.mock('../../../../helpers/system', () => ({ isSonarCloud: jest.fn() }));
@@ -30,7 +30,7 @@ beforeEach(() => {
it('selects java', () => {
const onDone = jest.fn();
- const wrapper = shallow(<LanguageStep onDone={onDone} onReset={jest.fn()} />);
+ const wrapper = shallow(<LanguageForm onDone={onDone} onReset={jest.fn()} />);
(wrapper.find('RadioToggle').prop('onCheck') as Function)('java');
wrapper.update();
@@ -55,7 +55,7 @@ it('selects java', () => {
it('selects c#', () => {
const onDone = jest.fn();
- const wrapper = shallow(<LanguageStep onDone={onDone} onReset={jest.fn()} />);
+ const wrapper = shallow(<LanguageForm onDone={onDone} onReset={jest.fn()} />);
(wrapper.find('RadioToggle').prop('onCheck') as Function)('dotnet');
wrapper.update();
@@ -68,7 +68,7 @@ it('selects c#', () => {
it('selects c-family', () => {
(isSonarCloud as jest.Mock<any>).mockImplementation(() => true);
const onDone = jest.fn();
- const wrapper = shallow(<LanguageStep onDone={onDone} onReset={jest.fn()} />);
+ const wrapper = shallow(<LanguageForm onDone={onDone} onReset={jest.fn()} />);
(wrapper.find('RadioToggle').prop('onCheck') as Function)('c-family');
wrapper.update();
@@ -113,7 +113,7 @@ it('selects c-family', () => {
it('selects other', () => {
const onDone = jest.fn();
- const wrapper = shallow(<LanguageStep onDone={onDone} onReset={jest.fn()} />);
+ const wrapper = shallow(<LanguageForm onDone={onDone} onReset={jest.fn()} />);
(wrapper.find('RadioToggle').prop('onCheck') as Function)('other');
wrapper.update();
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/NewOrganizationForm-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/NewOrganizationForm-test.tsx
index bb16f901167..bb16f901167 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/NewOrganizationForm-test.tsx
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/NewOrganizationForm-test.tsx
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/NewProjectForm-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/NewProjectForm-test.tsx
index 2c8c18cace4..2c8c18cace4 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/NewProjectForm-test.tsx
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/NewProjectForm-test.tsx
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/OrganizationStep-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/OrganizationStep-test.tsx
index b2192a0bce7..b2192a0bce7 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/OrganizationStep-test.tsx
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/OrganizationStep-test.tsx
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/Step-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/Step-test.tsx
index 8a9664f71c8..8a9664f71c8 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/Step-test.tsx
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/Step-test.tsx
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/TokenStep-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/TokenStep-test.tsx
index 25b5f0c7462..25b5f0c7462 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/TokenStep-test.tsx
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/TokenStep-test.tsx
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/LanguageStep-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/__snapshots__/LanguageForm-test.tsx.snap
index 8e82d384b3f..c653180e332 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/LanguageStep-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/__snapshots__/LanguageForm-test.tsx.snap
@@ -1,7 +1,7 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`selects c# 1`] = `
-<div>
+<React.Fragment>
<div>
<h4
className="spacer-bottom"
@@ -35,11 +35,11 @@ exports[`selects c# 1`] = `
onDelete={[Function]}
onDone={[Function]}
/>
-</div>
+</React.Fragment>
`;
exports[`selects c-family 1`] = `
-<div>
+<React.Fragment>
<div>
<h4
className="spacer-bottom"
@@ -100,11 +100,11 @@ exports[`selects c-family 1`] = `
value={null}
/>
</div>
-</div>
+</React.Fragment>
`;
exports[`selects c-family 2`] = `
-<div>
+<React.Fragment>
<div>
<h4
className="spacer-bottom"
@@ -169,11 +169,11 @@ exports[`selects c-family 2`] = `
onDelete={[Function]}
onDone={[Function]}
/>
-</div>
+</React.Fragment>
`;
exports[`selects c-family 3`] = `
-<div>
+<React.Fragment>
<div>
<h4
className="spacer-bottom"
@@ -265,11 +265,11 @@ exports[`selects c-family 3`] = `
value={null}
/>
</div>
-</div>
+</React.Fragment>
`;
exports[`selects c-family 4`] = `
-<div>
+<React.Fragment>
<div>
<h4
className="spacer-bottom"
@@ -366,11 +366,11 @@ exports[`selects c-family 4`] = `
onDone={[Function]}
projectKey="project-foo"
/>
-</div>
+</React.Fragment>
`;
exports[`selects java 1`] = `
-<div>
+<React.Fragment>
<div>
<h4
className="spacer-bottom"
@@ -427,11 +427,11 @@ exports[`selects java 1`] = `
value={null}
/>
</div>
-</div>
+</React.Fragment>
`;
exports[`selects java 2`] = `
-<div>
+<React.Fragment>
<div>
<h4
className="spacer-bottom"
@@ -488,11 +488,11 @@ exports[`selects java 2`] = `
value="maven"
/>
</div>
-</div>
+</React.Fragment>
`;
exports[`selects java 3`] = `
-<div>
+<React.Fragment>
<div>
<h4
className="spacer-bottom"
@@ -549,11 +549,11 @@ exports[`selects java 3`] = `
value="gradle"
/>
</div>
-</div>
+</React.Fragment>
`;
exports[`selects other 1`] = `
-<div>
+<React.Fragment>
<div>
<h4
className="spacer-bottom"
@@ -614,11 +614,11 @@ exports[`selects other 1`] = `
value={null}
/>
</div>
-</div>
+</React.Fragment>
`;
exports[`selects other 2`] = `
-<div>
+<React.Fragment>
<div>
<h4
className="spacer-bottom"
@@ -683,5 +683,5 @@ exports[`selects other 2`] = `
onDelete={[Function]}
onDone={[Function]}
/>
-</div>
+</React.Fragment>
`;
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/NewOrganizationForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/__snapshots__/NewOrganizationForm-test.tsx.snap
index eae8fcdb833..eae8fcdb833 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/NewOrganizationForm-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/__snapshots__/NewOrganizationForm-test.tsx.snap
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/NewProjectForm-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/__snapshots__/NewProjectForm-test.tsx.snap
index f6722a21bf6..f6722a21bf6 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/NewProjectForm-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/__snapshots__/NewProjectForm-test.tsx.snap
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/OrganizationStep-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/__snapshots__/OrganizationStep-test.tsx.snap
index 8ece74c899f..8ece74c899f 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/OrganizationStep-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/__snapshots__/OrganizationStep-test.tsx.snap
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/Step-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/__snapshots__/Step-test.tsx.snap
index 4667ca7ae8a..4667ca7ae8a 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/Step-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/__snapshots__/Step-test.tsx.snap
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/TokenStep-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/__snapshots__/TokenStep-test.tsx.snap
index 54847972e8c..54847972e8c 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/TokenStep-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/__tests__/__snapshots__/TokenStep-test.tsx.snap
diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/commands/AnalysisCommand.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/AnalysisCommand.tsx
new file mode 100644
index 00000000000..3bcdb9bdbdb
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/AnalysisCommand.tsx
@@ -0,0 +1,146 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import JavaMaven from './JavaMaven';
+import JavaGradle from './JavaGradle';
+import DotNet from './DotNet';
+import Msvc from './Msvc';
+import ClangGCC from './ClangGCC';
+import Other from './Other';
+import { getHostUrl } from '../../../../helpers/urls';
+import { Component } from '../../../../app/types';
+import { LanguageConfig } from '../../utils';
+
+interface Props {
+ component?: Component;
+ organization?: string;
+ languageConfig: LanguageConfig;
+ small?: boolean;
+ token?: string;
+}
+
+export default class AnalysisCommand extends React.PureComponent<Props> {
+ getProjectKey = ({ component, languageConfig } = this.props) => {
+ return (component && component.key) || languageConfig.projectKey;
+ };
+
+ renderCommandForMaven = () => {
+ const { token } = this.props;
+ if (!token) {
+ return null;
+ }
+ return <JavaMaven host={getHostUrl()} organization={this.props.organization} token={token} />;
+ };
+
+ renderCommandForGradle = () => {
+ const { token } = this.props;
+ if (!token) {
+ return null;
+ }
+ return <JavaGradle host={getHostUrl()} organization={this.props.organization} token={token} />;
+ };
+
+ renderCommandForDotNet = () => {
+ const { small, token } = this.props;
+ const projectKey = this.getProjectKey();
+ if (!projectKey || !token) {
+ return null;
+ }
+ return (
+ <DotNet
+ host={getHostUrl()}
+ organization={this.props.organization}
+ projectKey={projectKey}
+ small={small}
+ token={token}
+ />
+ );
+ };
+
+ renderCommandForMSVC = () => {
+ const { small, token } = this.props;
+ const projectKey = this.getProjectKey();
+ if (!projectKey || !token) {
+ return null;
+ }
+ return (
+ <Msvc
+ host={getHostUrl()}
+ organization={this.props.organization}
+ projectKey={projectKey}
+ small={small}
+ token={token}
+ />
+ );
+ };
+
+ renderCommandForClangGCC = () => {
+ const { languageConfig, small, token } = this.props;
+ const projectKey = this.getProjectKey();
+ if (!languageConfig || !projectKey || !languageConfig.os || !token) {
+ return null;
+ }
+ return (
+ <ClangGCC
+ host={getHostUrl()}
+ organization={this.props.organization}
+ os={languageConfig.os}
+ projectKey={projectKey}
+ small={small}
+ token={token}
+ />
+ );
+ };
+
+ renderCommandForOther = () => {
+ const { languageConfig, token } = this.props;
+ const projectKey = this.getProjectKey();
+ if (!languageConfig || !projectKey || !languageConfig.os || !token) {
+ return null;
+ }
+ return (
+ <Other
+ host={getHostUrl()}
+ organization={this.props.organization}
+ os={languageConfig.os}
+ projectKey={projectKey}
+ token={token}
+ />
+ );
+ };
+
+ render() {
+ const { languageConfig } = this.props;
+
+ if (languageConfig.language === 'java') {
+ return languageConfig.javaBuild === 'maven'
+ ? this.renderCommandForMaven()
+ : this.renderCommandForGradle();
+ } else if (languageConfig.language === 'dotnet') {
+ return this.renderCommandForDotNet();
+ } else if (languageConfig.language === 'c-family') {
+ return languageConfig.cFamilyCompiler === 'msvc'
+ ? this.renderCommandForMSVC()
+ : this.renderCommandForClangGCC();
+ } else {
+ return this.renderCommandForOther();
+ }
+ }
+}
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/BuildWrapper.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/BuildWrapper.tsx
index ed03adbf911..ed03adbf911 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/BuildWrapper.tsx
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/BuildWrapper.tsx
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/ClangGCC.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/ClangGCC.tsx
index 6ebe42a3ca9..0afc9783def 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/ClangGCC.tsx
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/ClangGCC.tsx
@@ -29,6 +29,7 @@ interface Props {
os: string;
organization?: string;
projectKey: string;
+ small?: boolean;
token: string;
}
@@ -67,7 +68,7 @@ export default function ClangGCC(props: Props) {
/>
)}
</InstanceMessage>
- <CodeSnippet isOneLine={true} snippet={command1} />
+ <CodeSnippet isOneLine={props.small} snippet={command1} />
<CodeSnippet isOneLine={props.os === 'win'} snippet={command2} />
<p
className="big-spacer-top markdown"
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/DotNet.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/DotNet.tsx
index 6dc321dbb42..12de244aaf8 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/DotNet.tsx
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/DotNet.tsx
@@ -27,6 +27,7 @@ interface Props {
host: string;
organization?: string;
projectKey: string;
+ small?: boolean;
token: string;
}
@@ -59,8 +60,8 @@ export default function DotNet(props: Props) {
)}
</InstanceMessage>
<CodeSnippet isOneLine={true} snippet={command1} />
- <CodeSnippet isOneLine={true} snippet={command2} />
- <CodeSnippet isOneLine={true} snippet={command3} />
+ <CodeSnippet isOneLine={false} snippet={command2} />
+ <CodeSnippet isOneLine={props.small} snippet={command3} />
<p
className="big-spacer-top markdown"
dangerouslySetInnerHTML={{ __html: translate('onboarding.analysis.msbuild.docs') }}
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/JavaGradle.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/JavaGradle.tsx
index 02da9fd1a2a..fa95c27bf5e 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/JavaGradle.tsx
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/JavaGradle.tsx
@@ -61,7 +61,9 @@ export default function JavaGradle(props: Props) {
<p
className="big-spacer-top markdown"
dangerouslySetInnerHTML={{
- __html: translate('onboarding.analysis.browse_url_after_analysis')
+ __html: props.projectKey
+ ? translate('onboarding.analysis.auto_refresh_after_analysis')
+ : translate('onboarding.analysis.browse_url_after_analysis')
}}
/>
</div>
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/JavaMaven.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/JavaMaven.tsx
index 5663b1f2911..8ade1b432bd 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/JavaMaven.tsx
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/JavaMaven.tsx
@@ -50,7 +50,9 @@ export default function JavaMaven(props: Props) {
<p
className="big-spacer-top markdown"
dangerouslySetInnerHTML={{
- __html: translate('onboarding.analysis.browse_url_after_analysis')
+ __html: props.projectKey
+ ? translate('onboarding.analysis.auto_refresh_after_analysis')
+ : translate('onboarding.analysis.browse_url_after_analysis')
}}
/>
</div>
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/MSBuildScanner.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/MSBuildScanner.tsx
index 65c4005af86..65c4005af86 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/MSBuildScanner.tsx
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/MSBuildScanner.tsx
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/Msvc.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/Msvc.tsx
index cf6120a3b31..838da876e26 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/Msvc.tsx
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/Msvc.tsx
@@ -28,6 +28,7 @@ interface Props {
host: string;
organization?: string;
projectKey: string;
+ small?: boolean;
token: string;
}
@@ -62,8 +63,8 @@ export default function Msvc(props: Props) {
)}
</InstanceMessage>
<CodeSnippet isOneLine={true} snippet={command1} />
- <CodeSnippet isOneLine={true} snippet={command2} />
- <CodeSnippet isOneLine={true} snippet={command3} />
+ <CodeSnippet isOneLine={props.small} snippet={command2} />
+ <CodeSnippet isOneLine={props.small} snippet={command3} />
<p
className="big-spacer-top markdown"
dangerouslySetInnerHTML={{ __html: translate('onboarding.analysis.msbuild.docs') }}
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/Other.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/Other.tsx
index 3d0b3b2a718..3d0b3b2a718 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/Other.tsx
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/Other.tsx
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/SQScanner.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/SQScanner.tsx
index 78b90f851bc..78b90f851bc 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/SQScanner.tsx
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/SQScanner.tsx
diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/AnalysisCommand-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/AnalysisCommand-test.tsx
new file mode 100644
index 00000000000..3dc16151384
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/AnalysisCommand-test.tsx
@@ -0,0 +1,71 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import { shallow } from 'enzyme';
+import AnalysisCommand from '../AnalysisCommand';
+
+jest.mock('../../../../../helpers/system', () => ({
+ isSonarCloud: jest.fn().mockReturnValue(true)
+}));
+
+it('display java command', () => {
+ expect(
+ getWrapper({ languageConfig: { language: 'java', javaBuild: 'gradle' } })
+ ).toMatchSnapshot();
+ expect(
+ getWrapper({ languageConfig: { language: 'java', javaBuild: 'maven' } })
+ ).toMatchSnapshot();
+});
+
+it('display c# command', () => {
+ expect(
+ getWrapper({ languageConfig: { language: 'dotnet', projectKey: 'project-foo' } })
+ ).toMatchSnapshot();
+});
+
+it('display c-family command', () => {
+ expect(
+ getWrapper({
+ languageConfig: { language: 'c-family', cFamilyCompiler: 'msvc', projectKey: 'project-foo' }
+ })
+ ).toMatchSnapshot();
+ expect(
+ getWrapper({
+ languageConfig: {
+ language: 'c-family',
+ cFamilyCompiler: 'clang-gcc',
+ os: 'linux',
+ projectKey: 'project-foo'
+ }
+ })
+ ).toMatchSnapshot();
+});
+
+it('display others command', () => {
+ expect(
+ getWrapper({
+ languageConfig: { language: 'other', os: 'window', projectKey: 'project-foo' }
+ })
+ ).toMatchSnapshot();
+});
+
+function getWrapper(props = {}) {
+ return shallow(<AnalysisCommand languageConfig={{}} token="myToken" {...props} />);
+}
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/BuildWrapper-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/BuildWrapper-test.tsx
index b19e334793b..b19e334793b 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/BuildWrapper-test.tsx
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/BuildWrapper-test.tsx
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/ClangGCC-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/ClangGCC-test.tsx
index a6f7c4f550a..8ffa75c7217 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/ClangGCC-test.tsx
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/ClangGCC-test.tsx
@@ -38,6 +38,7 @@ it('renders correctly', () => {
organization="organization"
os="linux"
projectKey="projectKey"
+ small={true}
token="token"
/>
)
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/DotNet-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/DotNet-test.tsx
index 91ecab828b2..e95302cb59a 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/DotNet-test.tsx
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/DotNet-test.tsx
@@ -26,7 +26,13 @@ it('renders correctly', () => {
expect(shallow(<DotNet host="host" projectKey="projectKey" token="token" />)).toMatchSnapshot();
expect(
shallow(
- <DotNet host="host" organization="organization" projectKey="projectKey" token="token" />
+ <DotNet
+ host="host"
+ organization="organization"
+ projectKey="projectKey"
+ small={true}
+ token="token"
+ />
)
).toMatchSnapshot();
});
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/JavaGradle-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/JavaGradle-test.tsx
index f0d130a248d..f0d130a248d 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/JavaGradle-test.tsx
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/JavaGradle-test.tsx
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/JavaMaven-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/JavaMaven-test.tsx
index dbda16ca13e..dbda16ca13e 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/JavaMaven-test.tsx
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/JavaMaven-test.tsx
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/MSBuildScanner-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/MSBuildScanner-test.tsx
index e5411341d10..e5411341d10 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/MSBuildScanner-test.tsx
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/MSBuildScanner-test.tsx
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/Msvc-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/Msvc-test.tsx
index 78470bbd2e6..68ee47b0de3 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/Msvc-test.tsx
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/Msvc-test.tsx
@@ -25,6 +25,14 @@ import Msvc from '../Msvc';
it('renders correctly', () => {
expect(shallow(<Msvc host="host" projectKey="projectKey" token="token" />)).toMatchSnapshot();
expect(
- shallow(<Msvc host="host" organization="organization" projectKey="projectKey" token="token" />)
+ shallow(
+ <Msvc
+ host="host"
+ organization="organization"
+ projectKey="projectKey"
+ small={true}
+ token="token"
+ />
+ )
).toMatchSnapshot();
});
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/Other-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/Other-test.tsx
index 16cc44ae69f..16cc44ae69f 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/Other-test.tsx
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/Other-test.tsx
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/SQScanner-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/SQScanner-test.tsx
index 2be4e546bb3..2be4e546bb3 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/SQScanner-test.tsx
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/SQScanner-test.tsx
diff --git a/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/AnalysisCommand-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/AnalysisCommand-test.tsx.snap
new file mode 100644
index 00000000000..f6a09725d51
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/AnalysisCommand-test.tsx.snap
@@ -0,0 +1,49 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`display c# command 1`] = `
+<DotNet
+ host="null"
+ projectKey="project-foo"
+ token="myToken"
+/>
+`;
+
+exports[`display c-family command 1`] = `
+<Msvc
+ host="null"
+ projectKey="project-foo"
+ token="myToken"
+/>
+`;
+
+exports[`display c-family command 2`] = `
+<ClangGCC
+ host="null"
+ os="linux"
+ projectKey="project-foo"
+ token="myToken"
+/>
+`;
+
+exports[`display java command 1`] = `
+<JavaGradle
+ host="null"
+ token="myToken"
+/>
+`;
+
+exports[`display java command 2`] = `
+<JavaMaven
+ host="null"
+ token="myToken"
+/>
+`;
+
+exports[`display others command 1`] = `
+<Other
+ host="null"
+ os="window"
+ projectKey="project-foo"
+ token="myToken"
+/>
+`;
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/BuildWrapper-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/BuildWrapper-test.tsx.snap
index 07e8eb45f0a..07e8eb45f0a 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/BuildWrapper-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/BuildWrapper-test.tsx.snap
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/ClangGCC-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/ClangGCC-test.tsx.snap
index cdffd4c2061..642935280e5 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/ClangGCC-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/ClangGCC-test.tsx.snap
@@ -18,7 +18,6 @@ exports[`renders correctly 1`] = `
message="onboarding.analysis.sq_scanner.execute.text"
/>
<CodeSnippet
- isOneLine={true}
snippet="build-wrapper-win-x86-64.exe --out-dir bw-output make clean all"
/>
<CodeSnippet
@@ -64,7 +63,6 @@ exports[`renders correctly 2`] = `
message="onboarding.analysis.sq_scanner.execute.text"
/>
<CodeSnippet
- isOneLine={true}
snippet="build-wrapper-linux-x86-64 --out-dir bw-output make clean all"
/>
<CodeSnippet
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/DotNet-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/DotNet-test.tsx.snap
index e072eef9d83..7f0e70d7242 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/DotNet-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/DotNet-test.tsx.snap
@@ -24,11 +24,10 @@ exports[`renders correctly 1`] = `
}
/>
<CodeSnippet
- isOneLine={true}
+ isOneLine={false}
snippet="MsBuild.exe /t:Rebuild"
/>
<CodeSnippet
- isOneLine={true}
snippet={
Array [
"SonarScanner.MSBuild.exe end",
@@ -71,7 +70,7 @@ exports[`renders correctly 2`] = `
}
/>
<CodeSnippet
- isOneLine={true}
+ isOneLine={false}
snippet="MsBuild.exe /t:Rebuild"
/>
<CodeSnippet
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/JavaGradle-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/JavaGradle-test.tsx.snap
index 401137a9234..c5ff1eb813c 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/JavaGradle-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/JavaGradle-test.tsx.snap
@@ -91,7 +91,7 @@ exports[`renders correctly 2`] = `
className="big-spacer-top markdown"
dangerouslySetInnerHTML={
Object {
- "__html": "onboarding.analysis.browse_url_after_analysis",
+ "__html": "onboarding.analysis.auto_refresh_after_analysis",
}
}
/>
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/JavaMaven-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/JavaMaven-test.tsx.snap
index d4462b957c6..7993a392397 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/JavaMaven-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/JavaMaven-test.tsx.snap
@@ -79,7 +79,7 @@ exports[`renders correctly 2`] = `
className="big-spacer-top markdown"
dangerouslySetInnerHTML={
Object {
- "__html": "onboarding.analysis.browse_url_after_analysis",
+ "__html": "onboarding.analysis.auto_refresh_after_analysis",
}
}
/>
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/MSBuildScanner-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/MSBuildScanner-test.tsx.snap
index 740e26ed12b..740e26ed12b 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/MSBuildScanner-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/MSBuildScanner-test.tsx.snap
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/Msvc-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/Msvc-test.tsx.snap
index 2240a13995c..accb581024c 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/Msvc-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/Msvc-test.tsx.snap
@@ -29,11 +29,9 @@ exports[`renders correctly 1`] = `
}
/>
<CodeSnippet
- isOneLine={true}
snippet="build-wrapper-win-x86-64.exe --out-dir bw-output MsBuild.exe /t:Rebuild"
/>
<CodeSnippet
- isOneLine={true}
snippet={
Array [
"SonarQube.Scanner.MSBuild.exe end",
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/Other-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/Other-test.tsx.snap
index 73aba357dca..73aba357dca 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/Other-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/Other-test.tsx.snap
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/SQScanner-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/SQScanner-test.tsx.snap
index cf6a8de4ce3..cf6a8de4ce3 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/SQScanner-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/SQScanner-test.tsx.snap
diff --git a/server/sonar-web/src/main/js/apps/tutorials/Onboarding.tsx b/server/sonar-web/src/main/js/apps/tutorials/onboarding/OnboardingModal.tsx
index 6f19ade590d..b8006ff3758 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/Onboarding.tsx
+++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/OnboardingModal.tsx
@@ -19,16 +19,16 @@
*/
import * as React from 'react';
import { connect } from 'react-redux';
-import handleRequiredAuthentication from '../../app/utils/handleRequiredAuthentication';
-import Modal from '../../components/controls/Modal';
-import OnboardingPrivateIcon from '../../components/icons-components/OnboardingPrivateIcon';
-import OnboardingProjectIcon from '../../components/icons-components/OnboardingProjectIcon';
-import OnboardingTeamIcon from '../../components/icons-components/OnboardingTeamIcon';
-import { Button, ResetButtonLink } from '../../components/ui/buttons';
-import { translate } from '../../helpers/l10n';
-import { CurrentUser, isLoggedIn } from '../../app/types';
-import { getCurrentUser } from '../../store/rootReducer';
-import './styles.css';
+import handleRequiredAuthentication from '../../../app/utils/handleRequiredAuthentication';
+import Modal from '../../../components/controls/Modal';
+import OnboardingPrivateIcon from '../../../components/icons-components/OnboardingPrivateIcon';
+import OnboardingProjectIcon from '../../../components/icons-components/OnboardingProjectIcon';
+import OnboardingTeamIcon from '../../../components/icons-components/OnboardingTeamIcon';
+import { Button, ResetButtonLink } from '../../../components/ui/buttons';
+import { translate } from '../../../helpers/l10n';
+import { CurrentUser, isLoggedIn } from '../../../app/types';
+import { getCurrentUser } from '../../../store/rootReducer';
+import '../styles.css';
interface OwnProps {
onClose: () => void;
@@ -43,7 +43,7 @@ interface StateProps {
type Props = OwnProps & StateProps;
-export class Onboarding extends React.PureComponent<Props> {
+export class OnboardingModal extends React.PureComponent<Props> {
componentDidMount() {
if (!isLoggedIn(this.props.currentUser)) {
handleRequiredAuthentication();
@@ -96,4 +96,4 @@ export class Onboarding extends React.PureComponent<Props> {
const mapStateToProps = (state: any): StateProps => ({ currentUser: getCurrentUser(state) });
-export default connect<StateProps, {}, OwnProps>(mapStateToProps)(Onboarding);
+export default connect<StateProps, {}, OwnProps>(mapStateToProps)(OnboardingModal);
diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/OnboardingPage.tsx b/server/sonar-web/src/main/js/apps/tutorials/onboarding/OnboardingPage.tsx
new file mode 100644
index 00000000000..d69e98ae561
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/OnboardingPage.tsx
@@ -0,0 +1,99 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+import * as React from 'react';
+import * as PropTypes from 'prop-types';
+import { connect } from 'react-redux';
+import OnboardingModal from './OnboardingModal';
+import { skipOnboarding } from '../../../api/users';
+import { skipOnboarding as skipOnboardingAction } from '../../../store/users/actions';
+import CreateOrganizationForm from '../../account/organizations/CreateOrganizationForm';
+import TeamOnboardingModal from '../teamOnboarding/TeamOnboardingModal';
+import { Organization } from '../../../app/types';
+
+interface DispatchProps {
+ skipOnboardingAction: () => void;
+}
+
+enum ModalKey {
+ onboarding,
+ organizationOnboarding,
+ teamOnboarding
+}
+
+interface State {
+ modal?: ModalKey;
+}
+
+export class OnboardingPage extends React.PureComponent<DispatchProps, State> {
+ static contextTypes = {
+ openProjectOnboarding: PropTypes.func.isRequired,
+ router: PropTypes.object.isRequired
+ };
+
+ state: State = { modal: ModalKey.onboarding };
+
+ closeOnboarding = () => {
+ skipOnboarding();
+ this.props.skipOnboardingAction();
+ this.context.router.replace('/');
+ };
+
+ closeOrganizationOnboarding = ({ key }: Pick<Organization, 'key'>) => {
+ this.closeOnboarding();
+ this.context.router.push(`/organizations/${key}`);
+ };
+
+ openOrganizationOnboarding = () => {
+ this.setState({ modal: ModalKey.organizationOnboarding });
+ };
+
+ openTeamOnboarding = () => {
+ this.setState({ modal: ModalKey.teamOnboarding });
+ };
+
+ render() {
+ const { modal } = this.state;
+ return (
+ <>
+ {modal === ModalKey.onboarding && (
+ <OnboardingModal
+ onClose={this.closeOnboarding}
+ onOpenOrganizationOnboarding={this.openOrganizationOnboarding}
+ onOpenProjectOnboarding={this.context.openProjectOnboarding}
+ onOpenTeamOnboarding={this.openTeamOnboarding}
+ />
+ )}
+ {modal === ModalKey.organizationOnboarding && (
+ <CreateOrganizationForm
+ onClose={this.closeOnboarding}
+ onCreate={this.closeOrganizationOnboarding}
+ />
+ )}
+ {modal === ModalKey.teamOnboarding && (
+ <TeamOnboardingModal onFinish={this.closeOnboarding} />
+ )}
+ </>
+ );
+ }
+}
+
+const mapDispatchToProps: DispatchProps = { skipOnboardingAction };
+
+export default connect<{}, DispatchProps>(null, mapDispatchToProps)(OnboardingPage);
diff --git a/server/sonar-web/src/main/js/apps/tutorials/__tests__/Onboarding-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/OnboardingModal-test.tsx
index 9bab36759a5..76c801faaf8 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/__tests__/Onboarding-test.tsx
+++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/OnboardingModal-test.tsx
@@ -19,13 +19,13 @@
*/
import * as React from 'react';
import { shallow } from 'enzyme';
-import { Onboarding } from '../Onboarding';
-import { click } from '../../../helpers/testUtils';
+import { OnboardingModal } from '../OnboardingModal';
+import { click } from '../../../../helpers/testUtils';
it('renders correctly', () => {
expect(
shallow(
- <Onboarding
+ <OnboardingModal
currentUser={{ isLoggedIn: true }}
onClose={jest.fn()}
onOpenOrganizationOnboarding={jest.fn()}
@@ -43,7 +43,7 @@ it('should correctly open the different tutorials', () => {
const onOpenTeamOnboarding = jest.fn();
const push = jest.fn();
const wrapper = shallow(
- <Onboarding
+ <OnboardingModal
currentUser={{ isLoggedIn: true }}
onClose={onClose}
onOpenOrganizationOnboarding={onOpenOrganizationOnboarding}
diff --git a/server/sonar-web/src/main/js/apps/tutorials/__tests__/__snapshots__/Onboarding-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/OnboardingModal-test.tsx.snap
index 18b2f16f846..18b2f16f846 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/__tests__/__snapshots__/Onboarding-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/__snapshots__/OnboardingModal-test.tsx.snap
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/AnalysisStep.tsx b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/AnalysisStep.tsx
deleted file mode 100644
index a91ff541119..00000000000
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/AnalysisStep.tsx
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2018 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import * as React from 'react';
-import Step from './Step';
-import LanguageStep, { Result } from './LanguageStep';
-import JavaMaven from './commands/JavaMaven';
-import JavaGradle from './commands/JavaGradle';
-import DotNet from './commands/DotNet';
-import Msvc from './commands/Msvc';
-import ClangGCC from './commands/ClangGCC';
-import Other from './commands/Other';
-import { translate } from '../../../helpers/l10n';
-import { getHostUrl } from '../../../helpers/urls';
-
-interface Props {
- onFinish: (projectKey?: string) => void;
- onReset: () => void;
- open: boolean;
- organization?: string;
- stepNumber: number;
- token?: string;
-}
-
-interface State {
- result?: Result;
-}
-
-export default class AnalysisStep extends React.PureComponent<Props, State> {
- state: State = {};
-
- handleLanguageSelect = (result?: Result) => {
- this.setState({ result });
- const projectKey = result && result.language !== 'java' ? result.projectKey : undefined;
- this.props.onFinish(projectKey);
- };
-
- handleLanguageReset = () => {
- this.setState({ result: undefined });
- this.props.onReset();
- };
-
- renderForm = () => {
- return (
- <div className="boxed-group-inner">
- <div className="flex-columns">
- <div className="flex-column flex-column-half bordered-right">
- <LanguageStep
- onDone={this.handleLanguageSelect}
- onReset={this.handleLanguageReset}
- organization={this.props.organization}
- />
- </div>
- <div className="flex-column flex-column-half">{this.renderCommand()}</div>
- </div>
- </div>
- );
- };
-
- renderFormattedCommand = (...lines: Array<string>) => (
- // keep this "useless" concatentation for the readability reason
- // eslint-disable-next-line no-useless-concat
- <pre>{lines.join(' ' + '\\' + '\n' + ' ')}</pre>
- );
-
- renderCommand = () => {
- const { result } = this.state;
-
- if (!result) {
- return null;
- }
-
- if (result.language === 'java') {
- return result.javaBuild === 'maven'
- ? this.renderCommandForMaven()
- : this.renderCommandForGradle();
- } else if (result.language === 'dotnet') {
- return this.renderCommandForDotNet();
- } else if (result.language === 'c-family') {
- return result.cFamilyCompiler === 'msvc'
- ? this.renderCommandForMSVC()
- : this.renderCommandForClangGCC();
- } else {
- return this.renderCommandForOther();
- }
- };
-
- renderCommandForMaven = () => {
- const { token } = this.props;
- if (!token) {
- return null;
- }
- return <JavaMaven host={getHostUrl()} organization={this.props.organization} token={token} />;
- };
-
- renderCommandForGradle = () => {
- const { token } = this.props;
- if (!token) {
- return null;
- }
- return <JavaGradle host={getHostUrl()} organization={this.props.organization} token={token} />;
- };
-
- renderCommandForDotNet = () => {
- const { token } = this.props;
- const { result } = this.state;
- if (!result || !result.projectKey || !token) {
- return null;
- }
- return (
- <DotNet
- host={getHostUrl()}
- organization={this.props.organization}
- projectKey={result.projectKey}
- token={token}
- />
- );
- };
-
- renderCommandForMSVC = () => {
- const { token } = this.props;
- const { result } = this.state;
- if (!result || !result.projectKey || !token) {
- return null;
- }
- return (
- <Msvc
- host={getHostUrl()}
- organization={this.props.organization}
- projectKey={result.projectKey}
- token={token}
- />
- );
- };
-
- renderCommandForClangGCC = () => {
- const { token } = this.props;
- const { result } = this.state;
- if (!result || !result.projectKey || !result.os || !token) {
- return null;
- }
- return (
- <ClangGCC
- host={getHostUrl()}
- organization={this.props.organization}
- os={result.os}
- projectKey={result.projectKey}
- token={token}
- />
- );
- };
-
- renderCommandForOther = () => {
- const { token } = this.props;
- const { result } = this.state;
- if (!result || !result.projectKey || !result.os || !token) {
- return null;
- }
- return (
- <Other
- host={getHostUrl()}
- organization={this.props.organization}
- os={result.os}
- projectKey={result.projectKey}
- token={token}
- />
- );
- };
-
- renderResult = () => null;
-
- render() {
- return (
- <Step
- finished={false}
- onOpen={() => {}}
- open={this.props.open}
- renderForm={this.renderForm}
- renderResult={this.renderResult}
- stepNumber={this.props.stepNumber}
- stepTitle={translate('onboarding.analysis.header')}
- />
- );
- }
-}
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/ProjectOnboarding.tsx b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/ProjectOnboarding.tsx
index 384e1726e39..e3511631aa4 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/ProjectOnboarding.tsx
+++ b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/ProjectOnboarding.tsx
@@ -21,10 +21,10 @@ import * as React from 'react';
import * as PropTypes from 'prop-types';
import Helmet from 'react-helmet';
import { connect } from 'react-redux';
-import TokenStep from './TokenStep';
-import OrganizationStep from './OrganizationStep';
-import AnalysisStep from './AnalysisStep';
import ProjectWatcher from './ProjectWatcher';
+import ProjectAnalysisStep from '../components/ProjectAnalysisStep';
+import OrganizationStep from '../components/OrganizationStep';
+import TokenStep from '../components/TokenStep';
import handleRequiredAuthentication from '../../../app/utils/handleRequiredAuthentication';
import { getCurrentUser, areThereCustomOrganizations } from '../../../store/rootReducer';
import { CurrentUser, isLoggedIn } from '../../../app/types';
@@ -161,7 +161,7 @@ export class ProjectOnboarding extends React.PureComponent<Props, State> {
stepNumber={stepNumber++}
/>
- <AnalysisStep
+ <ProjectAnalysisStep
onFinish={this.handleFinish}
onReset={this.handleReset}
open={step === 'analysis'}
diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/ProjectOnboarding-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/ProjectOnboarding-test.tsx.snap
index 0c5b93e108a..655ed26af50 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/ProjectOnboarding-test.tsx.snap
+++ b/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/ProjectOnboarding-test.tsx.snap
@@ -36,7 +36,7 @@ exports[`guides for on-premise 1`] = `
open={true}
stepNumber={1}
/>
- <AnalysisStep
+ <ProjectAnalysisStep
onFinish={[Function]}
onReset={[Function]}
open={false}
@@ -97,7 +97,7 @@ exports[`guides for on-premise 2`] = `
open={false}
stepNumber={1}
/>
- <AnalysisStep
+ <ProjectAnalysisStep
onFinish={[Function]}
onReset={[Function]}
open={true}
@@ -172,7 +172,7 @@ exports[`guides for sonarcloud 1`] = `
open={false}
stepNumber={2}
/>
- <AnalysisStep
+ <ProjectAnalysisStep
onFinish={[Function]}
onReset={[Function]}
open={false}
@@ -246,7 +246,7 @@ exports[`guides for sonarcloud 2`] = `
open={true}
stepNumber={2}
/>
- <AnalysisStep
+ <ProjectAnalysisStep
onFinish={[Function]}
onReset={[Function]}
open={false}
@@ -321,7 +321,7 @@ exports[`guides for sonarcloud 3`] = `
open={false}
stepNumber={2}
/>
- <AnalysisStep
+ <ProjectAnalysisStep
onFinish={[Function]}
onReset={[Function]}
open={true}
diff --git a/server/sonar-web/src/main/js/apps/tutorials/routes.ts b/server/sonar-web/src/main/js/apps/tutorials/routes.ts
index 5c8f9c88641..94c25460e0a 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/routes.ts
+++ b/server/sonar-web/src/main/js/apps/tutorials/routes.ts
@@ -26,7 +26,7 @@ const routes = [
component: lazyLoad(
() =>
isSonarCloud()
- ? import('./createProjectOnboarding/CreateProjectOnboarding')
+ ? import('./onboarding/OnboardingPage')
: import('./projectOnboarding/ProjectOnboardingPage')
)
}
diff --git a/server/sonar-web/src/main/js/apps/tutorials/styles.css b/server/sonar-web/src/main/js/apps/tutorials/styles.css
index 798fce21bcc..da2571a369d 100644
--- a/server/sonar-web/src/main/js/apps/tutorials/styles.css
+++ b/server/sonar-web/src/main/js/apps/tutorials/styles.css
@@ -58,8 +58,7 @@
.onboarding-choices {
display: flex;
justify-content: space-around;
- padding-top: 44px;
- padding-bottom: 44px;
+ padding: 44px 0;
background-color: var(--barBackgroundColor);
}
diff --git a/server/sonar-web/src/main/js/apps/tutorials/utils.ts b/server/sonar-web/src/main/js/apps/tutorials/utils.ts
new file mode 100644
index 00000000000..f84785ef61d
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/tutorials/utils.ts
@@ -0,0 +1,40 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2018 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+export interface LanguageConfig {
+ language?: string;
+ javaBuild?: string;
+ cFamilyCompiler?: string;
+ os?: string;
+ projectKey?: string;
+}
+
+export function isLanguageConfigured(config?: LanguageConfig) {
+ if (!config) {
+ return false;
+ }
+ const { language, javaBuild, cFamilyCompiler, os, projectKey } = config;
+ const isJavaConfigured = language === 'java' && javaBuild != null;
+ const isDotNetConfigured = language === 'dotnet' && projectKey != null;
+ const isCFamilyConfigured =
+ language === 'c-family' && (cFamilyCompiler === 'msvc' || os != null) && projectKey != null;
+ const isOtherConfigured = language === 'other' && projectKey != null;
+
+ return isJavaConfigured || isDotNetConfigured || isCFamilyConfigured || isOtherConfigured;
+}
diff --git a/server/sonar-web/src/main/js/components/icons-components/OnboardingPrivateIcon.tsx b/server/sonar-web/src/main/js/components/icons-components/OnboardingPrivateIcon.tsx
index 3592d9b0be0..7542f09a3aa 100644
--- a/server/sonar-web/src/main/js/components/icons-components/OnboardingPrivateIcon.tsx
+++ b/server/sonar-web/src/main/js/components/icons-components/OnboardingPrivateIcon.tsx
@@ -26,7 +26,7 @@ export default function OnboardingPrivateIcon({
size
}: IconProps) {
return (
- <Icon className={className} size={size || 64} viewBox="">
+ <Icon className={className} size={size || 64} viewBox="0 0 64 64">
<g fill="none" stroke={fill} strokeWidth="2">
<path d="M2 59h60V13H2zm0-46h60V5H2zm3-4h2m2 0h2m2 0h2m2 0h42" />
<path d="M59 34h-6l-2-4h-6l-2 5h-6l-2 2h-6l-2-4h-6l-2 5h-6l-2 4H5m1 14v-9m4 9v-6m4 6V43m4 13V45m4 11V42m4 14V39m4 17V41m4 15V46m4 10V40m4 16V44m4 12V37m4 19V38m4 18V43m4 13V39m-3-18h-2m-2 0h-2m-2 0h-2M9 29h14M9 33h7m17-12h8m-14 4h8m-8-4h4m-21 4h12v-4H10z" />
diff --git a/server/sonar-web/src/main/js/components/icons-components/OnboardingProjectIcon.tsx b/server/sonar-web/src/main/js/components/icons-components/OnboardingProjectIcon.tsx
index d2090eed867..d97972db6e7 100644
--- a/server/sonar-web/src/main/js/components/icons-components/OnboardingProjectIcon.tsx
+++ b/server/sonar-web/src/main/js/components/icons-components/OnboardingProjectIcon.tsx
@@ -26,7 +26,7 @@ export default function OnboardingProjectIcon({
size
}: IconProps) {
return (
- <Icon className={className} size={size || 64} viewBox="">
+ <Icon className={className} size={size || 64} viewBox="0 0 64 64">
<g fill="none" fillRule="evenodd" stroke={fill} strokeWidth="2">
<path d="M2 59h60V13H2zm0-46h60V5H2zm3-4h2m2 0h2m2 0h2m2 0h42" />
<path d="M59 34h-6l-2-4h-6l-2 5h-6l-2 2h-6l-2-4h-6l-2 5h-6l-2 4H5m1 14v-9m4 9v-6m4 6V43m4 13V45m4 11V42m4 14V39m4 17V41m4 15V46m4 10V40m4 16V44m4 12V37m4 19V38m4 18V43m4 13V39m-3-18h-2m-2 0h-2m-2 0h-2M9 29h14M9 33h7m17-12h8m-14 4h8m-8-4h4m-21 4h12v-4H10z" />
diff --git a/server/sonar-web/src/main/js/components/icons-components/OnboardingTeamIcon.tsx b/server/sonar-web/src/main/js/components/icons-components/OnboardingTeamIcon.tsx
index 6ce74838a0d..023067e74a8 100644
--- a/server/sonar-web/src/main/js/components/icons-components/OnboardingTeamIcon.tsx
+++ b/server/sonar-web/src/main/js/components/icons-components/OnboardingTeamIcon.tsx
@@ -22,7 +22,7 @@ import Icon, { IconProps } from './Icon';
export default function OnboardingTeamIcon({ className, fill = 'currentColor', size }: IconProps) {
return (
- <Icon className={className} size={size || 64} viewBox="">
+ <Icon className={className} size={size || 64} viewBox="0 0 64 64">
<g fill="none" fillRule="evenodd" stroke={fill} strokeWidth="2">
<path d="M32 9v5M11.5195 43.0898l7.48-4.091m33.481-18.0994l-7.48 4.1m-33.481-4.1l7.48 4.1M45 38.999l7.48 4.101M32 50v5m15-23c0 8.284-6.715 15-15 15s-15-6.716-15-15c0-8.285 6.715-15 15-15s15 6.715 15 15z" />
<path d="M40 38c0 1.656-3.58 2-8 2s-8-.344-8-2m16 0v-3l-5-3-1-1m-10 7v-3l5-3 1-1m6-4c0 2.2-1.8 4-4 4s-4-1.8-4-4v-1c0-2.2 1.8-4 4-4s4 1.8 4 4v1zm-.0098-21.71c7.18 1.069 13.439 4.96 17.609 10.51m-17.609 42.91c7.18-1.07 13.439-4.96 17.609-10.51M6.6299 41.25c-1.06-2.88-1.63-6-1.63-9.25s.57-6.37 1.63-9.25m3.7705-6.9502c4.17-5.55 10.43-9.44 17.609-10.51m-17.609 42.9104c4.17 5.55 10.43 9.439 17.609 10.51M57.3701 22.75c1.06 2.88 1.63 6 1.63 9.25s-.57 6.37-1.63 9.25" />
diff --git a/server/sonar-web/src/main/js/components/ui/buttons.css b/server/sonar-web/src/main/js/components/ui/buttons.css
index cc24ba79baf..032c0255117 100644
--- a/server/sonar-web/src/main/js/components/ui/buttons.css
+++ b/server/sonar-web/src/main/js/components/ui/buttons.css
@@ -130,6 +130,10 @@
transition: all 0.2s ease;
}
+.dropdown .button-link {
+ border-bottom: none;
+}
+
.button-link:hover {
background: transparent;
color: var(--blue);
diff --git a/server/sonar-web/src/main/js/helpers/markdown.js b/server/sonar-web/src/main/js/helpers/markdown.js
index 7f1c21325df..633c3450289 100644
--- a/server/sonar-web/src/main/js/helpers/markdown.js
+++ b/server/sonar-web/src/main/js/helpers/markdown.js
@@ -72,7 +72,7 @@ function parseFrontMatter(lines) {
* @returns {string}
*/
function filterContent(content) {
- const { isSonarCloud } = require('../helpers/system');
+ const { isSonarCloud } = require('./system');
const contentWithoutStatic = cutConditionalContent(content, 'static');
return isSonarCloud()
? cutConditionalContent(contentWithoutStatic, 'sonarqube')
diff --git a/server/sonar-web/src/main/js/helpers/urls.ts b/server/sonar-web/src/main/js/helpers/urls.ts
index 4d17bde0b09..9d3959260bf 100644
--- a/server/sonar-web/src/main/js/helpers/urls.ts
+++ b/server/sonar-web/src/main/js/helpers/urls.ts
@@ -49,10 +49,6 @@ export function getPathUrlAsString(path: Location): string {
return `${getBaseUrl()}${path.pathname}?${stringify(omitBy(path.query, isNil))}`;
}
-export function getSonarCloudUrlAsString(location: Location) {
- return 'https://sonarcloud.io' + getPathUrlAsString(location);
-}
-
export function getProjectUrl(project: string, branch?: string): Location {
return { pathname: '/dashboard', query: { id: project, branch } };
}