diff options
author | Stas Vilchik <stas.vilchik@sonarsource.com> | 2017-12-14 12:20:38 +0100 |
---|---|---|
committer | Stas Vilchik <stas.vilchik@sonarsource.com> | 2018-01-02 10:38:10 +0100 |
commit | 7b757f90537d99f1863407dfd2667874561d53aa (patch) | |
tree | 8c19f29af2c49718805962a2ab824e8ffaef0b83 /server/sonar-web/src/main/js/app/components | |
parent | 027514e6f94607fcd7df8e69e668fe32aeb2873e (diff) | |
download | sonarqube-7b757f90537d99f1863407dfd2667874561d53aa.tar.gz sonarqube-7b757f90537d99f1863407dfd2667874561d53aa.zip |
SONAR-10188 Update project/organization header
Diffstat (limited to 'server/sonar-web/src/main/js/app/components')
13 files changed, 238 insertions, 267 deletions
diff --git a/server/sonar-web/src/main/js/app/components/ComponentContainerNotFound.tsx b/server/sonar-web/src/main/js/app/components/ComponentContainerNotFound.tsx index e87bea11cce..c097f03da96 100644 --- a/server/sonar-web/src/main/js/app/components/ComponentContainerNotFound.tsx +++ b/server/sonar-web/src/main/js/app/components/ComponentContainerNotFound.tsx @@ -21,32 +21,16 @@ import * as React from 'react'; import { Link } from 'react-router'; import { translate } from '../../helpers/l10n'; -export default class ComponentContainerNotFound extends React.PureComponent { - componentDidMount() { - const html = document.querySelector('html'); - if (html) { - html.classList.add('dashboard-page'); - } - } - - componentWillUnmount() { - const html = document.querySelector('html'); - if (html) { - html.classList.remove('dashboard-page'); - } - } - - render() { - return ( - <div id="bd" className="page-wrapper-simple"> - <div id="nonav" className="page-simple"> - <h2 className="big-spacer-bottom">{translate('dashboard.project_not_found')}</h2> - <p className="spacer-bottom">{translate('dashboard.project_not_found.2')}</p> - <p> - <Link to="/">Go back to the homepage</Link> - </p> - </div> +export default function ComponentContainerNotFound() { + return ( + <div id="bd" className="page-wrapper-simple"> + <div id="nonav" className="page-simple"> + <h2 className="big-spacer-bottom">{translate('dashboard.project_not_found')}</h2> + <p className="spacer-bottom">{translate('dashboard.project_not_found.2')}</p> + <p> + <Link to="/">Go back to the homepage</Link> + </p> </div> - ); - } + </div> + ); } diff --git a/server/sonar-web/src/main/js/app/components/SimpleContainer.tsx b/server/sonar-web/src/main/js/app/components/SimpleContainer.tsx index 4e5e35b7cce..8c2efc977af 100644 --- a/server/sonar-web/src/main/js/app/components/SimpleContainer.tsx +++ b/server/sonar-web/src/main/js/app/components/SimpleContainer.tsx @@ -27,35 +27,19 @@ interface Props { hideLoggedInInfo?: boolean; } -export default class SimpleContainer extends React.PureComponent<Props> { - componentDidMount() { - const html = document.querySelector('html'); - if (html) { - html.classList.add('dashboard-page'); - } - } +export default function SimpleContainer(props: Props) { + return ( + <div className="global-container"> + <div className="page-wrapper" id="container"> + <NavBar className="navbar-global" height={theme.globalNavHeightRaw} /> - componentWillUnmount() { - const html = document.querySelector('html'); - if (html) { - html.classList.remove('dashboard-page'); - } - } - - render() { - return ( - <div className="global-container"> - <div className="page-wrapper" id="container"> - <NavBar className="navbar-global" height={theme.globalNavHeightRaw} /> - - <div id="bd" className="page-wrapper-simple"> - <div id="nonav" className="page-simple"> - {this.props.children} - </div> + <div id="bd" className="page-wrapper-simple"> + <div id="nonav" className="page-simple"> + {props.children} </div> </div> - <GlobalFooterContainer hideLoggedInInfo={this.props.hideLoggedInInfo} /> </div> - ); - } + <GlobalFooterContainer hideLoggedInInfo={props.hideLoggedInInfo} /> + </div> + ); } diff --git a/server/sonar-web/src/main/js/app/components/extensions/ExtensionNotFound.tsx b/server/sonar-web/src/main/js/app/components/extensions/ExtensionNotFound.tsx index 154b674f6b9..1cad19e3d20 100644 --- a/server/sonar-web/src/main/js/app/components/extensions/ExtensionNotFound.tsx +++ b/server/sonar-web/src/main/js/app/components/extensions/ExtensionNotFound.tsx @@ -20,34 +20,18 @@ import * as React from 'react'; import { Link } from 'react-router'; -export default class ExtensionNotFound extends React.PureComponent { - componentDidMount() { - const html = document.querySelector('html'); - if (html) { - html.classList.add('dashboard-page'); - } - } - - componentWillUnmount() { - const html = document.querySelector('html'); - if (html) { - html.classList.remove('dashboard-page'); - } - } - - render() { - return ( - <div id="bd" className="page-wrapper-simple"> - <div id="nonav" className="page-simple"> - <h2 className="big-spacer-bottom">The page you were looking for does not exist.</h2> - <p className="spacer-bottom"> - You may have mistyped the address or the page may have moved. - </p> - <p> - <Link to="/">Go back to the homepage</Link> - </p> - </div> +export default function ExtensionNotFound() { + return ( + <div id="bd" className="page-wrapper-simple"> + <div id="nonav" className="page-simple"> + <h2 className="big-spacer-bottom">The page you were looking for does not exist.</h2> + <p className="spacer-bottom"> + You may have mistyped the address or the page may have moved. + </p> + <p> + <Link to="/">Go back to the homepage</Link> + </p> </div> - ); - } + </div> + ); } diff --git a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.css b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.css index fd0f3a46df1..f9488b415e3 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.css +++ b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.css @@ -1,9 +1,9 @@ .navbar-context-branches { - display: inline-block; - vertical-align: top; - padding: var(--gridSize) 0; + display: inline-flex; + justify-content: center; + line-height: calc(2 * var(--gridSize)); margin-left: calc(2 * var(--gridSize)); - line-height: 16px; + font-size: var(--baseFontSize); } .navbar-context-meta-branch-menu-item { diff --git a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.tsx b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.tsx index ff2205adbb6..7d4cd235925 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNav.tsx @@ -18,8 +18,7 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import * as React from 'react'; -import ComponentNavBranch from './ComponentNavBranch'; -import ComponentNavBreadcrumbs from './ComponentNavBreadcrumbs'; +import ComponentNavHeader from './ComponentNavHeader'; import ComponentNavMeta from './ComponentNavMeta'; import ComponentNavMenu from './ComponentNavMenu'; import ComponentNavBgTaskNotif from './ComponentNavBgTaskNotif'; @@ -111,16 +110,13 @@ export default class ComponentNav extends React.PureComponent<Props, State> { id="context-navigation" height={notifComponent ? theme.contextNavHeightRaw + 20 : theme.contextNavHeightRaw} notif={notifComponent}> - <ComponentNavBreadcrumbs component={this.props.component} /> - {this.props.currentBranch && ( - <ComponentNavBranch - branches={this.props.branches} - component={this.props.component} - currentBranch={this.props.currentBranch} - // to close dropdown on any location change - location={this.props.location} - /> - )} + <ComponentNavHeader + branches={this.props.branches} + component={this.props.component} + currentBranch={this.props.currentBranch} + // to close dropdown on any location change + location={this.props.location} + /> <ComponentNavMeta branch={this.props.currentBranch} component={this.props.component} /> <ComponentNavMenu branch={this.props.currentBranch} diff --git a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBreadcrumbs.tsx b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavHeader.tsx index c8a75e8a105..e042b010d2e 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavBreadcrumbs.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/component/ComponentNavHeader.tsx @@ -20,7 +20,8 @@ import * as React from 'react'; import { connect } from 'react-redux'; import { Link } from 'react-router'; -import { Component, Organization } from '../../../types'; +import ComponentNavBranch from './ComponentNavBranch'; +import { Component, Organization, Branch, Breadcrumb } from '../../../types'; import QualifierIcon from '../../../../components/shared/QualifierIcon'; import { getOrganizationByKey, areThereCustomOrganizations } from '../../../../store/rootReducer'; import OrganizationAvatar from '../../../../components/common/OrganizationAvatar'; @@ -36,46 +37,16 @@ interface StateProps { } interface OwnProps { + branches: Branch[]; component: Component; + currentBranch?: Branch; + location?: any; } interface Props extends StateProps, OwnProps {} -export function ComponentNavBreadcrumbs(props: Props) { +export function ComponentNavHeader(props: Props) { const { component, organization, shouldOrganizationBeDisplayed } = props; - const { breadcrumbs } = component; - - const lastItem = breadcrumbs[breadcrumbs.length - 1]; - - const items: JSX.Element[] = []; - breadcrumbs.forEach((item, index) => { - const isPath = item.qualifier === 'DIR'; - const itemName = isPath ? collapsePath(item.name, 15) : limitComponentName(item.name); - - if (index === 0) { - items.push( - <QualifierIcon - className="spacer-right" - key={`qualifier-${item.key}`} - qualifier={lastItem.qualifier} - /> - ); - } - - items.push( - <Link - className="link-base-color link-no-underline" - key={`name-${item.key}`} - title={item.name} - to={getProjectUrl(item.key)}> - {itemName} - </Link> - ); - - if (index < breadcrumbs.length - 1) { - items.push(<span className="slash-separator" key={`separator-${item.key}`} />); - } - }); return ( <header className="navbar-context-header"> @@ -84,28 +55,59 @@ export function ComponentNavBreadcrumbs(props: Props) { organization={organization && shouldOrganizationBeDisplayed ? organization : undefined} /> {organization && - shouldOrganizationBeDisplayed && <OrganizationAvatar organization={organization} />} - {organization && shouldOrganizationBeDisplayed && ( - <OrganizationLink - organization={organization} - className="link-base-color link-no-underline spacer-left"> - {organization.name} - </OrganizationLink> + <> + <OrganizationAvatar organization={organization} /> + <OrganizationLink + organization={organization} + className="link-base-color link-no-underline spacer-left"> + {organization.name} + </OrganizationLink> + <span className="slash-separator" /> + </> )} - {organization && shouldOrganizationBeDisplayed && <span className="slash-separator" />} - {items} + {renderBreadcrumbs(component.breadcrumbs)} {component.visibility === 'private' && ( <PrivateBadge className="spacer-left" qualifier={component.qualifier} /> )} + {props.currentBranch && ( + <ComponentNavBranch + branches={props.branches} + component={component} + currentBranch={props.currentBranch} + // to close dropdown on any location change + location={props.location} + /> + )} </header> ); } +function renderBreadcrumbs(breadcrumbs: Breadcrumb[]) { + const lastItem = breadcrumbs[breadcrumbs.length - 1]; + return breadcrumbs.map((item, index) => { + const isPath = item.qualifier === 'DIR'; + const itemName = isPath ? collapsePath(item.name, 15) : limitComponentName(item.name); + + return ( + <React.Fragment key={item.key}> + {index === 0 && <QualifierIcon className="spacer-right" qualifier={lastItem.qualifier} />} + <Link + className="link-base-color link-no-underline" + title={item.name} + to={getProjectUrl(item.key)}> + {itemName} + </Link> + {index < breadcrumbs.length - 1 && <span className="slash-separator" />} + </React.Fragment> + ); + }); +} + const mapStateToProps = (state: any, ownProps: OwnProps): StateProps => ({ organization: ownProps.component.organization && getOrganizationByKey(state, ownProps.component.organization), shouldOrganizationBeDisplayed: areThereCustomOrganizations(state) }); -export default connect(mapStateToProps)(ComponentNavBreadcrumbs); +export default connect(mapStateToProps)(ComponentNavHeader); 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 01be74777a6..3b080ac9d4b 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 @@ -19,7 +19,7 @@ */ import * as React from 'react'; import { connect } from 'react-redux'; -import { Branch, Component, CurrentUser, isLoggedIn } from '../../../types'; +import { Branch, Component, CurrentUser, isLoggedIn, HomePageType } from '../../../types'; import BranchStatus from '../../../../components/common/BranchStatus'; import DateTimeFormatter from '../../../../components/intl/DateTimeFormatter'; import Favorite from '../../../../components/controls/Favorite'; @@ -60,14 +60,22 @@ export function ComponentNavMeta({ branch, component, currentUser }: Props) { {isLoggedIn(currentUser) && mainBranch && ( <div className="navbar-context-meta-secondary"> - <Favorite component={component.key} favorite={Boolean(component.isFavorite)} /> + <Favorite + component={component.key} + favorite={Boolean(component.isFavorite)} + qualifier={component.qualifier} + /> <HomePageSelect className="spacer-left" - currentPage={{ type: 'project', key: component.key }} + currentPage={{ type: HomePageType.Project, parameter: component.key }} /> </div> )} - {shortBranch && <BranchStatus branch={branch!} />} + {shortBranch && ( + <div className="navbar-context-meta-secondary"> + <BranchStatus branch={branch!} /> + </div> + )} </div> ); } diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNav-test.tsx b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNav-test.tsx index 26f876d34f0..4c30ef3b3a4 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNav-test.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNav-test.tsx @@ -29,9 +29,9 @@ jest.mock('../ComponentNavMeta', () => ({ } })); -jest.mock('../ComponentNavBreadcrumbs', () => ({ +jest.mock('../ComponentNavHeader', () => ({ // eslint-disable-next-line - default: function ComponentNavBreadcrumbs() { + default: function ComponentNavHeader() { return null; } })); diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavBreadcrumbs-test.tsx b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavHeader-test.tsx index 78a2eed1234..89d10f4ac78 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavBreadcrumbs-test.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/ComponentNavHeader-test.tsx @@ -19,7 +19,7 @@ */ import * as React from 'react'; import { shallow } from 'enzyme'; -import { ComponentNavBreadcrumbs } from '../ComponentNavBreadcrumbs'; +import { ComponentNavHeader } from '../ComponentNavHeader'; import { Visibility } from '../../../../types'; it('should not render breadcrumbs with one element', () => { @@ -32,7 +32,7 @@ it('should not render breadcrumbs with one element', () => { visibility: 'public' }; const result = shallow( - <ComponentNavBreadcrumbs component={component} shouldOrganizationBeDisplayed={false} /> + <ComponentNavHeader branches={[]} component={component} shouldOrganizationBeDisplayed={false} /> ); expect(result).toMatchSnapshot(); }); @@ -52,7 +52,8 @@ it('should render organization', () => { projectVisibility: Visibility.Public }; const result = shallow( - <ComponentNavBreadcrumbs + <ComponentNavHeader + branches={[]} component={component} organization={organization} shouldOrganizationBeDisplayed={true} @@ -71,7 +72,7 @@ it('renders private badge', () => { visibility: 'private' }; const result = shallow( - <ComponentNavBreadcrumbs component={component} shouldOrganizationBeDisplayed={false} /> + <ComponentNavHeader branches={[]} component={component} shouldOrganizationBeDisplayed={false} /> ); expect(result.find('PrivateBadge')).toHaveLength(1); }); diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNav-test.tsx.snap b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNav-test.tsx.snap index 6fea2eff38e..25470b77544 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNav-test.tsx.snap +++ b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNav-test.tsx.snap @@ -27,7 +27,8 @@ exports[`renders 1`] = ` /> } > - <ComponentNavBreadcrumbs + <ComponentNavHeader + branches={Array []} component={ Object { "breadcrumbs": Array [ @@ -43,6 +44,7 @@ exports[`renders 1`] = ` "qualifier": "TRK", } } + location={Object {}} /> <ComponentNavMeta component={ diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBreadcrumbs-test.tsx.snap b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBreadcrumbs-test.tsx.snap deleted file mode 100644 index e907a97d1b5..00000000000 --- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavBreadcrumbs-test.tsx.snap +++ /dev/null @@ -1,98 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`should not render breadcrumbs with one element 1`] = ` -<header - className="navbar-context-header" -> - <OrganizationHelmet - title="My Project" - /> - <QualifierIcon - className="spacer-right" - key="qualifier-my-project" - qualifier="TRK" - /> - <Link - className="link-base-color link-no-underline" - key="name-my-project" - onlyActiveOnIndex={false} - style={Object {}} - title="My Project" - to={ - Object { - "pathname": "/dashboard", - "query": Object { - "branch": undefined, - "id": "my-project", - }, - } - } - > - My Project - </Link> -</header> -`; - -exports[`should render organization 1`] = ` -<header - className="navbar-context-header" -> - <OrganizationHelmet - organization={ - Object { - "key": "foo", - "name": "The Foo Organization", - "projectVisibility": "public", - } - } - title="My Project" - /> - <OrganizationAvatar - organization={ - Object { - "key": "foo", - "name": "The Foo Organization", - "projectVisibility": "public", - } - } - /> - <OrganizationLink - className="link-base-color link-no-underline spacer-left" - organization={ - Object { - "key": "foo", - "name": "The Foo Organization", - "projectVisibility": "public", - } - } - > - The Foo Organization - </OrganizationLink> - <span - className="slash-separator" - /> - <QualifierIcon - className="spacer-right" - key="qualifier-my-project" - qualifier="TRK" - /> - <Link - className="link-base-color link-no-underline" - key="name-my-project" - onlyActiveOnIndex={false} - style={Object {}} - title="My Project" - to={ - Object { - "pathname": "/dashboard", - "query": Object { - "branch": undefined, - "id": "my-project", - }, - } - } - > - My Project - </Link> -</header> -`; 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 new file mode 100644 index 00000000000..eb990ac6401 --- /dev/null +++ b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavHeader-test.tsx.snap @@ -0,0 +1,104 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`should not render breadcrumbs with one element 1`] = ` +<header + className="navbar-context-header" +> + <OrganizationHelmet + title="My Project" + /> + <React.Fragment + key="my-project" + > + <QualifierIcon + className="spacer-right" + qualifier="TRK" + /> + <Link + className="link-base-color link-no-underline" + onlyActiveOnIndex={false} + style={Object {}} + title="My Project" + to={ + Object { + "pathname": "/dashboard", + "query": Object { + "branch": undefined, + "id": "my-project", + }, + } + } + > + My Project + </Link> + </React.Fragment> +</header> +`; + +exports[`should render organization 1`] = ` +<header + className="navbar-context-header" +> + <OrganizationHelmet + organization={ + Object { + "key": "foo", + "name": "The Foo Organization", + "projectVisibility": "public", + } + } + title="My Project" + /> + <React.Fragment> + <OrganizationAvatar + organization={ + Object { + "key": "foo", + "name": "The Foo Organization", + "projectVisibility": "public", + } + } + /> + <OrganizationLink + className="link-base-color link-no-underline spacer-left" + organization={ + Object { + "key": "foo", + "name": "The Foo Organization", + "projectVisibility": "public", + } + } + > + The Foo Organization + </OrganizationLink> + <span + className="slash-separator" + /> + </React.Fragment> + <React.Fragment + key="my-project" + > + <QualifierIcon + className="spacer-right" + qualifier="TRK" + /> + <Link + className="link-base-color link-no-underline" + onlyActiveOnIndex={false} + style={Object {}} + title="My Project" + to={ + Object { + "pathname": "/dashboard", + "query": Object { + "branch": undefined, + "id": "my-project", + }, + } + } + > + My Project + </Link> + </React.Fragment> +</header> +`; diff --git a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavMeta-test.tsx.snap b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavMeta-test.tsx.snap index 726f3168f9f..437ab7a3477 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavMeta-test.tsx.snap +++ b/server/sonar-web/src/main/js/app/components/nav/component/__tests__/__snapshots__/ComponentNavMeta-test.tsx.snap @@ -38,20 +38,24 @@ exports[`renders status of short-living branch 1`] = ` date="2017-01-02T00:00:00.000Z" /> </div> - <BranchStatus - branch={ - Object { - "isMain": false, - "mergeBranch": "master", - "name": "feature", - "status": Object { - "bugs": 0, - "codeSmells": 2, - "vulnerabilities": 3, - }, - "type": "SHORT", + <div + className="navbar-context-meta-secondary" + > + <BranchStatus + branch={ + Object { + "isMain": false, + "mergeBranch": "master", + "name": "feature", + "status": Object { + "bugs": 0, + "codeSmells": 2, + "vulnerabilities": 3, + }, + "type": "SHORT", + } } - } - /> + /> + </div> </div> `; |