import throwGlobalError from '../app/utils/throwGlobalError'; | import throwGlobalError from '../app/utils/throwGlobalError'; | ||||
import { getJSON, post, postJSON } from '../helpers/request'; | import { getJSON, post, postJSON } from '../helpers/request'; | ||||
import { BranchParameters } from '../types/branch-like'; | import { BranchParameters } from '../types/branch-like'; | ||||
import { QualityGateApplicationStatus, QualityGateProjectStatus } from '../types/quality-gates'; | |||||
import { | |||||
QualityGateApplicationStatus, | |||||
QualityGateProjectStatus, | |||||
SearchPermissionsParameters | |||||
} from '../types/quality-gates'; | |||||
export function fetchQualityGates(): Promise<{ | export function fetchQualityGates(): Promise<{ | ||||
actions: { create: boolean }; | actions: { create: boolean }; | ||||
.then(r => r.projectStatus) | .then(r => r.projectStatus) | ||||
.catch(throwGlobalError); | .catch(throwGlobalError); | ||||
} | } | ||||
export function searchUsers(data: SearchPermissionsParameters): Promise<{ users: T.UserBase[] }> { | |||||
return getJSON('/api/qualitygates/search_users', data).catch(throwGlobalError); | |||||
} |
*/ | */ | ||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import HelpTooltip from '../../../components/controls/HelpTooltip'; | import HelpTooltip from '../../../components/controls/HelpTooltip'; | ||||
import { withCurrentUser } from '../../../components/hoc/withCurrentUser'; | |||||
import { Alert } from '../../../components/ui/Alert'; | import { Alert } from '../../../components/ui/Alert'; | ||||
import { translate } from '../../../helpers/l10n'; | import { translate } from '../../../helpers/l10n'; | ||||
import { hasGlobalPermission } from '../../../helpers/users'; | |||||
import { Permissions } from '../../../types/permissions'; | |||||
import Conditions from './Conditions'; | import Conditions from './Conditions'; | ||||
import Projects from './Projects'; | import Projects from './Projects'; | ||||
import QualityGatePermissions from './QualityGatePermissions'; | |||||
export interface DetailsContentProps { | export interface DetailsContentProps { | ||||
currentUser: T.CurrentUser; | |||||
isDefault?: boolean; | isDefault?: boolean; | ||||
metrics: T.Dict<T.Metric>; | metrics: T.Dict<T.Metric>; | ||||
onAddCondition: (condition: T.Condition) => void; | onAddCondition: (condition: T.Condition) => void; | ||||
} | } | ||||
export function DetailsContent(props: DetailsContentProps) { | export function DetailsContent(props: DetailsContentProps) { | ||||
const { isDefault, metrics, qualityGate, updatedConditionId } = props; | |||||
const { currentUser, isDefault, metrics, qualityGate, updatedConditionId } = props; | |||||
const conditions = qualityGate.conditions || []; | const conditions = qualityGate.conditions || []; | ||||
const actions = qualityGate.actions || ({} as any); | |||||
const actions = qualityGate.actions || {}; | |||||
const displayPermissions = hasGlobalPermission(currentUser, Permissions.QualityGateAdmin); | |||||
return ( | return ( | ||||
<div className="layout-page-main-inner"> | <div className="layout-page-main-inner"> | ||||
)} | )} | ||||
<Conditions | <Conditions | ||||
canEdit={actions.manageConditions} | |||||
canEdit={Boolean(actions.manageConditions)} | |||||
conditions={conditions} | conditions={conditions} | ||||
metrics={metrics} | metrics={metrics} | ||||
onAddCondition={props.onAddCondition} | onAddCondition={props.onAddCondition} | ||||
updatedConditionId={updatedConditionId} | updatedConditionId={updatedConditionId} | ||||
/> | /> | ||||
<div className="quality-gate-section" id="quality-gate-projects"> | |||||
<header className="display-flex-center spacer-bottom"> | |||||
<h3>{translate('quality_gates.projects')}</h3> | |||||
<HelpTooltip | |||||
className="spacer-left" | |||||
overlay={ | |||||
<div className="big-padded-top big-padded-bottom"> | |||||
{translate('quality_gates.projects.help')} | |||||
</div> | |||||
} | |||||
/> | |||||
</header> | |||||
{isDefault ? ( | |||||
translate('quality_gates.projects_for_default') | |||||
) : ( | |||||
<Projects | |||||
canEdit={actions.associateProjects} | |||||
// pass unique key to re-mount the component when the quality gate changes | |||||
key={qualityGate.id} | |||||
qualityGate={qualityGate} | |||||
/> | |||||
<div className="display-flex-row huge-spacer-top"> | |||||
<div className="quality-gate-section width-50 big-padded-right" id="quality-gate-projects"> | |||||
<header className="display-flex-center spacer-bottom"> | |||||
<h3>{translate('quality_gates.projects')}</h3> | |||||
<HelpTooltip | |||||
className="spacer-left" | |||||
overlay={ | |||||
<div className="big-padded-top big-padded-bottom"> | |||||
{translate('quality_gates.projects.help')} | |||||
</div> | |||||
} | |||||
/> | |||||
</header> | |||||
{isDefault ? ( | |||||
translate('quality_gates.projects_for_default') | |||||
) : ( | |||||
<Projects | |||||
canEdit={actions.associateProjects} | |||||
// pass unique key to re-mount the component when the quality gate changes | |||||
key={qualityGate.id} | |||||
qualityGate={qualityGate} | |||||
/> | |||||
)} | |||||
</div> | |||||
{displayPermissions && ( | |||||
<div className="width-50 big-padded-left"> | |||||
<QualityGatePermissions qualityGate={qualityGate} /> | |||||
</div> | |||||
)} | )} | ||||
</div> | </div> | ||||
</div> | </div> | ||||
); | ); | ||||
} | } | ||||
export default React.memo(DetailsContent); | |||||
export default React.memo(withCurrentUser(DetailsContent)); |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2021 SonarSource SA | |||||
* mailto:info AT sonarsource DOT com | |||||
* | |||||
* This program is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU Lesser General Public | |||||
* License as published by the Free Software Foundation; either | |||||
* version 3 of the License, or (at your option) any later version. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
* Lesser General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Lesser General Public License | |||||
* along with this program; if not, write to the Free Software Foundation, | |||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||||
*/ | |||||
import * as React from 'react'; | |||||
import Avatar from '../../../components/ui/Avatar'; | |||||
interface Props { | |||||
user: T.UserBase; | |||||
} | |||||
export default function PermissionItem(props: Props) { | |||||
const { user } = props; | |||||
return ( | |||||
<div className="display-flex-row"> | |||||
<Avatar className="spacer-right" hash={user.avatar} name={user.name} size={32} /> | |||||
<div className="overflow-hidden"> | |||||
<strong>{user.name}</strong> | |||||
<div className="note">{user.login}</div> | |||||
</div> | |||||
</div> | |||||
); | |||||
} |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2021 SonarSource SA | |||||
* mailto:info AT sonarsource DOT com | |||||
* | |||||
* This program is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU Lesser General Public | |||||
* License as published by the Free Software Foundation; either | |||||
* version 3 of the License, or (at your option) any later version. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
* Lesser General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Lesser General Public License | |||||
* along with this program; if not, write to the Free Software Foundation, | |||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||||
*/ | |||||
import * as React from 'react'; | |||||
import { searchUsers } from '../../../api/quality-gates'; | |||||
import QualityGatePermissionsRenderer from './QualityGatePermissionsRenderer'; | |||||
interface Props { | |||||
qualityGate: T.QualityGate; | |||||
} | |||||
interface State { | |||||
loading: boolean; | |||||
users: T.UserBase[]; | |||||
} | |||||
export default class QualityGatePermissions extends React.Component<Props, State> { | |||||
mounted = false; | |||||
state: State = { | |||||
loading: true, | |||||
users: [] | |||||
}; | |||||
componentDidMount() { | |||||
this.mounted = true; | |||||
this.fetchPermissions(); | |||||
} | |||||
componentDidUpdate(newProps: Props) { | |||||
if (this.props.qualityGate.id !== newProps.qualityGate.id) { | |||||
this.fetchPermissions(); | |||||
} | |||||
} | |||||
componentWillUnmount() { | |||||
this.mounted = false; | |||||
} | |||||
fetchPermissions = async () => { | |||||
const { qualityGate } = this.props; | |||||
this.setState({ loading: true }); | |||||
const { users } = await searchUsers({ | |||||
qualityGate: qualityGate.id, | |||||
selected: 'selected' | |||||
}).catch(() => ({ | |||||
users: [] | |||||
})); | |||||
if (this.mounted) { | |||||
this.setState({ loading: false, users }); | |||||
} | |||||
}; | |||||
render() { | |||||
const { loading, users } = this.state; | |||||
return <QualityGatePermissionsRenderer loading={loading} users={users} />; | |||||
} | |||||
} |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2021 SonarSource SA | |||||
* mailto:info AT sonarsource DOT com | |||||
* | |||||
* This program is free software; you can redistribute it and/or | |||||
* modify it under the terms of the GNU Lesser General Public | |||||
* License as published by the Free Software Foundation; either | |||||
* version 3 of the License, or (at your option) any later version. | |||||
* | |||||
* This program is distributed in the hope that it will be useful, | |||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |||||
* Lesser General Public License for more details. | |||||
* | |||||
* You should have received a copy of the GNU Lesser General Public License | |||||
* along with this program; if not, write to the Free Software Foundation, | |||||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||||
*/ | |||||
import * as React from 'react'; | |||||
import DeferredSpinner from '../../../components/ui/DeferredSpinner'; | |||||
import { translate } from '../../../helpers/l10n'; | |||||
import PermissionItem from './PermissionItem'; | |||||
export interface QualityGatePermissionsRendererProps { | |||||
loading: boolean; | |||||
users: T.UserBase[]; | |||||
} | |||||
export default function QualityGatePermissionsRenderer(props: QualityGatePermissionsRendererProps) { | |||||
const { loading, users } = props; | |||||
return ( | |||||
<div> | |||||
<header className="display-flex-center spacer-bottom"> | |||||
<h3>{translate('quality_gates.permissions')}</h3> | |||||
</header> | |||||
<p className="spacer-bottom">{translate('quality_gates.permissions.help')}</p> | |||||
<DeferredSpinner loading={loading}> | |||||
<ul> | |||||
{users.map(user => ( | |||||
<li key={user.login} className="spacer-top"> | |||||
<PermissionItem user={user} /> | |||||
</li> | |||||
))} | |||||
</ul> | |||||
</DeferredSpinner> | |||||
</div> | |||||
); | |||||
} |
import { shallow } from 'enzyme'; | import { shallow } from 'enzyme'; | ||||
import * as React from 'react'; | import * as React from 'react'; | ||||
import { mockQualityGate } from '../../../../helpers/mocks/quality-gates'; | import { mockQualityGate } from '../../../../helpers/mocks/quality-gates'; | ||||
import { mockCondition } from '../../../../helpers/testMocks'; | |||||
import { mockCondition, mockLoggedInUser } from '../../../../helpers/testMocks'; | |||||
import { DetailsContent, DetailsContentProps } from '../DetailsContent'; | import { DetailsContent, DetailsContentProps } from '../DetailsContent'; | ||||
it('should render correctly', () => { | it('should render correctly', () => { | ||||
expect( | expect( | ||||
shallowRender({ isDefault: true, qualityGate: mockQualityGate({ conditions: [] }) }) | shallowRender({ isDefault: true, qualityGate: mockQualityGate({ conditions: [] }) }) | ||||
).toMatchSnapshot('is default, no conditions'); | ).toMatchSnapshot('is default, no conditions'); | ||||
expect( | |||||
shallowRender({ currentUser: mockLoggedInUser({ permissions: { global: ['gateadmin'] } }) }) | |||||
).toMatchSnapshot('Admin'); | |||||
}); | }); | ||||
function shallowRender(props: Partial<DetailsContentProps> = {}) { | function shallowRender(props: Partial<DetailsContentProps> = {}) { | ||||
return shallow( | return shallow( | ||||
<DetailsContent | <DetailsContent | ||||
currentUser={mockLoggedInUser()} | |||||
metrics={{}} | metrics={{}} | ||||
onAddCondition={jest.fn()} | onAddCondition={jest.fn()} | ||||
onRemoveCondition={jest.fn()} | onRemoveCondition={jest.fn()} |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2021 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 { shallow } from 'enzyme'; | |||||
import * as React from 'react'; | |||||
import { mockUser } from '../../../../helpers/testMocks'; | |||||
import PermissionItem from '../PermissionItem'; | |||||
it('should render correctly', () => { | |||||
expect(shallowRender()).toMatchSnapshot(); | |||||
}); | |||||
function shallowRender() { | |||||
return shallow(<PermissionItem user={mockUser()} />); | |||||
} |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2021 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 { shallow } from 'enzyme'; | |||||
import * as React from 'react'; | |||||
import { searchUsers } from '../../../../api/quality-gates'; | |||||
import { mockQualityGate } from '../../../../helpers/mocks/quality-gates'; | |||||
import { waitAndUpdate } from '../../../../helpers/testUtils'; | |||||
import QualityGatePermissions from '../QualityGatePermissions'; | |||||
jest.mock('../../../../api/quality-gates', () => ({ | |||||
searchUsers: jest.fn().mockResolvedValue({ users: [] }) | |||||
})); | |||||
it('should render correctly', () => { | |||||
expect(shallowRender()).toMatchSnapshot(); | |||||
}); | |||||
it('should fetch users', async () => { | |||||
const wrapper = shallowRender(); | |||||
await waitAndUpdate(wrapper); | |||||
expect(searchUsers).toBeCalledWith({ qualityGate: '1', selected: 'selected' }); | |||||
}); | |||||
function shallowRender(overrides: Partial<QualityGatePermissions['props']> = {}) { | |||||
return shallow(<QualityGatePermissions qualityGate={mockQualityGate()} {...overrides} />); | |||||
} |
/* | |||||
* SonarQube | |||||
* Copyright (C) 2009-2021 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 { shallow } from 'enzyme'; | |||||
import * as React from 'react'; | |||||
import { mockUser } from '../../../../helpers/testMocks'; | |||||
import QualityGatePermissionsRenderer, { | |||||
QualityGatePermissionsRendererProps | |||||
} from '../QualityGatePermissionsRenderer'; | |||||
it('should render correctly', () => { | |||||
expect(shallowRender()).toMatchSnapshot('with users'); | |||||
expect(shallowRender({ users: [] })).toMatchSnapshot('with no users'); | |||||
}); | |||||
function shallowRender(overrides: Partial<QualityGatePermissionsRendererProps> = {}) { | |||||
return shallow( | |||||
<QualityGatePermissionsRenderer loading={false} users={[mockUser()]} {...overrides} /> | |||||
); | |||||
} |
refreshItem={[Function]} | refreshItem={[Function]} | ||||
refreshList={[MockFunction]} | refreshList={[MockFunction]} | ||||
/> | /> | ||||
<Memo(DetailsContent) | |||||
<Memo(Connect(withCurrentUser(DetailsContent))) | |||||
isDefault={false} | isDefault={false} | ||||
metrics={Object {}} | metrics={Object {}} | ||||
onAddCondition={[Function]} | onAddCondition={[Function]} |
// Jest Snapshot v1, https://goo.gl/fbAQLP | // Jest Snapshot v1, https://goo.gl/fbAQLP | ||||
exports[`should render correctly: is default 1`] = ` | |||||
exports[`should render correctly: Admin 1`] = ` | |||||
<div | <div | ||||
className="layout-page-main-inner" | className="layout-page-main-inner" | ||||
> | > | ||||
<Connect(withAppState(Conditions)) | <Connect(withAppState(Conditions)) | ||||
canEdit={false} | |||||
conditions={ | conditions={ | ||||
Array [ | Array [ | ||||
Object { | Object { | ||||
} | } | ||||
/> | /> | ||||
<div | <div | ||||
className="quality-gate-section" | |||||
id="quality-gate-projects" | |||||
className="display-flex-row huge-spacer-top" | |||||
> | > | ||||
<header | |||||
className="display-flex-center spacer-bottom" | |||||
<div | |||||
className="quality-gate-section width-50 big-padded-right" | |||||
id="quality-gate-projects" | |||||
> | > | ||||
<h3> | |||||
quality_gates.projects | |||||
</h3> | |||||
<HelpTooltip | |||||
className="spacer-left" | |||||
overlay={ | |||||
<div | |||||
className="big-padded-top big-padded-bottom" | |||||
> | |||||
quality_gates.projects.help | |||||
</div> | |||||
<header | |||||
className="display-flex-center spacer-bottom" | |||||
> | |||||
<h3> | |||||
quality_gates.projects | |||||
</h3> | |||||
<HelpTooltip | |||||
className="spacer-left" | |||||
overlay={ | |||||
<div | |||||
className="big-padded-top big-padded-bottom" | |||||
> | |||||
quality_gates.projects.help | |||||
</div> | |||||
} | |||||
/> | |||||
</header> | |||||
<Projects | |||||
key="1" | |||||
qualityGate={ | |||||
Object { | |||||
"conditions": Array [ | |||||
Object { | |||||
"error": "10", | |||||
"id": 1, | |||||
"metric": "coverage", | |||||
"op": "LT", | |||||
}, | |||||
], | |||||
"id": "1", | |||||
"name": "qualitygate", | |||||
} | |||||
} | } | ||||
/> | /> | ||||
</header> | |||||
quality_gates.projects_for_default | |||||
</div> | |||||
<div | |||||
className="width-50 big-padded-left" | |||||
> | |||||
<QualityGatePermissions | |||||
qualityGate={ | |||||
Object { | |||||
"conditions": Array [ | |||||
Object { | |||||
"error": "10", | |||||
"id": 1, | |||||
"metric": "coverage", | |||||
"op": "LT", | |||||
}, | |||||
], | |||||
"id": "1", | |||||
"name": "qualitygate", | |||||
} | |||||
} | |||||
/> | |||||
</div> | |||||
</div> | |||||
</div> | |||||
`; | |||||
exports[`should render correctly: is default 1`] = ` | |||||
<div | |||||
className="layout-page-main-inner" | |||||
> | |||||
<Connect(withAppState(Conditions)) | |||||
canEdit={false} | |||||
conditions={ | |||||
Array [ | |||||
Object { | |||||
"error": "10", | |||||
"id": 1, | |||||
"metric": "coverage", | |||||
"op": "LT", | |||||
}, | |||||
] | |||||
} | |||||
metrics={Object {}} | |||||
onAddCondition={[MockFunction]} | |||||
onRemoveCondition={[MockFunction]} | |||||
onSaveCondition={[MockFunction]} | |||||
qualityGate={ | |||||
Object { | |||||
"conditions": Array [ | |||||
Object { | |||||
"error": "10", | |||||
"id": 1, | |||||
"metric": "coverage", | |||||
"op": "LT", | |||||
}, | |||||
], | |||||
"id": "1", | |||||
"name": "qualitygate", | |||||
} | |||||
} | |||||
/> | |||||
<div | |||||
className="display-flex-row huge-spacer-top" | |||||
> | |||||
<div | |||||
className="quality-gate-section width-50 big-padded-right" | |||||
id="quality-gate-projects" | |||||
> | |||||
<header | |||||
className="display-flex-center spacer-bottom" | |||||
> | |||||
<h3> | |||||
quality_gates.projects | |||||
</h3> | |||||
<HelpTooltip | |||||
className="spacer-left" | |||||
overlay={ | |||||
<div | |||||
className="big-padded-top big-padded-bottom" | |||||
> | |||||
quality_gates.projects.help | |||||
</div> | |||||
} | |||||
/> | |||||
</header> | |||||
quality_gates.projects_for_default | |||||
</div> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
`; | `; | ||||
quality_gates.is_default_no_conditions | quality_gates.is_default_no_conditions | ||||
</Alert> | </Alert> | ||||
<Connect(withAppState(Conditions)) | <Connect(withAppState(Conditions)) | ||||
canEdit={false} | |||||
conditions={Array []} | conditions={Array []} | ||||
metrics={Object {}} | metrics={Object {}} | ||||
onAddCondition={[MockFunction]} | onAddCondition={[MockFunction]} | ||||
} | } | ||||
/> | /> | ||||
<div | <div | ||||
className="quality-gate-section" | |||||
id="quality-gate-projects" | |||||
className="display-flex-row huge-spacer-top" | |||||
> | > | ||||
<header | |||||
className="display-flex-center spacer-bottom" | |||||
<div | |||||
className="quality-gate-section width-50 big-padded-right" | |||||
id="quality-gate-projects" | |||||
> | > | ||||
<h3> | |||||
quality_gates.projects | |||||
</h3> | |||||
<HelpTooltip | |||||
className="spacer-left" | |||||
overlay={ | |||||
<div | |||||
className="big-padded-top big-padded-bottom" | |||||
> | |||||
quality_gates.projects.help | |||||
</div> | |||||
} | |||||
/> | |||||
</header> | |||||
quality_gates.projects_for_default | |||||
<header | |||||
className="display-flex-center spacer-bottom" | |||||
> | |||||
<h3> | |||||
quality_gates.projects | |||||
</h3> | |||||
<HelpTooltip | |||||
className="spacer-left" | |||||
overlay={ | |||||
<div | |||||
className="big-padded-top big-padded-bottom" | |||||
> | |||||
quality_gates.projects.help | |||||
</div> | |||||
} | |||||
/> | |||||
</header> | |||||
quality_gates.projects_for_default | |||||
</div> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
`; | `; | ||||
className="layout-page-main-inner" | className="layout-page-main-inner" | ||||
> | > | ||||
<Connect(withAppState(Conditions)) | <Connect(withAppState(Conditions)) | ||||
canEdit={false} | |||||
conditions={ | conditions={ | ||||
Array [ | Array [ | ||||
Object { | Object { | ||||
} | } | ||||
/> | /> | ||||
<div | <div | ||||
className="quality-gate-section" | |||||
id="quality-gate-projects" | |||||
className="display-flex-row huge-spacer-top" | |||||
> | > | ||||
<header | |||||
className="display-flex-center spacer-bottom" | |||||
<div | |||||
className="quality-gate-section width-50 big-padded-right" | |||||
id="quality-gate-projects" | |||||
> | > | ||||
<h3> | |||||
quality_gates.projects | |||||
</h3> | |||||
<HelpTooltip | |||||
className="spacer-left" | |||||
overlay={ | |||||
<div | |||||
className="big-padded-top big-padded-bottom" | |||||
> | |||||
quality_gates.projects.help | |||||
</div> | |||||
<header | |||||
className="display-flex-center spacer-bottom" | |||||
> | |||||
<h3> | |||||
quality_gates.projects | |||||
</h3> | |||||
<HelpTooltip | |||||
className="spacer-left" | |||||
overlay={ | |||||
<div | |||||
className="big-padded-top big-padded-bottom" | |||||
> | |||||
quality_gates.projects.help | |||||
</div> | |||||
} | |||||
/> | |||||
</header> | |||||
<Projects | |||||
key="1" | |||||
qualityGate={ | |||||
Object { | |||||
"conditions": Array [ | |||||
Object { | |||||
"error": "10", | |||||
"id": 1, | |||||
"metric": "coverage", | |||||
"op": "LT", | |||||
}, | |||||
], | |||||
"id": "1", | |||||
"name": "qualitygate", | |||||
} | |||||
} | } | ||||
/> | /> | ||||
</header> | |||||
<Projects | |||||
key="1" | |||||
qualityGate={ | |||||
Object { | |||||
"conditions": Array [ | |||||
Object { | |||||
"error": "10", | |||||
"id": 1, | |||||
"metric": "coverage", | |||||
"op": "LT", | |||||
}, | |||||
], | |||||
"id": "1", | |||||
"name": "qualitygate", | |||||
} | |||||
} | |||||
/> | |||||
</div> | |||||
</div> | </div> | ||||
</div> | </div> | ||||
`; | `; |
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||||
exports[`should render correctly 1`] = ` | |||||
<div | |||||
className="display-flex-row" | |||||
> | |||||
<Connect(Avatar) | |||||
className="spacer-right" | |||||
name="John Doe" | |||||
size={32} | |||||
/> | |||||
<div | |||||
className="overflow-hidden" | |||||
> | |||||
<strong> | |||||
John Doe | |||||
</strong> | |||||
<div | |||||
className="note" | |||||
> | |||||
john.doe | |||||
</div> | |||||
</div> | |||||
</div> | |||||
`; |
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||||
exports[`should render correctly 1`] = ` | |||||
<QualityGatePermissionsRenderer | |||||
loading={true} | |||||
users={Array []} | |||||
/> | |||||
`; |
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||||
exports[`should render correctly: with no users 1`] = ` | |||||
<div> | |||||
<header | |||||
className="display-flex-center spacer-bottom" | |||||
> | |||||
<h3> | |||||
quality_gates.permissions | |||||
</h3> | |||||
</header> | |||||
<p | |||||
className="spacer-bottom" | |||||
> | |||||
quality_gates.permissions.help | |||||
</p> | |||||
<DeferredSpinner | |||||
loading={false} | |||||
> | |||||
<ul /> | |||||
</DeferredSpinner> | |||||
</div> | |||||
`; | |||||
exports[`should render correctly: with users 1`] = ` | |||||
<div> | |||||
<header | |||||
className="display-flex-center spacer-bottom" | |||||
> | |||||
<h3> | |||||
quality_gates.permissions | |||||
</h3> | |||||
</header> | |||||
<p | |||||
className="spacer-bottom" | |||||
> | |||||
quality_gates.permissions.help | |||||
</p> | |||||
<DeferredSpinner | |||||
loading={false} | |||||
> | |||||
<ul> | |||||
<li | |||||
className="spacer-top" | |||||
key="john.doe" | |||||
> | |||||
<PermissionItem | |||||
user={ | |||||
Object { | |||||
"active": true, | |||||
"local": true, | |||||
"login": "john.doe", | |||||
"name": "John Doe", | |||||
} | |||||
} | |||||
/> | |||||
</li> | |||||
</ul> | |||||
</DeferredSpinner> | |||||
</div> | |||||
`; |
export enum Permissions { | export enum Permissions { | ||||
Admin = 'admin', | Admin = 'admin', | ||||
ProjectCreation = 'provisioning', | ProjectCreation = 'provisioning', | ||||
ApplicationCreation = 'applicationcreator' | |||||
ApplicationCreation = 'applicationcreator', | |||||
QualityGateAdmin = 'gateadmin' | |||||
} | } |
export interface QualityGateStatusConditionEnhanced extends QualityGateStatusCondition { | export interface QualityGateStatusConditionEnhanced extends QualityGateStatusCondition { | ||||
measure: T.MeasureEnhanced; | measure: T.MeasureEnhanced; | ||||
} | } | ||||
export interface SearchPermissionsParameters { | |||||
qualityGate: string; | |||||
q?: string; | |||||
selected?: 'all' | 'selected' | 'deselected'; | |||||
} |
quality_gates.built_in.description.2=It will automatically be updated with the latest recommendations. | quality_gates.built_in.description.2=It will automatically be updated with the latest recommendations. | ||||
quality_gates.status=Quality Gate status | quality_gates.status=Quality Gate status | ||||
quality_gates.help=A Quality Gate is a set of measure-based, Boolean conditions. It helps you know immediately whether your projects are production-ready. Ideally, all projects will use the same quality gate. Each project's Quality Gate status is displayed prominently on its homepage. | quality_gates.help=A Quality Gate is a set of measure-based, Boolean conditions. It helps you know immediately whether your projects are production-ready. Ideally, all projects will use the same quality gate. Each project's Quality Gate status is displayed prominently on its homepage. | ||||
quality_gates.permissions=Permissions | |||||
quality_gates.permissions.help=Users with the global "Manage Quality Gates" permission can manage this Quality Gate. | |||||
#------------------------------------------------------------------------------ | #------------------------------------------------------------------------------ | ||||
# | # |