import { Link } from 'react-router'; | import { Link } from 'react-router'; | ||||
import { translate } from '../../helpers/l10n'; | 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> | ||||
); | |||||
} | |||||
</div> | |||||
); | |||||
} | } |
hideLoggedInInfo?: boolean; | 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> | ||||
</div> | </div> | ||||
<GlobalFooterContainer hideLoggedInInfo={this.props.hideLoggedInInfo} /> | |||||
</div> | </div> | ||||
); | |||||
} | |||||
<GlobalFooterContainer hideLoggedInInfo={props.hideLoggedInInfo} /> | |||||
</div> | |||||
); | |||||
} | } |
import * as React from 'react'; | import * as React from 'react'; | ||||
import { Link } from 'react-router'; | 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> | ||||
); | |||||
} | |||||
</div> | |||||
); | |||||
} | } |
.navbar-context-branches { | .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)); | margin-left: calc(2 * var(--gridSize)); | ||||
line-height: 16px; | |||||
font-size: var(--baseFontSize); | |||||
} | } | ||||
.navbar-context-meta-branch-menu-item { | .navbar-context-meta-branch-menu-item { |
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||||
*/ | */ | ||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import ComponentNavBranch from './ComponentNavBranch'; | |||||
import ComponentNavBreadcrumbs from './ComponentNavBreadcrumbs'; | |||||
import ComponentNavHeader from './ComponentNavHeader'; | |||||
import ComponentNavMeta from './ComponentNavMeta'; | import ComponentNavMeta from './ComponentNavMeta'; | ||||
import ComponentNavMenu from './ComponentNavMenu'; | import ComponentNavMenu from './ComponentNavMenu'; | ||||
import ComponentNavBgTaskNotif from './ComponentNavBgTaskNotif'; | import ComponentNavBgTaskNotif from './ComponentNavBgTaskNotif'; | ||||
id="context-navigation" | id="context-navigation" | ||||
height={notifComponent ? theme.contextNavHeightRaw + 20 : theme.contextNavHeightRaw} | height={notifComponent ? theme.contextNavHeightRaw + 20 : theme.contextNavHeightRaw} | ||||
notif={notifComponent}> | 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} /> | <ComponentNavMeta branch={this.props.currentBranch} component={this.props.component} /> | ||||
<ComponentNavMenu | <ComponentNavMenu | ||||
branch={this.props.currentBranch} | branch={this.props.currentBranch} |
import * as React from 'react'; | import * as React from 'react'; | ||||
import { connect } from 'react-redux'; | import { connect } from 'react-redux'; | ||||
import { Link } from 'react-router'; | 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 QualifierIcon from '../../../../components/shared/QualifierIcon'; | ||||
import { getOrganizationByKey, areThereCustomOrganizations } from '../../../../store/rootReducer'; | import { getOrganizationByKey, areThereCustomOrganizations } from '../../../../store/rootReducer'; | ||||
import OrganizationAvatar from '../../../../components/common/OrganizationAvatar'; | import OrganizationAvatar from '../../../../components/common/OrganizationAvatar'; | ||||
} | } | ||||
interface OwnProps { | interface OwnProps { | ||||
branches: Branch[]; | |||||
component: Component; | component: Component; | ||||
currentBranch?: Branch; | |||||
location?: any; | |||||
} | } | ||||
interface Props extends StateProps, OwnProps {} | interface Props extends StateProps, OwnProps {} | ||||
export function ComponentNavBreadcrumbs(props: Props) { | |||||
export function ComponentNavHeader(props: Props) { | |||||
const { component, organization, shouldOrganizationBeDisplayed } = 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 ( | return ( | ||||
<header className="navbar-context-header"> | <header className="navbar-context-header"> | ||||
title={component.name} | title={component.name} | ||||
organization={organization && shouldOrganizationBeDisplayed ? organization : undefined} | organization={organization && shouldOrganizationBeDisplayed ? organization : undefined} | ||||
/> | /> | ||||
{organization && | |||||
shouldOrganizationBeDisplayed && <OrganizationAvatar organization={organization} />} | |||||
{organization && | {organization && | ||||
shouldOrganizationBeDisplayed && ( | 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' && ( | {component.visibility === 'private' && ( | ||||
<PrivateBadge className="spacer-left" qualifier={component.qualifier} /> | <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> | </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 => ({ | const mapStateToProps = (state: any, ownProps: OwnProps): StateProps => ({ | ||||
organization: | organization: | ||||
ownProps.component.organization && getOrganizationByKey(state, ownProps.component.organization), | ownProps.component.organization && getOrganizationByKey(state, ownProps.component.organization), | ||||
shouldOrganizationBeDisplayed: areThereCustomOrganizations(state) | shouldOrganizationBeDisplayed: areThereCustomOrganizations(state) | ||||
}); | }); | ||||
export default connect(mapStateToProps)(ComponentNavBreadcrumbs); | |||||
export default connect(mapStateToProps)(ComponentNavHeader); |
*/ | */ | ||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import { connect } from 'react-redux'; | 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 BranchStatus from '../../../../components/common/BranchStatus'; | ||||
import DateTimeFormatter from '../../../../components/intl/DateTimeFormatter'; | import DateTimeFormatter from '../../../../components/intl/DateTimeFormatter'; | ||||
import Favorite from '../../../../components/controls/Favorite'; | import Favorite from '../../../../components/controls/Favorite'; | ||||
{isLoggedIn(currentUser) && | {isLoggedIn(currentUser) && | ||||
mainBranch && ( | mainBranch && ( | ||||
<div className="navbar-context-meta-secondary"> | <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 | <HomePageSelect | ||||
className="spacer-left" | className="spacer-left" | ||||
currentPage={{ type: 'project', key: component.key }} | |||||
currentPage={{ type: HomePageType.Project, parameter: component.key }} | |||||
/> | /> | ||||
</div> | </div> | ||||
)} | )} | ||||
{shortBranch && <BranchStatus branch={branch!} />} | |||||
{shortBranch && ( | |||||
<div className="navbar-context-meta-secondary"> | |||||
<BranchStatus branch={branch!} /> | |||||
</div> | |||||
)} | |||||
</div> | </div> | ||||
); | ); | ||||
} | } |
} | } | ||||
})); | })); | ||||
jest.mock('../ComponentNavBreadcrumbs', () => ({ | |||||
jest.mock('../ComponentNavHeader', () => ({ | |||||
// eslint-disable-next-line | // eslint-disable-next-line | ||||
default: function ComponentNavBreadcrumbs() { | |||||
default: function ComponentNavHeader() { | |||||
return null; | return null; | ||||
} | } | ||||
})); | })); |
*/ | */ | ||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import { shallow } from 'enzyme'; | import { shallow } from 'enzyme'; | ||||
import { ComponentNavBreadcrumbs } from '../ComponentNavBreadcrumbs'; | |||||
import { ComponentNavHeader } from '../ComponentNavHeader'; | |||||
import { Visibility } from '../../../../types'; | import { Visibility } from '../../../../types'; | ||||
it('should not render breadcrumbs with one element', () => { | it('should not render breadcrumbs with one element', () => { | ||||
visibility: 'public' | visibility: 'public' | ||||
}; | }; | ||||
const result = shallow( | const result = shallow( | ||||
<ComponentNavBreadcrumbs component={component} shouldOrganizationBeDisplayed={false} /> | |||||
<ComponentNavHeader branches={[]} component={component} shouldOrganizationBeDisplayed={false} /> | |||||
); | ); | ||||
expect(result).toMatchSnapshot(); | expect(result).toMatchSnapshot(); | ||||
}); | }); | ||||
projectVisibility: Visibility.Public | projectVisibility: Visibility.Public | ||||
}; | }; | ||||
const result = shallow( | const result = shallow( | ||||
<ComponentNavBreadcrumbs | |||||
<ComponentNavHeader | |||||
branches={[]} | |||||
component={component} | component={component} | ||||
organization={organization} | organization={organization} | ||||
shouldOrganizationBeDisplayed={true} | shouldOrganizationBeDisplayed={true} | ||||
visibility: 'private' | visibility: 'private' | ||||
}; | }; | ||||
const result = shallow( | const result = shallow( | ||||
<ComponentNavBreadcrumbs component={component} shouldOrganizationBeDisplayed={false} /> | |||||
<ComponentNavHeader branches={[]} component={component} shouldOrganizationBeDisplayed={false} /> | |||||
); | ); | ||||
expect(result.find('PrivateBadge')).toHaveLength(1); | expect(result.find('PrivateBadge')).toHaveLength(1); | ||||
}); | }); |
/> | /> | ||||
} | } | ||||
> | > | ||||
<ComponentNavBreadcrumbs | |||||
<ComponentNavHeader | |||||
branches={Array []} | |||||
component={ | component={ | ||||
Object { | Object { | ||||
"breadcrumbs": Array [ | "breadcrumbs": Array [ | ||||
"qualifier": "TRK", | "qualifier": "TRK", | ||||
} | } | ||||
} | } | ||||
location={Object {}} | |||||
/> | /> | ||||
<ComponentNavMeta | <ComponentNavMeta | ||||
component={ | component={ |
// 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> | |||||
`; |
// 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> | |||||
`; |
date="2017-01-02T00:00:00.000Z" | date="2017-01-02T00:00:00.000Z" | ||||
/> | /> | ||||
</div> | </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> | </div> | ||||
`; | `; |
* along with this program; if not, write to the Free Software Foundation, | * along with this program; if not, write to the Free Software Foundation, | ||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||||
*/ | */ | ||||
.white-page { | |||||
background-color: #fff !important; | |||||
} | |||||
.global-container { | .global-container { | ||||
display: flex; | display: flex; | ||||
flex-direction: column; | flex-direction: column; | ||||
padding-left: calc(50vw - 370px + 10px) !important; | padding-left: calc(50vw - 370px + 10px) !important; | ||||
} | } | ||||
.page-footer-with-sidebar div { | |||||
.page-footer-with-sidebar div, | |||||
.page-footer-with-sidebar .page-footer-menu { | |||||
max-width: 980px; | max-width: 980px; | ||||
} | } | ||||
html, | html, | ||||
body { | body { | ||||
background-color: #fff; | |||||
background-color: var(--barBackgroundColor); | |||||
} | } | ||||
body { | body { |
stroke-width: 1.41421356; | stroke-width: 1.41421356; | ||||
stroke-opacity: 1; | stroke-opacity: 1; | ||||
fill-opacity: 0; | fill-opacity: 0; | ||||
vector-effect: non-scaling-stroke; | |||||
transition: all 0.2s ease; | transition: all 0.2s ease; | ||||
} | } | ||||
display: none !important; | display: none !important; | ||||
} | } | ||||
.dashboard-page, | |||||
.dashboard-page body { | |||||
background-color: #fff; | |||||
html, | |||||
body { | |||||
background-color: #fff !important; | |||||
} | } | ||||
.widget thead, | .widget thead, | ||||
.widget tfoot { | .widget tfoot { | ||||
display: table-row-group; | display: table-row-group; |
* along with this program; if not, write to the Free Software Foundation, | * along with this program; if not, write to the Free Software Foundation, | ||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||||
*/ | */ | ||||
.dashboard-page, | |||||
.dashboard-page body { | |||||
background-color: var(--barBackgroundColor); | |||||
} | |||||
.tabs { | .tabs { | ||||
height: 20px; | height: 20px; | ||||
border-bottom: 1px solid #ddd; | border-bottom: 1px solid #ddd; |
name: string; | name: string; | ||||
} | } | ||||
export interface Breadcrumb { | |||||
key: string; | |||||
name: string; | |||||
qualifier: string; | |||||
} | |||||
export interface Component { | export interface Component { | ||||
analysisDate?: string; | analysisDate?: string; | ||||
breadcrumbs: Array<{ | |||||
key: string; | |||||
name: string; | |||||
qualifier: string; | |||||
}>; | |||||
breadcrumbs: Breadcrumb[]; | |||||
configuration?: ComponentConfiguration; | configuration?: ComponentConfiguration; | ||||
description?: string; | description?: string; | ||||
extensions?: Extension[]; | extensions?: Extension[]; | ||||
showOnboardingTutorial?: boolean; | showOnboardingTutorial?: boolean; | ||||
} | } | ||||
export enum HomePageType { | |||||
Project = 'PROJECT', | |||||
Organization = 'ORGANIZATION', | |||||
MyProjects = 'MY_PROJECTS', | |||||
MyIssues = 'MY_ISSUES' | |||||
} | |||||
export interface HomePage { | export interface HomePage { | ||||
key?: string; | |||||
type: string; | |||||
parameter?: string; | |||||
type: HomePageType; | |||||
} | } | ||||
export function isSameHomePage(a: HomePage, b: HomePage) { | export function isSameHomePage(a: HomePage, b: HomePage) { | ||||
return a.type === b.type && a.key === b.key; | |||||
return a.type === b.type && a.parameter === b.parameter; | |||||
} | } | ||||
export interface LoggedInUser extends CurrentUser { | export interface LoggedInUser extends CurrentUser { |
window.location = 'https://about.sonarcloud.io'; | window.location = 'https://about.sonarcloud.io'; | ||||
} else { | } else { | ||||
this.loadData(); | this.loadData(); | ||||
// $FlowFixMe | |||||
document.body.classList.add('white-page'); | |||||
} | } | ||||
} | } | ||||
componentWillUnmount() { | componentWillUnmount() { | ||||
this.mounted = false; | this.mounted = false; | ||||
// $FlowFixMe | |||||
document.body.classList.remove('white-page'); | |||||
} | } | ||||
loadProjects() { | loadProjects() { |
padding-top: 20px; | padding-top: 20px; | ||||
padding-bottom: 20px; | padding-bottom: 20px; | ||||
border-bottom: 1px solid var(--barBorderColor); | border-bottom: 1px solid var(--barBorderColor); | ||||
background-color: var(--barBackgroundColor); | |||||
background-color: #fff; | |||||
} | } | ||||
.account-nav { | .account-nav { |
const { success, errors } = this.state; | const { success, errors } = this.state; | ||||
return ( | return ( | ||||
<section> | |||||
<section className="boxed-group"> | |||||
<h2 className="spacer-bottom">{translate('my_profile.password.title')}</h2> | <h2 className="spacer-bottom">{translate('my_profile.password.title')}</h2> | ||||
<form onSubmit={this.handleChangePassword}> | |||||
<form className="boxed-group-inner" onSubmit={this.handleChangePassword}> | |||||
{success && ( | {success && ( | ||||
<div className="alert alert-success">{translate('my_profile.password.changed')}</div> | <div className="alert alert-success">{translate('my_profile.password.changed')}</div> | ||||
)} | )} |
return ( | return ( | ||||
<div className="account-body account-container"> | <div className="account-body account-container"> | ||||
<Helmet title={translate('my_account.security')} /> | <Helmet title={translate('my_account.security')} /> | ||||
<Tokens user={user} /> | <Tokens user={user} /> | ||||
{user.local && <hr className="account-separator" />} | |||||
{user.local && <Password user={user} />} | {user.local && <Password user={user} />} | ||||
</div> | </div> | ||||
); | ); |
function GlobalNotifications(props /*: Props */) { | function GlobalNotifications(props /*: Props */) { | ||||
return ( | return ( | ||||
<section> | |||||
<h2 className="spacer-bottom">{translate('my_profile.overall_notifications.title')}</h2> | |||||
<section className="boxed-group"> | |||||
<h2>{translate('my_profile.overall_notifications.title')}</h2> | |||||
<table className="form"> | |||||
<thead> | |||||
<tr> | |||||
<th /> | |||||
{props.channels.map(channel => ( | |||||
<th key={channel} className="text-center"> | |||||
<h4>{translate('notification.channel', channel)}</h4> | |||||
</th> | |||||
))} | |||||
</tr> | |||||
</thead> | |||||
<div className="boxed-group-inner"> | |||||
<table className="form"> | |||||
<thead> | |||||
<tr> | |||||
<th /> | |||||
{props.channels.map(channel => ( | |||||
<th key={channel} className="text-center"> | |||||
<h4>{translate('notification.channel', channel)}</h4> | |||||
</th> | |||||
))} | |||||
</tr> | |||||
</thead> | |||||
<NotificationsList | |||||
notifications={props.notifications} | |||||
channels={props.channels} | |||||
types={props.types} | |||||
checkboxId={(d, c) => `global-notification-${d}-${c}`} | |||||
onAdd={props.addNotification} | |||||
onRemove={props.removeNotification} | |||||
/> | |||||
</table> | |||||
<NotificationsList | |||||
notifications={props.notifications} | |||||
channels={props.channels} | |||||
types={props.types} | |||||
checkboxId={(d, c) => `global-notification-${d}-${c}`} | |||||
onAdd={props.addNotification} | |||||
onRemove={props.removeNotification} | |||||
/> | |||||
</table> | |||||
</div> | |||||
</section> | </section> | ||||
); | ); | ||||
} | } |
return ( | return ( | ||||
<div className="account-body account-container"> | <div className="account-body account-container"> | ||||
<Helmet title={translate('my_account.notifications')} /> | <Helmet title={translate('my_account.notifications')} /> | ||||
<p className="big-spacer-bottom">{translate('notification.dispatcher.information')}</p> | |||||
<p className="alert alert-info">{translate('notification.dispatcher.information')}</p> | |||||
<GlobalNotifications /> | <GlobalNotifications /> | ||||
<hr className="account-separator" /> | |||||
<Projects /> | <Projects /> | ||||
</div> | </div> | ||||
); | ); |
const allProjects = [...this.props.projects, ...this.state.addedProjects]; | const allProjects = [...this.props.projects, ...this.state.addedProjects]; | ||||
return ( | return ( | ||||
<section> | |||||
<h2 className="spacer-bottom">{translate('my_profile.per_project_notifications.title')}</h2> | |||||
{allProjects.length === 0 && ( | |||||
<div className="note">{translate('my_account.no_project_notifications')}</div> | |||||
)} | |||||
{allProjects.map(project => <ProjectNotifications key={project.key} project={project} />)} | |||||
<div className="spacer-top panel bg-muted"> | |||||
<span className="text-middle spacer-right"> | |||||
{translate('my_account.set_notifications_for')}: | |||||
</span> | |||||
<AsyncSelect | |||||
autoload={false} | |||||
cache={false} | |||||
name="new_project" | |||||
style={{ width: '300px' }} | |||||
loadOptions={this.loadOptions} | |||||
minimumInput={2} | |||||
optionRenderer={this.renderOption} | |||||
onChange={this.handleAddProject} | |||||
placeholder={translate('my_account.search_project')} | |||||
/> | |||||
<section className="boxed-group"> | |||||
<h2>{translate('my_profile.per_project_notifications.title')}</h2> | |||||
<div className="boxed-group-inner"> | |||||
{allProjects.length === 0 && ( | |||||
<div className="note">{translate('my_account.no_project_notifications')}</div> | |||||
)} | |||||
{allProjects.map(project => <ProjectNotifications key={project.key} project={project} />)} | |||||
<div className="spacer-top panel bg-muted"> | |||||
<span className="text-middle spacer-right"> | |||||
{translate('my_account.set_notifications_for')}: | |||||
</span> | |||||
<AsyncSelect | |||||
autoload={false} | |||||
cache={false} | |||||
name="new_project" | |||||
style={{ width: '300px' }} | |||||
loadOptions={this.loadOptions} | |||||
minimumInput={2} | |||||
optionRenderer={this.renderOption} | |||||
onChange={this.handleAddProject} | |||||
placeholder={translate('my_account.search_project')} | |||||
/> | |||||
</div> | |||||
</div> | </div> | ||||
</section> | </section> | ||||
); | ); |
// Jest Snapshot v1, https://goo.gl/fbAQLP | // Jest Snapshot v1, https://goo.gl/fbAQLP | ||||
exports[`should match snapshot 1`] = ` | exports[`should match snapshot 1`] = ` | ||||
<section> | |||||
<h2 | |||||
className="spacer-bottom" | |||||
> | |||||
<section | |||||
className="boxed-group" | |||||
> | |||||
<h2> | |||||
my_profile.overall_notifications.title | my_profile.overall_notifications.title | ||||
</h2> | </h2> | ||||
<table | |||||
className="form" | |||||
<div | |||||
className="boxed-group-inner" | |||||
> | > | ||||
<thead> | |||||
<tr> | |||||
<th /> | |||||
<th | |||||
className="text-center" | |||||
key="channel1" | |||||
> | |||||
<h4> | |||||
notification.channel.channel1 | |||||
</h4> | |||||
</th> | |||||
<th | |||||
className="text-center" | |||||
key="channel2" | |||||
> | |||||
<h4> | |||||
notification.channel.channel2 | |||||
</h4> | |||||
</th> | |||||
</tr> | |||||
</thead> | |||||
<NotificationsList | |||||
channels={ | |||||
Array [ | |||||
"channel1", | |||||
"channel2", | |||||
] | |||||
} | |||||
checkboxId={[Function]} | |||||
notifications={ | |||||
Array [ | |||||
Object { | |||||
"channel": "channel1", | |||||
"type": "type1", | |||||
}, | |||||
Object { | |||||
"channel": "channel1", | |||||
"type": "type2", | |||||
}, | |||||
Object { | |||||
"channel": "channel2", | |||||
"type": "type2", | |||||
}, | |||||
] | |||||
} | |||||
onAdd={[Function]} | |||||
onRemove={[Function]} | |||||
types={ | |||||
Array [ | |||||
"type1", | |||||
"type2", | |||||
] | |||||
} | |||||
/> | |||||
</table> | |||||
<table | |||||
className="form" | |||||
> | |||||
<thead> | |||||
<tr> | |||||
<th /> | |||||
<th | |||||
className="text-center" | |||||
key="channel1" | |||||
> | |||||
<h4> | |||||
notification.channel.channel1 | |||||
</h4> | |||||
</th> | |||||
<th | |||||
className="text-center" | |||||
key="channel2" | |||||
> | |||||
<h4> | |||||
notification.channel.channel2 | |||||
</h4> | |||||
</th> | |||||
</tr> | |||||
</thead> | |||||
<NotificationsList | |||||
channels={ | |||||
Array [ | |||||
"channel1", | |||||
"channel2", | |||||
] | |||||
} | |||||
checkboxId={[Function]} | |||||
notifications={ | |||||
Array [ | |||||
Object { | |||||
"channel": "channel1", | |||||
"type": "type1", | |||||
}, | |||||
Object { | |||||
"channel": "channel1", | |||||
"type": "type2", | |||||
}, | |||||
Object { | |||||
"channel": "channel2", | |||||
"type": "type2", | |||||
}, | |||||
] | |||||
} | |||||
onAdd={[Function]} | |||||
onRemove={[Function]} | |||||
types={ | |||||
Array [ | |||||
"type1", | |||||
"type2", | |||||
] | |||||
} | |||||
/> | |||||
</table> | |||||
</div> | |||||
</section> | </section> | ||||
`; | `; |
title="my_account.notifications" | title="my_account.notifications" | ||||
/> | /> | ||||
<p | <p | ||||
className="big-spacer-bottom" | |||||
className="alert alert-info" | |||||
> | > | ||||
notification.dispatcher.information | notification.dispatcher.information | ||||
</p> | </p> | ||||
<Connect(GlobalNotifications) /> | <Connect(GlobalNotifications) /> | ||||
<hr | |||||
className="account-separator" | |||||
/> | |||||
<Connect(Projects) /> | <Connect(Projects) /> | ||||
</div> | </div> | ||||
`; | `; |
// Jest Snapshot v1, https://goo.gl/fbAQLP | // Jest Snapshot v1, https://goo.gl/fbAQLP | ||||
exports[`should render projects 1`] = ` | exports[`should render projects 1`] = ` | ||||
<section> | |||||
<h2 | |||||
className="spacer-bottom" | |||||
> | |||||
<section | |||||
className="boxed-group" | |||||
> | |||||
<h2> | |||||
my_profile.per_project_notifications.title | my_profile.per_project_notifications.title | ||||
</h2> | </h2> | ||||
<Connect(ProjectNotifications) | |||||
key="foo" | |||||
project={ | |||||
Object { | |||||
"key": "foo", | |||||
"name": "Foo", | |||||
} | |||||
} | |||||
/> | |||||
<Connect(ProjectNotifications) | |||||
key="bar" | |||||
project={ | |||||
Object { | |||||
"key": "bar", | |||||
"name": "Bar", | |||||
} | |||||
} | |||||
/> | |||||
<div | <div | ||||
className="spacer-top panel bg-muted" | |||||
className="boxed-group-inner" | |||||
> | > | ||||
<span | |||||
className="text-middle spacer-right" | |||||
> | |||||
my_account.set_notifications_for | |||||
: | |||||
</span> | |||||
<AsyncSelect | |||||
autoload={false} | |||||
cache={false} | |||||
loadOptions={[Function]} | |||||
minimumInput={2} | |||||
name="new_project" | |||||
onChange={[Function]} | |||||
optionRenderer={[Function]} | |||||
placeholder="my_account.search_project" | |||||
style={ | |||||
<Connect(ProjectNotifications) | |||||
key="foo" | |||||
project={ | |||||
Object { | |||||
"key": "foo", | |||||
"name": "Foo", | |||||
} | |||||
} | |||||
/> | |||||
<Connect(ProjectNotifications) | |||||
key="bar" | |||||
project={ | |||||
Object { | Object { | ||||
"width": "300px", | |||||
"key": "bar", | |||||
"name": "Bar", | |||||
} | } | ||||
} | } | ||||
/> | /> | ||||
<div | |||||
className="spacer-top panel bg-muted" | |||||
> | |||||
<span | |||||
className="text-middle spacer-right" | |||||
> | |||||
my_account.set_notifications_for | |||||
: | |||||
</span> | |||||
<AsyncSelect | |||||
autoload={false} | |||||
cache={false} | |||||
loadOptions={[Function]} | |||||
minimumInput={2} | |||||
name="new_project" | |||||
onChange={[Function]} | |||||
optionRenderer={[Function]} | |||||
placeholder="my_account.search_project" | |||||
style={ | |||||
Object { | |||||
"width": "300px", | |||||
} | |||||
} | |||||
/> | |||||
</div> | |||||
</div> | </div> | ||||
</section> | </section> | ||||
`; | `; | ||||
exports[`should render projects 2`] = ` | exports[`should render projects 2`] = ` | ||||
<section> | |||||
<h2 | |||||
className="spacer-bottom" | |||||
> | |||||
<section | |||||
className="boxed-group" | |||||
> | |||||
<h2> | |||||
my_profile.per_project_notifications.title | my_profile.per_project_notifications.title | ||||
</h2> | </h2> | ||||
<Connect(ProjectNotifications) | |||||
key="foo" | |||||
project={ | |||||
Object { | |||||
"key": "foo", | |||||
"name": "Foo", | |||||
} | |||||
} | |||||
/> | |||||
<Connect(ProjectNotifications) | |||||
key="bar" | |||||
project={ | |||||
Object { | |||||
"key": "bar", | |||||
"name": "Bar", | |||||
} | |||||
} | |||||
/> | |||||
<Connect(ProjectNotifications) | |||||
key="qux" | |||||
project={ | |||||
Object { | |||||
"key": "qux", | |||||
"name": "Qux", | |||||
} | |||||
} | |||||
/> | |||||
<div | <div | ||||
className="spacer-top panel bg-muted" | |||||
className="boxed-group-inner" | |||||
> | > | ||||
<span | |||||
className="text-middle spacer-right" | |||||
> | |||||
my_account.set_notifications_for | |||||
: | |||||
</span> | |||||
<AsyncSelect | |||||
autoload={false} | |||||
cache={false} | |||||
loadOptions={[Function]} | |||||
minimumInput={2} | |||||
name="new_project" | |||||
onChange={[Function]} | |||||
optionRenderer={[Function]} | |||||
placeholder="my_account.search_project" | |||||
style={ | |||||
<Connect(ProjectNotifications) | |||||
key="foo" | |||||
project={ | |||||
Object { | |||||
"key": "foo", | |||||
"name": "Foo", | |||||
} | |||||
} | |||||
/> | |||||
<Connect(ProjectNotifications) | |||||
key="bar" | |||||
project={ | |||||
Object { | |||||
"key": "bar", | |||||
"name": "Bar", | |||||
} | |||||
} | |||||
/> | |||||
<Connect(ProjectNotifications) | |||||
key="qux" | |||||
project={ | |||||
Object { | Object { | ||||
"width": "300px", | |||||
"key": "qux", | |||||
"name": "Qux", | |||||
} | } | ||||
} | } | ||||
/> | /> | ||||
<div | |||||
className="spacer-top panel bg-muted" | |||||
> | |||||
<span | |||||
className="text-middle spacer-right" | |||||
> | |||||
my_account.set_notifications_for | |||||
: | |||||
</span> | |||||
<AsyncSelect | |||||
autoload={false} | |||||
cache={false} | |||||
loadOptions={[Function]} | |||||
minimumInput={2} | |||||
name="new_project" | |||||
onChange={[Function]} | |||||
optionRenderer={[Function]} | |||||
placeholder="my_account.search_project" | |||||
style={ | |||||
Object { | |||||
"width": "300px", | |||||
} | |||||
} | |||||
/> | |||||
</div> | |||||
</div> | </div> | ||||
</section> | </section> | ||||
`; | `; | ||||
exports[`should render projects 3`] = ` | exports[`should render projects 3`] = ` | ||||
<section> | |||||
<h2 | |||||
className="spacer-bottom" | |||||
> | |||||
<section | |||||
className="boxed-group" | |||||
> | |||||
<h2> | |||||
my_profile.per_project_notifications.title | my_profile.per_project_notifications.title | ||||
</h2> | </h2> | ||||
<Connect(ProjectNotifications) | |||||
key="foo" | |||||
project={ | |||||
Object { | |||||
"key": "foo", | |||||
"name": "Foo", | |||||
} | |||||
} | |||||
/> | |||||
<Connect(ProjectNotifications) | |||||
key="bar" | |||||
project={ | |||||
Object { | |||||
"key": "bar", | |||||
"name": "Bar", | |||||
} | |||||
} | |||||
/> | |||||
<Connect(ProjectNotifications) | |||||
key="qux" | |||||
project={ | |||||
Object { | |||||
"key": "qux", | |||||
"name": "Qux", | |||||
} | |||||
} | |||||
/> | |||||
<div | <div | ||||
className="spacer-top panel bg-muted" | |||||
className="boxed-group-inner" | |||||
> | > | ||||
<span | |||||
className="text-middle spacer-right" | |||||
> | |||||
my_account.set_notifications_for | |||||
: | |||||
</span> | |||||
<AsyncSelect | |||||
autoload={false} | |||||
cache={false} | |||||
loadOptions={[Function]} | |||||
minimumInput={2} | |||||
name="new_project" | |||||
onChange={[Function]} | |||||
optionRenderer={[Function]} | |||||
placeholder="my_account.search_project" | |||||
style={ | |||||
<Connect(ProjectNotifications) | |||||
key="foo" | |||||
project={ | |||||
Object { | Object { | ||||
"width": "300px", | |||||
"key": "foo", | |||||
"name": "Foo", | |||||
} | } | ||||
} | } | ||||
/> | /> | ||||
<Connect(ProjectNotifications) | |||||
key="bar" | |||||
project={ | |||||
Object { | |||||
"key": "bar", | |||||
"name": "Bar", | |||||
} | |||||
} | |||||
/> | |||||
<Connect(ProjectNotifications) | |||||
key="qux" | |||||
project={ | |||||
Object { | |||||
"key": "qux", | |||||
"name": "Qux", | |||||
} | |||||
} | |||||
/> | |||||
<div | |||||
className="spacer-top panel bg-muted" | |||||
> | |||||
<span | |||||
className="text-middle spacer-right" | |||||
> | |||||
my_account.set_notifications_for | |||||
: | |||||
</span> | |||||
<AsyncSelect | |||||
autoload={false} | |||||
cache={false} | |||||
loadOptions={[Function]} | |||||
minimumInput={2} | |||||
name="new_project" | |||||
onChange={[Function]} | |||||
optionRenderer={[Function]} | |||||
placeholder="my_account.search_project" | |||||
style={ | |||||
Object { | |||||
"width": "300px", | |||||
} | |||||
} | |||||
/> | |||||
</div> | |||||
</div> | </div> | ||||
</section> | </section> | ||||
`; | `; |
import { sortBy } from 'lodash'; | import { sortBy } from 'lodash'; | ||||
import OrganizationCard from './OrganizationCard'; | import OrganizationCard from './OrganizationCard'; | ||||
import { Organization } from '../../../app/types'; | import { Organization } from '../../../app/types'; | ||||
import { translate } from '../../../helpers/l10n'; | |||||
interface Props { | interface Props { | ||||
organizations: Organization[]; | organizations: Organization[]; | ||||
} | } | ||||
export default function OrganizationsList({ organizations }: Props) { | export default function OrganizationsList({ organizations }: Props) { | ||||
if (organizations.length === 0) { | |||||
return <div>{translate('my_account.organizations.no_results')}</div>; | |||||
} | |||||
return ( | return ( | ||||
<ul className="account-projects-list"> | <ul className="account-projects-list"> | ||||
{sortBy(organizations, organization => organization.name.toLocaleLowerCase()).map( | {sortBy(organizations, organization => organization.name.toLocaleLowerCase()).map( |
<div className="account-body account-container"> | <div className="account-body account-container"> | ||||
<Helmet title={translate('my_account.organizations')} /> | <Helmet title={translate('my_account.organizations')} /> | ||||
<header className="page-header"> | |||||
<h2 className="page-title">{translate('my_account.organizations')}</h2> | |||||
<div className="boxed-group"> | |||||
{canCreateOrganizations && ( | {canCreateOrganizations && ( | ||||
<div className="page-actions"> | |||||
<button onClick={this.handleCreateClick}>{translate('create')}</button> | |||||
<div className="clearfix"> | |||||
<div className="boxed-group-actions"> | |||||
<button onClick={this.handleCreateClick}>{translate('create')}</button> | |||||
</div> | |||||
</div> | </div> | ||||
)} | )} | ||||
{this.props.organizations.length > 0 ? ( | |||||
<div className="page-description"> | |||||
{translate('my_account.organizations.description')} | |||||
</div> | |||||
) : ( | |||||
<div className="page-description"> | |||||
{translate('my_account.organizations.no_results')} | |||||
</div> | |||||
)} | |||||
</header> | |||||
{this.state.loading ? ( | |||||
<i className="spinner" /> | |||||
) : ( | |||||
<OrganizationsList organizations={this.props.organizations} /> | |||||
)} | |||||
<div className="boxed-group-inner"> | |||||
{this.state.loading ? ( | |||||
<i className="spinner" /> | |||||
) : ( | |||||
<OrganizationsList organizations={this.props.organizations} /> | |||||
)} | |||||
</div> | |||||
</div> | |||||
{this.state.createOrganization && ( | {this.state.createOrganization && ( | ||||
<CreateOrganizationForm | <CreateOrganizationForm |
return ( | return ( | ||||
<div className="account-body account-container"> | <div className="account-body account-container"> | ||||
<div className="spacer-bottom"> | |||||
{translate('login')}: <strong id="login">{user.login}</strong> | |||||
</div> | |||||
<div className="boxed-group boxed-group-inner"> | |||||
<div className="spacer-bottom"> | |||||
{translate('login')}: <strong id="login">{user.login}</strong> | |||||
</div> | |||||
{!user.local && | |||||
user.externalProvider !== 'sonarqube' && ( | |||||
<div id="identity-provider" className="spacer-bottom"> | |||||
<UserExternalIdentity user={user} /> | |||||
</div> | |||||
)} | |||||
{!user.local && | |||||
user.externalProvider !== 'sonarqube' && ( | |||||
<div id="identity-provider" className="spacer-bottom"> | |||||
<UserExternalIdentity user={user} /> | |||||
{!!user.email && ( | |||||
<div className="spacer-bottom"> | |||||
{translate('my_profile.email')}: <strong id="email">{user.email}</strong> | |||||
</div> | </div> | ||||
)} | )} | ||||
{!!user.email && ( | |||||
<div className="spacer-bottom"> | |||||
{translate('my_profile.email')}: <strong id="email">{user.email}</strong> | |||||
</div> | |||||
)} | |||||
{!customOrganizations && <hr className="account-separator" />} | |||||
{!customOrganizations && <UserGroups groups={user.groups} />} | |||||
{!customOrganizations && <hr className="account-separator" />} | |||||
{!customOrganizations && <UserGroups groups={user.groups} />} | |||||
<hr /> | |||||
<hr className="account-separator" /> | |||||
<UserScmAccounts user={user} scmAccounts={user.scmAccounts} /> | |||||
<UserScmAccounts user={user} scmAccounts={user.scmAccounts} /> | |||||
</div> | |||||
</div> | </div> | ||||
); | ); | ||||
} | } |
<h2 class="spacer-bottom">{{t 'users.tokens'}}</h2> | |||||
<div class="boxed-group"> | |||||
<h2>{{t 'users.tokens'}}</h2> | |||||
<div class="big-spacer-bottom big-spacer-right markdown"> | |||||
<p>{{t 'my_account.tokens_description'}}</p> | |||||
</div> | |||||
<div class="boxed-group-inner"> | |||||
<div class="big-spacer-bottom big-spacer-right markdown"> | |||||
<p>{{t 'my_account.tokens_description'}}</p> | |||||
</div> | |||||
{{#notNull tokens}} | |||||
<table class="data"> | |||||
<thead> | |||||
<tr> | |||||
<th>{{t 'name'}}</th> | |||||
<th class="text-right">{{t 'created'}}</th> | |||||
<th> </th> | |||||
</tr> | |||||
</thead> | |||||
<tbody> | |||||
{{#each tokens}} | |||||
<tr> | |||||
<td> | |||||
<div title="{{name}}"> | |||||
{{limitString name}} | |||||
</div> | |||||
</td> | |||||
<td class="thin nowrap text-right"> | |||||
{{d createdAt}} | |||||
</td> | |||||
<td class="thin nowrap text-right"> | |||||
<div class="big-spacer-left"> | |||||
<form class="js-revoke-token-form" data-token="{{name}}"> | |||||
{{#if deleting}} | |||||
<button class="button-red active input-small">{{t 'users.tokens.sure'}}</button> | |||||
{{else}} | |||||
<button class="button-red input-small">{{t 'users.tokens.revoke'}}</button> | |||||
{{/if}} | |||||
</form> | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
{{else}} | |||||
{{#notNull tokens}} | |||||
<table class="data"> | |||||
<thead> | |||||
<tr> | <tr> | ||||
<td colspan="3"> | |||||
<span class="note">{{t 'users.no_tokens'}}</span> | |||||
</td> | |||||
<th>{{t 'name'}}</th> | |||||
<th class="text-right">{{t 'created'}}</th> | |||||
<th> </th> | |||||
</tr> | </tr> | ||||
{{/each}} | |||||
</tbody> | |||||
</table> | |||||
{{/notNull}} | |||||
</thead> | |||||
<tbody> | |||||
{{#each tokens}} | |||||
<tr> | |||||
<td> | |||||
<div title="{{name}}"> | |||||
{{limitString name}} | |||||
</div> | |||||
</td> | |||||
<td class="thin nowrap text-right"> | |||||
{{d createdAt}} | |||||
</td> | |||||
<td class="thin nowrap text-right"> | |||||
<div class="big-spacer-left"> | |||||
<form class="js-revoke-token-form" data-token="{{name}}"> | |||||
{{#if deleting}} | |||||
<button class="button-red active input-small">{{t 'users.tokens.sure'}}</button> | |||||
{{else}} | |||||
<button class="button-red input-small">{{t 'users.tokens.revoke'}}</button> | |||||
{{/if}} | |||||
</form> | |||||
</div> | |||||
</td> | |||||
</tr> | |||||
{{else}} | |||||
<tr> | |||||
<td colspan="3"> | |||||
<span class="note">{{t 'users.no_tokens'}}</span> | |||||
</td> | |||||
</tr> | |||||
{{/each}} | |||||
</tbody> | |||||
</table> | |||||
{{/notNull}} | |||||
{{#each errors}} | |||||
<div class="alert alert-danger">{{msg}}</div> | |||||
{{/each}} | |||||
{{#each errors}} | |||||
<div class="alert alert-danger">{{msg}}</div> | |||||
{{/each}} | |||||
<form class="js-generate-token-form spacer-top panel bg-muted"> | |||||
<label>{{t 'users.generate_new_token'}}:</label> | |||||
<input type="text" required maxlength="100" placeholder="{{t 'users.enter_token_name'}}"> | |||||
<button>{{t 'users.generate'}}</button> | |||||
</form> | |||||
<form class="js-generate-token-form spacer-top panel bg-muted"> | |||||
<label>{{t 'users.generate_new_token'}}:</label> | |||||
<input type="text" required maxlength="100" placeholder="{{t 'users.enter_token_name'}}"> | |||||
<button>{{t 'users.generate'}}</button> | |||||
</form> | |||||
{{#if newToken}} | |||||
<div class="panel panel-white big-spacer-top"> | |||||
<div class="alert alert-warning"> | |||||
{{tp 'users.tokens.new_token_created' newToken.name}} | |||||
</div> | |||||
{{#if newToken}} | |||||
<div class="panel panel-white big-spacer-top"> | |||||
<div class="alert alert-warning"> | |||||
{{tp 'users.tokens.new_token_created' newToken.name}} | |||||
</div> | |||||
<table class="data"> | |||||
<tr> | |||||
<td class="thin"> | |||||
<button class="js-copy-to-clipboard" data-clipboard-text="{{newToken.token}}">{{t 'copy'}}</button> | |||||
</td> | |||||
<td class="nowrap"> | |||||
<div class="monospaced text-success">{{newToken.token}}</div> | |||||
</td> | |||||
</tr> | |||||
</table> | |||||
</div> | |||||
{{/if}} | |||||
<table class="data"> | |||||
<tr> | |||||
<td class="thin"> | |||||
<button class="js-copy-to-clipboard" data-clipboard-text="{{newToken.token}}">{{t 'copy'}}</button> | |||||
</td> | |||||
<td class="nowrap"> | |||||
<div class="monospaced text-success">{{newToken.token}}</div> | |||||
</td> | |||||
</tr> | |||||
</table> | |||||
</div> | |||||
{{/if}} | |||||
</div> | |||||
</div> |
}); | }); | ||||
return ( | return ( | ||||
<table className={className}> | |||||
<thead> | |||||
<tr> | |||||
<th>{translate('background_tasks.table.status')}</th> | |||||
<th>{translate('background_tasks.table.task')}</th> | |||||
<th>{translate('background_tasks.table.id')}</th> | |||||
<th> </th> | |||||
<th className="text-right">{translate('background_tasks.table.submitted')}</th> | |||||
<th className="text-right">{translate('background_tasks.table.started')}</th> | |||||
<th className="text-right">{translate('background_tasks.table.finished')}</th> | |||||
<th className="text-right">{translate('background_tasks.table.duration')}</th> | |||||
<th> </th> | |||||
</tr> | |||||
</thead> | |||||
<tbody> | |||||
{tasks.map((task, index, tasks) => ( | |||||
<Task | |||||
key={task.id} | |||||
task={task} | |||||
tasks={tasks} | |||||
component={component} | |||||
onCancelTask={onCancelTask} | |||||
onFilterTask={onFilterTask} | |||||
previousTask={index > 0 ? tasks[index - 1] : undefined} | |||||
/> | |||||
))} | |||||
</tbody> | |||||
</table> | |||||
<div className="boxed-group boxed-group-inner"> | |||||
<table className={className}> | |||||
<thead> | |||||
<tr> | |||||
<th>{translate('background_tasks.table.status')}</th> | |||||
<th>{translate('background_tasks.table.task')}</th> | |||||
<th>{translate('background_tasks.table.id')}</th> | |||||
<th> </th> | |||||
<th className="text-right">{translate('background_tasks.table.submitted')}</th> | |||||
<th className="text-right">{translate('background_tasks.table.started')}</th> | |||||
<th className="text-right">{translate('background_tasks.table.finished')}</th> | |||||
<th className="text-right">{translate('background_tasks.table.duration')}</th> | |||||
<th> </th> | |||||
</tr> | |||||
</thead> | |||||
<tbody> | |||||
{tasks.map((task, index, tasks) => ( | |||||
<Task | |||||
key={task.id} | |||||
task={task} | |||||
tasks={tasks} | |||||
component={component} | |||||
onCancelTask={onCancelTask} | |||||
onFilterTask={onFilterTask} | |||||
previousTask={index > 0 ? tasks[index - 1] : undefined} | |||||
/> | |||||
))} | |||||
</tbody> | |||||
</table> | |||||
</div> | |||||
); | ); | ||||
} | } | ||||
} | } |
const shouldShowBreadcrumbs = breadcrumbs.length > 1; | const shouldShowBreadcrumbs = breadcrumbs.length > 1; | ||||
const componentsClassName = classNames('spacer-top', { 'new-loading': loading }); | |||||
const componentsClassName = classNames('boxed-group', 'boxed-group-inner', 'spacer-top', { | |||||
'new-loading': loading | |||||
}); | |||||
return ( | return ( | ||||
<div className="page page-limited"> | <div className="page page-limited"> |
{loading && <i className="spinner spacer-left" />} | {loading && <i className="spinner spacer-left" />} | ||||
{results != null && ( | {results != null && ( | ||||
<Components | |||||
branch={this.props.branch} | |||||
components={results} | |||||
rootComponent={component} | |||||
selected={selected} | |||||
/> | |||||
<div className="boxed-group boxed-group-inner spacer-top"> | |||||
<Components | |||||
branch={this.props.branch} | |||||
components={results} | |||||
rootComponent={component} | |||||
selected={selected} | |||||
/> | |||||
</div> | |||||
)} | )} | ||||
</div> | </div> | ||||
); | ); |
*/ | */ | ||||
componentDidMount() { | componentDidMount() { | ||||
// $FlowFixMe | |||||
document.body.classList.add('white-page'); | |||||
if (this.props.appState.organizationsEnabled && !this.props.params.organizationKey) { | if (this.props.appState.organizationsEnabled && !this.props.params.organizationKey) { | ||||
// redirect to organization-level rules page | // redirect to organization-level rules page | ||||
this.props.router.replace( | this.props.router.replace( | ||||
} | } | ||||
componentWillUnmount() { | componentWillUnmount() { | ||||
// $FlowFixMe | |||||
document.body.classList.remove('white-page'); | |||||
if (this.stop) { | if (this.stop) { | ||||
this.stop(); | this.stop(); | ||||
} | } |
componentDidMount() { | componentDidMount() { | ||||
this.mounted = true; | this.mounted = true; | ||||
// $FlowFixMe | |||||
document.body.classList.add('white-page'); | |||||
this.props.fetchMetrics(); | this.props.fetchMetrics(); | ||||
this.fetchMeasures(this.props); | this.fetchMeasures(this.props); | ||||
key.setScope('measures-files'); | key.setScope('measures-files'); | ||||
componentWillUnmount() { | componentWillUnmount() { | ||||
this.mounted = false; | this.mounted = false; | ||||
// $FlowFixMe | |||||
document.body.classList.remove('white-page'); | |||||
key.deleteScope('measures-files'); | key.deleteScope('measures-files'); | ||||
const footer = document.getElementById('footer'); | const footer = document.getElementById('footer'); | ||||
if (footer) { | if (footer) { |
<table class="data zebra"> | |||||
<thead> | |||||
<tr> | |||||
<th>{{t 'custom_measures.metric'}}</th> | |||||
<th>{{t 'value'}}</th> | |||||
<th>{{t 'description'}}</th> | |||||
<th>{{t 'date'}}</th> | |||||
<th> </th> | |||||
</tr> | |||||
</thead> | |||||
<tbody></tbody> | |||||
</table> | |||||
<div class="boxed-group boxed-group-inner"> | |||||
<table class="data zebra"> | |||||
<thead> | |||||
<tr> | |||||
<th>{{t 'custom_measures.metric'}}</th> | |||||
<th>{{t 'value'}}</th> | |||||
<th>{{t 'description'}}</th> | |||||
<th>{{t 'date'}}</th> | |||||
<th> </th> | |||||
</tr> | |||||
</thead> | |||||
<tbody></tbody> | |||||
</table> | |||||
</div> |
<div> | |||||
<div class="boxed-group boxed-group-inner"> | |||||
{{#isNull organization}} | {{#isNull organization}} | ||||
<div class="panel panel-vertical js-anyone"> | <div class="panel panel-vertical js-anyone"> | ||||
<div class="display-inline-block text-top width-20"> | <div class="display-inline-block text-top width-20"> |
<div class="panel panel-vertical bordered-bottom spacer-bottom"> | |||||
<div class="big-spacer-bottom"> | |||||
<form id="groups-search-form" class="search-box"> | <form id="groups-search-form" class="search-box"> | ||||
<input id="groups-search-query" class="search-box-input" type="text" name="q" placeholder="{{t 'search.search_by_name'}}" maxlength="100"> | <input id="groups-search-query" class="search-box-input" type="text" name="q" placeholder="{{t 'search.search_by_name'}}" maxlength="100"> | ||||
<svg class="search-box-magnifier" width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;"> | <svg class="search-box-magnifier" width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:1.41421;"> |
return; | return; | ||||
} | } | ||||
// $FlowFixMe | |||||
document.body.classList.add('white-page'); | |||||
const footer = document.getElementById('footer'); | const footer = document.getElementById('footer'); | ||||
if (footer) { | if (footer) { | ||||
footer.classList.add('page-footer-with-sidebar'); | footer.classList.add('page-footer-with-sidebar'); | ||||
componentWillUnmount() { | componentWillUnmount() { | ||||
this.detachShortcuts(); | this.detachShortcuts(); | ||||
// $FlowFixMe | |||||
document.body.classList.remove('white-page'); | |||||
const footer = document.getElementById('footer'); | const footer = document.getElementById('footer'); | ||||
if (footer) { | if (footer) { | ||||
footer.classList.remove('page-footer-with-sidebar'); | footer.classList.remove('page-footer-with-sidebar'); |
import IssuesCounter from './IssuesCounter'; | import IssuesCounter from './IssuesCounter'; | ||||
import ReloadButton from './ReloadButton'; | import ReloadButton from './ReloadButton'; | ||||
/*:: import type { Paging } from '../utils'; */ | /*:: import type { Paging } from '../utils'; */ | ||||
import { HomePageType } from '../../../app/types'; | |||||
import DeferredSpinner from '../../../components/common/DeferredSpinner'; | import DeferredSpinner from '../../../components/common/DeferredSpinner'; | ||||
import HomePageSelect from '../../../components/controls/HomePageSelect'; | import HomePageSelect from '../../../components/controls/HomePageSelect'; | ||||
import { translate } from '../../../helpers/l10n'; | import { translate } from '../../../helpers/l10n'; | ||||
</div> | </div> | ||||
{this.props.canSetHome && ( | {this.props.canSetHome && ( | ||||
<HomePageSelect className="huge-spacer-left" currentPage={{ type: 'my-issues' }} /> | |||||
<HomePageSelect | |||||
className="huge-spacer-left" | |||||
currentPage={{ type: HomePageType.MyIssues }} | |||||
/> | |||||
)} | )} | ||||
</div> | </div> | ||||
); | ); |
render() { | render() { | ||||
return ( | return ( | ||||
<div id="marketplace-plugins"> | |||||
<div className="boxed-group boxed-group-inner" id="marketplace-plugins"> | |||||
<ul> | <ul> | ||||
{this.props.plugins.map(plugin => ( | {this.props.plugins.map(plugin => ( | ||||
<li key={plugin.key} className="panel panel-vertical"> | <li key={plugin.key} className="panel panel-vertical"> |
} | } | ||||
]; | ]; | ||||
return ( | return ( | ||||
<div id="marketplace-search" className="panel panel-vertical bordered-bottom spacer-bottom"> | |||||
<div id="marketplace-search" className="big-spacer-bottom"> | |||||
<div className="display-inline-block text-top nowrap abs-width-150 spacer-right"> | <div className="display-inline-block text-top nowrap abs-width-150 spacer-right"> | ||||
<RadioToggle | <RadioToggle | ||||
name="marketplace-filter" | name="marketplace-filter" |
display: flex; | display: flex; | ||||
flex-direction: column; | flex-direction: column; | ||||
justify-content: space-between; | justify-content: space-between; | ||||
background-color: #f3f3f3; | |||||
margin-left: 8px; | margin-left: 8px; | ||||
margin-right: 8px; | margin-right: 8px; | ||||
} | } |
<div class="page page-limited"> | <div class="page page-limited"> | ||||
<div id="metrics-header"></div> | <div id="metrics-header"></div> | ||||
<div id="metrics-list"></div> | |||||
<div id="metrics-list" class="boxed-group boxed-group-inner"></div> | |||||
<div id="metrics-list-footer"></div> | <div id="metrics-list-footer"></div> | ||||
</div> | </div> |
render() { | render() { | ||||
return ( | return ( | ||||
<table className="data zebra"> | |||||
<tbody> | |||||
{this.props.members.map(member => ( | |||||
<MembersListItem | |||||
key={member.login} | |||||
member={member} | |||||
organizationGroups={this.props.organizationGroups} | |||||
organization={this.props.organization} | |||||
removeMember={this.props.removeMember} | |||||
updateMemberGroups={this.props.updateMemberGroups} | |||||
/> | |||||
))} | |||||
</tbody> | |||||
</table> | |||||
<div className="boxed-group boxed-group-inner"> | |||||
<table className="data zebra"> | |||||
<tbody> | |||||
{this.props.members.map(member => ( | |||||
<MembersListItem | |||||
key={member.login} | |||||
member={member} | |||||
organizationGroups={this.props.organizationGroups} | |||||
organization={this.props.organization} | |||||
removeMember={this.props.removeMember} | |||||
updateMemberGroups={this.props.updateMemberGroups} | |||||
/> | |||||
))} | |||||
</tbody> | |||||
</table> | |||||
</div> | |||||
); | ); | ||||
} | } | ||||
} | } |
<h1 className="page-title">{title}</h1> | <h1 className="page-title">{title}</h1> | ||||
</header> | </header> | ||||
<form onSubmit={this.handleSubmit}> | |||||
<div className="modal-field"> | |||||
<label htmlFor="organization-name"> | |||||
{translate('organization.name')} | |||||
<em className="mandatory">*</em> | |||||
</label> | |||||
<input | |||||
id="organization-name" | |||||
name="name" | |||||
required={true} | |||||
type="text" | |||||
maxLength="64" | |||||
value={this.state.name} | |||||
disabled={this.state.loading} | |||||
onChange={e => this.setState({ name: e.target.value })} | |||||
/> | |||||
<div className="modal-field-description"> | |||||
{translate('organization.name.description')} | |||||
</div> | |||||
</div> | |||||
<div className="modal-field"> | |||||
<label htmlFor="organization-avatar">{translate('organization.avatar')}</label> | |||||
<input | |||||
id="organization-avatar" | |||||
name="avatar" | |||||
type="text" | |||||
maxLength="256" | |||||
value={this.state.avatar} | |||||
disabled={this.state.loading} | |||||
onChange={this.handleAvatarInputChange} | |||||
/> | |||||
<div className="modal-field-description"> | |||||
{translate('organization.avatar.description')} | |||||
<div className="boxed-group boxed-group-inner"> | |||||
<form onSubmit={this.handleSubmit}> | |||||
<div className="modal-field"> | |||||
<label htmlFor="organization-name"> | |||||
{translate('organization.name')} | |||||
<em className="mandatory">*</em> | |||||
</label> | |||||
<input | |||||
id="organization-name" | |||||
name="name" | |||||
required={true} | |||||
type="text" | |||||
maxLength="64" | |||||
value={this.state.name} | |||||
disabled={this.state.loading} | |||||
onChange={e => this.setState({ name: e.target.value })} | |||||
/> | |||||
<div className="modal-field-description"> | |||||
{translate('organization.name.description')} | |||||
</div> | |||||
</div> | </div> | ||||
{!!this.state.avatarImage && ( | |||||
<div className="spacer-top spacer-bottom"> | |||||
<div className="little-spacer-bottom"> | |||||
{translate('organization.avatar.preview')} | |||||
{':'} | |||||
<div className="modal-field"> | |||||
<label htmlFor="organization-avatar">{translate('organization.avatar')}</label> | |||||
<input | |||||
id="organization-avatar" | |||||
name="avatar" | |||||
type="text" | |||||
maxLength="256" | |||||
value={this.state.avatar} | |||||
disabled={this.state.loading} | |||||
onChange={this.handleAvatarInputChange} | |||||
/> | |||||
<div className="modal-field-description"> | |||||
{translate('organization.avatar.description')} | |||||
</div> | |||||
{!!this.state.avatarImage && ( | |||||
<div className="spacer-top spacer-bottom"> | |||||
<div className="little-spacer-bottom"> | |||||
{translate('organization.avatar.preview')} | |||||
{':'} | |||||
</div> | |||||
<img src={this.state.avatarImage} alt="" height={30} /> | |||||
</div> | </div> | ||||
<img src={this.state.avatarImage} alt="" height={30} /> | |||||
)} | |||||
</div> | |||||
<div className="modal-field"> | |||||
<label htmlFor="organization-description">{translate('description')}</label> | |||||
<textarea | |||||
id="organization-description" | |||||
name="description" | |||||
rows="3" | |||||
maxLength="256" | |||||
value={this.state.description} | |||||
disabled={this.state.loading} | |||||
onChange={e => this.setState({ description: e.target.value })} | |||||
/> | |||||
<div className="modal-field-description"> | |||||
{translate('organization.description.description')} | |||||
</div> | |||||
</div> | |||||
<div className="modal-field"> | |||||
<label htmlFor="organization-url">{translate('organization.url')}</label> | |||||
<input | |||||
id="organization-url" | |||||
name="url" | |||||
type="text" | |||||
maxLength="256" | |||||
value={this.state.url} | |||||
disabled={this.state.loading} | |||||
onChange={e => this.setState({ url: e.target.value })} | |||||
/> | |||||
<div className="modal-field-description"> | |||||
{translate('organization.url.description')} | |||||
</div> | </div> | ||||
)} | |||||
</div> | |||||
<div className="modal-field"> | |||||
<label htmlFor="organization-description">{translate('description')}</label> | |||||
<textarea | |||||
id="organization-description" | |||||
name="description" | |||||
rows="3" | |||||
maxLength="256" | |||||
value={this.state.description} | |||||
disabled={this.state.loading} | |||||
onChange={e => this.setState({ description: e.target.value })} | |||||
/> | |||||
<div className="modal-field-description"> | |||||
{translate('organization.description.description')} | |||||
</div> | </div> | ||||
</div> | |||||
<div className="modal-field"> | |||||
<label htmlFor="organization-url">{translate('organization.url')}</label> | |||||
<input | |||||
id="organization-url" | |||||
name="url" | |||||
type="text" | |||||
maxLength="256" | |||||
value={this.state.url} | |||||
disabled={this.state.loading} | |||||
onChange={e => this.setState({ url: e.target.value })} | |||||
/> | |||||
<div className="modal-field-description"> | |||||
{translate('organization.url.description')} | |||||
<div className="modal-field"> | |||||
<button type="submit" disabled={this.state.loading}> | |||||
{translate('save')} | |||||
</button> | |||||
{this.state.loading && <i className="spinner spacer-left" />} | |||||
</div> | </div> | ||||
</div> | |||||
<div className="modal-field"> | |||||
<button type="submit" disabled={this.state.loading}> | |||||
{translate('save')} | |||||
</button> | |||||
{this.state.loading && <i className="spinner spacer-left" />} | |||||
</div> | |||||
</form> | |||||
</form> | |||||
</div> | |||||
</div> | </div> | ||||
); | ); | ||||
} | } |
// Jest Snapshot v1, https://goo.gl/fbAQLP | // Jest Snapshot v1, https://goo.gl/fbAQLP | ||||
exports[`should render a list of members of an organization 1`] = ` | exports[`should render a list of members of an organization 1`] = ` | ||||
<table | |||||
className="data zebra" | |||||
<div | |||||
className="boxed-group boxed-group-inner" | |||||
> | > | ||||
<tbody> | |||||
<MembersListItem | |||||
key="admin" | |||||
member={ | |||||
Object { | |||||
"avatar": "", | |||||
"groupCount": 3, | |||||
"login": "admin", | |||||
"name": "Admin Istrator", | |||||
<table | |||||
className="data zebra" | |||||
> | |||||
<tbody> | |||||
<MembersListItem | |||||
key="admin" | |||||
member={ | |||||
Object { | |||||
"avatar": "", | |||||
"groupCount": 3, | |||||
"login": "admin", | |||||
"name": "Admin Istrator", | |||||
} | |||||
} | } | ||||
} | |||||
organization={ | |||||
Object { | |||||
"key": "foo", | |||||
"name": "Foo", | |||||
organization={ | |||||
Object { | |||||
"key": "foo", | |||||
"name": "Foo", | |||||
} | |||||
} | } | ||||
} | |||||
/> | |||||
<MembersListItem | |||||
key="john" | |||||
member={ | |||||
Object { | |||||
"avatar": "7daf6c79d4802916d83f6266e24850af", | |||||
"groupCount": 1, | |||||
"login": "john", | |||||
"name": "John Doe", | |||||
/> | |||||
<MembersListItem | |||||
key="john" | |||||
member={ | |||||
Object { | |||||
"avatar": "7daf6c79d4802916d83f6266e24850af", | |||||
"groupCount": 1, | |||||
"login": "john", | |||||
"name": "John Doe", | |||||
} | |||||
} | } | ||||
} | |||||
organization={ | |||||
Object { | |||||
"key": "foo", | |||||
"name": "Foo", | |||||
organization={ | |||||
Object { | |||||
"key": "foo", | |||||
"name": "Foo", | |||||
} | |||||
} | } | ||||
} | |||||
/> | |||||
</tbody> | |||||
</table> | |||||
/> | |||||
</tbody> | |||||
</table> | |||||
</div> | |||||
`; | `; |
organization.edit | organization.edit | ||||
</h1> | </h1> | ||||
</header> | </header> | ||||
<form | |||||
onSubmit={[Function]} | |||||
<div | |||||
className="boxed-group boxed-group-inner" | |||||
> | > | ||||
<div | |||||
className="modal-field" | |||||
<form | |||||
onSubmit={[Function]} | |||||
> | > | ||||
<label | |||||
htmlFor="organization-name" | |||||
<div | |||||
className="modal-field" | |||||
> | > | ||||
organization.name | |||||
<em | |||||
className="mandatory" | |||||
<label | |||||
htmlFor="organization-name" | |||||
> | |||||
organization.name | |||||
<em | |||||
className="mandatory" | |||||
> | |||||
* | |||||
</em> | |||||
</label> | |||||
<input | |||||
disabled={false} | |||||
id="organization-name" | |||||
maxLength="64" | |||||
name="name" | |||||
onChange={[Function]} | |||||
required={true} | |||||
type="text" | |||||
value="Foo" | |||||
/> | |||||
<div | |||||
className="modal-field-description" | |||||
> | > | ||||
* | |||||
</em> | |||||
</label> | |||||
<input | |||||
disabled={false} | |||||
id="organization-name" | |||||
maxLength="64" | |||||
name="name" | |||||
onChange={[Function]} | |||||
required={true} | |||||
type="text" | |||||
value="Foo" | |||||
/> | |||||
organization.name.description | |||||
</div> | |||||
</div> | |||||
<div | <div | ||||
className="modal-field-description" | |||||
className="modal-field" | |||||
> | > | ||||
organization.name.description | |||||
<label | |||||
htmlFor="organization-avatar" | |||||
> | |||||
organization.avatar | |||||
</label> | |||||
<input | |||||
disabled={false} | |||||
id="organization-avatar" | |||||
maxLength="256" | |||||
name="avatar" | |||||
onChange={[Function]} | |||||
type="text" | |||||
value="" | |||||
/> | |||||
<div | |||||
className="modal-field-description" | |||||
> | |||||
organization.avatar.description | |||||
</div> | |||||
</div> | </div> | ||||
</div> | |||||
<div | |||||
className="modal-field" | |||||
> | |||||
<label | |||||
htmlFor="organization-avatar" | |||||
> | |||||
organization.avatar | |||||
</label> | |||||
<input | |||||
disabled={false} | |||||
id="organization-avatar" | |||||
maxLength="256" | |||||
name="avatar" | |||||
onChange={[Function]} | |||||
type="text" | |||||
value="" | |||||
/> | |||||
<div | <div | ||||
className="modal-field-description" | |||||
className="modal-field" | |||||
> | > | ||||
organization.avatar.description | |||||
<label | |||||
htmlFor="organization-description" | |||||
> | |||||
description | |||||
</label> | |||||
<textarea | |||||
disabled={false} | |||||
id="organization-description" | |||||
maxLength="256" | |||||
name="description" | |||||
onChange={[Function]} | |||||
rows="3" | |||||
value="" | |||||
/> | |||||
<div | |||||
className="modal-field-description" | |||||
> | |||||
organization.description.description | |||||
</div> | |||||
</div> | </div> | ||||
</div> | |||||
<div | |||||
className="modal-field" | |||||
> | |||||
<label | |||||
htmlFor="organization-description" | |||||
> | |||||
description | |||||
</label> | |||||
<textarea | |||||
disabled={false} | |||||
id="organization-description" | |||||
maxLength="256" | |||||
name="description" | |||||
onChange={[Function]} | |||||
rows="3" | |||||
value="" | |||||
/> | |||||
<div | <div | ||||
className="modal-field-description" | |||||
className="modal-field" | |||||
> | > | ||||
organization.description.description | |||||
<label | |||||
htmlFor="organization-url" | |||||
> | |||||
organization.url | |||||
</label> | |||||
<input | |||||
disabled={false} | |||||
id="organization-url" | |||||
maxLength="256" | |||||
name="url" | |||||
onChange={[Function]} | |||||
type="text" | |||||
value="" | |||||
/> | |||||
<div | |||||
className="modal-field-description" | |||||
> | |||||
organization.url.description | |||||
</div> | |||||
</div> | </div> | ||||
</div> | |||||
<div | |||||
className="modal-field" | |||||
> | |||||
<label | |||||
htmlFor="organization-url" | |||||
> | |||||
organization.url | |||||
</label> | |||||
<input | |||||
disabled={false} | |||||
id="organization-url" | |||||
maxLength="256" | |||||
name="url" | |||||
onChange={[Function]} | |||||
type="text" | |||||
value="" | |||||
/> | |||||
<div | <div | ||||
className="modal-field-description" | |||||
className="modal-field" | |||||
> | > | ||||
organization.url.description | |||||
<button | |||||
disabled={false} | |||||
type="submit" | |||||
> | |||||
save | |||||
</button> | |||||
</div> | </div> | ||||
</div> | |||||
<div | |||||
className="modal-field" | |||||
> | |||||
<button | |||||
disabled={false} | |||||
type="submit" | |||||
> | |||||
save | |||||
</button> | |||||
</div> | |||||
</form> | |||||
</form> | |||||
</div> | |||||
</div> | </div> | ||||
`; | `; | ||||
organization.edit | organization.edit | ||||
</h1> | </h1> | ||||
</header> | </header> | ||||
<form | |||||
onSubmit={[Function]} | |||||
<div | |||||
className="boxed-group boxed-group-inner" | |||||
> | > | ||||
<div | |||||
className="modal-field" | |||||
<form | |||||
onSubmit={[Function]} | |||||
> | > | ||||
<label | |||||
htmlFor="organization-name" | |||||
> | |||||
organization.name | |||||
<em | |||||
className="mandatory" | |||||
> | |||||
* | |||||
</em> | |||||
</label> | |||||
<input | |||||
disabled={false} | |||||
id="organization-name" | |||||
maxLength="64" | |||||
name="name" | |||||
onChange={[Function]} | |||||
required={true} | |||||
type="text" | |||||
value="New Foo" | |||||
/> | |||||
<div | <div | ||||
className="modal-field-description" | |||||
className="modal-field" | |||||
> | > | ||||
organization.name.description | |||||
<label | |||||
htmlFor="organization-name" | |||||
> | |||||
organization.name | |||||
<em | |||||
className="mandatory" | |||||
> | |||||
* | |||||
</em> | |||||
</label> | |||||
<input | |||||
disabled={false} | |||||
id="organization-name" | |||||
maxLength="64" | |||||
name="name" | |||||
onChange={[Function]} | |||||
required={true} | |||||
type="text" | |||||
value="New Foo" | |||||
/> | |||||
<div | |||||
className="modal-field-description" | |||||
> | |||||
organization.name.description | |||||
</div> | |||||
</div> | </div> | ||||
</div> | |||||
<div | |||||
className="modal-field" | |||||
> | |||||
<label | |||||
htmlFor="organization-avatar" | |||||
> | |||||
organization.avatar | |||||
</label> | |||||
<input | |||||
disabled={false} | |||||
id="organization-avatar" | |||||
maxLength="256" | |||||
name="avatar" | |||||
onChange={[Function]} | |||||
type="text" | |||||
value="foo-avatar" | |||||
/> | |||||
<div | <div | ||||
className="modal-field-description" | |||||
className="modal-field" | |||||
> | > | ||||
organization.avatar.description | |||||
<label | |||||
htmlFor="organization-avatar" | |||||
> | |||||
organization.avatar | |||||
</label> | |||||
<input | |||||
disabled={false} | |||||
id="organization-avatar" | |||||
maxLength="256" | |||||
name="avatar" | |||||
onChange={[Function]} | |||||
type="text" | |||||
value="foo-avatar" | |||||
/> | |||||
<div | |||||
className="modal-field-description" | |||||
> | |||||
organization.avatar.description | |||||
</div> | |||||
<div | |||||
className="spacer-top spacer-bottom" | |||||
> | |||||
<div | |||||
className="little-spacer-bottom" | |||||
> | |||||
organization.avatar.preview | |||||
: | |||||
</div> | |||||
<img | |||||
alt="" | |||||
height={30} | |||||
src="foo-avatar-image" | |||||
/> | |||||
</div> | |||||
</div> | </div> | ||||
<div | <div | ||||
className="spacer-top spacer-bottom" | |||||
className="modal-field" | |||||
> | > | ||||
<label | |||||
htmlFor="organization-description" | |||||
> | |||||
description | |||||
</label> | |||||
<textarea | |||||
disabled={false} | |||||
id="organization-description" | |||||
maxLength="256" | |||||
name="description" | |||||
onChange={[Function]} | |||||
rows="3" | |||||
value="foo-description" | |||||
/> | |||||
<div | <div | ||||
className="little-spacer-bottom" | |||||
className="modal-field-description" | |||||
> | > | ||||
organization.avatar.preview | |||||
: | |||||
organization.description.description | |||||
</div> | </div> | ||||
<img | |||||
alt="" | |||||
height={30} | |||||
src="foo-avatar-image" | |||||
/> | |||||
</div> | </div> | ||||
</div> | |||||
<div | |||||
className="modal-field" | |||||
> | |||||
<label | |||||
htmlFor="organization-description" | |||||
> | |||||
description | |||||
</label> | |||||
<textarea | |||||
disabled={false} | |||||
id="organization-description" | |||||
maxLength="256" | |||||
name="description" | |||||
onChange={[Function]} | |||||
rows="3" | |||||
value="foo-description" | |||||
/> | |||||
<div | <div | ||||
className="modal-field-description" | |||||
className="modal-field" | |||||
> | > | ||||
organization.description.description | |||||
<label | |||||
htmlFor="organization-url" | |||||
> | |||||
organization.url | |||||
</label> | |||||
<input | |||||
disabled={false} | |||||
id="organization-url" | |||||
maxLength="256" | |||||
name="url" | |||||
onChange={[Function]} | |||||
type="text" | |||||
value="foo-url" | |||||
/> | |||||
<div | |||||
className="modal-field-description" | |||||
> | |||||
organization.url.description | |||||
</div> | |||||
</div> | </div> | ||||
</div> | |||||
<div | |||||
className="modal-field" | |||||
> | |||||
<label | |||||
htmlFor="organization-url" | |||||
> | |||||
organization.url | |||||
</label> | |||||
<input | |||||
disabled={false} | |||||
id="organization-url" | |||||
maxLength="256" | |||||
name="url" | |||||
onChange={[Function]} | |||||
type="text" | |||||
value="foo-url" | |||||
/> | |||||
<div | <div | ||||
className="modal-field-description" | |||||
className="modal-field" | |||||
> | > | ||||
organization.url.description | |||||
<button | |||||
disabled={false} | |||||
type="submit" | |||||
> | |||||
save | |||||
</button> | |||||
</div> | </div> | ||||
</div> | |||||
<div | |||||
className="modal-field" | |||||
> | |||||
<button | |||||
disabled={false} | |||||
type="submit" | |||||
> | |||||
save | |||||
</button> | |||||
</div> | |||||
</form> | |||||
</form> | |||||
</div> | |||||
</div> | </div> | ||||
`; | `; | ||||
organization.edit | organization.edit | ||||
</h1> | </h1> | ||||
</header> | </header> | ||||
<form | |||||
onSubmit={[Function]} | |||||
<div | |||||
className="boxed-group boxed-group-inner" | |||||
> | > | ||||
<div | |||||
className="modal-field" | |||||
<form | |||||
onSubmit={[Function]} | |||||
> | > | ||||
<label | |||||
htmlFor="organization-name" | |||||
> | |||||
organization.name | |||||
<em | |||||
className="mandatory" | |||||
> | |||||
* | |||||
</em> | |||||
</label> | |||||
<input | |||||
disabled={true} | |||||
id="organization-name" | |||||
maxLength="64" | |||||
name="name" | |||||
onChange={[Function]} | |||||
required={true} | |||||
type="text" | |||||
value="New Foo" | |||||
/> | |||||
<div | <div | ||||
className="modal-field-description" | |||||
className="modal-field" | |||||
> | > | ||||
organization.name.description | |||||
<label | |||||
htmlFor="organization-name" | |||||
> | |||||
organization.name | |||||
<em | |||||
className="mandatory" | |||||
> | |||||
* | |||||
</em> | |||||
</label> | |||||
<input | |||||
disabled={true} | |||||
id="organization-name" | |||||
maxLength="64" | |||||
name="name" | |||||
onChange={[Function]} | |||||
required={true} | |||||
type="text" | |||||
value="New Foo" | |||||
/> | |||||
<div | |||||
className="modal-field-description" | |||||
> | |||||
organization.name.description | |||||
</div> | |||||
</div> | </div> | ||||
</div> | |||||
<div | |||||
className="modal-field" | |||||
> | |||||
<label | |||||
htmlFor="organization-avatar" | |||||
> | |||||
organization.avatar | |||||
</label> | |||||
<input | |||||
disabled={true} | |||||
id="organization-avatar" | |||||
maxLength="256" | |||||
name="avatar" | |||||
onChange={[Function]} | |||||
type="text" | |||||
value="foo-avatar" | |||||
/> | |||||
<div | <div | ||||
className="modal-field-description" | |||||
className="modal-field" | |||||
> | > | ||||
organization.avatar.description | |||||
<label | |||||
htmlFor="organization-avatar" | |||||
> | |||||
organization.avatar | |||||
</label> | |||||
<input | |||||
disabled={true} | |||||
id="organization-avatar" | |||||
maxLength="256" | |||||
name="avatar" | |||||
onChange={[Function]} | |||||
type="text" | |||||
value="foo-avatar" | |||||
/> | |||||
<div | |||||
className="modal-field-description" | |||||
> | |||||
organization.avatar.description | |||||
</div> | |||||
<div | |||||
className="spacer-top spacer-bottom" | |||||
> | |||||
<div | |||||
className="little-spacer-bottom" | |||||
> | |||||
organization.avatar.preview | |||||
: | |||||
</div> | |||||
<img | |||||
alt="" | |||||
height={30} | |||||
src="foo-avatar-image" | |||||
/> | |||||
</div> | |||||
</div> | </div> | ||||
<div | <div | ||||
className="spacer-top spacer-bottom" | |||||
className="modal-field" | |||||
> | > | ||||
<label | |||||
htmlFor="organization-description" | |||||
> | |||||
description | |||||
</label> | |||||
<textarea | |||||
disabled={true} | |||||
id="organization-description" | |||||
maxLength="256" | |||||
name="description" | |||||
onChange={[Function]} | |||||
rows="3" | |||||
value="foo-description" | |||||
/> | |||||
<div | <div | ||||
className="little-spacer-bottom" | |||||
className="modal-field-description" | |||||
> | > | ||||
organization.avatar.preview | |||||
: | |||||
organization.description.description | |||||
</div> | </div> | ||||
<img | |||||
alt="" | |||||
height={30} | |||||
src="foo-avatar-image" | |||||
/> | |||||
</div> | </div> | ||||
</div> | |||||
<div | |||||
className="modal-field" | |||||
> | |||||
<label | |||||
htmlFor="organization-description" | |||||
> | |||||
description | |||||
</label> | |||||
<textarea | |||||
disabled={true} | |||||
id="organization-description" | |||||
maxLength="256" | |||||
name="description" | |||||
onChange={[Function]} | |||||
rows="3" | |||||
value="foo-description" | |||||
/> | |||||
<div | <div | ||||
className="modal-field-description" | |||||
className="modal-field" | |||||
> | > | ||||
organization.description.description | |||||
<label | |||||
htmlFor="organization-url" | |||||
> | |||||
organization.url | |||||
</label> | |||||
<input | |||||
disabled={true} | |||||
id="organization-url" | |||||
maxLength="256" | |||||
name="url" | |||||
onChange={[Function]} | |||||
type="text" | |||||
value="foo-url" | |||||
/> | |||||
<div | |||||
className="modal-field-description" | |||||
> | |||||
organization.url.description | |||||
</div> | |||||
</div> | </div> | ||||
</div> | |||||
<div | |||||
className="modal-field" | |||||
> | |||||
<label | |||||
htmlFor="organization-url" | |||||
> | |||||
organization.url | |||||
</label> | |||||
<input | |||||
disabled={true} | |||||
id="organization-url" | |||||
maxLength="256" | |||||
name="url" | |||||
onChange={[Function]} | |||||
type="text" | |||||
value="foo-url" | |||||
/> | |||||
<div | <div | ||||
className="modal-field-description" | |||||
className="modal-field" | |||||
> | > | ||||
organization.url.description | |||||
<button | |||||
disabled={true} | |||||
type="submit" | |||||
> | |||||
save | |||||
</button> | |||||
<i | |||||
className="spinner spacer-left" | |||||
/> | |||||
</div> | </div> | ||||
</div> | |||||
<div | |||||
className="modal-field" | |||||
> | |||||
<button | |||||
disabled={true} | |||||
type="submit" | |||||
> | |||||
save | |||||
</button> | |||||
<i | |||||
className="spinner spacer-left" | |||||
/> | |||||
</div> | |||||
</form> | |||||
</form> | |||||
</div> | |||||
</div> | </div> | ||||
`; | `; |
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | ||||
*/ | */ | ||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import { Organization } from '../../../app/types'; | |||||
import { connect } from 'react-redux'; | |||||
import { Organization, HomePageType } from '../../../app/types'; | |||||
import HomePageSelect from '../../../components/controls/HomePageSelect'; | import HomePageSelect from '../../../components/controls/HomePageSelect'; | ||||
import { translate } from '../../../helpers/l10n'; | import { translate } from '../../../helpers/l10n'; | ||||
import { getGlobalSettingValue } from '../../../store/rootReducer'; | |||||
interface Props { | |||||
interface StateProps { | |||||
onSonarCloud: boolean; | |||||
} | |||||
interface Props extends StateProps { | |||||
organization: Organization; | organization: Organization; | ||||
} | } | ||||
export default function OrganizationNavigationMeta({ organization }: Props) { | |||||
export function OrganizationNavigationMeta({ onSonarCloud, organization }: Props) { | |||||
return ( | return ( | ||||
<div className="navbar-context-meta"> | <div className="navbar-context-meta"> | ||||
{organization.url != null && ( | {organization.url != null && ( | ||||
<div className="text-muted"> | <div className="text-muted"> | ||||
<strong>{translate('organization.key')}:</strong> {organization.key} | <strong>{translate('organization.key')}:</strong> {organization.key} | ||||
</div> | </div> | ||||
<div className="navbar-context-meta-secondary"> | |||||
<HomePageSelect currentPage={{ type: 'organization', key: organization.key }} /> | |||||
</div> | |||||
{onSonarCloud && ( | |||||
<div className="navbar-context-meta-secondary"> | |||||
<HomePageSelect | |||||
currentPage={{ type: HomePageType.Organization, parameter: organization.key }} | |||||
/> | |||||
</div> | |||||
)} | |||||
</div> | </div> | ||||
); | ); | ||||
} | } | ||||
const mapStateToProps = (state: any): StateProps => { | |||||
const sonarCloudSetting = getGlobalSettingValue(state, 'sonar.sonarcloud.enabled'); | |||||
return { | |||||
onSonarCloud: Boolean(sonarCloudSetting && sonarCloudSetting.value === 'true') | |||||
}; | |||||
}; | |||||
export default connect(mapStateToProps)(OrganizationNavigationMeta); |
*/ | */ | ||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import { shallow } from 'enzyme'; | import { shallow } from 'enzyme'; | ||||
import OrganizationNavigationMeta from '../OrganizationNavigationMeta'; | |||||
import { OrganizationNavigationMeta } from '../OrganizationNavigationMeta'; | |||||
import { Visibility } from '../../../../app/types'; | import { Visibility } from '../../../../app/types'; | ||||
it('renders', () => { | it('renders', () => { | ||||
expect( | expect( | ||||
shallow( | shallow( | ||||
<OrganizationNavigationMeta | <OrganizationNavigationMeta | ||||
onSonarCloud={true} | |||||
organization={{ | organization={{ | ||||
key: 'foo', | key: 'foo', | ||||
name: 'Foo', | name: 'Foo', |
} | } | ||||
} | } | ||||
/> | /> | ||||
<OrganizationNavigationMeta | |||||
<Connect(OrganizationNavigationMeta) | |||||
organization={ | organization={ | ||||
Object { | Object { | ||||
"key": "foo", | "key": "foo", |
<Connect(HomePageSelect) | <Connect(HomePageSelect) | ||||
currentPage={ | currentPage={ | ||||
Object { | Object { | ||||
"key": "foo", | |||||
"type": "organization", | |||||
"parameter": "foo", | |||||
"type": "ORGANIZATION", | |||||
} | } | ||||
} | } | ||||
/> | /> |
componentDidMount() { | componentDidMount() { | ||||
this.mounted = true; | this.mounted = true; | ||||
const domElement = document.querySelector('html'); | |||||
if (domElement) { | |||||
domElement.classList.add('dashboard-page'); | |||||
} | |||||
this.loadMeasures().then(this.loadHistory); | this.loadMeasures().then(this.loadHistory); | ||||
} | } | ||||
componentWillUnmount() { | componentWillUnmount() { | ||||
this.mounted = false; | this.mounted = false; | ||||
const domElement = document.querySelector('html'); | |||||
if (domElement) { | |||||
domElement.classList.remove('dashboard-page'); | |||||
} | |||||
} | } | ||||
loadMeasures() { | loadMeasures() { |
)); | )); | ||||
return ( | return ( | ||||
<table id="permission-templates" className="data zebra permissions-table"> | |||||
<ListHeader organization={this.props.organization} permissions={this.props.permissions} /> | |||||
<tbody>{permissionTemplates}</tbody> | |||||
</table> | |||||
<div className="boxed-group boxed-group-inner"> | |||||
<table id="permission-templates" className="data zebra permissions-table"> | |||||
<ListHeader organization={this.props.organization} permissions={this.props.permissions} /> | |||||
<tbody>{permissionTemplates}</tbody> | |||||
</table> | |||||
</div> | |||||
); | ); | ||||
} | } | ||||
} | } |
)); | )); | ||||
return ( | return ( | ||||
<table className="data zebra permissions-table"> | |||||
{this.renderTableHeader()} | |||||
<tbody> | |||||
{users.length === 0 && groups.length === 0 && this.renderEmpty()} | |||||
{users} | |||||
{groups} | |||||
</tbody> | |||||
</table> | |||||
<div className="boxed-group boxed-group-inner"> | |||||
<table className="data zebra permissions-table"> | |||||
{this.renderTableHeader()} | |||||
<tbody> | |||||
{users.length === 0 && groups.length === 0 && this.renderEmpty()} | |||||
{users} | |||||
{groups} | |||||
</tbody> | |||||
</table> | |||||
</div> | |||||
); | ); | ||||
} | } | ||||
} | } |
componentDidMount() { | componentDidMount() { | ||||
this.mounted = true; | this.mounted = true; | ||||
const html = document.querySelector('html'); | |||||
if (html) { | |||||
html.classList.add('dashboard-page'); | |||||
} | |||||
this.fetchData(); | this.fetchData(); | ||||
} | } | ||||
componentWillUnmount() { | componentWillUnmount() { | ||||
this.mounted = false; | this.mounted = false; | ||||
const html = document.querySelector('html'); | |||||
if (html) { | |||||
html.classList.remove('dashboard-page'); | |||||
} | |||||
} | } | ||||
fetchData() { | fetchData() { |
)} | )} | ||||
{hasModules && ( | {hasModules && ( | ||||
<div> | |||||
<div className="boxed-group boxed-group-inner"> | |||||
<div className="big-spacer-bottom"> | <div className="big-spacer-bottom"> | ||||
<ul className="tabs"> | <ul className="tabs"> | ||||
<li> | <li> |
)); | )); | ||||
return ( | return ( | ||||
<table id="project-links" className="data zebra"> | |||||
{this.renderHeader()} | |||||
<tbody>{linkRows}</tbody> | |||||
</table> | |||||
<div className="boxed-group boxed-group-inner"> | |||||
<table id="project-links" className="data zebra"> | |||||
{this.renderHeader()} | |||||
<tbody>{linkRows}</tbody> | |||||
</table> | |||||
</div> | |||||
); | ); | ||||
} | } | ||||
} | } |
componentDidMount() { | componentDidMount() { | ||||
this.mounted = true; | this.mounted = true; | ||||
const elem = document.querySelector('html'); | |||||
elem && elem.classList.add('dashboard-page'); | |||||
if (this.shouldRedirect()) { | if (this.shouldRedirect()) { | ||||
const newQuery = { ...this.state.query, graph: getGraph() }; | const newQuery = { ...this.state.query, graph: getGraph() }; | ||||
if (isCustomGraph(newQuery.graph)) { | if (isCustomGraph(newQuery.graph)) { | ||||
componentWillUnmount() { | componentWillUnmount() { | ||||
this.mounted = false; | this.mounted = false; | ||||
const elem = document.querySelector('html'); | |||||
elem && elem.classList.remove('dashboard-page'); | |||||
} | } | ||||
addCustomEvent = (analysis /*: string */, name /*: string */, category /*: ?string */) => | addCustomEvent = (analysis /*: string */, name /*: string */, category /*: ?string */) => |
{this.renderBranchLifeTime()} | {this.renderBranchLifeTime()} | ||||
</header> | </header> | ||||
<table className="data zebra zebra-hover"> | |||||
<thead> | |||||
<tr> | |||||
<th>{translate('branch')}</th> | |||||
<th className="thin nowrap text-right">{translate('status')}</th> | |||||
<th className="thin nowrap text-right">{translate('branches.last_analysis_date')}</th> | |||||
<th className="thin nowrap text-right">{translate('actions')}</th> | |||||
</tr> | |||||
</thead> | |||||
<tbody> | |||||
{sortBranchesAsTree(branches).map(branch => ( | |||||
<BranchRow | |||||
branch={branch} | |||||
component={component.key} | |||||
key={branch.name} | |||||
onChange={onBranchesChange} | |||||
/> | |||||
))} | |||||
</tbody> | |||||
</table> | |||||
<div className="boxed-group boxed-group-inner"> | |||||
<table className="data zebra zebra-hover"> | |||||
<thead> | |||||
<tr> | |||||
<th>{translate('branch')}</th> | |||||
<th className="thin nowrap text-right">{translate('status')}</th> | |||||
<th className="thin nowrap text-right"> | |||||
{translate('branches.last_analysis_date')} | |||||
</th> | |||||
<th className="thin nowrap text-right">{translate('actions')}</th> | |||||
</tr> | |||||
</thead> | |||||
<tbody> | |||||
{sortBranchesAsTree(branches).map(branch => ( | |||||
<BranchRow | |||||
branch={branch} | |||||
component={component.key} | |||||
key={branch.name} | |||||
onChange={onBranchesChange} | |||||
/> | |||||
))} | |||||
</tbody> | |||||
</table> | |||||
</div> | |||||
</div> | </div> | ||||
); | ); | ||||
} | } |
/> | /> | ||||
</p> | </p> | ||||
</header> | </header> | ||||
<table | |||||
className="data zebra zebra-hover" | |||||
<div | |||||
className="boxed-group boxed-group-inner" | |||||
> | > | ||||
<thead> | |||||
<tr> | |||||
<th> | |||||
branch | |||||
</th> | |||||
<th | |||||
className="thin nowrap text-right" | |||||
> | |||||
status | |||||
</th> | |||||
<th | |||||
className="thin nowrap text-right" | |||||
> | |||||
branches.last_analysis_date | |||||
</th> | |||||
<th | |||||
className="thin nowrap text-right" | |||||
> | |||||
actions | |||||
</th> | |||||
</tr> | |||||
</thead> | |||||
<tbody> | |||||
<BranchRow | |||||
branch={ | |||||
Object { | |||||
"isMain": true, | |||||
"name": "master", | |||||
<table | |||||
className="data zebra zebra-hover" | |||||
> | |||||
<thead> | |||||
<tr> | |||||
<th> | |||||
branch | |||||
</th> | |||||
<th | |||||
className="thin nowrap text-right" | |||||
> | |||||
status | |||||
</th> | |||||
<th | |||||
className="thin nowrap text-right" | |||||
> | |||||
branches.last_analysis_date | |||||
</th> | |||||
<th | |||||
className="thin nowrap text-right" | |||||
> | |||||
actions | |||||
</th> | |||||
</tr> | |||||
</thead> | |||||
<tbody> | |||||
<BranchRow | |||||
branch={ | |||||
Object { | |||||
"isMain": true, | |||||
"name": "master", | |||||
} | |||||
} | } | ||||
} | |||||
component="foo" | |||||
key="master" | |||||
onChange={[Function]} | |||||
/> | |||||
<BranchRow | |||||
branch={ | |||||
Object { | |||||
"isMain": false, | |||||
"mergeBranch": "master", | |||||
"name": "branch-1.0", | |||||
"type": "SHORT", | |||||
component="foo" | |||||
key="master" | |||||
onChange={[Function]} | |||||
/> | |||||
<BranchRow | |||||
branch={ | |||||
Object { | |||||
"isMain": false, | |||||
"mergeBranch": "master", | |||||
"name": "branch-1.0", | |||||
"type": "SHORT", | |||||
} | |||||
} | } | ||||
} | |||||
component="foo" | |||||
key="branch-1.0" | |||||
onChange={[Function]} | |||||
/> | |||||
<BranchRow | |||||
branch={ | |||||
Object { | |||||
"isMain": false, | |||||
"name": "branch-1.0", | |||||
"type": "LONG", | |||||
component="foo" | |||||
key="branch-1.0" | |||||
onChange={[Function]} | |||||
/> | |||||
<BranchRow | |||||
branch={ | |||||
Object { | |||||
"isMain": false, | |||||
"name": "branch-1.0", | |||||
"type": "LONG", | |||||
} | |||||
} | } | ||||
} | |||||
component="foo" | |||||
key="branch-1.0" | |||||
onChange={[Function]} | |||||
/> | |||||
</tbody> | |||||
</table> | |||||
component="foo" | |||||
key="branch-1.0" | |||||
onChange={[Function]} | |||||
/> | |||||
</tbody> | |||||
</table> | |||||
</div> | |||||
</div> | </div> | ||||
`; | `; |
)); | )); | ||||
return ( | return ( | ||||
<table className="data zebra"> | |||||
<thead> | |||||
<tr> | |||||
<th className="thin nowrap">{translate('language')}</th> | |||||
<th className="thin nowrap">{translate('quality_profile')}</th> | |||||
{/* keep one empty cell for the spinner */} | |||||
<th> </th> | |||||
</tr> | |||||
</thead> | |||||
<tbody>{profileRows}</tbody> | |||||
</table> | |||||
<div className="boxed-group boxed-group-inner"> | |||||
<table className="data zebra"> | |||||
<thead> | |||||
<tr> | |||||
<th className="thin nowrap">{translate('language')}</th> | |||||
<th className="thin nowrap">{translate('quality_profile')}</th> | |||||
{/* keep one empty cell for the spinner */} | |||||
<th> </th> | |||||
</tr> | |||||
</thead> | |||||
<tbody>{profileRows}</tbody> | |||||
</table> | |||||
</div> | |||||
); | ); | ||||
} | } |
// Jest Snapshot v1, https://goo.gl/fbAQLP | // Jest Snapshot v1, https://goo.gl/fbAQLP | ||||
exports[`renders 1`] = ` | exports[`renders 1`] = ` | ||||
<table | |||||
className="data zebra" | |||||
<div | |||||
className="boxed-group boxed-group-inner" | |||||
> | > | ||||
<thead> | |||||
<tr> | |||||
<th | |||||
className="thin nowrap" | |||||
> | |||||
language | |||||
</th> | |||||
<th | |||||
className="thin nowrap" | |||||
> | |||||
quality_profile | |||||
</th> | |||||
<th> | |||||
</th> | |||||
</tr> | |||||
</thead> | |||||
<tbody> | |||||
<ProfileRow | |||||
key="java" | |||||
onChangeProfile={[Function]} | |||||
possibleProfiles={ | |||||
Array [ | |||||
<table | |||||
className="data zebra" | |||||
> | |||||
<thead> | |||||
<tr> | |||||
<th | |||||
className="thin nowrap" | |||||
> | |||||
language | |||||
</th> | |||||
<th | |||||
className="thin nowrap" | |||||
> | |||||
quality_profile | |||||
</th> | |||||
<th> | |||||
</th> | |||||
</tr> | |||||
</thead> | |||||
<tbody> | |||||
<ProfileRow | |||||
key="java" | |||||
onChangeProfile={[Function]} | |||||
possibleProfiles={ | |||||
Array [ | |||||
Object { | |||||
"activeDeprecatedRuleCount": 0, | |||||
"activeRuleCount": 17, | |||||
"key": "foo-java", | |||||
"language": "java", | |||||
"languageName": "java", | |||||
"name": "foo-java", | |||||
"organization": "org", | |||||
}, | |||||
Object { | |||||
"activeDeprecatedRuleCount": 0, | |||||
"activeRuleCount": 17, | |||||
"key": "bar-java", | |||||
"language": "java", | |||||
"languageName": "java", | |||||
"name": "bar-java", | |||||
"organization": "org", | |||||
}, | |||||
Object { | |||||
"activeDeprecatedRuleCount": 0, | |||||
"activeRuleCount": 17, | |||||
"key": "baz-java", | |||||
"language": "java", | |||||
"languageName": "java", | |||||
"name": "baz-java", | |||||
"organization": "org", | |||||
}, | |||||
] | |||||
} | |||||
profile={ | |||||
Object { | Object { | ||||
"activeDeprecatedRuleCount": 0, | "activeDeprecatedRuleCount": 0, | ||||
"activeRuleCount": 17, | "activeRuleCount": 17, | ||||
"languageName": "java", | "languageName": "java", | ||||
"name": "foo-java", | "name": "foo-java", | ||||
"organization": "org", | "organization": "org", | ||||
}, | |||||
Object { | |||||
"activeDeprecatedRuleCount": 0, | |||||
"activeRuleCount": 17, | |||||
"key": "bar-java", | |||||
"language": "java", | |||||
"languageName": "java", | |||||
"name": "bar-java", | |||||
"organization": "org", | |||||
}, | |||||
Object { | |||||
"activeDeprecatedRuleCount": 0, | |||||
"activeRuleCount": 17, | |||||
"key": "baz-java", | |||||
"language": "java", | |||||
"languageName": "java", | |||||
"name": "baz-java", | |||||
"organization": "org", | |||||
}, | |||||
] | |||||
} | |||||
profile={ | |||||
Object { | |||||
"activeDeprecatedRuleCount": 0, | |||||
"activeRuleCount": 17, | |||||
"key": "foo-java", | |||||
"language": "java", | |||||
"languageName": "java", | |||||
"name": "foo-java", | |||||
"organization": "org", | |||||
} | |||||
} | |||||
/> | |||||
<ProfileRow | |||||
key="js" | |||||
onChangeProfile={[Function]} | |||||
possibleProfiles={ | |||||
Array [ | |||||
Object { | |||||
"activeDeprecatedRuleCount": 0, | |||||
"activeRuleCount": 17, | |||||
"key": "foo-js", | |||||
"language": "js", | |||||
"languageName": "js", | |||||
"name": "foo-js", | |||||
"organization": "org", | |||||
}, | |||||
] | |||||
} | } | ||||
} | |||||
/> | |||||
<ProfileRow | |||||
key="js" | |||||
onChangeProfile={[Function]} | |||||
possibleProfiles={ | |||||
Array [ | |||||
profile={ | |||||
Object { | Object { | ||||
"activeDeprecatedRuleCount": 0, | "activeDeprecatedRuleCount": 0, | ||||
"activeRuleCount": 17, | "activeRuleCount": 17, | ||||
"languageName": "js", | "languageName": "js", | ||||
"name": "foo-js", | "name": "foo-js", | ||||
"organization": "org", | "organization": "org", | ||||
}, | |||||
] | |||||
} | |||||
profile={ | |||||
Object { | |||||
"activeDeprecatedRuleCount": 0, | |||||
"activeRuleCount": 17, | |||||
"key": "foo-js", | |||||
"language": "js", | |||||
"languageName": "js", | |||||
"name": "foo-js", | |||||
"organization": "org", | |||||
} | |||||
} | } | ||||
} | |||||
/> | |||||
</tbody> | |||||
</table> | |||||
/> | |||||
</tbody> | |||||
</table> | |||||
</div> | |||||
`; | `; |
componentDidMount() { | componentDidMount() { | ||||
this.mounted = true; | this.mounted = true; | ||||
const html = document.querySelector('html'); | |||||
if (html) { | |||||
html.classList.add('dashboard-page'); | |||||
} | |||||
if (this.props.isFavorite && !isLoggedIn(this.props.currentUser)) { | if (this.props.isFavorite && !isLoggedIn(this.props.currentUser)) { | ||||
handleRequiredAuthentication(); | handleRequiredAuthentication(); | ||||
return; | return; | ||||
componentWillUnmount() { | componentWillUnmount() { | ||||
this.mounted = false; | this.mounted = false; | ||||
const html = document.querySelector('html'); | |||||
if (html) { | |||||
html.classList.remove('dashboard-page'); | |||||
} | |||||
const footer = document.getElementById('footer'); | const footer = document.getElementById('footer'); | ||||
if (footer) { | if (footer) { | ||||
footer.classList.remove('page-footer-with-sidebar'); | footer.classList.remove('page-footer-with-sidebar'); |
import Tooltip from '../../../components/controls/Tooltip'; | import Tooltip from '../../../components/controls/Tooltip'; | ||||
import PerspectiveSelect from './PerspectiveSelect'; | import PerspectiveSelect from './PerspectiveSelect'; | ||||
import ProjectsSortingSelect from './ProjectsSortingSelect'; | import ProjectsSortingSelect from './ProjectsSortingSelect'; | ||||
import { CurrentUser, isLoggedIn } from '../../../app/types'; | |||||
import { CurrentUser, isLoggedIn, HomePageType } from '../../../app/types'; | |||||
import HomePageSelect from '../../../components/controls/HomePageSelect'; | import HomePageSelect from '../../../components/controls/HomePageSelect'; | ||||
import { translate } from '../../../helpers/l10n'; | import { translate } from '../../../helpers/l10n'; | ||||
import { RawQuery } from '../../../helpers/query'; | import { RawQuery } from '../../../helpers/query'; | ||||
)} | )} | ||||
</div> | </div> | ||||
{props.onSonarCloud && | |||||
isLoggedIn(currentUser) && | |||||
props.isFavorite && | |||||
!props.organization && ( | |||||
<HomePageSelect className="huge-spacer-left" currentPage={{ type: 'my-projects' }} /> | |||||
)} | |||||
{props.isFavorite && ( | |||||
<HomePageSelect | |||||
className="huge-spacer-left" | |||||
currentPage={{ type: HomePageType.MyProjects }} | |||||
/> | |||||
)} | |||||
</header> | </header> | ||||
); | ); | ||||
} | } |
className="spacer-right" | className="spacer-right" | ||||
component={project.key} | component={project.key} | ||||
favorite={project.isFavorite} | favorite={project.isFavorite} | ||||
qualifier="TRK" | |||||
/> | /> | ||||
)} | )} | ||||
<h2 className="project-card-name"> | <h2 className="project-card-name"> |
className="spacer-right" | className="spacer-right" | ||||
component={project.key} | component={project.key} | ||||
favorite={project.isFavorite} | favorite={project.isFavorite} | ||||
qualifier="TRK" | |||||
/> | /> | ||||
)} | )} | ||||
<h2 className="project-card-name"> | <h2 className="project-card-name"> |
render() { | render() { | ||||
return ( | return ( | ||||
<table | |||||
className={classNames('data', 'zebra', { 'new-loading': !this.props.ready })} | |||||
id="projects-management-page-projects"> | |||||
<thead> | |||||
<tr> | |||||
<th /> | |||||
<th>{translate('name')}</th> | |||||
<th /> | |||||
<th>{translate('key')}</th> | |||||
<th className="thin nowrap text-right">{translate('last_analysis')}</th> | |||||
<th /> | |||||
</tr> | |||||
</thead> | |||||
<tbody> | |||||
{this.props.projects.map(project => ( | |||||
<ProjectRow | |||||
currentUser={this.props.currentUser} | |||||
key={project.key} | |||||
onApplyTemplate={this.handleApplyTemplate} | |||||
onProjectCheck={this.onProjectCheck} | |||||
project={project} | |||||
selected={this.props.selection.includes(project.key)} | |||||
/> | |||||
))} | |||||
</tbody> | |||||
</table> | |||||
<div className="boxed-group boxed-group-inner"> | |||||
<table | |||||
className={classNames('data', 'zebra', { 'new-loading': !this.props.ready })} | |||||
id="projects-management-page-projects"> | |||||
<thead> | |||||
<tr> | |||||
<th /> | |||||
<th>{translate('name')}</th> | |||||
<th /> | |||||
<th>{translate('key')}</th> | |||||
<th className="thin nowrap text-right">{translate('last_analysis')}</th> | |||||
<th /> | |||||
</tr> | |||||
</thead> | |||||
<tbody> | |||||
{this.props.projects.map(project => ( | |||||
<ProjectRow | |||||
currentUser={this.props.currentUser} | |||||
key={project.key} | |||||
onApplyTemplate={this.handleApplyTemplate} | |||||
onProjectCheck={this.onProjectCheck} | |||||
project={project} | |||||
selected={this.props.selection.includes(project.key)} | |||||
/> | |||||
))} | |||||
</tbody> | |||||
</table> | |||||
</div> | |||||
); | ); | ||||
} | } | ||||
} | } |
// Jest Snapshot v1, https://goo.gl/fbAQLP | // Jest Snapshot v1, https://goo.gl/fbAQLP | ||||
exports[`renders list of projects 1`] = ` | exports[`renders list of projects 1`] = ` | ||||
<table | |||||
className="data zebra new-loading" | |||||
id="projects-management-page-projects" | |||||
<div | |||||
className="boxed-group boxed-group-inner" | |||||
> | > | ||||
<thead> | |||||
<tr> | |||||
<th /> | |||||
<th> | |||||
name | |||||
</th> | |||||
<th /> | |||||
<th> | |||||
key | |||||
</th> | |||||
<th | |||||
className="thin nowrap text-right" | |||||
> | |||||
last_analysis | |||||
</th> | |||||
<th /> | |||||
</tr> | |||||
</thead> | |||||
<tbody> | |||||
<ProjectRow | |||||
currentUser={ | |||||
Object { | |||||
"login": "foo", | |||||
<table | |||||
className="data zebra new-loading" | |||||
id="projects-management-page-projects" | |||||
> | |||||
<thead> | |||||
<tr> | |||||
<th /> | |||||
<th> | |||||
name | |||||
</th> | |||||
<th /> | |||||
<th> | |||||
key | |||||
</th> | |||||
<th | |||||
className="thin nowrap text-right" | |||||
> | |||||
last_analysis | |||||
</th> | |||||
<th /> | |||||
</tr> | |||||
</thead> | |||||
<tbody> | |||||
<ProjectRow | |||||
currentUser={ | |||||
Object { | |||||
"login": "foo", | |||||
} | |||||
} | } | ||||
} | |||||
key="a" | |||||
onApplyTemplate={[Function]} | |||||
onProjectCheck={[Function]} | |||||
project={ | |||||
Object { | |||||
"key": "a", | |||||
"name": "A", | |||||
"qualifier": "TRK", | |||||
"visibility": "public", | |||||
key="a" | |||||
onApplyTemplate={[Function]} | |||||
onProjectCheck={[Function]} | |||||
project={ | |||||
Object { | |||||
"key": "a", | |||||
"name": "A", | |||||
"qualifier": "TRK", | |||||
"visibility": "public", | |||||
} | |||||
} | } | ||||
} | |||||
selected={true} | |||||
/> | |||||
<ProjectRow | |||||
currentUser={ | |||||
Object { | |||||
"login": "foo", | |||||
selected={true} | |||||
/> | |||||
<ProjectRow | |||||
currentUser={ | |||||
Object { | |||||
"login": "foo", | |||||
} | |||||
} | } | ||||
} | |||||
key="b" | |||||
onApplyTemplate={[Function]} | |||||
onProjectCheck={[Function]} | |||||
project={ | |||||
Object { | |||||
"key": "b", | |||||
"name": "B", | |||||
"qualifier": "TRK", | |||||
"visibility": "public", | |||||
key="b" | |||||
onApplyTemplate={[Function]} | |||||
onProjectCheck={[Function]} | |||||
project={ | |||||
Object { | |||||
"key": "b", | |||||
"name": "B", | |||||
"qualifier": "TRK", | |||||
"visibility": "public", | |||||
} | |||||
} | } | ||||
} | |||||
selected={false} | |||||
/> | |||||
</tbody> | |||||
</table> | |||||
selected={false} | |||||
/> | |||||
</tbody> | |||||
</table> | |||||
</div> | |||||
`; | `; |
componentDidMount() { | componentDidMount() { | ||||
this.fetchQualityGates(); | this.fetchQualityGates(); | ||||
// $FlowFixMe | |||||
document.body.classList.add('white-page'); | |||||
const footer = document.getElementById('footer'); | const footer = document.getElementById('footer'); | ||||
if (footer) { | if (footer) { | ||||
footer.classList.add('page-footer-with-sidebar'); | footer.classList.add('page-footer-with-sidebar'); | ||||
} | } | ||||
componentWillUnmount() { | componentWillUnmount() { | ||||
// $FlowFixMe | |||||
document.body.classList.remove('white-page'); | |||||
const footer = document.getElementById('footer'); | const footer = document.getElementById('footer'); | ||||
if (footer) { | if (footer) { | ||||
footer.classList.remove('page-footer-with-sidebar'); | footer.classList.remove('page-footer-with-sidebar'); |
mounted: boolean; | mounted: boolean; | ||||
state: State = { loading: true }; | state: State = { loading: true }; | ||||
componentWillMount() { | |||||
const html = document.querySelector('html'); | |||||
if (html) { | |||||
html.classList.add('dashboard-page'); | |||||
} | |||||
} | |||||
componentDidMount() { | componentDidMount() { | ||||
this.mounted = true; | this.mounted = true; | ||||
this.loadData(); | this.loadData(); | ||||
componentWillUnmount() { | componentWillUnmount() { | ||||
this.mounted = false; | this.mounted = false; | ||||
const html = document.querySelector('html'); | |||||
if (html) { | |||||
html.classList.remove('dashboard-page'); | |||||
} | |||||
} | } | ||||
fetchProfiles() { | fetchProfiles() { |
state /*: State */ = { loaded: false }; | state /*: State */ = { loaded: false }; | ||||
componentDidMount() { | componentDidMount() { | ||||
const html = document.querySelector('html'); | |||||
if (html) { | |||||
html.classList.add('dashboard-page'); | |||||
} | |||||
const componentKey = this.props.component ? this.props.component.key : null; | const componentKey = this.props.component ? this.props.component.key : null; | ||||
this.props.fetchSettings(componentKey).then(() => this.setState({ loaded: true })); | this.props.fetchSettings(componentKey).then(() => this.setState({ loaded: true })); | ||||
} | } | ||||
} | } | ||||
} | } | ||||
componentWillUnmount() { | |||||
const html = document.querySelector('html'); | |||||
if (html) { | |||||
html.classList.remove('dashboard-page'); | |||||
} | |||||
} | |||||
render() { | render() { | ||||
if (!this.state.loaded) { | if (!this.state.loaded) { | ||||
return null; | return null; |
users | users | ||||
}: Props) { | }: Props) { | ||||
return ( | return ( | ||||
<table id="users-list" className="data zebra"> | |||||
<thead> | |||||
<tr> | |||||
<th /> | |||||
<th className="nowrap" /> | |||||
<th className="nowrap">{translate('my_profile.scm_accounts')}</th> | |||||
{!organizationsEnabled && <th className="nowrap">{translate('my_profile.groups')}</th>} | |||||
<th className="nowrap">{translate('users.tokens')}</th> | |||||
<th className="nowrap"> </th> | |||||
</tr> | |||||
</thead> | |||||
<tbody> | |||||
{users.map(user => ( | |||||
<UserListItem | |||||
identityProvider={identityProviders.find( | |||||
provider => user.externalProvider === provider.key | |||||
)} | |||||
isCurrentUser={currentUser.isLoggedIn && currentUser.login === user.login} | |||||
key={user.login} | |||||
onUpdateUsers={onUpdateUsers} | |||||
organizationsEnabled={organizationsEnabled} | |||||
user={user} | |||||
/> | |||||
))} | |||||
</tbody> | |||||
</table> | |||||
<div className="boxed-group boxed-group-inner"> | |||||
<table id="users-list" className="data zebra"> | |||||
<thead> | |||||
<tr> | |||||
<th /> | |||||
<th className="nowrap" /> | |||||
<th className="nowrap">{translate('my_profile.scm_accounts')}</th> | |||||
{!organizationsEnabled && <th className="nowrap">{translate('my_profile.groups')}</th>} | |||||
<th className="nowrap">{translate('users.tokens')}</th> | |||||
<th className="nowrap"> </th> | |||||
</tr> | |||||
</thead> | |||||
<tbody> | |||||
{users.map(user => ( | |||||
<UserListItem | |||||
identityProvider={identityProviders.find( | |||||
provider => user.externalProvider === provider.key | |||||
)} | |||||
isCurrentUser={currentUser.isLoggedIn && currentUser.login === user.login} | |||||
key={user.login} | |||||
onUpdateUsers={onUpdateUsers} | |||||
organizationsEnabled={organizationsEnabled} | |||||
user={user} | |||||
/> | |||||
))} | |||||
</tbody> | |||||
</table> | |||||
</div> | |||||
); | ); | ||||
} | } |
// Jest Snapshot v1, https://goo.gl/fbAQLP | // Jest Snapshot v1, https://goo.gl/fbAQLP | ||||
exports[`should render correctly 1`] = ` | exports[`should render correctly 1`] = ` | ||||
<table | |||||
className="data zebra" | |||||
id="users-list" | |||||
<div | |||||
className="boxed-group boxed-group-inner" | |||||
> | > | ||||
<thead> | |||||
<tr> | |||||
<th /> | |||||
<th | |||||
className="nowrap" | |||||
/> | |||||
<th | |||||
className="nowrap" | |||||
> | |||||
my_profile.scm_accounts | |||||
</th> | |||||
<th | |||||
className="nowrap" | |||||
> | |||||
users.tokens | |||||
</th> | |||||
<th | |||||
className="nowrap" | |||||
> | |||||
</th> | |||||
</tr> | |||||
</thead> | |||||
<tbody> | |||||
<UserListItem | |||||
isCurrentUser={true} | |||||
key="luke" | |||||
onUpdateUsers={[Function]} | |||||
organizationsEnabled={true} | |||||
user={ | |||||
Object { | |||||
"active": true, | |||||
"local": false, | |||||
"login": "luke", | |||||
"name": "Luke", | |||||
"scmAccounts": Array [], | |||||
<table | |||||
className="data zebra" | |||||
id="users-list" | |||||
> | |||||
<thead> | |||||
<tr> | |||||
<th /> | |||||
<th | |||||
className="nowrap" | |||||
/> | |||||
<th | |||||
className="nowrap" | |||||
> | |||||
my_profile.scm_accounts | |||||
</th> | |||||
<th | |||||
className="nowrap" | |||||
> | |||||
users.tokens | |||||
</th> | |||||
<th | |||||
className="nowrap" | |||||
> | |||||
</th> | |||||
</tr> | |||||
</thead> | |||||
<tbody> | |||||
<UserListItem | |||||
isCurrentUser={true} | |||||
key="luke" | |||||
onUpdateUsers={[Function]} | |||||
organizationsEnabled={true} | |||||
user={ | |||||
Object { | |||||
"active": true, | |||||
"local": false, | |||||
"login": "luke", | |||||
"name": "Luke", | |||||
"scmAccounts": Array [], | |||||
} | |||||
} | } | ||||
} | |||||
/> | |||||
<UserListItem | |||||
isCurrentUser={false} | |||||
key="obi" | |||||
onUpdateUsers={[Function]} | |||||
organizationsEnabled={true} | |||||
user={ | |||||
Object { | |||||
"active": true, | |||||
"local": false, | |||||
"login": "obi", | |||||
"name": "One", | |||||
"scmAccounts": Array [], | |||||
/> | |||||
<UserListItem | |||||
isCurrentUser={false} | |||||
key="obi" | |||||
onUpdateUsers={[Function]} | |||||
organizationsEnabled={true} | |||||
user={ | |||||
Object { | |||||
"active": true, | |||||
"local": false, | |||||
"login": "obi", | |||||
"name": "One", | |||||
"scmAccounts": Array [], | |||||
} | |||||
} | } | ||||
} | |||||
/> | |||||
</tbody> | |||||
</table> | |||||
/> | |||||
</tbody> | |||||
</table> | |||||
</div> | |||||
`; | `; |
); | ); | ||||
} | } | ||||
return <hr />; | |||||
return null; | |||||
} | } | ||||
render() { | render() { | ||||
const actionKey = getActionKey(domain.path, action.key); | const actionKey = getActionKey(domain.path, action.key); | ||||
return ( | return ( | ||||
<div id={actionKey} className="web-api-action"> | |||||
<header className="web-api-action-header"> | |||||
<div id={actionKey} className="boxed-group"> | |||||
<header className="web-api-action-header boxed-group-header"> | |||||
<Link | <Link | ||||
to={{ pathname: '/web_api/' + actionKey }} | to={{ pathname: '/web_api/' + actionKey }} | ||||
className="spacer-right link-no-underline"> | className="spacer-right link-no-underline"> | ||||
)} | )} | ||||
</header> | </header> | ||||
<div | |||||
className="web-api-action-description markdown" | |||||
dangerouslySetInnerHTML={{ __html: action.description }} | |||||
/> | |||||
<div className="boxed-group-inner"> | |||||
<div | |||||
className="web-api-action-description markdown" | |||||
dangerouslySetInnerHTML={{ __html: action.description }} | |||||
/> | |||||
{this.renderTabs()} | |||||
{this.renderTabs()} | |||||
{showParams && | |||||
action.params && ( | |||||
<Params | |||||
params={action.params} | |||||
showDeprecated={this.props.showDeprecated} | |||||
showInternal={this.props.showInternal} | |||||
/> | |||||
)} | |||||
{showParams && | |||||
action.params && ( | |||||
<Params | |||||
params={action.params} | |||||
showDeprecated={this.props.showDeprecated} | |||||
showInternal={this.props.showInternal} | |||||
/> | |||||
)} | |||||
{showResponse && | |||||
action.hasResponseExample && <ResponseExample domain={domain} action={action} />} | |||||
{showResponse && | |||||
action.hasResponseExample && <ResponseExample domain={domain} action={action} />} | |||||
{showChangelog && <ActionChangelog changelog={action.changelog} />} | |||||
{showChangelog && <ActionChangelog changelog={action.changelog} />} | |||||
</div> | |||||
</div> | </div> | ||||
); | ); | ||||
} | } |
exports[`should render correctly 1`] = ` | exports[`should render correctly 1`] = ` | ||||
<div | <div | ||||
className="web-api-action" | |||||
className="boxed-group" | |||||
id="foo/foo" | id="foo/foo" | ||||
> | > | ||||
<header | <header | ||||
className="web-api-action-header" | |||||
className="web-api-action-header boxed-group-header" | |||||
> | > | ||||
<Link | <Link | ||||
className="spacer-right link-no-underline" | className="spacer-right link-no-underline" | ||||
</h3> | </h3> | ||||
</header> | </header> | ||||
<div | <div | ||||
className="web-api-action-description markdown" | |||||
dangerouslySetInnerHTML={ | |||||
Object { | |||||
"__html": "Foo Desc", | |||||
} | |||||
} | |||||
/> | |||||
<ul | |||||
className="web-api-action-actions tabs" | |||||
className="boxed-group-inner" | |||||
> | > | ||||
<li> | |||||
<a | |||||
className="" | |||||
href="#" | |||||
onClick={[Function]} | |||||
> | |||||
api_documentation.parameters | |||||
</a> | |||||
</li> | |||||
<li> | |||||
<a | |||||
className="" | |||||
href="#" | |||||
onClick={[Function]} | |||||
> | |||||
api_documentation.response_example | |||||
</a> | |||||
</li> | |||||
<li> | |||||
<a | |||||
className="" | |||||
href="#" | |||||
onClick={[Function]} | |||||
> | |||||
api_documentation.changelog | |||||
</a> | |||||
</li> | |||||
</ul> | |||||
<div | |||||
className="web-api-action-description markdown" | |||||
dangerouslySetInnerHTML={ | |||||
Object { | |||||
"__html": "Foo Desc", | |||||
} | |||||
} | |||||
/> | |||||
<ul | |||||
className="web-api-action-actions tabs" | |||||
> | |||||
<li> | |||||
<a | |||||
className="" | |||||
href="#" | |||||
onClick={[Function]} | |||||
> | |||||
api_documentation.parameters | |||||
</a> | |||||
</li> | |||||
<li> | |||||
<a | |||||
className="" | |||||
href="#" | |||||
onClick={[Function]} | |||||
> | |||||
api_documentation.response_example | |||||
</a> | |||||
</li> | |||||
<li> | |||||
<a | |||||
className="" | |||||
href="#" | |||||
onClick={[Function]} | |||||
> | |||||
api_documentation.changelog | |||||
</a> | |||||
</li> | |||||
</ul> | |||||
</div> | |||||
</div> | </div> | ||||
`; | `; |
} | } | ||||
.web-api-domain-actions { | .web-api-domain-actions { | ||||
} | |||||
.web-api-action { | |||||
padding-top: 30px; | |||||
margin-top: calc(2 * var(--gridSize)); | |||||
} | } | ||||
.web-api-action-title { | .web-api-action-title { |
.source-viewer { | .source-viewer { | ||||
width: 100%; | width: 100%; | ||||
min-height: 200px; | min-height: 200px; | ||||
border: 1px solid var(--barBorderColor); | |||||
border: 1px solid var(--gray80); | |||||
box-sizing: border-box; | box-sizing: border-box; | ||||
background-color: #fff; | background-color: #fff; | ||||
overflow-x: auto; | overflow-x: auto; |
.branch-status { | .branch-status { | ||||
display: flex; | |||||
align-items: center; | |||||
min-width: 64px; | min-width: 64px; | ||||
line-height: calc(2 * var(--gridSize)); | |||||
text-align: right; | text-align: right; | ||||
} | } | ||||
const indicatorColor = totalIssues > 0 ? 'red' : 'green'; | const indicatorColor = totalIssues > 0 ? 'red' : 'green'; | ||||
return concise ? ( | return concise ? ( | ||||
<ul className="list-inline branch-status"> | |||||
<ul className="branch-status"> | |||||
<li>{totalIssues}</li> | <li>{totalIssues}</li> | ||||
<li className="spacer-left"> | <li className="spacer-left"> | ||||
<StatusIndicator color={indicatorColor} size="small" /> | <StatusIndicator color={indicatorColor} size="small" /> | ||||
</li> | </li> | ||||
</ul> | </ul> | ||||
) : ( | ) : ( | ||||
<ul className="list-inline branch-status"> | |||||
<ul className="branch-status"> | |||||
<li className="spacer-right"> | <li className="spacer-right"> | ||||
<StatusIndicator color={indicatorColor} size="small" /> | <StatusIndicator color={indicatorColor} size="small" /> | ||||
</li> | </li> | ||||
<li> | |||||
<li className="spacer-left"> | |||||
{branch.status.bugs} | {branch.status.bugs} | ||||
<BugIcon /> | <BugIcon /> | ||||
</li> | </li> | ||||
<li> | |||||
<li className="spacer-left"> | |||||
{branch.status.vulnerabilities} | {branch.status.vulnerabilities} | ||||
<VulnerabilityIcon /> | <VulnerabilityIcon /> | ||||
</li> | </li> | ||||
<li> | |||||
<li className="spacer-left"> | |||||
{branch.status.codeSmells} | {branch.status.codeSmells} | ||||
<CodeSmellIcon /> | <CodeSmellIcon /> | ||||
</li> | </li> |
exports[`renders status of short-living branches 1`] = ` | exports[`renders status of short-living branches 1`] = ` | ||||
<ul | <ul | ||||
className="list-inline branch-status" | |||||
className="branch-status" | |||||
> | > | ||||
<li | <li | ||||
className="spacer-right" | className="spacer-right" | ||||
size="small" | size="small" | ||||
/> | /> | ||||
</li> | </li> | ||||
<li> | |||||
<li | |||||
className="spacer-left" | |||||
> | |||||
0 | 0 | ||||
<BugIcon /> | <BugIcon /> | ||||
</li> | </li> | ||||
<li> | |||||
<li | |||||
className="spacer-left" | |||||
> | |||||
0 | 0 | ||||
<VulnerabilityIcon /> | <VulnerabilityIcon /> | ||||
</li> | </li> | ||||
<li> | |||||
<li | |||||
className="spacer-left" | |||||
> | |||||
0 | 0 | ||||
<CodeSmellIcon /> | <CodeSmellIcon /> | ||||
</li> | </li> | ||||
exports[`renders status of short-living branches 2`] = ` | exports[`renders status of short-living branches 2`] = ` | ||||
<ul | <ul | ||||
className="list-inline branch-status" | |||||
className="branch-status" | |||||
> | > | ||||
<li | <li | ||||
className="spacer-right" | className="spacer-right" | ||||
size="small" | size="small" | ||||
/> | /> | ||||
</li> | </li> | ||||
<li> | |||||
<li | |||||
className="spacer-left" | |||||
> | |||||
0 | 0 | ||||
<BugIcon /> | <BugIcon /> | ||||
</li> | </li> | ||||
<li> | |||||
<li | |||||
className="spacer-left" | |||||
> | |||||
0 | 0 | ||||
<VulnerabilityIcon /> | <VulnerabilityIcon /> | ||||
</li> | </li> | ||||
<li> | |||||
<li | |||||
className="spacer-left" | |||||
> | |||||
1 | 1 | ||||
<CodeSmellIcon /> | <CodeSmellIcon /> | ||||
</li> | </li> | ||||
exports[`renders status of short-living branches 3`] = ` | exports[`renders status of short-living branches 3`] = ` | ||||
<ul | <ul | ||||
className="list-inline branch-status" | |||||
className="branch-status" | |||||
> | > | ||||
<li | <li | ||||
className="spacer-right" | className="spacer-right" | ||||
size="small" | size="small" | ||||
/> | /> | ||||
</li> | </li> | ||||
<li> | |||||
<li | |||||
className="spacer-left" | |||||
> | |||||
7 | 7 | ||||
<BugIcon /> | <BugIcon /> | ||||
</li> | </li> | ||||
<li> | |||||
<li | |||||
className="spacer-left" | |||||
> | |||||
6 | 6 | ||||
<VulnerabilityIcon /> | <VulnerabilityIcon /> | ||||
</li> | </li> | ||||
<li> | |||||
<li | |||||
className="spacer-left" | |||||
> | |||||
3 | 3 | ||||
<CodeSmellIcon /> | <CodeSmellIcon /> | ||||
</li> | </li> |
className?: string; | className?: string; | ||||
component: string; | component: string; | ||||
favorite: boolean; | favorite: boolean; | ||||
qualifier: string; | |||||
} | } | ||||
export default function Favorite({ favorite, component, ...other }: Props) { | |||||
export default function Favorite({ component, ...other }: Props) { | |||||
return ( | return ( | ||||
<FavoriteBase | <FavoriteBase | ||||
{...other} | {...other} | ||||
favorite={favorite} | |||||
addFavorite={() => addFavorite(component)} | addFavorite={() => addFavorite(component)} | ||||
removeFavorite={() => removeFavorite(component)} | removeFavorite={() => removeFavorite(component)} | ||||
/> | /> |
import FavoriteIcon from '../icons-components/FavoriteIcon'; | import FavoriteIcon from '../icons-components/FavoriteIcon'; | ||||
import { translate } from '../../helpers/l10n'; | import { translate } from '../../helpers/l10n'; | ||||
interface Props { | |||||
export interface Props { | |||||
addFavorite: () => Promise<void>; | addFavorite: () => Promise<void>; | ||||
className?: string; | className?: string; | ||||
favorite: boolean; | favorite: boolean; | ||||
qualifier: string; | |||||
removeFavorite: () => Promise<void>; | removeFavorite: () => Promise<void>; | ||||
} | } | ||||
render() { | render() { | ||||
const tooltip = this.state.favorite | const tooltip = this.state.favorite | ||||
? translate('favorite.current') | |||||
: translate('favorite.check'); | |||||
? translate('favorite.current', this.props.qualifier) | |||||
: translate('favorite.check', this.props.qualifier); | |||||
return ( | return ( | ||||
<Tooltip overlay={tooltip}> | |||||
<Tooltip overlay={tooltip} placement="left"> | |||||
<a | <a | ||||
className={classNames('display-inline-block', 'link-no-underline', this.props.className)} | className={classNames('display-inline-block', 'link-no-underline', this.props.className)} | ||||
href="#" | href="#" |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2017 SonarSource SA | |||||
* mailto:info AT sonarsource DOT com | |||||
* | |||||
* This program is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU Lesser General Public | |||||
* License as published by the Free Software Foundation; either | |||||
* version 3 of the License, or (at your option) any later version. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
* Lesser General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Lesser General Public License | |||||
* along with this program; if not, write to the Free Software Foundation, | |||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||||
*/ | |||||
import React from 'react'; | |||||
import PropTypes from 'prop-types'; | |||||
import FavoriteBase from './FavoriteBase'; | |||||
import { toggleIssueFilter } from '../../api/issue-filters'; | |||||
export default class FavoriteIssueFilter extends React.PureComponent { | |||||
static propTypes = { | |||||
favorite: PropTypes.bool.isRequired, | |||||
filter: PropTypes.shape({ | |||||
id: PropTypes.string.isRequired | |||||
}).isRequired | |||||
}; | |||||
render() { | |||||
return ( | |||||
<FavoriteBase | |||||
favorite={this.props.favorite} | |||||
addFavorite={() => toggleIssueFilter(this.props.filter.id)} | |||||
removeFavorite={() => toggleIssueFilter(this.props.filter.id)} | |||||
/> | |||||
); | |||||
} | |||||
} |
import HomeIcon from '../icons-components/HomeIcon'; | import HomeIcon from '../icons-components/HomeIcon'; | ||||
import { CurrentUser, isLoggedIn, HomePage, isSameHomePage } from '../../app/types'; | import { CurrentUser, isLoggedIn, HomePage, isSameHomePage } from '../../app/types'; | ||||
import { translate } from '../../helpers/l10n'; | import { translate } from '../../helpers/l10n'; | ||||
import { getCurrentUser } from '../../store/rootReducer'; | |||||
import { getCurrentUser, getGlobalSettingValue } from '../../store/rootReducer'; | |||||
import { setHomePage } from '../../store/users/actions'; | import { setHomePage } from '../../store/users/actions'; | ||||
interface StateProps { | interface StateProps { | ||||
currentUser: CurrentUser; | currentUser: CurrentUser; | ||||
onSonarCloud: boolean; | |||||
} | } | ||||
interface DispatchProps { | interface DispatchProps { | ||||
}; | }; | ||||
render() { | render() { | ||||
const { currentPage, currentUser } = this.props; | |||||
const { currentPage, currentUser, onSonarCloud } = this.props; | |||||
if (!isLoggedIn(currentUser)) { | |||||
if (!isLoggedIn(currentUser) || !onSonarCloud) { | |||||
return null; | return null; | ||||
} | } | ||||
const tooltip = checked ? translate('homepage.current') : translate('homepage.check'); | const tooltip = checked ? translate('homepage.current') : translate('homepage.check'); | ||||
return ( | return ( | ||||
<Tooltip overlay={tooltip}> | |||||
<Tooltip overlay={tooltip} placement="left"> | |||||
{checked ? ( | {checked ? ( | ||||
<span className={classNames('display-inline-block', this.props.className)}> | <span className={classNames('display-inline-block', this.props.className)}> | ||||
<HomeIcon filled={checked} /> | <HomeIcon filled={checked} /> | ||||
} | } | ||||
} | } | ||||
const mapStateToProps = (state: any): StateProps => ({ | |||||
currentUser: getCurrentUser(state) | |||||
}); | |||||
const mapStateToProps = (state: any): StateProps => { | |||||
const sonarCloudSetting = getGlobalSettingValue(state, 'sonar.sonarcloud.enabled'); | |||||
return { | |||||
currentUser: getCurrentUser(state), | |||||
onSonarCloud: Boolean(sonarCloudSetting && sonarCloudSetting.value === 'true') | |||||
}; | |||||
}; | |||||
const mapDispatchToProps: DispatchProps = { setHomePage }; | const mapDispatchToProps: DispatchProps = { setHomePage }; | ||||
import Favorite from '../Favorite'; | import Favorite from '../Favorite'; | ||||
it('renders', () => { | it('renders', () => { | ||||
expect(shallow(<Favorite component="foo" favorite={true} />)).toMatchSnapshot(); | |||||
expect(shallow(<Favorite component="foo" favorite={true} qualifier="TRK" />)).toMatchSnapshot(); | |||||
}); | }); |
*/ | */ | ||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import { shallow } from 'enzyme'; | import { shallow } from 'enzyme'; | ||||
import FavoriteBase from '../FavoriteBase'; | |||||
import FavoriteBase, { Props } from '../FavoriteBase'; | |||||
import { click } from '../../../helpers/testUtils'; | import { click } from '../../../helpers/testUtils'; | ||||
it('should render favorite', () => { | it('should render favorite', () => { | ||||
expect(removeFavorite).toBeCalled(); | expect(removeFavorite).toBeCalled(); | ||||
}); | }); | ||||
function renderFavoriteBase(props?: any) { | |||||
function renderFavoriteBase(props: Partial<Props> = {}) { | |||||
return shallow( | return shallow( | ||||
<FavoriteBase favorite={true} addFavorite={jest.fn()} removeFavorite={jest.fn()} {...props} /> | |||||
<FavoriteBase | |||||
favorite={true} | |||||
addFavorite={jest.fn()} | |||||
qualifier="TRK" | |||||
removeFavorite={jest.fn()} | |||||
{...props} | |||||
/> | |||||
); | ); | ||||
} | } |
<FavoriteBase | <FavoriteBase | ||||
addFavorite={[Function]} | addFavorite={[Function]} | ||||
favorite={true} | favorite={true} | ||||
qualifier="TRK" | |||||
removeFavorite={[Function]} | removeFavorite={[Function]} | ||||
/> | /> | ||||
`; | `; |
exports[`should render favorite 1`] = ` | exports[`should render favorite 1`] = ` | ||||
<Tooltip | <Tooltip | ||||
overlay="favorite.current" | |||||
placement="bottom" | |||||
overlay="favorite.current.TRK" | |||||
placement="left" | |||||
> | > | ||||
<a | <a | ||||
className="display-inline-block link-no-underline" | className="display-inline-block link-no-underline" | ||||
exports[`should render not favorite 1`] = ` | exports[`should render not favorite 1`] = ` | ||||
<Tooltip | <Tooltip | ||||
overlay="favorite.check" | |||||
placement="bottom" | |||||
overlay="favorite.check.TRK" | |||||
placement="left" | |||||
> | > | ||||
<a | <a | ||||
className="display-inline-block link-no-underline" | className="display-inline-block link-no-underline" |
.navbar-context, | .navbar-context, | ||||
.navbar-context .navbar-inner { | .navbar-context .navbar-inner { | ||||
background-color: var(--barBackgroundColor); | |||||
background-color: #fff; | |||||
z-index: 420; | z-index: 420; | ||||
} | } | ||||
} | } | ||||
.navbar-context-header { | .navbar-context-header { | ||||
display: inline-flex; | |||||
display: flex; | |||||
align-items: center; | align-items: center; | ||||
height: calc(4 * var(--gridSize)); | height: calc(4 * var(--gridSize)); | ||||
font-size: var(--bigFontSize); | font-size: var(--bigFontSize); | ||||
top: 36px; | top: 36px; | ||||
right: 0; | right: 0; | ||||
padding: 0 20px; | padding: 0 20px; | ||||
white-space: nowrap; | |||||
} | } | ||||
.navbar-context-description { | .navbar-context-description { |
import { omitBy, isNil } from 'lodash'; | import { omitBy, isNil } from 'lodash'; | ||||
import { isShortLivingBranch } from './branches'; | import { isShortLivingBranch } from './branches'; | ||||
import { getProfilePath } from '../apps/quality-profiles/utils'; | import { getProfilePath } from '../apps/quality-profiles/utils'; | ||||
import { Branch, HomePage } from '../app/types'; | |||||
import { Branch, HomePage, HomePageType } from '../app/types'; | |||||
interface Query { | interface Query { | ||||
[x: string]: string | undefined; | [x: string]: string | undefined; | ||||
export function getHomePageUrl(homepage: HomePage) { | export function getHomePageUrl(homepage: HomePage) { | ||||
switch (homepage.type) { | switch (homepage.type) { | ||||
case 'project': | |||||
return getProjectUrl(homepage.key!); | |||||
case 'organization': | |||||
return getOrganizationUrl(homepage.key!); | |||||
case 'my-projects': | |||||
case HomePageType.Project: | |||||
return getProjectUrl(homepage.parameter!); | |||||
case HomePageType.Organization: | |||||
return getOrganizationUrl(homepage.parameter!); | |||||
case HomePageType.MyProjects: | |||||
return '/projects'; | return '/projects'; | ||||
case 'my-issues': | |||||
case HomePageType.MyIssues: | |||||
return { pathname: '/issues', query: { resolved: 'false' } }; | return { pathname: '/issues', query: { resolved: 'false' } }; | ||||
} | } | ||||
# | # | ||||
#------------------------------------------------------------------------------ | #------------------------------------------------------------------------------ | ||||
notification.channel.EmailNotificationChannel=Email | notification.channel.EmailNotificationChannel=Email | ||||
notification.dispatcher.information=Receive notifications when specific types of events occur. A notification is never sent to the author of the event. | |||||
notification.dispatcher.information=A notification is never sent to the author of the event. | |||||
notification.dispatcher.ChangesOnMyIssue=Changes in issues assigned to me | notification.dispatcher.ChangesOnMyIssue=Changes in issues assigned to me | ||||
notification.dispatcher.NewIssues=New issues | notification.dispatcher.NewIssues=New issues | ||||
notification.dispatcher.NewAlerts=New quality gate status | notification.dispatcher.NewAlerts=New quality gate status | ||||
# FAVORITE | # FAVORITE | ||||
# | # | ||||
#------------------------------------------------------------------------------ | #------------------------------------------------------------------------------ | ||||
favorite.current=This is your favorite component. Click to unset. | |||||
favorite.check=Click to mark this component as favorite. | |||||
favorite.check.TRK=Click to mark this project as favorite. | |||||
favorite.check.BRC=Click to mark this sub-project as favorite. | |||||
favorite.check.DIR=Click to mark this directory as favorite. | |||||
favorite.check.PAC=Click to mark this package as favorite. | |||||
favorite.check.VW=Click to mark this portfolio as favorite. | |||||
favorite.check.SVW=Click to mark this sub-ortfolio as favorite. | |||||
favorite.check.APP=Click to mark this application as favorite. | |||||
favorite.check.FIL=Click to mark this file as favorite. | |||||
favorite.check.CLA=Click to mark this file as favorite. | |||||
favorite.check.UTS=Click to mark this test file as favorite. | |||||
favorite.current.TRK=This project is marked as favorite. | |||||
favorite.current.BRC=This sub-project is marked as favorite. | |||||
favorite.current.DIR=This directory is marked as favorite. | |||||
favorite.current.PAC=This package is marked as favorite. | |||||
favorite.current.VW=This portfolio is marked as favorite. | |||||
favorite.current.SVW=This sub-ortfolio is marked as favorite. | |||||
favorite.current.APP=This application is marked as favorite. | |||||
favorite.current.FIL=This file is marked as favorite. | |||||
favorite.current.CLA=This file is marked as favorite. | |||||
favorite.current.UTS=This test file is marked as favorite. |