mirror of
https://github.com/ansible/awx.git
synced 2026-01-12 18:40:01 -03:30
Merge pull request #203 from AlexSCorey/178-AddOrgBtnV2
178 add org btn v2
This commit is contained in:
commit
dc1bfaac3f
@ -15,7 +15,7 @@ exports[`<ToolbarDeleteButton /> should render button 1`] = `
|
||||
entryDelay={500}
|
||||
exitDelay={500}
|
||||
maxWidth="18.75rem"
|
||||
position="left"
|
||||
position="top"
|
||||
trigger="mouseenter focus"
|
||||
zIndex={9999}
|
||||
>
|
||||
@ -49,7 +49,7 @@ exports[`<ToolbarDeleteButton /> should render button 1`] = `
|
||||
maxWidth="18.75rem"
|
||||
onCreate={[Function]}
|
||||
performance={true}
|
||||
placement="left"
|
||||
placement="top"
|
||||
popperOptions={
|
||||
Object {
|
||||
"modifiers": Object {
|
||||
@ -66,96 +66,94 @@ exports[`<ToolbarDeleteButton /> should render button 1`] = `
|
||||
trigger="mouseenter focus"
|
||||
zIndex={9999}
|
||||
>
|
||||
<ToolbarDeleteButton__Button
|
||||
aria-label="Delete"
|
||||
className="awx-ToolBarBtn"
|
||||
isDisabled={true}
|
||||
onClick={[Function]}
|
||||
variant="plain"
|
||||
>
|
||||
<StyledComponent
|
||||
<div>
|
||||
<ToolbarDeleteButton__DeleteButton
|
||||
aria-label="Delete"
|
||||
className="awx-ToolBarBtn"
|
||||
forwardedComponent={
|
||||
Object {
|
||||
"$$typeof": Symbol(react.forward_ref),
|
||||
"attrs": Array [],
|
||||
"componentStyle": ComponentStyle {
|
||||
"componentId": "ToolbarDeleteButton__Button-sc-1e3r0eg-0",
|
||||
"isStatic": true,
|
||||
"lastClassName": "iyjqWq",
|
||||
"rules": Array [
|
||||
"width:30px;height:30px;display:flex;justify-content:center;margin-right:20px;border-radius:3px;padding:0;&:disabled{cursor:not-allowed;&:hover{background-color:white;> svg{color:#d2d2d2;}}}&:hover{background-color:#d9534f;> svg{color:white;}}",
|
||||
],
|
||||
},
|
||||
"displayName": "ToolbarDeleteButton__Button",
|
||||
"foldedComponentIds": Array [],
|
||||
"render": [Function],
|
||||
"styledComponentId": "ToolbarDeleteButton__Button-sc-1e3r0eg-0",
|
||||
"target": [Function],
|
||||
"toString": [Function],
|
||||
"warnTooManyClasses": [Function],
|
||||
"withComponent": [Function],
|
||||
}
|
||||
}
|
||||
forwardedRef={null}
|
||||
isDisabled={true}
|
||||
onClick={[Function]}
|
||||
variant="plain"
|
||||
>
|
||||
<Button
|
||||
<StyledComponent
|
||||
aria-label="Delete"
|
||||
className="awx-ToolBarBtn ToolbarDeleteButton__Button-sc-1e3r0eg-0 iyjqWq"
|
||||
component="button"
|
||||
isActive={false}
|
||||
isBlock={false}
|
||||
forwardedComponent={
|
||||
Object {
|
||||
"$$typeof": Symbol(react.forward_ref),
|
||||
"attrs": Array [],
|
||||
"componentStyle": ComponentStyle {
|
||||
"componentId": "ToolbarDeleteButton__DeleteButton-sc-1e3r0eg-0",
|
||||
"isStatic": true,
|
||||
"lastClassName": "bQjfFG",
|
||||
"rules": Array [
|
||||
"padding:5px 8px;&:hover{background-color:#d9534f;color:white;}&[disabled]{color:var(--pf-c-button--m-plain--Color);pointer-events:initial;cursor:not-allowed;}",
|
||||
],
|
||||
},
|
||||
"displayName": "ToolbarDeleteButton__DeleteButton",
|
||||
"foldedComponentIds": Array [],
|
||||
"render": [Function],
|
||||
"styledComponentId": "ToolbarDeleteButton__DeleteButton-sc-1e3r0eg-0",
|
||||
"target": [Function],
|
||||
"toString": [Function],
|
||||
"warnTooManyClasses": [Function],
|
||||
"withComponent": [Function],
|
||||
}
|
||||
}
|
||||
forwardedRef={null}
|
||||
isDisabled={true}
|
||||
isFocus={false}
|
||||
isHover={false}
|
||||
onClick={[Function]}
|
||||
type="button"
|
||||
variant="plain"
|
||||
>
|
||||
<button
|
||||
aria-disabled={null}
|
||||
<Button
|
||||
aria-label="Delete"
|
||||
className="pf-c-button pf-m-plain pf-m-disabled awx-ToolBarBtn ToolbarDeleteButton__Button-sc-1e3r0eg-0 iyjqWq"
|
||||
disabled={true}
|
||||
className="ToolbarDeleteButton__DeleteButton-sc-1e3r0eg-0 bQjfFG"
|
||||
component="button"
|
||||
isActive={false}
|
||||
isBlock={false}
|
||||
isDisabled={true}
|
||||
isFocus={false}
|
||||
isHover={false}
|
||||
onClick={[Function]}
|
||||
tabIndex={null}
|
||||
type="button"
|
||||
variant="plain"
|
||||
>
|
||||
<TrashAltIcon
|
||||
className="awx-ToolBarTrashCanIcon"
|
||||
color="currentColor"
|
||||
size="sm"
|
||||
title={null}
|
||||
<button
|
||||
aria-disabled={null}
|
||||
aria-label="Delete"
|
||||
className="pf-c-button pf-m-plain pf-m-disabled ToolbarDeleteButton__DeleteButton-sc-1e3r0eg-0 bQjfFG"
|
||||
disabled={true}
|
||||
onClick={[Function]}
|
||||
tabIndex={null}
|
||||
type="button"
|
||||
>
|
||||
<svg
|
||||
aria-hidden={true}
|
||||
aria-labelledby={null}
|
||||
className="awx-ToolBarTrashCanIcon"
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
role="img"
|
||||
style={
|
||||
Object {
|
||||
"verticalAlign": "-0.125em",
|
||||
}
|
||||
}
|
||||
viewBox="0 0 448 512"
|
||||
width="1em"
|
||||
<TrashAltIcon
|
||||
color="currentColor"
|
||||
size="sm"
|
||||
title={null}
|
||||
>
|
||||
<path
|
||||
d="M32 464a48 48 0 0 0 48 48h288a48 48 0 0 0 48-48V128H32zm272-256a16 16 0 0 1 32 0v224a16 16 0 0 1-32 0zm-96 0a16 16 0 0 1 32 0v224a16 16 0 0 1-32 0zm-96 0a16 16 0 0 1 32 0v224a16 16 0 0 1-32 0zM432 32H312l-9.4-18.7A24 24 0 0 0 281.1 0H166.8a23.72 23.72 0 0 0-21.4 13.3L136 32H16A16 16 0 0 0 0 48v32a16 16 0 0 0 16 16h416a16 16 0 0 0 16-16V48a16 16 0 0 0-16-16z"
|
||||
transform=""
|
||||
/>
|
||||
</svg>
|
||||
</TrashAltIcon>
|
||||
</button>
|
||||
</Button>
|
||||
</StyledComponent>
|
||||
</ToolbarDeleteButton__Button>
|
||||
<svg
|
||||
aria-hidden={true}
|
||||
aria-labelledby={null}
|
||||
fill="currentColor"
|
||||
height="1em"
|
||||
role="img"
|
||||
style={
|
||||
Object {
|
||||
"verticalAlign": "-0.125em",
|
||||
}
|
||||
}
|
||||
viewBox="0 0 448 512"
|
||||
width="1em"
|
||||
>
|
||||
<path
|
||||
d="M32 464a48 48 0 0 0 48 48h288a48 48 0 0 0 48-48V128H32zm272-256a16 16 0 0 1 32 0v224a16 16 0 0 1-32 0zm-96 0a16 16 0 0 1 32 0v224a16 16 0 0 1-32 0zm-96 0a16 16 0 0 1 32 0v224a16 16 0 0 1-32 0zM432 32H312l-9.4-18.7A24 24 0 0 0 281.1 0H166.8a23.72 23.72 0 0 0-21.4 13.3L136 32H16A16 16 0 0 0 0 48v32a16 16 0 0 0 16 16h416a16 16 0 0 0 16-16V48a16 16 0 0 0-16-16z"
|
||||
transform=""
|
||||
/>
|
||||
</svg>
|
||||
</TrashAltIcon>
|
||||
</button>
|
||||
</Button>
|
||||
</StyledComponent>
|
||||
</ToolbarDeleteButton__DeleteButton>
|
||||
</div>
|
||||
<Portal
|
||||
containerInfo={
|
||||
<div>
|
||||
|
||||
@ -72,21 +72,20 @@ describe('<OrganizationDetail />', () => {
|
||||
const custom_virtualenvDetail = detailWrapper.findWhere(node => node.props().label === 'Ansible Environment');
|
||||
const createdDetail = detailWrapper.findWhere(node => node.props().label === 'Created');
|
||||
const modifiedDetail = detailWrapper.findWhere(node => node.props().label === 'Last Modified');
|
||||
expect(nameDetail.find('dt').text()).toBe('Name');
|
||||
expect(nameDetail.find('dd').text()).toBe('Foo');
|
||||
|
||||
expect(nameDetail.find('h6').text()).toBe('Name');
|
||||
expect(nameDetail.find('p').text()).toBe('Foo');
|
||||
expect(descriptionDetail.find('dt').text()).toBe('Description');
|
||||
expect(descriptionDetail.find('dd').text()).toBe('Bar');
|
||||
|
||||
expect(descriptionDetail.find('h6').text()).toBe('Description');
|
||||
expect(descriptionDetail.find('p').text()).toBe('Bar');
|
||||
expect(custom_virtualenvDetail.find('dt').text()).toBe('Ansible Environment');
|
||||
expect(custom_virtualenvDetail.find('dd').text()).toBe('Fizz');
|
||||
|
||||
expect(custom_virtualenvDetail.find('h6').text()).toBe('Ansible Environment');
|
||||
expect(custom_virtualenvDetail.find('p').text()).toBe('Fizz');
|
||||
expect(createdDetail.find('dt').text()).toBe('Created');
|
||||
expect(createdDetail.find('dd').text()).toBe('Bat');
|
||||
|
||||
expect(createdDetail.find('h6').text()).toBe('Created');
|
||||
expect(createdDetail.find('p').text()).toBe('Bat');
|
||||
|
||||
expect(modifiedDetail.find('h6').text()).toBe('Last Modified');
|
||||
expect(modifiedDetail.find('p').text()).toBe('Boo');
|
||||
expect(modifiedDetail.find('dt').text()).toBe('Last Modified');
|
||||
expect(modifiedDetail.find('dd').text()).toBe('Boo');
|
||||
});
|
||||
|
||||
test('should show edit button for users with edit permission', () => {
|
||||
@ -95,9 +94,8 @@ describe('<OrganizationDetail />', () => {
|
||||
organization={mockDetails}
|
||||
/>
|
||||
).find('OrganizationDetail');
|
||||
|
||||
const editLink = wrapper.findWhere(node => node.props().to === '/organizations/undefined/edit');
|
||||
expect(editLink.length).toBe(1);
|
||||
const editButton = wrapper.find('Button');
|
||||
expect((editButton).prop('to')).toBe('/organizations/undefined/edit');
|
||||
});
|
||||
|
||||
test('should hide edit button for users without edit permission', () => {
|
||||
@ -109,7 +107,8 @@ describe('<OrganizationDetail />', () => {
|
||||
/>
|
||||
).find('OrganizationDetail');
|
||||
|
||||
const editLink = wrapper.findWhere(node => node.props().to === '/organizations/undefined/edit');
|
||||
const editLink = wrapper
|
||||
.findWhere(node => node.props().to === '/organizations/undefined/edit');
|
||||
expect(editLink.length).toBe(0);
|
||||
});
|
||||
});
|
||||
|
||||
@ -368,11 +368,11 @@ exports[`<OrganizationNotifications /> initially renders succesfully 1`] = `
|
||||
"componentStyle": ComponentStyle {
|
||||
"componentId": "DataListToolbar__Toolbar-ajzso8-1",
|
||||
"isStatic": false,
|
||||
"lastClassName": "dwCtVz",
|
||||
"lastClassName": "exECbH",
|
||||
"rules": Array [
|
||||
"flex-grow:1;margin-left:",
|
||||
[Function],
|
||||
";",
|
||||
";margin-right:20px;",
|
||||
],
|
||||
},
|
||||
"displayName": "DataListToolbar__Toolbar",
|
||||
@ -389,11 +389,11 @@ exports[`<OrganizationNotifications /> initially renders succesfully 1`] = `
|
||||
marginleft={0}
|
||||
>
|
||||
<Toolbar
|
||||
className="DataListToolbar__Toolbar-ajzso8-1 dwCtVz"
|
||||
className="DataListToolbar__Toolbar-ajzso8-1 exECbH"
|
||||
marginleft={0}
|
||||
>
|
||||
<div
|
||||
className="pf-l-toolbar DataListToolbar__Toolbar-ajzso8-1 dwCtVz"
|
||||
className="pf-l-toolbar DataListToolbar__Toolbar-ajzso8-1 exECbH"
|
||||
marginleft={0}
|
||||
>
|
||||
<DataListToolbar__ColumnLeft>
|
||||
@ -1563,9 +1563,9 @@ exports[`<OrganizationNotifications /> initially renders succesfully 1`] = `
|
||||
"componentStyle": ComponentStyle {
|
||||
"componentId": "DataListToolbar__AdditionalControlsWrapper-ajzso8-5",
|
||||
"isStatic": true,
|
||||
"lastClassName": "cAcBQW",
|
||||
"lastClassName": "bWuACV",
|
||||
"rules": Array [
|
||||
"display:flex;flex-grow:1;justify-content:flex-end;",
|
||||
"display:flex;flex-grow:1;justify-content:flex-end;align-items:center;& >:not(:first-child){margin-left:20px;}",
|
||||
],
|
||||
},
|
||||
"displayName": "DataListToolbar__AdditionalControlsWrapper",
|
||||
@ -1581,7 +1581,7 @@ exports[`<OrganizationNotifications /> initially renders succesfully 1`] = `
|
||||
forwardedRef={null}
|
||||
>
|
||||
<div
|
||||
className="DataListToolbar__AdditionalControlsWrapper-ajzso8-5 cAcBQW"
|
||||
className="DataListToolbar__AdditionalControlsWrapper-ajzso8-5 bWuACV"
|
||||
/>
|
||||
</StyledComponent>
|
||||
</DataListToolbar__AdditionalControlsWrapper>
|
||||
@ -1770,9 +1770,9 @@ exports[`<OrganizationNotifications /> initially renders succesfully 1`] = `
|
||||
"$$typeof": Symbol(react.forward_ref),
|
||||
"attrs": Array [],
|
||||
"componentStyle": ComponentStyle {
|
||||
"componentId": "sc-htpNat",
|
||||
"componentId": "sc-bxivhb",
|
||||
"isStatic": true,
|
||||
"lastClassName": "dlcYLn",
|
||||
"lastClassName": "lohjuH",
|
||||
"rules": Array [
|
||||
"margin-right: 1.5em;",
|
||||
],
|
||||
@ -1780,7 +1780,7 @@ exports[`<OrganizationNotifications /> initially renders succesfully 1`] = `
|
||||
"displayName": "Styled(Link)",
|
||||
"foldedComponentIds": Array [],
|
||||
"render": [Function],
|
||||
"styledComponentId": "sc-htpNat",
|
||||
"styledComponentId": "sc-bxivhb",
|
||||
"target": [Function],
|
||||
"toString": [Function],
|
||||
"warnTooManyClasses": [Function],
|
||||
@ -1795,7 +1795,7 @@ exports[`<OrganizationNotifications /> initially renders succesfully 1`] = `
|
||||
}
|
||||
>
|
||||
<Link
|
||||
className="sc-htpNat dlcYLn"
|
||||
className="sc-bxivhb lohjuH"
|
||||
replace={false}
|
||||
to={
|
||||
Object {
|
||||
@ -1804,7 +1804,7 @@ exports[`<OrganizationNotifications /> initially renders succesfully 1`] = `
|
||||
}
|
||||
>
|
||||
<a
|
||||
className="sc-htpNat dlcYLn"
|
||||
className="sc-bxivhb lohjuH"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<b
|
||||
@ -1825,9 +1825,9 @@ exports[`<OrganizationNotifications /> initially renders succesfully 1`] = `
|
||||
"$$typeof": Symbol(react.forward_ref),
|
||||
"attrs": Array [],
|
||||
"componentStyle": ComponentStyle {
|
||||
"componentId": "sc-bxivhb",
|
||||
"componentId": "sc-ifAKCX",
|
||||
"isStatic": true,
|
||||
"lastClassName": "iZoxgU",
|
||||
"lastClassName": "jGZNNo",
|
||||
"rules": Array [
|
||||
"text-transform: capitalize;",
|
||||
],
|
||||
@ -1835,7 +1835,7 @@ exports[`<OrganizationNotifications /> initially renders succesfully 1`] = `
|
||||
"displayName": "Styled(Badge)",
|
||||
"foldedComponentIds": Array [],
|
||||
"render": [Function],
|
||||
"styledComponentId": "sc-bxivhb",
|
||||
"styledComponentId": "sc-ifAKCX",
|
||||
"target": [Function],
|
||||
"toString": [Function],
|
||||
"warnTooManyClasses": [Function],
|
||||
@ -1846,11 +1846,11 @@ exports[`<OrganizationNotifications /> initially renders succesfully 1`] = `
|
||||
isRead={true}
|
||||
>
|
||||
<Badge
|
||||
className="sc-bxivhb iZoxgU"
|
||||
className="sc-ifAKCX jGZNNo"
|
||||
isRead={true}
|
||||
>
|
||||
<span
|
||||
className="pf-c-badge pf-m-read sc-bxivhb iZoxgU"
|
||||
className="pf-c-badge pf-m-read sc-ifAKCX jGZNNo"
|
||||
>
|
||||
email
|
||||
</span>
|
||||
@ -2245,9 +2245,9 @@ exports[`<OrganizationNotifications /> initially renders succesfully 1`] = `
|
||||
"$$typeof": Symbol(react.forward_ref),
|
||||
"attrs": Array [],
|
||||
"componentStyle": ComponentStyle {
|
||||
"componentId": "sc-htpNat",
|
||||
"componentId": "sc-bxivhb",
|
||||
"isStatic": true,
|
||||
"lastClassName": "dlcYLn",
|
||||
"lastClassName": "lohjuH",
|
||||
"rules": Array [
|
||||
"margin-right: 1.5em;",
|
||||
],
|
||||
@ -2255,7 +2255,7 @@ exports[`<OrganizationNotifications /> initially renders succesfully 1`] = `
|
||||
"displayName": "Styled(Link)",
|
||||
"foldedComponentIds": Array [],
|
||||
"render": [Function],
|
||||
"styledComponentId": "sc-htpNat",
|
||||
"styledComponentId": "sc-bxivhb",
|
||||
"target": [Function],
|
||||
"toString": [Function],
|
||||
"warnTooManyClasses": [Function],
|
||||
@ -2270,7 +2270,7 @@ exports[`<OrganizationNotifications /> initially renders succesfully 1`] = `
|
||||
}
|
||||
>
|
||||
<Link
|
||||
className="sc-htpNat dlcYLn"
|
||||
className="sc-bxivhb lohjuH"
|
||||
replace={false}
|
||||
to={
|
||||
Object {
|
||||
@ -2279,7 +2279,7 @@ exports[`<OrganizationNotifications /> initially renders succesfully 1`] = `
|
||||
}
|
||||
>
|
||||
<a
|
||||
className="sc-htpNat dlcYLn"
|
||||
className="sc-bxivhb lohjuH"
|
||||
onClick={[Function]}
|
||||
>
|
||||
<b
|
||||
@ -2300,9 +2300,9 @@ exports[`<OrganizationNotifications /> initially renders succesfully 1`] = `
|
||||
"$$typeof": Symbol(react.forward_ref),
|
||||
"attrs": Array [],
|
||||
"componentStyle": ComponentStyle {
|
||||
"componentId": "sc-bxivhb",
|
||||
"componentId": "sc-ifAKCX",
|
||||
"isStatic": true,
|
||||
"lastClassName": "iZoxgU",
|
||||
"lastClassName": "jGZNNo",
|
||||
"rules": Array [
|
||||
"text-transform: capitalize;",
|
||||
],
|
||||
@ -2310,7 +2310,7 @@ exports[`<OrganizationNotifications /> initially renders succesfully 1`] = `
|
||||
"displayName": "Styled(Badge)",
|
||||
"foldedComponentIds": Array [],
|
||||
"render": [Function],
|
||||
"styledComponentId": "sc-bxivhb",
|
||||
"styledComponentId": "sc-ifAKCX",
|
||||
"target": [Function],
|
||||
"toString": [Function],
|
||||
"warnTooManyClasses": [Function],
|
||||
@ -2321,11 +2321,11 @@ exports[`<OrganizationNotifications /> initially renders succesfully 1`] = `
|
||||
isRead={true}
|
||||
>
|
||||
<Badge
|
||||
className="sc-bxivhb iZoxgU"
|
||||
className="sc-ifAKCX jGZNNo"
|
||||
isRead={true}
|
||||
>
|
||||
<span
|
||||
className="pf-c-badge pf-m-read sc-bxivhb iZoxgU"
|
||||
className="pf-c-badge pf-m-read sc-ifAKCX jGZNNo"
|
||||
>
|
||||
email
|
||||
</span>
|
||||
|
||||
@ -34,6 +34,7 @@ const AWXToolbar = styled.div`
|
||||
const Toolbar = styled(PFToolbar)`
|
||||
flex-grow: 1;
|
||||
margin-left: ${props => (props.marginleft ? '0' : '20px')};
|
||||
margin-right: 20px;
|
||||
`;
|
||||
|
||||
const ToolbarGroup = styled(PFToolbarGroup)`
|
||||
@ -67,6 +68,11 @@ const AdditionalControlsWrapper = styled.div`
|
||||
display: flex;
|
||||
flex-grow: 1;
|
||||
justify-content: flex-end;
|
||||
align-items: center;
|
||||
|
||||
& > :not(:first-child) {
|
||||
margin-left: 20px;
|
||||
}
|
||||
`;
|
||||
|
||||
class DataListToolbar extends React.Component {
|
||||
|
||||
@ -6,17 +6,17 @@ import {
|
||||
DataListItemRow,
|
||||
DataListItemCells,
|
||||
DataListCell,
|
||||
Text,
|
||||
TextContent,
|
||||
Title,
|
||||
EmptyState,
|
||||
EmptyStateIcon,
|
||||
EmptyStateBody,
|
||||
EmptyStateBody
|
||||
} from '@patternfly/react-core';
|
||||
import { CubesIcon } from '@patternfly/react-icons';
|
||||
import { withI18n } from '@lingui/react';
|
||||
import { t } from '@lingui/macro';
|
||||
import { withRouter, Link } from 'react-router-dom';
|
||||
import styled from 'styled-components';
|
||||
|
||||
import Pagination from '../Pagination';
|
||||
import DataListToolbar from '../DataListToolbar';
|
||||
@ -24,19 +24,26 @@ import {
|
||||
parseNamespacedQueryString,
|
||||
updateNamespacedQueryString,
|
||||
} from '../../util/qs';
|
||||
import { pluralize, getArticle, ucFirst } from '../../util/strings';
|
||||
import { pluralize, ucFirst } from '../../util/strings';
|
||||
import { QSConfig } from '../../types';
|
||||
|
||||
const detailWrapperStyle = {
|
||||
display: 'grid',
|
||||
gridTemplateColumns: 'minmax(70px, max-content) minmax(60px, max-content)',
|
||||
};
|
||||
const EmptyStateControlsWrapper = styled.div`
|
||||
display: flex;
|
||||
margin-top: 20px;
|
||||
margin-right: 20px;
|
||||
margin-bottom: 20px;
|
||||
justify-content: flex-end;
|
||||
|
||||
const detailLabelStyle = {
|
||||
fontWeight: '700',
|
||||
lineHeight: '24px',
|
||||
marginRight: '20px',
|
||||
};
|
||||
& > :not(:first-child) {
|
||||
margin-left: 20px;
|
||||
}
|
||||
`;
|
||||
|
||||
const ListItemGrid = styled(TextContent)`
|
||||
display: grid;
|
||||
grid-template-columns: minmax(70px,max-content) repeat(auto-fit, minmax(60px,max-content));
|
||||
grid-gap: 10px;
|
||||
`;
|
||||
|
||||
class PaginatedDataList extends React.Component {
|
||||
constructor (props) {
|
||||
@ -95,6 +102,7 @@ class PaginatedDataList extends React.Component {
|
||||
|
||||
render () {
|
||||
const {
|
||||
emptyStateControls,
|
||||
items,
|
||||
itemCount,
|
||||
qsConfig,
|
||||
@ -125,72 +133,78 @@ class PaginatedDataList extends React.Component {
|
||||
)}
|
||||
</Fragment> // TODO: replace with proper error handling
|
||||
)}
|
||||
{items.length === 0 ? (
|
||||
<EmptyState>
|
||||
<EmptyStateIcon icon={CubesIcon} />
|
||||
<Title size="lg">
|
||||
{i18n._(t`No ${ucFirst(itemNamePlural || pluralize(itemName))} Found`)}
|
||||
</Title>
|
||||
<EmptyStateBody>
|
||||
{i18n._(t`Please add ${getArticle(itemName)} ${itemName} to populate this list`)}
|
||||
</EmptyStateBody>
|
||||
</EmptyState>
|
||||
) : (
|
||||
<Fragment>
|
||||
<DataListToolbar
|
||||
sortedColumnKey={orderBy}
|
||||
sortOrder={sortOrder}
|
||||
columns={columns}
|
||||
onSearch={() => { }}
|
||||
onSort={this.handleSort}
|
||||
showSelectAll={showSelectAll}
|
||||
isAllSelected={isAllSelected}
|
||||
onSelectAll={onSelectAll}
|
||||
additionalControls={additionalControls}
|
||||
noLeftMargin={alignToolbarLeft}
|
||||
/>
|
||||
<DataList aria-label={i18n._(t`${ucFirst(pluralize(itemName))} List`)}>
|
||||
{items.map(item => (renderItem ? renderItem(item) : (
|
||||
<DataListItem
|
||||
aria-labelledby={`items-list-item-${item.id}`}
|
||||
key={item.id}
|
||||
>
|
||||
<DataListItemRow>
|
||||
<DataListItemCells dataListCells={[
|
||||
<DataListCell key="team-name">
|
||||
<TextContent style={detailWrapperStyle}>
|
||||
<Link to={{ pathname: item.url }}>
|
||||
<Text
|
||||
id={`items-list-item-${item.id}`}
|
||||
style={detailLabelStyle}
|
||||
>
|
||||
{item.name}
|
||||
</Text>
|
||||
</Link>
|
||||
</TextContent>
|
||||
</DataListCell>
|
||||
]}
|
||||
/>
|
||||
</DataListItemRow>
|
||||
</DataListItem>
|
||||
)))}
|
||||
</DataList>
|
||||
<Pagination
|
||||
variant="bottom"
|
||||
itemCount={itemCount}
|
||||
page={queryParams.page || 1}
|
||||
perPage={queryParams.page_size}
|
||||
perPageOptions={showPageSizeOptions ? [
|
||||
{ title: '5', value: 5 },
|
||||
{ title: '10', value: 10 },
|
||||
{ title: '20', value: 20 },
|
||||
{ title: '50', value: 50 }
|
||||
] : []}
|
||||
onSetPage={this.handleSetPage}
|
||||
onPerPageSelect={this.handleSetPageSize}
|
||||
/>
|
||||
</Fragment>
|
||||
)}
|
||||
{items.length === 0
|
||||
? (
|
||||
<Fragment>
|
||||
<EmptyStateControlsWrapper>
|
||||
{emptyStateControls}
|
||||
</EmptyStateControlsWrapper>
|
||||
<div css="border-bottom: 1px solid #d2d2d2" />
|
||||
<EmptyState>
|
||||
<EmptyStateIcon icon={CubesIcon} />
|
||||
<Title size="lg">
|
||||
{i18n._(t`No ${ucFirst(itemNamePlural || pluralize(itemName))} Found `)}
|
||||
</Title>
|
||||
<EmptyStateBody>
|
||||
{i18n._(t`Please add ${ucFirst(itemNamePlural || pluralize(itemName))} to populate this list `)}
|
||||
</EmptyStateBody>
|
||||
</EmptyState>
|
||||
</Fragment>
|
||||
)
|
||||
: (
|
||||
<Fragment>
|
||||
<DataListToolbar
|
||||
sortedColumnKey={orderBy}
|
||||
sortOrder={sortOrder}
|
||||
columns={columns}
|
||||
onSearch={() => { }}
|
||||
onSort={this.handleSort}
|
||||
showSelectAll={showSelectAll}
|
||||
isAllSelected={isAllSelected}
|
||||
onSelectAll={onSelectAll}
|
||||
additionalControls={additionalControls}
|
||||
noLeftMargin={alignToolbarLeft}
|
||||
|
||||
/>
|
||||
<DataList aria-label={i18n._(t`${ucFirst(pluralize(itemName))} List`)}>
|
||||
{items.map(item => (renderItem ? renderItem(item) : (
|
||||
<DataListItem
|
||||
aria-labelledby={`items-list-item-${item.id}`}
|
||||
key={item.id}
|
||||
>
|
||||
<DataListItemRow>
|
||||
<DataListItemCells dataListCells={[
|
||||
<DataListCell key="team-name">
|
||||
<ListItemGrid>
|
||||
<Link to={{ pathname: item.url }}>
|
||||
<b id={`items-list-item-${item.id}`}>
|
||||
{item.name}
|
||||
</b>
|
||||
</Link>
|
||||
</ListItemGrid>
|
||||
</DataListCell>
|
||||
]}
|
||||
/>
|
||||
</DataListItemRow>
|
||||
</DataListItem>
|
||||
)))}
|
||||
</DataList>
|
||||
<Pagination
|
||||
variant="bottom"
|
||||
itemCount={itemCount}
|
||||
page={queryParams.page || 1}
|
||||
perPage={queryParams.page_size}
|
||||
perPageOptions={showPageSizeOptions ? [
|
||||
{ title: '5', value: 5 },
|
||||
{ title: '10', value: 10 },
|
||||
{ title: '20', value: 20 },
|
||||
{ title: '50', value: 50 }
|
||||
] : []}
|
||||
onSetPage={this.handleSetPage}
|
||||
onPerPageSelect={this.handleSetPageSize}
|
||||
/>
|
||||
</Fragment>
|
||||
)}
|
||||
</Fragment>
|
||||
);
|
||||
}
|
||||
|
||||
@ -1,22 +1,17 @@
|
||||
import React from 'react';
|
||||
import { string, func } from 'prop-types';
|
||||
import { Link } from 'react-router-dom';
|
||||
import { Button as PFButton } from '@patternfly/react-core';
|
||||
import { Button as PFButton, Tooltip } from '@patternfly/react-core';
|
||||
import { PlusIcon } from '@patternfly/react-icons';
|
||||
import { withI18n } from '@lingui/react';
|
||||
import { t } from '@lingui/macro';
|
||||
import styled from 'styled-components';
|
||||
|
||||
const Button = styled(PFButton)`
|
||||
&&& { /* higher specificity order */
|
||||
&& {
|
||||
background-color: #5cb85c;
|
||||
min-width: 0;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
text-align: center;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
margin-right: 20px;
|
||||
padding: 5px 8px;
|
||||
--pf-global--FontSize--md: 14px;
|
||||
}
|
||||
`;
|
||||
|
||||
@ -25,19 +20,22 @@ function ToolbarAddButton ({ linkTo, onClick, i18n }) {
|
||||
throw new Error('ToolbarAddButton requires either `linkTo` or `onClick` prop');
|
||||
}
|
||||
if (linkTo) {
|
||||
// TODO: This should only be a <Link> (no <Button>) but CSS is off
|
||||
return (
|
||||
<Link to={linkTo}>
|
||||
<Tooltip
|
||||
content={i18n._(t`Add`)}
|
||||
position="top"
|
||||
>
|
||||
<Button
|
||||
component={Link}
|
||||
to={linkTo}
|
||||
variant="primary"
|
||||
aria-label={i18n._(t`Add`)}
|
||||
>
|
||||
<PlusIcon />
|
||||
</Button>
|
||||
</Link>
|
||||
</Tooltip>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Button
|
||||
variant="primary"
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import React, { Fragment } from 'react';
|
||||
import { func, bool, number, string, arrayOf, shape } from 'prop-types';
|
||||
import { Button as PFButton, Tooltip } from '@patternfly/react-core';
|
||||
import { Button, Tooltip } from '@patternfly/react-core';
|
||||
import { TrashAltIcon } from '@patternfly/react-icons';
|
||||
import styled from 'styled-components';
|
||||
import { withI18n } from '@lingui/react';
|
||||
@ -8,32 +8,18 @@ import { t } from '@lingui/macro';
|
||||
import AlertModal from '../AlertModal';
|
||||
import { pluralize } from '../../util/strings';
|
||||
|
||||
const Button = styled(PFButton)`
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
margin-right: 20px;
|
||||
border-radius: 3px;
|
||||
padding: 0;
|
||||
|
||||
|
||||
&:disabled {
|
||||
cursor: not-allowed;
|
||||
&:hover {
|
||||
background-color: white;
|
||||
|
||||
> svg {
|
||||
color: #d2d2d2;
|
||||
}
|
||||
}
|
||||
}
|
||||
const DeleteButton = styled(Button)`
|
||||
padding: 5px 8px;
|
||||
|
||||
&:hover {
|
||||
background-color:#d9534f;
|
||||
> svg {
|
||||
color: white;
|
||||
}
|
||||
color: white;
|
||||
}
|
||||
|
||||
&[disabled] {
|
||||
color: var(--pf-c-button--m-plain--Color);
|
||||
pointer-events: initial;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
`;
|
||||
|
||||
@ -118,21 +104,25 @@ class ToolbarDeleteButton extends React.Component {
|
||||
const isDisabled = itemsToDelete.length === 0
|
||||
|| itemsToDelete.some(cannotDelete);
|
||||
|
||||
// NOTE: Once PF supports tooltips on disabled elements,
|
||||
// we can delete the extra <div> around the <DeleteButton> below.
|
||||
// See: https://github.com/patternfly/patternfly-react/issues/1894
|
||||
return (
|
||||
<Fragment>
|
||||
<Tooltip
|
||||
content={this.renderTooltip()}
|
||||
position="left"
|
||||
position="top"
|
||||
>
|
||||
<Button
|
||||
className="awx-ToolBarBtn"
|
||||
variant="plain"
|
||||
aria-label={i18n._(t`Delete`)}
|
||||
onClick={this.handleConfirmDelete}
|
||||
isDisabled={isDisabled}
|
||||
>
|
||||
<TrashAltIcon className="awx-ToolBarTrashCanIcon" />
|
||||
</Button>
|
||||
<div>
|
||||
<DeleteButton
|
||||
variant="plain"
|
||||
aria-label={i18n._(t`Delete`)}
|
||||
onClick={this.handleConfirmDelete}
|
||||
isDisabled={isDisabled}
|
||||
>
|
||||
<TrashAltIcon />
|
||||
</DeleteButton>
|
||||
</div>
|
||||
</Tooltip>
|
||||
{ isModalOpen && (
|
||||
<AlertModal
|
||||
|
||||
@ -113,12 +113,6 @@ class Organization extends Component {
|
||||
isAdminOfThisOrg
|
||||
} = this.state;
|
||||
|
||||
const tabsStyle = {
|
||||
paddingTop: '0px',
|
||||
paddingLeft: '0px',
|
||||
paddingRight: '0px',
|
||||
};
|
||||
|
||||
const canSeeNotificationsTab = me.is_system_auditor || isNotifAdmin || isAuditorOfThisOrg;
|
||||
const canToggleNotifications = isNotifAdmin && (
|
||||
me.is_system_auditor
|
||||
@ -141,11 +135,9 @@ class Organization extends Component {
|
||||
}
|
||||
|
||||
let cardHeader = (
|
||||
loading ? ''
|
||||
: (
|
||||
<CardHeader
|
||||
style={tabsStyle}
|
||||
>
|
||||
loading ? '' : (
|
||||
<CardHeader style={{ padding: 0 }}>
|
||||
<React.Fragment>
|
||||
<div className="awx-orgTabs-container">
|
||||
<RoutedTabs
|
||||
match={match}
|
||||
@ -158,8 +150,10 @@ class Organization extends Component {
|
||||
className="awx-orgTabs__bottom-border"
|
||||
/>
|
||||
</div>
|
||||
</CardHeader>
|
||||
));
|
||||
</React.Fragment>
|
||||
</CardHeader>
|
||||
)
|
||||
);
|
||||
if (!match) {
|
||||
cardHeader = null;
|
||||
}
|
||||
|
||||
@ -4,45 +4,60 @@ import { withI18n } from '@lingui/react';
|
||||
import { t } from '@lingui/macro';
|
||||
|
||||
import {
|
||||
CardBody,
|
||||
CardBody as PFCardBody,
|
||||
Button,
|
||||
Text,
|
||||
TextContent,
|
||||
TextVariants,
|
||||
TextList,
|
||||
TextListItem,
|
||||
TextListVariants,
|
||||
TextListItemVariants,
|
||||
} from '@patternfly/react-core';
|
||||
|
||||
import styled from 'styled-components';
|
||||
import { withNetwork } from '../../../../contexts/Network';
|
||||
|
||||
import BasicChip from '../../../../components/BasicChip/BasicChip';
|
||||
|
||||
const detailWrapperStyle = {
|
||||
display: 'flex'
|
||||
};
|
||||
const CardBody = styled(PFCardBody)`
|
||||
padding-top: 20px;
|
||||
`;
|
||||
|
||||
const detailLabelStyle = {
|
||||
fontWeight: '700',
|
||||
lineHeight: '24px',
|
||||
marginRight: '20px',
|
||||
minWidth: '150px',
|
||||
textAlign: 'right'
|
||||
};
|
||||
const DetailList = styled(TextList)`
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(270px, 1fr));
|
||||
grid-gap: 20px;
|
||||
|
||||
const detailValueStyle = {
|
||||
lineHeight: '24px',
|
||||
wordBreak: 'break-all'
|
||||
};
|
||||
& > div {
|
||||
display: grid;
|
||||
grid-template-columns: 10em 1fr;
|
||||
grid-gap: 20px;
|
||||
}
|
||||
`;
|
||||
|
||||
const DetailName = styled(TextListItem)`
|
||||
&& {
|
||||
grid-column: 1;
|
||||
font-weight: var(--pf-global--FontWeight--bold);
|
||||
text-align: right;
|
||||
}
|
||||
`;
|
||||
|
||||
const DetailValue = styled(TextListItem)`
|
||||
&& {
|
||||
grid-column: 2;
|
||||
word-break: break-all;
|
||||
}
|
||||
`;
|
||||
|
||||
const InstanceGroupsDetail = styled.div`
|
||||
grid-column: 1 / -1;
|
||||
`;
|
||||
|
||||
const Detail = ({ label, value }) => {
|
||||
let detail = null;
|
||||
if (value) {
|
||||
detail = (
|
||||
<TextContent style={detailWrapperStyle}>
|
||||
<Text component={TextVariants.h6} style={detailLabelStyle}>{ label }</Text>
|
||||
<Text component={TextVariants.p} style={detailValueStyle}>{ value }</Text>
|
||||
</TextContent>
|
||||
);
|
||||
}
|
||||
return detail;
|
||||
if (!value) return null;
|
||||
return (
|
||||
<div>
|
||||
<DetailName component={TextListItemVariants.dt}>{label}</DetailName>
|
||||
<DetailValue component={TextListItemVariants.dd}>{value}</DetailValue>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
class OrganizationDetail extends Component {
|
||||
@ -129,7 +144,7 @@ class OrganizationDetail extends Component {
|
||||
|
||||
return (
|
||||
<CardBody>
|
||||
<div className="pf-l-grid pf-m-gutter pf-m-all-12-col-on-md pf-m-all-6-col-on-lg pf-m-all-4-col-on-xl">
|
||||
<DetailList component={TextListVariants.dl}>
|
||||
<Detail
|
||||
label={i18n._(t`Name`)}
|
||||
value={name}
|
||||
@ -151,25 +166,25 @@ class OrganizationDetail extends Component {
|
||||
value={modified}
|
||||
/>
|
||||
{(instanceGroups && instanceGroups.length > 0) && (
|
||||
<TextContent style={{ display: 'flex', gridColumn: '1 / -1' }}>
|
||||
<Text
|
||||
component={TextVariants.h6}
|
||||
style={detailLabelStyle}
|
||||
>
|
||||
<InstanceGroupsDetail>
|
||||
<DetailName component={TextListItemVariants.dt}>
|
||||
{i18n._(t`Instance Groups`)}
|
||||
</Text>
|
||||
<div style={detailValueStyle}>
|
||||
</DetailName>
|
||||
<DetailValue component={TextListItemVariants.dd}>
|
||||
{instanceGroupChips}
|
||||
{overflowChip}
|
||||
</div>
|
||||
</TextContent>
|
||||
</DetailValue>
|
||||
</InstanceGroupsDetail>
|
||||
)}
|
||||
</div>
|
||||
</DetailList>
|
||||
{summary_fields.user_capabilities.edit && (
|
||||
<div style={{ display: 'flex', flexDirection: 'row-reverse', marginTop: '20px' }}>
|
||||
<Link to={`/organizations/${match.params.id}/edit`}>
|
||||
<Button>{i18n._(t`Edit`)}</Button>
|
||||
</Link>
|
||||
<div css="margin-top: 10px; text-align: right;">
|
||||
<Button
|
||||
component={Link}
|
||||
to={`/organizations/${match.params.id}/edit`}
|
||||
>
|
||||
{i18n._(t`Edit`)}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
{error ? 'error!' : ''}
|
||||
|
||||
@ -186,6 +186,10 @@ class OrganizationsList extends Component {
|
||||
onSelect={() => this.handleSelect(o)}
|
||||
/>
|
||||
)}
|
||||
emptyStateControls={
|
||||
canAdd ? <ToolbarAddButton key="add" linkTo={`${match.url}/add`} />
|
||||
: null
|
||||
}
|
||||
/>
|
||||
)}
|
||||
{ isLoading ? <div>loading...</div> : '' }
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user