diff options
author | Pascal Mugnier <pascal.mugnier@sonarsource.com> | 2018-06-21 11:08:48 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2018-06-29 09:10:16 +0200 |
commit | e5827b3671013c14776ca189e400e3687bfa0983 (patch) | |
tree | 74bbf5d4f5bd10c1c214c7252b349df31137ce52 /server/sonar-web/src/main/js/app | |
parent | f94bc6f1b9be3b9180aef88abe1804b4aaaa194a (diff) | |
download | sonarqube-e5827b3671013c14776ca189e400e3687bfa0983.tar.gz sonarqube-e5827b3671013c14776ca189e400e3687bfa0983.zip |
SONAR-10813 Add project branches
Diffstat (limited to 'server/sonar-web/src/main/js/app')
9 files changed, 87 insertions, 28 deletions
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBranch.tsx b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBranch.tsx index 8cba10a5dbc..d02389be63d 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBranch.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBranch.tsx @@ -20,6 +20,7 @@ import * as React from 'react'; import * as PropTypes from 'prop-types'; import { FormattedMessage } from 'react-intl'; +import { Link } from 'react-router'; import ComponentNavBranchesMenu from './ComponentNavBranchesMenu'; import DocTooltip from '../../../../components/docs/DocTooltip'; import { BranchLike, Component } from '../../../types'; @@ -53,7 +54,8 @@ export default class ComponentNavBranch extends React.PureComponent<Props, State mounted = false; static contextTypes = { - branchesEnabled: PropTypes.bool.isRequired + branchesEnabled: PropTypes.bool.isRequired, + canAdmin: PropTypes.bool.isRequired }; state: State = { @@ -125,17 +127,34 @@ export default class ComponentNavBranch extends React.PureComponent<Props, State } }; + renderOverlay = () => { + const adminLink = { + pathname: '/project/admin/extension/governance/console', + query: { id: this.props.component.breadcrumbs[0].key, qualifier: 'APP' } + }; + return ( + <> + <p>{translate('application.branches.help')}</p> + <hr className="spacer-top spacer-bottom" /> + <Link className="spacer-left link-no-underline" to={adminLink}> + {translate('application.branches.link')} + </Link> + </> + ); + }; + render() { const { branchLikes, currentBranchLike } = this.props; - const { configuration } = this.props.component; + const { configuration, breadcrumbs } = this.props.component; if (isSonarCloud() && !this.context.branchesEnabled) { return null; } const displayName = getBranchLikeDisplayName(currentBranchLike); + const isApp = breadcrumbs && breadcrumbs[0] && breadcrumbs[0].qualifier === 'APP'; - if (!this.context.branchesEnabled) { + if (isApp && branchLikes.length < 2) { return ( <div className="navbar-context-branches"> <BranchIcon @@ -144,23 +163,42 @@ export default class ComponentNavBranch extends React.PureComponent<Props, State fill={theme.gray80} /> <span className="note">{displayName}</span> - <DocTooltip className="spacer-left" doc="branches/no-branch-support"> - <PlusCircleIcon fill={theme.gray71} size={12} /> - </DocTooltip> - </div> - ); - } - - if (branchLikes.length < 2) { - return ( - <div className="navbar-context-branches"> - <BranchIcon branchLike={currentBranchLike} className="little-spacer-right" /> - <span className="note">{displayName}</span> - <DocTooltip className="spacer-left" doc="branches/single-branch"> - <PlusCircleIcon fill={theme.blue} size={12} /> - </DocTooltip> + {configuration && + configuration.showSettings && ( + <HelpTooltip className="spacer-left" overlay={this.renderOverlay()}> + <PlusCircleIcon className="vertical-middle" fill={theme.blue} size={12} /> + </HelpTooltip> + )} </div> ); + } else { + if (!this.context.branchesEnabled) { + return ( + <div className="navbar-context-branches"> + <BranchIcon + branchLike={currentBranchLike} + className="little-spacer-right" + fill={theme.gray80} + /> + <span className="note">{displayName}</span> + <DocTooltip className="spacer-left" doc="branches/no-branch-support"> + <PlusCircleIcon fill={theme.gray71} size={12} /> + </DocTooltip> + </div> + ); + } + + if (branchLikes.length < 2) { + return ( + <div className="navbar-context-branches"> + <BranchIcon branchLike={currentBranchLike} className="little-spacer-right" /> + <span className="note">{displayName}</span> + <DocTooltip className="spacer-left" doc="branches/single-branch"> + <PlusCircleIcon fill={theme.blue} size={12} /> + </DocTooltip> + </div> + ); + } } return ( diff --git a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMenu.tsx b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMenu.tsx index 1f3045cfc52..53009cc4d40 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMenu.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMenu.tsx @@ -400,9 +400,10 @@ export default class ComponentNavMenu extends React.PureComponent<Props> { renderExtension = ({ key, name }: Extension, isAdmin: boolean) => { const pathname = isAdmin ? `/project/admin/extension/${key}` : `/project/extension/${key}`; + const query = { id: this.props.component.key, qualifier: this.props.component.qualifier }; return ( <li key={key}> - <Link to={{ pathname, query: { id: this.props.component.key } }} activeClassName="active"> + <Link activeClassName="active" to={{ pathname, query }}> {name} </Link> </li> diff --git a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMeta.tsx b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMeta.tsx index 6b52b5eefbf..7b2f2e2c221 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMeta.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavMeta.tsx @@ -111,7 +111,8 @@ function getCurrentPage(component: Component, branchLike: BranchLike | undefined if (component.qualifier === 'VW' || component.qualifier === 'SVW') { currentPage = { type: HomePageType.Portfolio, component: component.key }; } else if (component.qualifier === 'APP') { - currentPage = { type: HomePageType.Application, component: component.key }; + const branch = isLongLivingBranch(branchLike) ? branchLike.name : undefined; + currentPage = { type: HomePageType.Application, component: component.key, branch }; } else if (component.qualifier === 'TRK') { // when home page is set to the default branch of a project, its name is returned as `undefined` const branch = isLongLivingBranch(branchLike) ? branchLike.name : undefined; diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavBranch-test.tsx b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavBranch-test.tsx index 9a805b74c82..3fd20dbc41e 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavBranch-test.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavBranch-test.tsx @@ -49,7 +49,7 @@ it('renders main branch', () => { component={component} currentBranchLike={mainBranch} />, - { context: { branchesEnabled: true } } + { context: { branchesEnabled: true, canAdmin: true } } ) ).toMatchSnapshot(); }); @@ -70,7 +70,7 @@ it('renders short-living branch', () => { component={component} currentBranchLike={branch} />, - { context: { branchesEnabled: true } } + { context: { branchesEnabled: true, canAdmin: true } } ) ).toMatchSnapshot(); }); @@ -91,7 +91,7 @@ it('renders pull request', () => { component={component} currentBranchLike={pullRequest} />, - { context: { branchesEnabled: true } } + { context: { branchesEnabled: true, canAdmin: true } } ) ).toMatchSnapshot(); }); @@ -104,7 +104,7 @@ it('opens menu', () => { component={component} currentBranchLike={mainBranch} />, - { context: { branchesEnabled: true } } + { context: { branchesEnabled: true, canAdmin: true } } ); expect(wrapper.find('Toggler').prop('open')).toBe(false); click(wrapper.find('a')); @@ -119,7 +119,7 @@ it('renders single branch popup', () => { component={component} currentBranchLike={mainBranch} />, - { context: { branchesEnabled: true } } + { context: { branchesEnabled: true, canAdmin: true } } ); expect(wrapper.find('DocTooltip')).toMatchSnapshot(); }); @@ -132,7 +132,7 @@ it('renders no branch support popup', () => { component={component} currentBranchLike={mainBranch} />, - { context: { branchesEnabled: false } } + { context: { branchesEnabled: false, canAdmin: true } } ); expect(wrapper.find('DocTooltip')).toMatchSnapshot(); }); @@ -146,7 +146,7 @@ it('renders nothing on SonarCloud without branch support', () => { component={component} currentBranchLike={mainBranch} />, - { context: { branchesEnabled: false, onSonarCloud: true } } + { context: { branchesEnabled: false, onSonarCloud: true, canAdmin: true } } ); expect(wrapper.type()).toBeNull(); }); diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBranchesMenuItem-test.tsx.snap b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBranchesMenuItem-test.tsx.snap index b4c9f37a5d3..25528a5523c 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBranchesMenuItem-test.tsx.snap +++ b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBranchesMenuItem-test.tsx.snap @@ -13,6 +13,7 @@ exports[`renders main branch 1`] = ` Object { "pathname": "/dashboard", "query": Object { + "branch": undefined, "id": "component", }, } diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavHeader-test.tsx.snap b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavHeader-test.tsx.snap index 4d85fb56b11..b8498689bda 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavHeader-test.tsx.snap +++ b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavHeader-test.tsx.snap @@ -23,6 +23,7 @@ exports[`should not render breadcrumbs with one element 1`] = ` Object { "pathname": "/dashboard", "query": Object { + "branch": undefined, "id": "my-project", }, } @@ -90,6 +91,7 @@ exports[`should render organization 1`] = ` Object { "pathname": "/dashboard", "query": Object { + "branch": undefined, "id": "my-project", }, } diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavMenu-test.tsx.snap b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavMenu-test.tsx.snap index 3abe30c25f4..a62c3ce9e0e 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavMenu-test.tsx.snap +++ b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavMenu-test.tsx.snap @@ -873,6 +873,7 @@ exports[`should work with extensions 1`] = ` "pathname": "/project/extension/component-foo", "query": Object { "id": "foo", + "qualifier": "TRK", }, } } @@ -954,6 +955,7 @@ exports[`should work with extensions 2`] = ` "pathname": "/project/admin/extension/foo", "query": Object { "id": "foo", + "qualifier": "TRK", }, } } @@ -1001,6 +1003,7 @@ exports[`should work with multiple extensions 1`] = ` "pathname": "/project/extension/component-foo", "query": Object { "id": "foo", + "qualifier": "TRK", }, } } @@ -1018,6 +1021,7 @@ exports[`should work with multiple extensions 1`] = ` "pathname": "/project/extension/component-bar", "query": Object { "id": "foo", + "qualifier": "TRK", }, } } @@ -1099,6 +1103,7 @@ exports[`should work with multiple extensions 2`] = ` "pathname": "/project/admin/extension/foo", "query": Object { "id": "foo", + "qualifier": "TRK", }, } } @@ -1116,6 +1121,7 @@ exports[`should work with multiple extensions 2`] = ` "pathname": "/project/admin/extension/bar", "query": Object { "id": "foo", + "qualifier": "TRK", }, } } diff --git a/server/sonar-web/src/main/js/app/components/search/__tests__/__snapshots__/SearchResult-test.js.snap b/server/sonar-web/src/main/js/app/components/search/__tests__/__snapshots__/SearchResult-test.js.snap index 4ad1c1e2e2d..0a9d6781bf0 100644 --- a/server/sonar-web/src/main/js/app/components/search/__tests__/__snapshots__/SearchResult-test.js.snap +++ b/server/sonar-web/src/main/js/app/components/search/__tests__/__snapshots__/SearchResult-test.js.snap @@ -21,6 +21,7 @@ exports[`renders favorite 1`] = ` Object { "pathname": "/dashboard", "query": Object { + "branch": undefined, "id": "foo", }, } @@ -69,6 +70,7 @@ exports[`renders match 1`] = ` Object { "pathname": "/dashboard", "query": Object { + "branch": undefined, "id": "foo", }, } @@ -116,6 +118,7 @@ exports[`renders organizations 1`] = ` Object { "pathname": "/dashboard", "query": Object { + "branch": undefined, "id": "foo", }, } @@ -168,6 +171,7 @@ exports[`renders organizations 2`] = ` Object { "pathname": "/dashboard", "query": Object { + "branch": undefined, "id": "foo", }, } @@ -215,6 +219,7 @@ exports[`renders projects 1`] = ` Object { "pathname": "/dashboard", "query": Object { + "branch": undefined, "id": "qwe", }, } @@ -267,6 +272,7 @@ exports[`renders recently browsed 1`] = ` Object { "pathname": "/dashboard", "query": Object { + "branch": undefined, "id": "foo", }, } @@ -314,6 +320,7 @@ exports[`renders selected 1`] = ` Object { "pathname": "/dashboard", "query": Object { + "branch": undefined, "id": "foo", }, } @@ -359,6 +366,7 @@ exports[`renders selected 2`] = ` Object { "pathname": "/dashboard", "query": Object { + "branch": undefined, "id": "foo", }, } diff --git a/server/sonar-web/src/main/js/app/types.ts b/server/sonar-web/src/main/js/app/types.ts index 11e29502c06..75ac42d3237 100644 --- a/server/sonar-web/src/main/js/app/types.ts +++ b/server/sonar-web/src/main/js/app/types.ts @@ -169,7 +169,7 @@ export interface Group { } export type HomePage = - | { type: HomePageType.Application; component: string } + | { type: HomePageType.Application; branch: string | undefined; component: string } | { type: HomePageType.Issues } | { type: HomePageType.MyIssues } | { type: HomePageType.MyProjects } @@ -220,6 +220,7 @@ export interface Issue { assigneeLogin?: string; assigneeName?: string; author?: string; + branch?: string; comments?: IssueComment[]; component: string; componentLongName: string; @@ -237,6 +238,7 @@ export interface Issue { projectName: string; projectOrganization: string; projectUuid: string; + pullRequest?: string; resolution?: string; rule: string; ruleName: string; |