From 4f5f81d6c146d6cc873239258343141e9631c9b6 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Gr=C3=A9goire=20Aubert?= Date: Thu, 26 Jul 2018 11:44:57 +0200 Subject: [PATCH] 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 --- server/sonar-docs/src/templates/page.css | 2 +- .../js/app/components/ComponentContainer.tsx | 7 +- .../main/js/app/components/StartupModal.tsx | 6 +- .../__tests__/ComponentContainer-test.tsx | 40 ++- .../main/js/app/styles/components/alerts.css | 2 +- .../js/app/styles/components/boxed-group.css | 2 +- .../main/js/app/styles/components/page.css | 12 - .../src/main/js/app/styles/init/misc.css | 5 + .../src/main/js/app/styles/sonarcloud.css | 9 +- server/sonar-web/src/main/js/app/types.ts | 2 + .../coding-rules/components/FacetsList.tsx | 4 +- .../component-measures/sidebar/Sidebar.js | 2 +- .../__snapshots__/Sidebar-test.js.snap | 4 +- .../main/js/apps/issues/sidebar/Sidebar.tsx | 4 +- .../main/js/apps/overview/components/App.tsx | 65 +++-- .../overview/components/EmptyOverview.tsx | 49 ++-- .../apps/overview/components/OverviewApp.tsx | 14 +- .../components/SonarCloudEmptyOverview.tsx | 126 ++++++++++ .../components/__tests__/App-test.tsx | 32 ++- .../__tests__/EmptyOverview-test.tsx | 30 ++- .../SonarCloudEmptyOverview-test.tsx | 117 +++++++++ .../components/__tests__/Timeline-test.js | 51 ---- .../__snapshots__/EmptyOverview-test.tsx.snap | 75 ++++-- .../SonarCloudEmptyOverview-test.tsx.snap | 229 ++++++++++++++++++ .../__snapshots__/Timeline-test.js.snap | 71 ------ .../js/apps/overview/meta/MetaContainer.tsx | 29 ++- .../src/main/js/apps/overview/styles.css | 1 + .../create}/AlmRepositoryItem.tsx | 0 .../create}/AutoProjectCreate.tsx | 0 .../create/CreateProjectPage.tsx} | 63 +++-- .../create}/ManualProjectCreate.tsx | 2 +- .../__tests__/AlmRepositoryItem-test.tsx | 0 .../__tests__/AutoProjectCreate-test.tsx | 0 .../__tests__/CreateProjectPage-test.tsx} | 16 +- .../__tests__/ManualProjectCreate-test.tsx | 0 .../AlmRepositoryItem-test.tsx.snap | 0 .../AutoProjectCreate-test.tsx.snap | 0 .../CreateProjectPage-test.tsx.snap} | 2 +- .../ManualProjectCreate-test.tsx.snap | 0 .../src/main/js/apps/projects/create/utils.ts | 42 ++++ .../src/main/js/apps/projects/routes.ts | 10 +- .../analyzeProject/AnalyzeTutorial.tsx | 94 +++++++ .../AnalyzeTutorialSuggestion.tsx | 88 +++++++ .../__tests__/AnalyzeTutorial-test.tsx | 47 ++++ .../AnalyzeTutorialSuggestion-test.tsx | 38 +++ .../AnalyzeTutorial-test.tsx.snap | 54 +++++ .../AnalyzeTutorialSuggestion-test.tsx.snap | 78 ++++++ .../LanguageForm.tsx} | 91 ++++--- .../NewOrganizationForm.tsx | 0 .../NewProjectForm.tsx | 0 .../OrganizationStep.tsx | 0 .../components/ProjectAnalysisStep.tsx | 120 +++++++++ .../Step.tsx | 0 .../TokenStep.tsx | 0 .../__tests__/LanguageForm-test.tsx} | 10 +- .../__tests__/NewOrganizationForm-test.tsx | 0 .../__tests__/NewProjectForm-test.tsx | 0 .../__tests__/OrganizationStep-test.tsx | 0 .../__tests__/Step-test.tsx | 0 .../__tests__/TokenStep-test.tsx | 0 .../__snapshots__/LanguageForm-test.tsx.snap} | 40 +-- .../NewOrganizationForm-test.tsx.snap | 0 .../NewProjectForm-test.tsx.snap | 0 .../OrganizationStep-test.tsx.snap | 0 .../__snapshots__/Step-test.tsx.snap | 0 .../__snapshots__/TokenStep-test.tsx.snap | 0 .../components/commands/AnalysisCommand.tsx | 146 +++++++++++ .../commands/BuildWrapper.tsx | 0 .../commands/ClangGCC.tsx | 3 +- .../commands/DotNet.tsx | 5 +- .../commands/JavaGradle.tsx | 4 +- .../commands/JavaMaven.tsx | 4 +- .../commands/MSBuildScanner.tsx | 0 .../commands/Msvc.tsx | 5 +- .../commands/Other.tsx | 0 .../commands/SQScanner.tsx | 0 .../__tests__/AnalysisCommand-test.tsx | 71 ++++++ .../commands/__tests__/BuildWrapper-test.tsx | 0 .../commands/__tests__/ClangGCC-test.tsx | 1 + .../commands/__tests__/DotNet-test.tsx | 8 +- .../commands/__tests__/JavaGradle-test.tsx | 0 .../commands/__tests__/JavaMaven-test.tsx | 0 .../__tests__/MSBuildScanner-test.tsx | 0 .../commands/__tests__/Msvc-test.tsx | 10 +- .../commands/__tests__/Other-test.tsx | 0 .../commands/__tests__/SQScanner-test.tsx | 0 .../AnalysisCommand-test.tsx.snap | 49 ++++ .../__snapshots__/BuildWrapper-test.tsx.snap | 0 .../__snapshots__/ClangGCC-test.tsx.snap | 2 - .../__snapshots__/DotNet-test.tsx.snap | 5 +- .../__snapshots__/JavaGradle-test.tsx.snap | 2 +- .../__snapshots__/JavaMaven-test.tsx.snap | 2 +- .../MSBuildScanner-test.tsx.snap | 0 .../__snapshots__/Msvc-test.tsx.snap | 2 - .../__snapshots__/Other-test.tsx.snap | 0 .../__snapshots__/SQScanner-test.tsx.snap | 0 .../OnboardingModal.tsx} | 24 +- .../tutorials/onboarding/OnboardingPage.tsx | 99 ++++++++ .../__tests__/OnboardingModal-test.tsx} | 8 +- .../OnboardingModal-test.tsx.snap} | 0 .../projectOnboarding/AnalysisStep.tsx | 201 --------------- .../projectOnboarding/ProjectOnboarding.tsx | 8 +- .../ProjectOnboarding-test.tsx.snap | 10 +- .../src/main/js/apps/tutorials/routes.ts | 2 +- .../src/main/js/apps/tutorials/styles.css | 3 +- .../src/main/js/apps/tutorials/utils.ts | 40 +++ .../OnboardingPrivateIcon.tsx | 2 +- .../OnboardingProjectIcon.tsx | 2 +- .../icons-components/OnboardingTeamIcon.tsx | 2 +- .../src/main/js/components/ui/buttons.css | 4 + .../sonar-web/src/main/js/helpers/markdown.js | 2 +- server/sonar-web/src/main/js/helpers/urls.ts | 4 - .../resources/org/sonar/l10n/core.properties | 21 +- 113 files changed, 1906 insertions(+), 630 deletions(-) create mode 100644 server/sonar-web/src/main/js/apps/overview/components/SonarCloudEmptyOverview.tsx create mode 100644 server/sonar-web/src/main/js/apps/overview/components/__tests__/SonarCloudEmptyOverview-test.tsx delete mode 100644 server/sonar-web/src/main/js/apps/overview/components/__tests__/Timeline-test.js create mode 100644 server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/SonarCloudEmptyOverview-test.tsx.snap delete mode 100644 server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/Timeline-test.js.snap rename server/sonar-web/src/main/js/apps/{tutorials/createProjectOnboarding => projects/create}/AlmRepositoryItem.tsx (100%) rename server/sonar-web/src/main/js/apps/{tutorials/createProjectOnboarding => projects/create}/AutoProjectCreate.tsx (100%) rename server/sonar-web/src/main/js/apps/{tutorials/createProjectOnboarding/CreateProjectOnboarding.tsx => projects/create/CreateProjectPage.tsx} (79%) rename server/sonar-web/src/main/js/apps/{tutorials/createProjectOnboarding => projects/create}/ManualProjectCreate.tsx (98%) rename server/sonar-web/src/main/js/apps/{tutorials/createProjectOnboarding => projects/create}/__tests__/AlmRepositoryItem-test.tsx (100%) rename server/sonar-web/src/main/js/apps/{tutorials/createProjectOnboarding => projects/create}/__tests__/AutoProjectCreate-test.tsx (100%) rename server/sonar-web/src/main/js/apps/{tutorials/createProjectOnboarding/__tests__/CreateProjectOnboarding-test.tsx => projects/create/__tests__/CreateProjectPage-test.tsx} (79%) rename server/sonar-web/src/main/js/apps/{tutorials/createProjectOnboarding => projects/create}/__tests__/ManualProjectCreate-test.tsx (100%) rename server/sonar-web/src/main/js/apps/{tutorials/createProjectOnboarding => projects/create}/__tests__/__snapshots__/AlmRepositoryItem-test.tsx.snap (100%) rename server/sonar-web/src/main/js/apps/{tutorials/createProjectOnboarding => projects/create}/__tests__/__snapshots__/AutoProjectCreate-test.tsx.snap (100%) rename server/sonar-web/src/main/js/apps/{tutorials/createProjectOnboarding/__tests__/__snapshots__/CreateProjectOnboarding-test.tsx.snap => projects/create/__tests__/__snapshots__/CreateProjectPage-test.tsx.snap} (97%) rename server/sonar-web/src/main/js/apps/{tutorials/createProjectOnboarding => projects/create}/__tests__/__snapshots__/ManualProjectCreate-test.tsx.snap (100%) create mode 100644 server/sonar-web/src/main/js/apps/projects/create/utils.ts create mode 100644 server/sonar-web/src/main/js/apps/tutorials/analyzeProject/AnalyzeTutorial.tsx create mode 100644 server/sonar-web/src/main/js/apps/tutorials/analyzeProject/AnalyzeTutorialSuggestion.tsx create mode 100644 server/sonar-web/src/main/js/apps/tutorials/analyzeProject/__tests__/AnalyzeTutorial-test.tsx create mode 100644 server/sonar-web/src/main/js/apps/tutorials/analyzeProject/__tests__/AnalyzeTutorialSuggestion-test.tsx create mode 100644 server/sonar-web/src/main/js/apps/tutorials/analyzeProject/__tests__/__snapshots__/AnalyzeTutorial-test.tsx.snap create mode 100644 server/sonar-web/src/main/js/apps/tutorials/analyzeProject/__tests__/__snapshots__/AnalyzeTutorialSuggestion-test.tsx.snap rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding/LanguageStep.tsx => components/LanguageForm.tsx} (68%) rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding => components}/NewOrganizationForm.tsx (100%) rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding => components}/NewProjectForm.tsx (100%) rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding => components}/OrganizationStep.tsx (100%) create mode 100644 server/sonar-web/src/main/js/apps/tutorials/components/ProjectAnalysisStep.tsx rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding => components}/Step.tsx (100%) rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding => components}/TokenStep.tsx (100%) rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding/__tests__/LanguageStep-test.tsx => components/__tests__/LanguageForm-test.tsx} (92%) rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding => components}/__tests__/NewOrganizationForm-test.tsx (100%) rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding => components}/__tests__/NewProjectForm-test.tsx (100%) rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding => components}/__tests__/OrganizationStep-test.tsx (100%) rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding => components}/__tests__/Step-test.tsx (100%) rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding => components}/__tests__/TokenStep-test.tsx (100%) rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding/__tests__/__snapshots__/LanguageStep-test.tsx.snap => components/__tests__/__snapshots__/LanguageForm-test.tsx.snap} (97%) rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding => components}/__tests__/__snapshots__/NewOrganizationForm-test.tsx.snap (100%) rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding => components}/__tests__/__snapshots__/NewProjectForm-test.tsx.snap (100%) rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding => components}/__tests__/__snapshots__/OrganizationStep-test.tsx.snap (100%) rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding => components}/__tests__/__snapshots__/Step-test.tsx.snap (100%) rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding => components}/__tests__/__snapshots__/TokenStep-test.tsx.snap (100%) create mode 100644 server/sonar-web/src/main/js/apps/tutorials/components/commands/AnalysisCommand.tsx rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding => components}/commands/BuildWrapper.tsx (100%) rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding => components}/commands/ClangGCC.tsx (97%) rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding => components}/commands/DotNet.tsx (94%) rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding => components}/commands/JavaGradle.tsx (92%) rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding => components}/commands/JavaMaven.tsx (91%) rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding => components}/commands/MSBuildScanner.tsx (100%) rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding => components}/commands/Msvc.tsx (94%) rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding => components}/commands/Other.tsx (100%) rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding => components}/commands/SQScanner.tsx (100%) create mode 100644 server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/AnalysisCommand-test.tsx rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding => components}/commands/__tests__/BuildWrapper-test.tsx (100%) rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding => components}/commands/__tests__/ClangGCC-test.tsx (98%) rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding => components}/commands/__tests__/DotNet-test.tsx (88%) rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding => components}/commands/__tests__/JavaGradle-test.tsx (100%) rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding => components}/commands/__tests__/JavaMaven-test.tsx (100%) rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding => components}/commands/__tests__/MSBuildScanner-test.tsx (100%) rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding => components}/commands/__tests__/Msvc-test.tsx (86%) rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding => components}/commands/__tests__/Other-test.tsx (100%) rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding => components}/commands/__tests__/SQScanner-test.tsx (100%) create mode 100644 server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/__snapshots__/AnalysisCommand-test.tsx.snap rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding => components}/commands/__tests__/__snapshots__/BuildWrapper-test.tsx.snap (100%) rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding => components}/commands/__tests__/__snapshots__/ClangGCC-test.tsx.snap (98%) rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding => components}/commands/__tests__/__snapshots__/DotNet-test.tsx.snap (96%) rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding => components}/commands/__tests__/__snapshots__/JavaGradle-test.tsx.snap (96%) rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding => components}/commands/__tests__/__snapshots__/JavaMaven-test.tsx.snap (95%) rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding => components}/commands/__tests__/__snapshots__/MSBuildScanner-test.tsx.snap (100%) rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding => components}/commands/__tests__/__snapshots__/Msvc-test.tsx.snap (98%) rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding => components}/commands/__tests__/__snapshots__/Other-test.tsx.snap (100%) rename server/sonar-web/src/main/js/apps/tutorials/{projectOnboarding => components}/commands/__tests__/__snapshots__/SQScanner-test.tsx.snap (100%) rename server/sonar-web/src/main/js/apps/tutorials/{Onboarding.tsx => onboarding/OnboardingModal.tsx} (80%) create mode 100644 server/sonar-web/src/main/js/apps/tutorials/onboarding/OnboardingPage.tsx rename server/sonar-web/src/main/js/apps/tutorials/{__tests__/Onboarding-test.tsx => onboarding/__tests__/OnboardingModal-test.tsx} (93%) rename server/sonar-web/src/main/js/apps/tutorials/{__tests__/__snapshots__/Onboarding-test.tsx.snap => onboarding/__tests__/__snapshots__/OnboardingModal-test.tsx.snap} (100%) delete mode 100644 server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/AnalysisStep.tsx create mode 100644 server/sonar-web/src/main/js/apps/tutorials/utils.ts diff --git a/server/sonar-docs/src/templates/page.css b/server/sonar-docs/src/templates/page.css index 73515b1460d..3b7180f4baf 100644 --- a/server/sonar-docs/src/templates/page.css +++ b/server/sonar-docs/src/templates/page.css @@ -24,7 +24,7 @@ .alert-info { border-color: #bce8f1; background-color: #d9edf7; - color: #31708f; + color: #666666; } .alert-success { diff --git a/server/sonar-web/src/main/js/app/components/ComponentContainer.tsx b/server/sonar-web/src/main/js/app/components/ComponentContainer.tsx index 82d4b81197e..176a21d06ac 100644 --- a/server/sonar-web/src/main/js/app/components/ComponentContainer.tsx +++ b/server/sonar-web/src/main/js/app/components/ComponentContainer.tsx @@ -176,7 +176,12 @@ export class ComponentContainer extends React.PureComponent { differenceBy(newTasksInProgress, tasksInProgress, 'id').length > 0); shouldFetchComponent = Boolean(currentTaskChanged || progressChanged); - if (!shouldFetchComponent && component && newTasksInProgress.length > 0) { + if ( + !shouldFetchComponent && + component && + (newTasksInProgress.length > 0 || !component.analysisDate) + ) { + // Refresh the status as long as there is tasks in progress or no analysis window.clearTimeout(this.watchStatusTimer); this.watchStatusTimer = window.setTimeout( () => this.fetchStatus(component), diff --git a/server/sonar-web/src/main/js/app/components/StartupModal.tsx b/server/sonar-web/src/main/js/app/components/StartupModal.tsx index 8a7e7e2f444..b85885bbcd0 100644 --- a/server/sonar-web/src/main/js/app/components/StartupModal.tsx +++ b/server/sonar-web/src/main/js/app/components/StartupModal.tsx @@ -35,7 +35,7 @@ import { lazyLoad } from '../../components/lazyLoad'; const CreateOrganizationForm = lazyLoad(() => import('../../apps/account/organizations/CreateOrganizationForm') ); -const Onboarding = lazyLoad(() => import('../../apps/tutorials/Onboarding')); +const OnboardingModal = lazyLoad(() => import('../../apps/tutorials/onboarding/OnboardingModal')); const LicensePromptModal = lazyLoad( () => import('../../apps/marketplace/components/LicensePromptModal'), 'LicensePromptModal' @@ -135,7 +135,7 @@ export class StartupModal extends React.PureComponent { openProjectOnboarding = () => { if (isSonarCloud()) { this.setState({ automatic: false, modal: undefined }); - this.context.router.push(`/onboarding`); + this.context.router.push(`/projects/create`); } else { this.setState({ modal: ModalKey.projectOnboarding }); } @@ -189,7 +189,7 @@ export class StartupModal extends React.PureComponent { {this.props.children} {modal === ModalKey.license && } {modal === ModalKey.onboarding && ( - ({ - getBranches: jest.fn(() => Promise.resolve([])), - getPullRequests: jest.fn(() => Promise.resolve([])) + getBranches: jest.fn().mockResolvedValue([]), + getPullRequests: jest.fn().mockResolvedValue([]) })); jest.mock('../../../api/ce', () => ({ - getTasksForComponent: jest.fn(() => Promise.resolve({ queue: [] })) + getTasksForComponent: jest.fn().mockResolvedValue({ queue: [] }) })); jest.mock('../../../api/components', () => ({ - getComponentData: jest.fn(() => Promise.resolve({})) + getComponentData: jest.fn().mockResolvedValue({ analysisDate: '2018-07-30' }) })); jest.mock('../../../api/nav', () => ({ - getComponentNavigation: jest.fn(() => - Promise.resolve({ - breadcrumbs: [{ key: 'portfolioKey', name: 'portfolio', qualifier: 'VW' }], - key: 'portfolioKey' - }) - ) + getComponentNavigation: jest.fn().mockResolvedValue({ + breadcrumbs: [{ key: 'portfolioKey', name: 'portfolio', qualifier: 'VW' }], + key: 'portfolioKey' + }) })); // mock this, because some of its children are using redux store @@ -90,14 +88,12 @@ it('changes component', () => { }); it("loads branches for module's project", async () => { - (getComponentNavigation as jest.Mock).mockImplementationOnce(() => - Promise.resolve({ - breadcrumbs: [ - { key: 'projectKey', name: 'project', qualifier: 'TRK' }, - { key: 'moduleKey', name: 'module', qualifier: 'BRC' } - ] - }) - ); + (getComponentNavigation as jest.Mock).mockResolvedValueOnce({ + breadcrumbs: [ + { key: 'projectKey', name: 'project', qualifier: 'TRK' }, + { key: 'moduleKey', name: 'module', qualifier: 'BRC' } + ] + }); mount( @@ -149,9 +145,7 @@ it('updates branches on change', () => { }); it('loads organization', async () => { - (getComponentData as jest.Mock).mockImplementationOnce(() => - Promise.resolve({ organization: 'org' }) - ); + (getComponentData as jest.Mock).mockResolvedValueOnce({ organization: 'org' }); const fetchOrganizations = jest.fn(); mount( @@ -166,9 +160,7 @@ it('loads organization', async () => { }); it('fetches status', async () => { - (getComponentData as jest.Mock).mockImplementationOnce(() => - Promise.resolve({ organization: 'org' }) - ); + (getComponentData as jest.Mock).mockResolvedValueOnce({ organization: 'org' }); mount( diff --git a/server/sonar-web/src/main/js/app/styles/components/alerts.css b/server/sonar-web/src/main/js/app/styles/components/alerts.css index b965dced2d6..97457fe8dd6 100644 --- a/server/sonar-web/src/main/js/app/styles/components/alerts.css +++ b/server/sonar-web/src/main/js/app/styles/components/alerts.css @@ -51,7 +51,7 @@ .alert-info { border-color: #bce8f1; background-color: #d9edf7; - color: #31708f; + color: #666666; } .alert-success { diff --git a/server/sonar-web/src/main/js/app/styles/components/boxed-group.css b/server/sonar-web/src/main/js/app/styles/components/boxed-group.css index e77b22430da..5a79c7f70e8 100644 --- a/server/sonar-web/src/main/js/app/styles/components/boxed-group.css +++ b/server/sonar-web/src/main/js/app/styles/components/boxed-group.css @@ -18,7 +18,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ .boxed-group { - margin-bottom: 20px; + margin-bottom: calc(2.5 * var(--gridSize)); border: 1px solid var(--barBorderColor); border-radius: 2px; background-color: #fff; diff --git a/server/sonar-web/src/main/js/app/styles/components/page.css b/server/sonar-web/src/main/js/app/styles/components/page.css index c493b82d22c..a18b282cc45 100644 --- a/server/sonar-web/src/main/js/app/styles/components/page.css +++ b/server/sonar-web/src/main/js/app/styles/components/page.css @@ -187,7 +187,6 @@ } .page-sidebar-fixed { - width: 30%; min-width: 300px; flex-shrink: 0; padding-left: 40px; @@ -228,17 +227,6 @@ } } -.page-sidebar-sticky .page-sidebar-sticky-inner .search-navigator-facets-list { - width: 260px; - margin-left: calc(50vw - 640px + 290px - 260px - 37px); -} - -@media (max-width: 1335px) { - .page-sidebar-sticky .page-sidebar-sticky-inner .search-navigator-facets-list { - margin-left: 20px; - } -} - .layout-page { display: flex; align-items: stretch; diff --git a/server/sonar-web/src/main/js/app/styles/init/misc.css b/server/sonar-web/src/main/js/app/styles/init/misc.css index c0f7bd23abb..11bbc4bb9f7 100644 --- a/server/sonar-web/src/main/js/app/styles/init/misc.css +++ b/server/sonar-web/src/main/js/app/styles/init/misc.css @@ -293,6 +293,11 @@ td.big-spacer-top { flex-direction: row; } +.display-flex-column { + display: flex !important; + flex-direction: column; +} + .display-flex-center { display: flex !important; align-items: center; diff --git a/server/sonar-web/src/main/js/app/styles/sonarcloud.css b/server/sonar-web/src/main/js/app/styles/sonarcloud.css index 66a4f2f0ba8..aa5ab408659 100644 --- a/server/sonar-web/src/main/js/app/styles/sonarcloud.css +++ b/server/sonar-web/src/main/js/app/styles/sonarcloud.css @@ -37,19 +37,22 @@ display: flex; clear: left; margin-bottom: calc(3 * var(--gridSize)); - box-shadow: 0 1px 0 var(--barBorderColor); + border-bottom: 1px solid var(--barBorderColor); + font-size: var(--mediumFontSize); } .sonarcloud .flex-tabs > li > a { + position: relative; display: block; + top: 1px; height: 100%; width: 100%; box-sizing: border-box; color: var(--secondFontColor); font-weight: 600; cursor: pointer; - padding-bottom: var(--gridSize); - border-bottom: 2px solid transparent; + padding-bottom: calc(1.5 * var(--gridSize)); + border-bottom: 3px solid transparent; transition: color 0.2s ease; } diff --git a/server/sonar-web/src/main/js/app/types.ts b/server/sonar-web/src/main/js/app/types.ts index ea3be59fc5c..4b55b604c22 100644 --- a/server/sonar-web/src/main/js/app/types.ts +++ b/server/sonar-web/src/main/js/app/types.ts @@ -61,6 +61,8 @@ export interface Breadcrumb { } export interface Component extends LightComponent { + almId?: string; + almRepoUrl?: string; analysisDate?: string; breadcrumbs: Breadcrumb[]; configuration?: ComponentConfiguration; diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/FacetsList.tsx b/server/sonar-web/src/main/js/apps/coding-rules/components/FacetsList.tsx index 9eb8edb79ed..2540d76707c 100644 --- a/server/sonar-web/src/main/js/apps/coding-rules/components/FacetsList.tsx +++ b/server/sonar-web/src/main/js/apps/coding-rules/components/FacetsList.tsx @@ -57,7 +57,7 @@ export default function FacetsList(props: Props) { props.selectedProfile === undefined || !props.query.activation; return ( -
+ <> )} -
+ ); } diff --git a/server/sonar-web/src/main/js/apps/component-measures/sidebar/Sidebar.js b/server/sonar-web/src/main/js/apps/component-measures/sidebar/Sidebar.js index 4b8edc255c3..183875dc425 100644 --- a/server/sonar-web/src/main/js/apps/component-measures/sidebar/Sidebar.js +++ b/server/sonar-web/src/main/js/apps/component-measures/sidebar/Sidebar.js @@ -77,7 +77,7 @@ export default class Sidebar extends React.PureComponent { render() { return ( -
+
+
{ (this.props.organization && this.props.organization.key); return ( -
+ <> { stats={facets.authors} /> )} -
+ ); } } diff --git a/server/sonar-web/src/main/js/apps/overview/components/App.tsx b/server/sonar-web/src/main/js/apps/overview/components/App.tsx index d54ea53f10b..68c8238c23c 100644 --- a/server/sonar-web/src/main/js/apps/overview/components/App.tsx +++ b/server/sonar-web/src/main/js/apps/overview/components/App.tsx @@ -19,11 +19,21 @@ */ import * as React from 'react'; import * as PropTypes from 'prop-types'; -import OverviewApp from './OverviewApp'; +import { Helmet } from 'react-helmet'; import EmptyOverview from './EmptyOverview'; +import OverviewApp from './OverviewApp'; +import SonarCloudEmptyOverview from './SonarCloudEmptyOverview'; +import Suggestions from '../../../app/components/embed-docs-modal/Suggestions'; import { Component, BranchLike } from '../../../app/types'; import { isShortLivingBranch } from '../../../helpers/branches'; -import { getShortLivingBranchUrl, getCodeUrl } from '../../../helpers/urls'; +import { + getShortLivingBranchUrl, + getCodeUrl, + getProjectUrl, + getBaseUrl, + getPathUrlAsString +} from '../../../helpers/urls'; +import { isSonarCloud } from '../../../helpers/system'; interface Props { branchLike?: BranchLike; @@ -67,22 +77,43 @@ export default class App extends React.PureComponent { return null; } - if (!component.analysisDate) { - return ( - 1} - showWarning={!this.props.isPending && !this.props.isInProgress} - /> - ); - } - return ( - + <> + {isSonarCloud() && ( + + + + )} + + + {!component.analysisDate && + (isSonarCloud() ? ( + + ) : ( + + ))} + {component.analysisDate && ( + + )} + ); } } diff --git a/server/sonar-web/src/main/js/apps/overview/components/EmptyOverview.tsx b/server/sonar-web/src/main/js/apps/overview/components/EmptyOverview.tsx index 9beed6e65b5..69c3d81ae27 100644 --- a/server/sonar-web/src/main/js/apps/overview/components/EmptyOverview.tsx +++ b/server/sonar-web/src/main/js/apps/overview/components/EmptyOverview.tsx @@ -21,30 +21,39 @@ import * as React from 'react'; import { Link } from 'react-router'; import { FormattedMessage } from 'react-intl'; import { translate } from '../../../helpers/l10n'; +import { BranchLike } from '../../../app/types'; +import { isBranch, isLongLivingBranch } from '../../../helpers/branches'; interface Props { + branchLike?: BranchLike; + branchLikes: BranchLike[]; component: string; - hasBranches?: boolean; showWarning?: boolean; } -export default function EmptyOverview({ component, hasBranches, showWarning }: Props) { - const rawMessage = translate('provisioning.no_analysis.delete'); - const head = rawMessage.substr(0, rawMessage.indexOf('{0}')); - const tail = rawMessage.substr(rawMessage.indexOf('{0}') + 3); +export default function EmptyOverview({ branchLike, branchLikes, component, showWarning }: Props) { + const hasBranches = branchLikes.length > 1; + const hasBadConfig = + branchLikes.length > 2 || + (branchLikes.length === 2 && branchLikes.some(branch => isLongLivingBranch(branch))); + + const branchWarnMsg = hasBadConfig + ? translate('provisioning.no_analysis_on_main_branch.bad_configuration') + : translate('provisioning.no_analysis_on_main_branch'); return (
{showWarning && (
- {hasBranches ? ( + {hasBranches && isBranch(branchLike) ? ( + branchName: branchLike.name, + branchType: ( +
{translate('branches.main_branch')}
) @@ -57,13 +66,19 @@ export default function EmptyOverview({ component, hasBranches, showWarning }: P {!hasBranches && (
- {head} - - {translate('provisioning.no_analysis.delete_project')} - - {tail} + + {translate('provisioning.no_analysis.delete_project')} + + ) + }} + />
)}
diff --git a/server/sonar-web/src/main/js/apps/overview/components/OverviewApp.tsx b/server/sonar-web/src/main/js/apps/overview/components/OverviewApp.tsx index 402725bdc71..dcf365a6615 100644 --- a/server/sonar-web/src/main/js/apps/overview/components/OverviewApp.tsx +++ b/server/sonar-web/src/main/js/apps/overview/components/OverviewApp.tsx @@ -20,16 +20,14 @@ import * as React from 'react'; import { uniq } from 'lodash'; import { connect } from 'react-redux'; -import { Helmet } from 'react-helmet'; -import QualityGate from '../qualityGate/QualityGate'; import ApplicationQualityGate from '../qualityGate/ApplicationQualityGate'; import BugsAndVulnerabilities from '../main/BugsAndVulnerabilities'; import CodeSmells from '../main/CodeSmells'; import Coverage from '../main/Coverage'; import Duplications from '../main/Duplications'; import MetaContainer from '../meta/MetaContainer'; +import QualityGate from '../qualityGate/QualityGate'; import throwGlobalError from '../../../app/utils/throwGlobalError'; -import Suggestions from '../../../app/components/embed-docs-modal/Suggestions'; import { getMeasuresAndMeta } from '../../../api/measures'; import { getAllTimeMachineData, History } from '../../../api/time-machine'; import { parseDate } from '../../../helpers/dates'; @@ -52,8 +50,6 @@ import { fetchMetrics } from '../../../store/rootActions'; import { getMetrics } from '../../../store/rootReducer'; import { BranchLike, Component, Metric } from '../../../app/types'; import { translate } from '../../../helpers/l10n'; -import { getProjectUrl, getSonarCloudUrlAsString } from '../../../helpers/urls'; -import { isSonarCloud } from '../../../helpers/system'; import '../styles.css'; interface OwnProps { @@ -246,14 +242,6 @@ export class OverviewApp extends React.PureComponent { return (
- - - {isSonarCloud() && ( - - - - )} - {this.renderMain()}
diff --git a/server/sonar-web/src/main/js/apps/overview/components/SonarCloudEmptyOverview.tsx b/server/sonar-web/src/main/js/apps/overview/components/SonarCloudEmptyOverview.tsx new file mode 100644 index 00000000000..53dace6236e --- /dev/null +++ b/server/sonar-web/src/main/js/apps/overview/components/SonarCloudEmptyOverview.tsx @@ -0,0 +1,126 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import * as React from 'react'; +import { connect } from 'react-redux'; +import { FormattedMessage } from 'react-intl'; +import AnalyzeTutorial from '../../tutorials/analyzeProject/AnalyzeTutorial'; +import MetaContainer from '../meta/MetaContainer'; +import { BranchLike, Component, CurrentUser, isLoggedIn } from '../../../app/types'; +import { isLongLivingBranch, isBranch, isMainBranch } from '../../../helpers/branches'; +import { translate } from '../../../helpers/l10n'; +import { getCurrentUser } from '../../../store/rootReducer'; +import '../../../app/styles/sonarcloud.css'; + +interface OwnProps { + branchLike?: BranchLike; + branchLikes: BranchLike[]; + component: Component; + hasAnalyses?: boolean; + onComponentChange: (changes: {}) => void; +} + +interface StateProps { + currentUser: CurrentUser; +} + +type Props = OwnProps & StateProps; + +export function SonarCloudEmptyOverview({ + branchLike, + branchLikes, + component, + currentUser, + hasAnalyses, + onComponentChange +}: Props) { + const hasBranches = branchLikes.length > 1; + const hasBadBranchConfig = + branchLikes.length > 2 || + (branchLikes.length === 2 && branchLikes.some(branch => isLongLivingBranch(branch))); + return ( +
+
+
+ {isLoggedIn(currentUser) && isMainBranch(branchLike) ? ( + <> + {hasBranches && ( + + )} + {!hasBranches && + !hasAnalyses && } + + ) : ( + + )} +
+ +
+ +
+
+
+ ); +} + +export function WarningMessage({ + branchLike, + message +}: { + branchLike?: BranchLike; + message: string; +}) { + if (!isBranch(branchLike)) { + return null; + } + return ( +
+ {translate('branches.main_branch')}
+ ) + }} + /> +
+ ); +} + +const mapStateToProps = (state: any) => ({ + currentUser: getCurrentUser(state) +}); + +export default connect(mapStateToProps)(SonarCloudEmptyOverview); diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/App-test.tsx b/server/sonar-web/src/main/js/apps/overview/components/__tests__/App-test.tsx index ac84c986293..73eb99d9350 100644 --- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/App-test.tsx +++ b/server/sonar-web/src/main/js/apps/overview/components/__tests__/App-test.tsx @@ -20,9 +20,10 @@ import * as React from 'react'; import { mount, shallow } from 'enzyme'; import App from '../App'; -import OverviewApp from '../OverviewApp'; -import EmptyOverview from '../EmptyOverview'; import { BranchType, LongLivingBranch } from '../../../../app/types'; +import { isSonarCloud } from '../../../../helpers/system'; + +jest.mock('../../../../helpers/system', () => ({ isSonarCloud: jest.fn() })); const component = { key: 'foo', @@ -34,13 +35,34 @@ const component = { version: '0.0.1' }; +beforeEach(() => { + (isSonarCloud as jest.Mock).mockClear(); + (isSonarCloud as jest.Mock).mockReturnValue(false); +}); + it('should render OverviewApp', () => { - expect(getWrapper().type()).toBe(OverviewApp); + expect( + getWrapper() + .find('Connect(OverviewApp)') + .exists() + ).toBeTruthy(); }); it('should render EmptyOverview', () => { - const output = getWrapper({ component: { key: 'foo' } }); - expect(output.type()).toBe(EmptyOverview); + expect( + getWrapper({ component: { key: 'foo' } }) + .find('EmptyOverview') + .exists() + ).toBeTruthy(); +}); + +it('should render SonarCloudEmptyOverview', () => { + (isSonarCloud as jest.Mock).mockReturnValue(true); + expect( + getWrapper({ component: { key: 'foo' } }) + .find('Connect(SonarCloudEmptyOverview)') + .exists() + ).toBeTruthy(); }); it('redirects on Code page for files', () => { diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/EmptyOverview-test.tsx b/server/sonar-web/src/main/js/apps/overview/components/__tests__/EmptyOverview-test.tsx index c2468df3638..6fd204472ab 100644 --- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/EmptyOverview-test.tsx +++ b/server/sonar-web/src/main/js/apps/overview/components/__tests__/EmptyOverview-test.tsx @@ -20,17 +20,41 @@ import * as React from 'react'; import { shallow } from 'enzyme'; import EmptyOverview from '../EmptyOverview'; +import { BranchType } from '../../../../app/types'; + +const branch = { isMain: true, name: 'b', type: BranchType.LONG }; it('renders', () => { - expect(shallow()).toMatchSnapshot(); + expect( + shallow() + ).toMatchSnapshot(); }); it('does not render warning', () => { - expect(shallow()).toMatchSnapshot(); + expect( + shallow() + ).toMatchSnapshot(); }); it('should render another message when there are branches', () => { expect( - shallow() + shallow( + + ) + ).toMatchSnapshot(); + expect( + shallow( + + ) ).toMatchSnapshot(); }); diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/SonarCloudEmptyOverview-test.tsx b/server/sonar-web/src/main/js/apps/overview/components/__tests__/SonarCloudEmptyOverview-test.tsx new file mode 100644 index 00000000000..278fca079d1 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/overview/components/__tests__/SonarCloudEmptyOverview-test.tsx @@ -0,0 +1,117 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import * as React from 'react'; +import { shallow } from 'enzyme'; +import { SonarCloudEmptyOverview, WarningMessage } from '../SonarCloudEmptyOverview'; +import { BranchType } from '../../../../app/types'; + +const branch = { isMain: true, name: 'b', type: BranchType.LONG }; + +const component = { + key: 'foo', + analysisDate: '2016-01-01', + breadcrumbs: [], + name: 'Foo', + organization: 'org', + qualifier: 'TRK', + version: '0.0.1' +}; + +const LoggedInUser = { + isLoggedIn: true, + login: 'luke', + name: 'Skywalker' +}; + +it('renders correctly', () => { + expect( + shallow( + + ) + ).toMatchSnapshot(); +}); + +it('should render another message when there are branches', () => { + expect( + shallow( + + ) + ).toMatchSnapshot(); + expect( + shallow( + + ) + ).toMatchSnapshot(); +}); + +it('should not render the tutorial', () => { + expect( + shallow( + + ) + ).toMatchSnapshot(); +}); + +it('should render warning message', () => { + expect(shallow()).toMatchSnapshot(); +}); + +it('should not render warning message', () => { + expect( + shallow( + + ) + .find('FormattedMessage') + .exists() + ).toBeFalsy(); +}); diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/Timeline-test.js b/server/sonar-web/src/main/js/apps/overview/components/__tests__/Timeline-test.js deleted file mode 100644 index 0d9a0fdc23b..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/Timeline-test.js +++ /dev/null @@ -1,51 +0,0 @@ -/* - * SonarQube - * Copyright (C) 2009-2018 SonarSource SA - * mailto:info AT sonarsource DOT com - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 3 of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ -import React from 'react'; -import { shallow } from 'enzyme'; -import Timeline from '../Timeline'; -import { parseDate } from '../../../../helpers/dates'; - -const range = parseDate('2017-05-01T00:00:00.000Z'); -const history = [ - { date: parseDate('2017-04-08T00:00:00.000Z'), value: '29.6' }, - { date: parseDate('2017-04-09T00:00:00.000Z'), value: '170.8' }, - { date: parseDate('2017-05-08T00:00:00.000Z'), value: '360' }, - { date: parseDate('2017-05-09T00:00:00.000Z'), value: '39' } -]; - -it('should render correctly with an "after" range', () => { - expect(shallow()).toMatchSnapshot(); -}); - -it('should render correctly with a "before" range', () => { - expect(shallow()).toMatchSnapshot(); -}); - -it('should have a correct domain with strings or numbers', () => { - const date = parseDate('2017-05-08T00:00:00.000Z'); - const wrapper = shallow(); - expect(wrapper.find('LineChart').props().domain).toEqual([0, 360]); - - wrapper.setProps({ history: [{ date, value: '360.33' }, { date, value: '39.54' }] }); - expect(wrapper.find('LineChart').props().domain).toEqual([0, 360.33]); - - wrapper.setProps({ history: [{ date, value: 360 }, { date, value: 39 }] }); - expect(wrapper.find('LineChart').props().domain).toEqual([0, 360]); -}); diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/EmptyOverview-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/EmptyOverview-test.tsx.snap index 4d8cdf63248..cede657480c 100644 --- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/EmptyOverview-test.tsx.snap +++ b/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/EmptyOverview-test.tsx.snap @@ -30,22 +30,29 @@ exports[`renders 1`] = `
- + provisioning.no_analysis.delete_project + , } } - > - provisioning.no_analysis.delete_project - - ovisioning.no_analysis.delete + />
@@ -74,8 +81,46 @@ exports[`should render another message when there are branches 1`] = ` id="provisioning.no_analysis_on_main_branch" values={ Object { - "branch":
+ branches.main_branch +
, + } + } + /> +
+
+
+

+ key +

+ + abcd + +
+
+`; + +exports[`should render another message when there are branches 2`] = ` +
+
+
+ branches.main_branch
, diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/SonarCloudEmptyOverview-test.tsx.snap b/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/SonarCloudEmptyOverview-test.tsx.snap new file mode 100644 index 00000000000..1dd9c747b5a --- /dev/null +++ b/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/SonarCloudEmptyOverview-test.tsx.snap @@ -0,0 +1,229 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders correctly 1`] = ` +
+
+
+ + + +
+
+ +
+
+
+`; + +exports[`should not render the tutorial 1`] = ` +
+
+
+ +
+
+ +
+
+
+`; + +exports[`should render another message when there are branches 1`] = ` +
+
+
+ + + +
+
+ +
+
+
+`; + +exports[`should render another message when there are branches 2`] = ` +
+
+
+ + + +
+
+ +
+
+
+`; + +exports[`should render warning message 1`] = ` +
+ + branches.main_branch +
, + } + } + /> +
+`; diff --git a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/Timeline-test.js.snap b/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/Timeline-test.js.snap deleted file mode 100644 index 3c01c85264d..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/components/__tests__/__snapshots__/Timeline-test.js.snap +++ /dev/null @@ -1,71 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should render correctly with a "before" range 1`] = ` - -`; - -exports[`should render correctly with an "after" range 1`] = ` - -`; diff --git a/server/sonar-web/src/main/js/apps/overview/meta/MetaContainer.tsx b/server/sonar-web/src/main/js/apps/overview/meta/MetaContainer.tsx index 3e7749343a5..64a0a9e4ea6 100644 --- a/server/sonar-web/src/main/js/apps/overview/meta/MetaContainer.tsx +++ b/server/sonar-web/src/main/js/apps/overview/meta/MetaContainer.tsx @@ -58,8 +58,8 @@ interface OwnProps { branchLike?: BranchLike; component: Component; history?: History; - measures: MeasureEnhanced[]; - metrics: { [key: string]: Metric }; + measures?: MeasureEnhanced[]; + metrics?: { [key: string]: Metric }; onComponentChange: (changes: {}) => void; } @@ -106,7 +106,7 @@ export class Meta extends React.PureComponent { render() { const { organizationsEnabled } = this.context; - const { branchLike, component, metrics, organization } = this.props; + const { branchLike, component, measures, metrics, organization } = this.props; const { qualifier, description, visibility } = component; const isProject = qualifier === 'TRK'; @@ -131,16 +131,20 @@ export class Meta extends React.PureComponent { {isProject && ( )} - + {measures && ( + + )}
- + {metrics && ( + + )} {this.renderQualityInfos()} @@ -152,7 +156,8 @@ export class Meta extends React.PureComponent {
{!isPrivate && - (isProject || isApp) && ( + (isProject || isApp) && + metrics && ( void; + router: Pick; } 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 { +export class CreateProjectPage extends React.PureComponent { mounted = false; - static contextTypes = { - router: PropTypes.object - }; constructor(props: Props) { super(props); - this.state = { activeTab: this.shouldDisplayTabs(props) ? Tabs.AUTO : Tabs.MANUAL }; + if (!this.canAutoCreate(props)) { + this.updateQuery({ manual: true }); + } } componentDidMount() { @@ -85,13 +78,13 @@ export class CreateProjectOnboarding extends React.PureComponent { handleProjectCreate = (projects: Pick[], 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 { showAuto = (event: React.MouseEvent) => { event.preventDefault(); - this.setState({ activeTab: Tabs.AUTO }); + this.updateQuery({ manual: false }); }; showManual = (event: React.MouseEvent) => { event.preventDefault(); - this.setState({ activeTab: Tabs.MANUAL }); + this.updateQuery({ manual: true }); + }; + + updateQuery = (changes: Partial) => { + this.props.router.replace({ + pathname: this.props.location.pathname, + query: serializeQuery({ ...parseQuery(this.props.location.query), ...changes }) + }); }; render() { @@ -113,8 +113,7 @@ export class CreateProjectOnboarding extends React.PureComponent { 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 {

{header}

- {this.shouldDisplayTabs() && ( + {this.canAutoCreate() && ( )} - {activeTab === Tabs.AUTO ? ( - ) : ( - @@ -181,5 +180,5 @@ const mapStateToProps = (state: any): StateProps => { const mapDispatchToProps: DispatchProps = { skipOnboarding }; export default connect(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 similarity index 98% rename from server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/ManualProjectCreate.tsx rename to 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 { 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 similarity index 100% rename from server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/AlmRepositoryItem-test.tsx rename to 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 similarity index 100% rename from server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/AutoProjectCreate-test.tsx rename to 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 similarity index 79% rename from server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/CreateProjectOnboarding-test.tsx rename to 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( - 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 similarity index 100% rename from server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/ManualProjectCreate-test.tsx rename to 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 similarity index 100% rename from server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/__snapshots__/AlmRepositoryItem-test.tsx.snap rename to 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 similarity index 100% rename from server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/__snapshots__/AutoProjectCreate-test.tsx.snap rename to 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 similarity index 97% rename from server/sonar-web/src/main/js/apps/tutorials/createProjectOnboarding/__tests__/__snapshots__/CreateProjectOnboarding-test.tsx.snap rename to 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`] = ` { + 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 { + state: State = { step: Steps.TOKEN }; + + handleTokenDone = (token: string) => { + this.setState({ step: Steps.ANALYSIS, token }); + }; + + handleTokenOpen = () => { + this.setState({ step: Steps.TOKEN }); + }; + + render() { + const { component, currentUser } = this.props; + const { step, token } = this.state; + let stepNumber = 1; + + const almId = component.almId || currentUser.externalProvider; + const showTutorial = almId !== 'microsoft'; + return ( + <> +
+

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

+

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

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

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

+

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

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

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

+ ); + } + return null; +} diff --git a/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/__tests__/AnalyzeTutorial-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/__tests__/AnalyzeTutorial-test.tsx new file mode 100644 index 00000000000..39f0233081f --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/__tests__/AnalyzeTutorial-test.tsx @@ -0,0 +1,47 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import * as React from 'react'; +import { shallow } from 'enzyme'; +import AnalyzeTutorial from '../AnalyzeTutorial'; +import { LoggedInUser } from '../../../../app/types'; + +const component = { + key: 'foo', + analysisDate: '2016-01-01', + breadcrumbs: [], + name: 'Foo', + organization: 'org', + qualifier: 'TRK', + version: '0.0.1' +}; + +const loggedInUser: LoggedInUser = { + isLoggedIn: true, + login: 'luke', + name: 'Skywalker' +}; + +it('renders correctly', () => { + expect(getWrapper()).toMatchSnapshot(); +}); + +function getWrapper(props = {}) { + return shallow(); +} diff --git a/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/__tests__/AnalyzeTutorialSuggestion-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/__tests__/AnalyzeTutorialSuggestion-test.tsx new file mode 100644 index 00000000000..bc4a6d7b55b --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/__tests__/AnalyzeTutorialSuggestion-test.tsx @@ -0,0 +1,38 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import * as React from 'react'; +import { shallow } from 'enzyme'; +import AnalyzeTutorialSuggestion from '../AnalyzeTutorialSuggestion'; + +it('should not render', () => { + expect(shallow().type()).toBeNull(); +}); + +it('renders bitbucket suggestions correctly', () => { + expect(shallow()).toMatchSnapshot(); +}); + +it('renders github suggestions correctly', () => { + expect(shallow()).toMatchSnapshot(); +}); + +it('renders vsts suggestions correctly', () => { + expect(shallow()).toMatchSnapshot(); +}); diff --git a/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/__tests__/__snapshots__/AnalyzeTutorial-test.tsx.snap b/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/__tests__/__snapshots__/AnalyzeTutorial-test.tsx.snap new file mode 100644 index 00000000000..af09b977a36 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/analyzeProject/__tests__/__snapshots__/AnalyzeTutorial-test.tsx.snap @@ -0,0 +1,54 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`renders correctly 1`] = ` + +
+

+ onboarding.project_analysis.header +

+

+ onboarding.project_analysis.description +

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

+ onboarding.project_analysis.commands_for_analysis +

+

+ onboarding.project_analysis.suggestions.bitbucket +

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

+ onboarding.project_analysis.commands_for_analysis + +

+

+ onboarding.project_analysis.suggestions.github +

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

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

+`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/LanguageStep.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/LanguageForm.tsx similarity index 68% rename from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/LanguageStep.tsx rename to 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 { - 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 { + 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 {
); - renderProjectKey = () => ( - - ); + 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 ( + + ); + }; + + render() { + const { cFamilyCompiler, language } = this.state; const languages = isSonarCloud() ? ['java', 'dotnet', 'c-family', 'other'] : ['java', 'dotnet', 'other']; return ( -
+ <>

{translate('onboarding.language')}

{ label: translate('onboarding.language', language), value: language }))} - value={this.state.language} + value={language} />
- {this.state.language === 'java' && this.renderJavaBuild()} - {this.state.language === 'c-family' && this.renderCFamilyCompiler()} - {((this.state.language === 'c-family' && this.state.cFamilyCompiler === 'clang-gcc') || - this.state.language === 'other') && + {language === 'java' && this.renderJavaBuild()} + {language === 'c-family' && this.renderCFamilyCompiler()} + {((language === 'c-family' && cFamilyCompiler === 'clang-gcc') || language === 'other') && this.renderOS()} - {shouldAskProjectKey && this.renderProjectKey()} -
+ {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 similarity index 100% rename from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/NewOrganizationForm.tsx rename to 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 similarity index 100% rename from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/NewProjectForm.tsx rename to 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 similarity index 100% rename from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/OrganizationStep.tsx rename to 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 { + 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 = ( + + ); + const analysisComponent = this.state.config && ( + + ); + + if (this.props.displayRowLayout) { + return ( +
+
+ {languageComponent} + {analysisComponent &&
{analysisComponent}
} +
+
+ ); + } + + return ( +
+
+
{languageComponent}
+
{analysisComponent}
+
+
+ ); + }; + + renderResult = () => null; + + render() { + return ( + {}} + open={this.props.open} + renderForm={this.renderForm} + renderResult={this.renderResult} + stepNumber={this.props.stepNumber} + stepTitle={translate('onboarding.analysis.header')} + /> + ); + } +} diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/Step.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/Step.tsx similarity index 100% rename from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/Step.tsx rename to 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 similarity index 100% rename from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/TokenStep.tsx rename to 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 similarity index 92% rename from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/LanguageStep-test.tsx rename to 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(); + const wrapper = shallow(); (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(); + const wrapper = shallow(); (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).mockImplementation(() => true); const onDone = jest.fn(); - const wrapper = shallow(); + const wrapper = shallow(); (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(); + const wrapper = shallow(); (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 similarity index 100% rename from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/NewOrganizationForm-test.tsx rename to 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 similarity index 100% rename from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/NewProjectForm-test.tsx rename to 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 similarity index 100% rename from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/OrganizationStep-test.tsx rename to 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 similarity index 100% rename from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/Step-test.tsx rename to 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 similarity index 100% rename from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/TokenStep-test.tsx rename to 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 similarity index 97% rename from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/LanguageStep-test.tsx.snap rename to 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`] = ` -
+

-

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

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

-

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

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

-

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

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

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

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

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

-

+
`; 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 similarity index 100% rename from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/NewOrganizationForm-test.tsx.snap rename to 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 similarity index 100% rename from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/NewProjectForm-test.tsx.snap rename to 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 similarity index 100% rename from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/OrganizationStep-test.tsx.snap rename to 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 similarity index 100% rename from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/Step-test.tsx.snap rename to 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 similarity index 100% rename from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/__tests__/__snapshots__/TokenStep-test.tsx.snap rename to 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 { + getProjectKey = ({ component, languageConfig } = this.props) => { + return (component && component.key) || languageConfig.projectKey; + }; + + renderCommandForMaven = () => { + const { token } = this.props; + if (!token) { + return null; + } + return ; + }; + + renderCommandForGradle = () => { + const { token } = this.props; + if (!token) { + return null; + } + return ; + }; + + renderCommandForDotNet = () => { + const { small, token } = this.props; + const projectKey = this.getProjectKey(); + if (!projectKey || !token) { + return null; + } + return ( + + ); + }; + + renderCommandForMSVC = () => { + const { small, token } = this.props; + const projectKey = this.getProjectKey(); + if (!projectKey || !token) { + return null; + } + return ( + + ); + }; + + renderCommandForClangGCC = () => { + const { languageConfig, small, token } = this.props; + const projectKey = this.getProjectKey(); + if (!languageConfig || !projectKey || !languageConfig.os || !token) { + return null; + } + return ( + + ); + }; + + renderCommandForOther = () => { + const { languageConfig, token } = this.props; + const projectKey = this.getProjectKey(); + if (!languageConfig || !projectKey || !languageConfig.os || !token) { + return null; + } + return ( + + ); + }; + + render() { + const { languageConfig } = this.props; + + if (languageConfig.language === 'java') { + return languageConfig.javaBuild === 'maven' + ? this.renderCommandForMaven() + : this.renderCommandForGradle(); + } else if (languageConfig.language === 'dotnet') { + return this.renderCommandForDotNet(); + } else if (languageConfig.language === 'c-family') { + return languageConfig.cFamilyCompiler === 'msvc' + ? this.renderCommandForMSVC() + : this.renderCommandForClangGCC(); + } else { + return this.renderCommandForOther(); + } + } +} diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/BuildWrapper.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/BuildWrapper.tsx similarity index 100% rename from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/BuildWrapper.tsx rename to 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 similarity index 97% rename from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/ClangGCC.tsx rename to 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) { /> )} - +

- - + +

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 similarity index 91% rename from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/JavaMaven.tsx rename to 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) {

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 similarity index 100% rename from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/MSBuildScanner.tsx rename to 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 similarity index 94% rename from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/Msvc.tsx rename to 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) { )} - - + +

({ + isSonarCloud: jest.fn().mockReturnValue(true) +})); + +it('display java command', () => { + expect( + getWrapper({ languageConfig: { language: 'java', javaBuild: 'gradle' } }) + ).toMatchSnapshot(); + expect( + getWrapper({ languageConfig: { language: 'java', javaBuild: 'maven' } }) + ).toMatchSnapshot(); +}); + +it('display c# command', () => { + expect( + getWrapper({ languageConfig: { language: 'dotnet', projectKey: 'project-foo' } }) + ).toMatchSnapshot(); +}); + +it('display c-family command', () => { + expect( + getWrapper({ + languageConfig: { language: 'c-family', cFamilyCompiler: 'msvc', projectKey: 'project-foo' } + }) + ).toMatchSnapshot(); + expect( + getWrapper({ + languageConfig: { + language: 'c-family', + cFamilyCompiler: 'clang-gcc', + os: 'linux', + projectKey: 'project-foo' + } + }) + ).toMatchSnapshot(); +}); + +it('display others command', () => { + expect( + getWrapper({ + languageConfig: { language: 'other', os: 'window', projectKey: 'project-foo' } + }) + ).toMatchSnapshot(); +}); + +function getWrapper(props = {}) { + return shallow(); +} diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/BuildWrapper-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/BuildWrapper-test.tsx similarity index 100% rename from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/BuildWrapper-test.tsx rename to 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 similarity index 98% rename from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/ClangGCC-test.tsx rename to 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 similarity index 88% rename from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/DotNet-test.tsx rename to 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()).toMatchSnapshot(); expect( shallow( - + ) ).toMatchSnapshot(); }); diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/JavaGradle-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/JavaGradle-test.tsx similarity index 100% rename from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/JavaGradle-test.tsx rename to 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 similarity index 100% rename from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/JavaMaven-test.tsx rename to 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 similarity index 100% rename from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/MSBuildScanner-test.tsx rename to 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 similarity index 86% rename from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/Msvc-test.tsx rename to 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()).toMatchSnapshot(); expect( - shallow() + shallow( + + ) ).toMatchSnapshot(); }); diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/Other-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/components/commands/__tests__/Other-test.tsx similarity index 100% rename from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/Other-test.tsx rename to 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 similarity index 100% rename from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/SQScanner-test.tsx rename to 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`] = ` + +`; + +exports[`display c-family command 1`] = ` + +`; + +exports[`display c-family command 2`] = ` + +`; + +exports[`display java command 1`] = ` + +`; + +exports[`display java command 2`] = ` + +`; + +exports[`display others command 1`] = ` + +`; diff --git a/server/sonar-web/src/main/js/apps/tutorials/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 similarity index 100% rename from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/BuildWrapper-test.tsx.snap rename to 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 similarity index 98% rename from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/ClangGCC-test.tsx.snap rename to 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" /> 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 similarity index 95% rename from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/JavaMaven-test.tsx.snap rename to 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 similarity index 100% rename from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/MSBuildScanner-test.tsx.snap rename to 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 similarity index 98% rename from server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/commands/__tests__/__snapshots__/Msvc-test.tsx.snap rename to 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`] = ` } /> void; @@ -43,7 +43,7 @@ interface StateProps { type Props = OwnProps & StateProps; -export class Onboarding extends React.PureComponent { +export class OnboardingModal extends React.PureComponent { componentDidMount() { if (!isLoggedIn(this.props.currentUser)) { handleRequiredAuthentication(); @@ -96,4 +96,4 @@ export class Onboarding extends React.PureComponent { const mapStateToProps = (state: any): StateProps => ({ currentUser: getCurrentUser(state) }); -export default connect(mapStateToProps)(Onboarding); +export default connect(mapStateToProps)(OnboardingModal); diff --git a/server/sonar-web/src/main/js/apps/tutorials/onboarding/OnboardingPage.tsx b/server/sonar-web/src/main/js/apps/tutorials/onboarding/OnboardingPage.tsx new file mode 100644 index 00000000000..d69e98ae561 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/onboarding/OnboardingPage.tsx @@ -0,0 +1,99 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +import * as React from 'react'; +import * as PropTypes from 'prop-types'; +import { connect } from 'react-redux'; +import OnboardingModal from './OnboardingModal'; +import { skipOnboarding } from '../../../api/users'; +import { skipOnboarding as skipOnboardingAction } from '../../../store/users/actions'; +import CreateOrganizationForm from '../../account/organizations/CreateOrganizationForm'; +import TeamOnboardingModal from '../teamOnboarding/TeamOnboardingModal'; +import { Organization } from '../../../app/types'; + +interface DispatchProps { + skipOnboardingAction: () => void; +} + +enum ModalKey { + onboarding, + organizationOnboarding, + teamOnboarding +} + +interface State { + modal?: ModalKey; +} + +export class OnboardingPage extends React.PureComponent { + static contextTypes = { + openProjectOnboarding: PropTypes.func.isRequired, + router: PropTypes.object.isRequired + }; + + state: State = { modal: ModalKey.onboarding }; + + closeOnboarding = () => { + skipOnboarding(); + this.props.skipOnboardingAction(); + this.context.router.replace('/'); + }; + + closeOrganizationOnboarding = ({ key }: Pick) => { + this.closeOnboarding(); + this.context.router.push(`/organizations/${key}`); + }; + + openOrganizationOnboarding = () => { + this.setState({ modal: ModalKey.organizationOnboarding }); + }; + + openTeamOnboarding = () => { + this.setState({ modal: ModalKey.teamOnboarding }); + }; + + render() { + const { modal } = this.state; + return ( + <> + {modal === ModalKey.onboarding && ( + + )} + {modal === ModalKey.organizationOnboarding && ( + + )} + {modal === ModalKey.teamOnboarding && ( + + )} + + ); + } +} + +const mapDispatchToProps: DispatchProps = { skipOnboardingAction }; + +export default connect<{}, DispatchProps>(null, mapDispatchToProps)(OnboardingPage); diff --git a/server/sonar-web/src/main/js/apps/tutorials/__tests__/Onboarding-test.tsx b/server/sonar-web/src/main/js/apps/tutorials/onboarding/__tests__/OnboardingModal-test.tsx similarity index 93% rename from server/sonar-web/src/main/js/apps/tutorials/__tests__/Onboarding-test.tsx rename to 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( - { const onOpenTeamOnboarding = jest.fn(); const push = jest.fn(); const wrapper = shallow( - void; - onReset: () => void; - open: boolean; - organization?: string; - stepNumber: number; - token?: string; -} - -interface State { - result?: Result; -} - -export default class AnalysisStep extends React.PureComponent { - state: State = {}; - - handleLanguageSelect = (result?: Result) => { - this.setState({ result }); - const projectKey = result && result.language !== 'java' ? result.projectKey : undefined; - this.props.onFinish(projectKey); - }; - - handleLanguageReset = () => { - this.setState({ result: undefined }); - this.props.onReset(); - }; - - renderForm = () => { - return ( -

-
-
- -
-
{this.renderCommand()}
-
-
- ); - }; - - renderFormattedCommand = (...lines: Array) => ( - // keep this "useless" concatentation for the readability reason - // eslint-disable-next-line no-useless-concat -
{lines.join(' ' + '\\' + '\n' + '  ')}
- ); - - renderCommand = () => { - const { result } = this.state; - - if (!result) { - return null; - } - - if (result.language === 'java') { - return result.javaBuild === 'maven' - ? this.renderCommandForMaven() - : this.renderCommandForGradle(); - } else if (result.language === 'dotnet') { - return this.renderCommandForDotNet(); - } else if (result.language === 'c-family') { - return result.cFamilyCompiler === 'msvc' - ? this.renderCommandForMSVC() - : this.renderCommandForClangGCC(); - } else { - return this.renderCommandForOther(); - } - }; - - renderCommandForMaven = () => { - const { token } = this.props; - if (!token) { - return null; - } - return ; - }; - - renderCommandForGradle = () => { - const { token } = this.props; - if (!token) { - return null; - } - return ; - }; - - renderCommandForDotNet = () => { - const { token } = this.props; - const { result } = this.state; - if (!result || !result.projectKey || !token) { - return null; - } - return ( - - ); - }; - - renderCommandForMSVC = () => { - const { token } = this.props; - const { result } = this.state; - if (!result || !result.projectKey || !token) { - return null; - } - return ( - - ); - }; - - renderCommandForClangGCC = () => { - const { token } = this.props; - const { result } = this.state; - if (!result || !result.projectKey || !result.os || !token) { - return null; - } - return ( - - ); - }; - - renderCommandForOther = () => { - const { token } = this.props; - const { result } = this.state; - if (!result || !result.projectKey || !result.os || !token) { - return null; - } - return ( - - ); - }; - - renderResult = () => null; - - render() { - return ( - {}} - open={this.props.open} - renderForm={this.renderForm} - renderResult={this.renderResult} - stepNumber={this.props.stepNumber} - stepTitle={translate('onboarding.analysis.header')} - /> - ); - } -} diff --git a/server/sonar-web/src/main/js/apps/tutorials/projectOnboarding/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 { stepNumber={stepNumber++} /> - - - - - - isSonarCloud() - ? import('./createProjectOnboarding/CreateProjectOnboarding') + ? import('./onboarding/OnboardingPage') : import('./projectOnboarding/ProjectOnboardingPage') ) } diff --git a/server/sonar-web/src/main/js/apps/tutorials/styles.css b/server/sonar-web/src/main/js/apps/tutorials/styles.css index 798fce21bcc..da2571a369d 100644 --- a/server/sonar-web/src/main/js/apps/tutorials/styles.css +++ b/server/sonar-web/src/main/js/apps/tutorials/styles.css @@ -58,8 +58,7 @@ .onboarding-choices { display: flex; justify-content: space-around; - padding-top: 44px; - padding-bottom: 44px; + padding: 44px 0; background-color: var(--barBackgroundColor); } diff --git a/server/sonar-web/src/main/js/apps/tutorials/utils.ts b/server/sonar-web/src/main/js/apps/tutorials/utils.ts new file mode 100644 index 00000000000..f84785ef61d --- /dev/null +++ b/server/sonar-web/src/main/js/apps/tutorials/utils.ts @@ -0,0 +1,40 @@ +/* + * SonarQube + * Copyright (C) 2009-2018 SonarSource SA + * mailto:info AT sonarsource DOT com + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ +export interface LanguageConfig { + language?: string; + javaBuild?: string; + cFamilyCompiler?: string; + os?: string; + projectKey?: string; +} + +export function isLanguageConfigured(config?: LanguageConfig) { + if (!config) { + return false; + } + const { language, javaBuild, cFamilyCompiler, os, projectKey } = config; + const isJavaConfigured = language === 'java' && javaBuild != null; + const isDotNetConfigured = language === 'dotnet' && projectKey != null; + const isCFamilyConfigured = + language === 'c-family' && (cFamilyCompiler === 'msvc' || os != null) && projectKey != null; + const isOtherConfigured = language === 'other' && projectKey != null; + + return isJavaConfigured || isDotNetConfigured || isCFamilyConfigured || isOtherConfigured; +} diff --git a/server/sonar-web/src/main/js/components/icons-components/OnboardingPrivateIcon.tsx b/server/sonar-web/src/main/js/components/icons-components/OnboardingPrivateIcon.tsx index 3592d9b0be0..7542f09a3aa 100644 --- a/server/sonar-web/src/main/js/components/icons-components/OnboardingPrivateIcon.tsx +++ b/server/sonar-web/src/main/js/components/icons-components/OnboardingPrivateIcon.tsx @@ -26,7 +26,7 @@ export default function OnboardingPrivateIcon({ size }: IconProps) { return ( - + diff --git a/server/sonar-web/src/main/js/components/icons-components/OnboardingProjectIcon.tsx b/server/sonar-web/src/main/js/components/icons-components/OnboardingProjectIcon.tsx index d2090eed867..d97972db6e7 100644 --- a/server/sonar-web/src/main/js/components/icons-components/OnboardingProjectIcon.tsx +++ b/server/sonar-web/src/main/js/components/icons-components/OnboardingProjectIcon.tsx @@ -26,7 +26,7 @@ export default function OnboardingProjectIcon({ size }: IconProps) { return ( - + diff --git a/server/sonar-web/src/main/js/components/icons-components/OnboardingTeamIcon.tsx b/server/sonar-web/src/main/js/components/icons-components/OnboardingTeamIcon.tsx index 6ce74838a0d..023067e74a8 100644 --- a/server/sonar-web/src/main/js/components/icons-components/OnboardingTeamIcon.tsx +++ b/server/sonar-web/src/main/js/components/icons-components/OnboardingTeamIcon.tsx @@ -22,7 +22,7 @@ import Icon, { IconProps } from './Icon'; export default function OnboardingTeamIcon({ className, fill = 'currentColor', size }: IconProps) { return ( - + diff --git a/server/sonar-web/src/main/js/components/ui/buttons.css b/server/sonar-web/src/main/js/components/ui/buttons.css index cc24ba79baf..032c0255117 100644 --- a/server/sonar-web/src/main/js/components/ui/buttons.css +++ b/server/sonar-web/src/main/js/components/ui/buttons.css @@ -130,6 +130,10 @@ transition: all 0.2s ease; } +.dropdown .button-link { + border-bottom: none; +} + .button-link:hover { background: transparent; color: var(--blue); diff --git a/server/sonar-web/src/main/js/helpers/markdown.js b/server/sonar-web/src/main/js/helpers/markdown.js index 7f1c21325df..633c3450289 100644 --- a/server/sonar-web/src/main/js/helpers/markdown.js +++ b/server/sonar-web/src/main/js/helpers/markdown.js @@ -72,7 +72,7 @@ function parseFrontMatter(lines) { * @returns {string} */ function filterContent(content) { - const { isSonarCloud } = require('../helpers/system'); + const { isSonarCloud } = require('./system'); const contentWithoutStatic = cutConditionalContent(content, 'static'); return isSonarCloud() ? cutConditionalContent(contentWithoutStatic, 'sonarqube') diff --git a/server/sonar-web/src/main/js/helpers/urls.ts b/server/sonar-web/src/main/js/helpers/urls.ts index 4d17bde0b09..9d3959260bf 100644 --- a/server/sonar-web/src/main/js/helpers/urls.ts +++ b/server/sonar-web/src/main/js/helpers/urls.ts @@ -49,10 +49,6 @@ export function getPathUrlAsString(path: Location): string { return `${getBaseUrl()}${path.pathname}?${stringify(omitBy(path.query, isNil))}`; } -export function getSonarCloudUrlAsString(location: Location) { - return 'https://sonarcloud.io' + getPathUrlAsString(location); -} - export function getProjectUrl(project: string, branch?: string): Location { return { pathname: '/dashboard', query: { id: project, branch } }; } diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties index 2265fcc9f90..a2e9ef14fc6 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -1496,9 +1496,10 @@ my_account.create_new_organization=Create new organization #------------------------------------------------------------------------------ provisioning.create_new_project=Create new project provisioning.no_analysis=No analysis has been performed since creation. The only available section is the configuration. -provisioning.no_analysis.delete=Either you should retry analysis or simply {0}. +provisioning.no_analysis.delete=Either you should retry analysis or simply {link}. provisioning.no_analysis.delete_project=delete the project -provisioning.no_analysis_on_main_branch={branch} has not been analyzed yet. +provisioning.no_analysis_on_main_branch="{branchName}" branch has not been analyzed yet. +provisioning.no_analysis_on_main_branch.bad_configuration="{branchName}" branch has not been analyzed yet and you have multiple branches already. It looks like it is not your {branchType}, check your configuration. provisioning.only_provisioned=Only Provisioned provisioning.only_provisioned.tooltip=Provisioned projects are projects that have been created, but have not been analyzed yet. @@ -2659,13 +2660,21 @@ onboarding.footer=Don't worry you can do all of this later. Just click the "+" i onboarding.project.header=Analyze a project onboarding.project.header.description=Want to quickly analyze a first project? Follow these {0} easy steps. +onboarding.project_analysis.header=Analyze your project +onboarding.project_analysis.description=We initialized your project on SonarCloud, now it's up to you to launch analyses! +onboarding.project_analysis.commands_for_analysis=Bellow are the commands to use to do an analysis. +onboarding.project_analysis.guide_to_integrate_piplines=follow the guide to integrating with Pipelines +onboarding.project_analysis.guide_to_integrate_travis=follow the guide to integrating with Travis CI +onboarding.project_analysis.guide_to_integrate_vsts=follow the guide to integrating with VSTS +onboarding.project_analysis.simply_link=Simply {link}. +onboarding.project_analysis.suggestions.bitbucket=If you are using Bitbucket Cloud Pipelines, the SonarCloud App makes it easier to run these commands with your CI process. +onboarding.project_analysis.suggestions.github=If you are using Travis CI, the SonarCloud Travis Add-on makes it easier to run these commands with your CI process. + onboarding.create_project.header=Create project(s) onboarding.create_project.already_imported=Repository already imported -onboarding.create_project.beta_feature_x=This feature is being beta tested. We offer to create projects from your {0} repositories only for public personal projects on your personal SonarCloud organization. For other kind of projects please create them maually. +onboarding.create_project.beta_feature_x=This feature is being beta tested. We offer to create projects from your {0} repositories only for public personal projects on your personal SonarCloud organization. For other kind of projects please create them manually. onboarding.create_project.create_manually=Create manually onboarding.create_project.create_new_org=I want to create another organization -onboarding.create_project.create_project=Create project -onboarding.create_project.create_projects=Create projects onboarding.create_project.install_app_x=We need you to install the Sonarcloud {0} application in order to select which repositories you want to analyze. onboarding.create_project.install_app_x.button=Install SonarCloud {0} application onboarding.create_project.organization=Organization @@ -2706,9 +2715,11 @@ onboarding.organization.key_requirement=2 to 32 characters. All chars must be lo onboarding.project_key_requirement=Allowed characters are alphanumeric, '-', '_', '.' and ':', with at least one non-digit. 400 characters max. onboarding.analysis.header=Run analysis on your project +onboarding.analysis.auto_refresh_after_analysis=Once the analysis is completed, this page will automatically refresh and you will be able to browse the analysis results. onboarding.analysis.browse_url_after_analysis=Once the analysis is completed, you will be able to browse your project at the URL displayed at the end of the logs. onboarding.language=What is your project's main language? +onboarding.language.header=Which primary language are you using? onboarding.language.java=Java onboarding.language.java.build_technology=You are developing primarily in Java: what is your build technology? onboarding.language.java.build_technology.maven=Maven -- 2.39.5