mirror of
https://github.com/ansible/awx.git
synced 2026-02-20 12:40:06 -03:30
Migrate EE list to tables
Migrate EE list to tables. See:https://github.com/ansible/awx/issues/7884
This commit is contained in:
@@ -15,6 +15,7 @@ const executionEnvironments = {
|
|||||||
data: {
|
data: {
|
||||||
results: [
|
results: [
|
||||||
{
|
{
|
||||||
|
name: 'Foo',
|
||||||
id: 1,
|
id: 1,
|
||||||
image: 'https://registry.com/r/image/manifest',
|
image: 'https://registry.com/r/image/manifest',
|
||||||
organization: null,
|
organization: null,
|
||||||
@@ -23,6 +24,7 @@ const executionEnvironments = {
|
|||||||
summary_fields: { user_capabilities: { edit: true, delete: true } },
|
summary_fields: { user_capabilities: { edit: true, delete: true } },
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
name: 'Bar',
|
||||||
id: 2,
|
id: 2,
|
||||||
image: 'https://registry.com/r/image2/manifest',
|
image: 'https://registry.com/r/image2/manifest',
|
||||||
organization: null,
|
organization: null,
|
||||||
@@ -38,6 +40,14 @@ const executionEnvironments = {
|
|||||||
const options = { data: { actions: { POST: true } } };
|
const options = { data: { actions: { POST: true } } };
|
||||||
|
|
||||||
describe('<ExecutionEnvironmentList/>', () => {
|
describe('<ExecutionEnvironmentList/>', () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
ExecutionEnvironmentsAPI.read.mockResolvedValue(executionEnvironments);
|
||||||
|
ExecutionEnvironmentsAPI.readOptions.mockResolvedValue(options);
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(() => {
|
||||||
|
jest.clearAllMocks();
|
||||||
|
});
|
||||||
let wrapper;
|
let wrapper;
|
||||||
|
|
||||||
test('should mount successfully', async () => {
|
test('should mount successfully', async () => {
|
||||||
@@ -52,9 +62,6 @@ describe('<ExecutionEnvironmentList/>', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('should have data fetched and render 2 rows', async () => {
|
test('should have data fetched and render 2 rows', async () => {
|
||||||
ExecutionEnvironmentsAPI.read.mockResolvedValue(executionEnvironments);
|
|
||||||
ExecutionEnvironmentsAPI.readOptions.mockResolvedValue(options);
|
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper = mountWithContexts(<ExecutionEnvironmentList />);
|
wrapper = mountWithContexts(<ExecutionEnvironmentList />);
|
||||||
});
|
});
|
||||||
@@ -69,10 +76,7 @@ describe('<ExecutionEnvironmentList/>', () => {
|
|||||||
expect(ExecutionEnvironmentsAPI.readOptions).toBeCalled();
|
expect(ExecutionEnvironmentsAPI.readOptions).toBeCalled();
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should delete item successfully', async () => {
|
test('should delete items successfully', async () => {
|
||||||
ExecutionEnvironmentsAPI.read.mockResolvedValue(executionEnvironments);
|
|
||||||
ExecutionEnvironmentsAPI.readOptions.mockResolvedValue(options);
|
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper = mountWithContexts(<ExecutionEnvironmentList />);
|
wrapper = mountWithContexts(<ExecutionEnvironmentList />);
|
||||||
});
|
});
|
||||||
@@ -82,27 +86,25 @@ describe('<ExecutionEnvironmentList/>', () => {
|
|||||||
el => el.length > 0
|
el => el.length > 0
|
||||||
);
|
);
|
||||||
|
|
||||||
wrapper
|
|
||||||
.find('input#select-execution-environment-1')
|
|
||||||
.simulate('change', executionEnvironments.data.results[0]);
|
|
||||||
wrapper.update();
|
|
||||||
|
|
||||||
expect(
|
|
||||||
wrapper.find('input#select-execution-environment-1').prop('checked')
|
|
||||||
).toBe(true);
|
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper.find('Button[aria-label="Delete"]').prop('onClick')();
|
wrapper
|
||||||
|
.find('ExecutionEnvironmentListItem')
|
||||||
|
.at(0)
|
||||||
|
.invoke('onSelect')();
|
||||||
});
|
});
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper.find('Button[aria-label="confirm delete"]').prop('onClick')();
|
wrapper
|
||||||
|
.find('ExecutionEnvironmentListItem')
|
||||||
|
.at(1)
|
||||||
|
.invoke('onSelect')();
|
||||||
|
});
|
||||||
|
wrapper.update();
|
||||||
|
await act(async () => {
|
||||||
|
wrapper.find('ToolbarDeleteButton').invoke('onDelete')();
|
||||||
});
|
});
|
||||||
|
|
||||||
expect(ExecutionEnvironmentsAPI.destroy).toBeCalledWith(
|
expect(ExecutionEnvironmentsAPI.destroy).toHaveBeenCalledTimes(2);
|
||||||
executionEnvironments.data.results[0].id
|
|
||||||
);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should render deletion error modal', async () => {
|
test('should render deletion error modal', async () => {
|
||||||
@@ -117,19 +119,24 @@ describe('<ExecutionEnvironmentList/>', () => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
ExecutionEnvironmentsAPI.read.mockResolvedValue(executionEnvironments);
|
|
||||||
ExecutionEnvironmentsAPI.readOptions.mockResolvedValue(options);
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper = mountWithContexts(<ExecutionEnvironmentList />);
|
wrapper = mountWithContexts(<ExecutionEnvironmentList />);
|
||||||
});
|
});
|
||||||
waitForElement(wrapper, 'ExecutionEnvironmentList', el => el.length > 0);
|
waitForElement(wrapper, 'ExecutionEnvironmentList', el => el.length > 0);
|
||||||
|
|
||||||
wrapper
|
wrapper
|
||||||
.find('input#select-execution-environment-1')
|
.find('ExecutionEnvironmentListItem')
|
||||||
|
.at(0)
|
||||||
|
.find('input')
|
||||||
.simulate('change', 'a');
|
.simulate('change', 'a');
|
||||||
wrapper.update();
|
wrapper.update();
|
||||||
|
|
||||||
expect(
|
expect(
|
||||||
wrapper.find('input#select-execution-environment-1').prop('checked')
|
wrapper
|
||||||
|
.find('ExecutionEnvironmentListItem')
|
||||||
|
.at(0)
|
||||||
|
.find('input')
|
||||||
|
.prop('checked')
|
||||||
).toBe(true);
|
).toBe(true);
|
||||||
|
|
||||||
await act(async () =>
|
await act(async () =>
|
||||||
@@ -156,7 +163,6 @@ describe('<ExecutionEnvironmentList/>', () => {
|
|||||||
},
|
},
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
ExecutionEnvironmentsAPI.readOptions.mockResolvedValue(options);
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper = mountWithContexts(<ExecutionEnvironmentList />);
|
wrapper = mountWithContexts(<ExecutionEnvironmentList />);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -8,10 +8,14 @@ import { ExecutionEnvironmentsAPI } from '../../../api';
|
|||||||
import { getQSConfig, parseQueryString } from '../../../util/qs';
|
import { getQSConfig, parseQueryString } from '../../../util/qs';
|
||||||
import useRequest, { useDeleteItems } from '../../../util/useRequest';
|
import useRequest, { useDeleteItems } from '../../../util/useRequest';
|
||||||
import useSelected from '../../../util/useSelected';
|
import useSelected from '../../../util/useSelected';
|
||||||
import PaginatedDataList, {
|
import {
|
||||||
ToolbarDeleteButton,
|
ToolbarDeleteButton,
|
||||||
ToolbarAddButton,
|
ToolbarAddButton,
|
||||||
} from '../../../components/PaginatedDataList';
|
} from '../../../components/PaginatedDataList';
|
||||||
|
import PaginatedTable, {
|
||||||
|
HeaderRow,
|
||||||
|
HeaderCell,
|
||||||
|
} from '../../../components/PaginatedTable';
|
||||||
import ErrorDetail from '../../../components/ErrorDetail';
|
import ErrorDetail from '../../../components/ErrorDetail';
|
||||||
import AlertModal from '../../../components/AlertModal';
|
import AlertModal from '../../../components/AlertModal';
|
||||||
import DatalistToolbar from '../../../components/DataListToolbar';
|
import DatalistToolbar from '../../../components/DataListToolbar';
|
||||||
@@ -21,7 +25,7 @@ import ExecutionEnvironmentsListItem from './ExecutionEnvironmentListItem';
|
|||||||
const QS_CONFIG = getQSConfig('execution_environments', {
|
const QS_CONFIG = getQSConfig('execution_environments', {
|
||||||
page: 1,
|
page: 1,
|
||||||
page_size: 20,
|
page_size: 20,
|
||||||
order_by: 'image',
|
order_by: 'name',
|
||||||
});
|
});
|
||||||
|
|
||||||
function ExecutionEnvironmentList({ i18n }) {
|
function ExecutionEnvironmentList({ i18n }) {
|
||||||
@@ -106,7 +110,7 @@ function ExecutionEnvironmentList({ i18n }) {
|
|||||||
<>
|
<>
|
||||||
<PageSection>
|
<PageSection>
|
||||||
<Card>
|
<Card>
|
||||||
<PaginatedDataList
|
<PaginatedTable
|
||||||
contentError={contentError}
|
contentError={contentError}
|
||||||
hasContentLoading={isLoading || deleteLoading}
|
hasContentLoading={isLoading || deleteLoading}
|
||||||
items={executionEnvironments}
|
items={executionEnvironments}
|
||||||
@@ -141,6 +145,13 @@ function ExecutionEnvironmentList({ i18n }) {
|
|||||||
key: 'description',
|
key: 'description',
|
||||||
},
|
},
|
||||||
]}
|
]}
|
||||||
|
headerRow={
|
||||||
|
<HeaderRow qsConfig={QS_CONFIG}>
|
||||||
|
<HeaderCell sortKey="name">{i18n._(t`Name`)}</HeaderCell>
|
||||||
|
<HeaderCell>{i18n._(t`Image`)}</HeaderCell>
|
||||||
|
<HeaderCell>{i18n._(t`Organization`)}</HeaderCell>
|
||||||
|
</HeaderRow>
|
||||||
|
}
|
||||||
renderToolbar={props => (
|
renderToolbar={props => (
|
||||||
<DatalistToolbar
|
<DatalistToolbar
|
||||||
{...props}
|
{...props}
|
||||||
@@ -168,9 +179,10 @@ function ExecutionEnvironmentList({ i18n }) {
|
|||||||
]}
|
]}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
renderItem={executionEnvironment => (
|
renderRow={(executionEnvironment, index) => (
|
||||||
<ExecutionEnvironmentsListItem
|
<ExecutionEnvironmentsListItem
|
||||||
key={executionEnvironment.id}
|
key={executionEnvironment.id}
|
||||||
|
rowIndex={index}
|
||||||
executionEnvironment={executionEnvironment}
|
executionEnvironment={executionEnvironment}
|
||||||
detailUrl={`${match.url}/${executionEnvironment.id}/details`}
|
detailUrl={`${match.url}/${executionEnvironment.id}/details`}
|
||||||
onSelect={() => handleSelect(executionEnvironment)}
|
onSelect={() => handleSelect(executionEnvironment)}
|
||||||
|
|||||||
@@ -3,18 +3,11 @@ import { string, bool, func } from 'prop-types';
|
|||||||
import { withI18n } from '@lingui/react';
|
import { withI18n } from '@lingui/react';
|
||||||
import { t } from '@lingui/macro';
|
import { t } from '@lingui/macro';
|
||||||
import { Link } from 'react-router-dom';
|
import { Link } from 'react-router-dom';
|
||||||
import {
|
import { Button } from '@patternfly/react-core';
|
||||||
Button,
|
import { Tr, Td } from '@patternfly/react-table';
|
||||||
DataListAction,
|
|
||||||
DataListCheck,
|
|
||||||
DataListItem,
|
|
||||||
DataListItemRow,
|
|
||||||
DataListItemCells,
|
|
||||||
Tooltip,
|
|
||||||
} from '@patternfly/react-core';
|
|
||||||
import { PencilAltIcon } from '@patternfly/react-icons';
|
import { PencilAltIcon } from '@patternfly/react-icons';
|
||||||
|
|
||||||
import DataListCell from '../../../components/DataListCell';
|
import { ActionsTd, ActionItem } from '../../../components/PaginatedTable';
|
||||||
import { ExecutionEnvironment } from '../../../types';
|
import { ExecutionEnvironment } from '../../../types';
|
||||||
|
|
||||||
function ExecutionEnvironmentListItem({
|
function ExecutionEnvironmentListItem({
|
||||||
@@ -23,55 +16,56 @@ function ExecutionEnvironmentListItem({
|
|||||||
isSelected,
|
isSelected,
|
||||||
onSelect,
|
onSelect,
|
||||||
i18n,
|
i18n,
|
||||||
|
rowIndex,
|
||||||
}) {
|
}) {
|
||||||
const labelId = `check-action-${executionEnvironment.id}`;
|
const labelId = `check-action-${executionEnvironment.id}`;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DataListItem
|
<Tr id={`ee-row-${executionEnvironment.id}`}>
|
||||||
key={executionEnvironment.id}
|
<Td
|
||||||
aria-labelledby={labelId}
|
select={{
|
||||||
id={`${executionEnvironment.id} `}
|
rowIndex,
|
||||||
>
|
isSelected,
|
||||||
<DataListItemRow>
|
onSelect,
|
||||||
<DataListCheck
|
disable: false,
|
||||||
id={`select-execution-environment-${executionEnvironment.id}`}
|
}}
|
||||||
checked={isSelected}
|
dataLabel={i18n._(t`Selected`)}
|
||||||
onChange={onSelect}
|
/>
|
||||||
aria-labelledby={labelId}
|
<Td id={labelId} dataLabel={i18n._(t`Name`)}>
|
||||||
/>
|
<Link to={`${detailUrl}`}>
|
||||||
<DataListItemCells
|
<b>{executionEnvironment.name}</b>
|
||||||
dataListCells={[
|
</Link>
|
||||||
<DataListCell
|
</Td>
|
||||||
key="image"
|
<Td id={labelId} dataLabel={i18n._(t`Image`)}>
|
||||||
aria-label={i18n._(t`execution environment image`)}
|
{executionEnvironment.image}
|
||||||
>
|
</Td>
|
||||||
<Link to={`${detailUrl}`}>
|
<Td id={labelId} dataLabel={i18n._(t`Organization`)}>
|
||||||
<b>{executionEnvironment.image}</b>
|
{executionEnvironment.organization ? (
|
||||||
</Link>
|
<Link
|
||||||
</DataListCell>,
|
to={`/organizations/${executionEnvironment?.summary_fields?.organization?.id}/details`}
|
||||||
]}
|
|
||||||
/>
|
|
||||||
<DataListAction
|
|
||||||
aria-label={i18n._(t`actions`)}
|
|
||||||
aria-labelledby={labelId}
|
|
||||||
id={labelId}
|
|
||||||
>
|
|
||||||
<Tooltip
|
|
||||||
content={i18n._(t`Edit execution environment`)}
|
|
||||||
position="top"
|
|
||||||
>
|
>
|
||||||
<Button
|
<b>{executionEnvironment?.summary_fields?.organization?.name}</b>
|
||||||
aria-label={i18n._(t`Edit execution environment`)}
|
</Link>
|
||||||
variant="plain"
|
) : (
|
||||||
component={Link}
|
i18n._(t`Globally Available`)
|
||||||
to={`/execution_environments/${executionEnvironment.id}/edit`}
|
)}
|
||||||
>
|
</Td>
|
||||||
<PencilAltIcon />
|
<ActionsTd dataLabel={i18n._(t`Actions`)}>
|
||||||
</Button>
|
<ActionItem
|
||||||
</Tooltip>
|
visible={executionEnvironment.summary_fields.user_capabilities.edit}
|
||||||
</DataListAction>
|
tooltip={i18n._(t`Edit Execution Environment`)}
|
||||||
</DataListItemRow>
|
>
|
||||||
</DataListItem>
|
<Button
|
||||||
|
aria-label={i18n._(t`Edit Execution Environment`)}
|
||||||
|
variant="plain"
|
||||||
|
component={Link}
|
||||||
|
to={`/execution_environments/${executionEnvironment.id}/edit`}
|
||||||
|
>
|
||||||
|
<PencilAltIcon />
|
||||||
|
</Button>
|
||||||
|
</ActionItem>
|
||||||
|
</ActionsTd>
|
||||||
|
</Tr>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,21 +8,27 @@ import ExecutionEnvironmentListItem from './ExecutionEnvironmentListItem';
|
|||||||
describe('<ExecutionEnvironmentListItem/>', () => {
|
describe('<ExecutionEnvironmentListItem/>', () => {
|
||||||
let wrapper;
|
let wrapper;
|
||||||
const executionEnvironment = {
|
const executionEnvironment = {
|
||||||
|
name: 'Foo',
|
||||||
id: 1,
|
id: 1,
|
||||||
image: 'https://registry.com/r/image/manifest',
|
image: 'https://registry.com/r/image/manifest',
|
||||||
organization: null,
|
organization: null,
|
||||||
credential: null,
|
credential: null,
|
||||||
|
summary_fields: { user_capabilities: { edit: true } },
|
||||||
};
|
};
|
||||||
|
|
||||||
test('should mount successfully', async () => {
|
test('should mount successfully', async () => {
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper = mountWithContexts(
|
wrapper = mountWithContexts(
|
||||||
<ExecutionEnvironmentListItem
|
<table>
|
||||||
executionEnvironment={executionEnvironment}
|
<tbody>
|
||||||
detailUrl="execution_environments/1/details"
|
<ExecutionEnvironmentListItem
|
||||||
isSelected={false}
|
executionEnvironment={executionEnvironment}
|
||||||
onSelect={() => {}}
|
detailUrl="execution_environments/1/details"
|
||||||
/>
|
isSelected={false}
|
||||||
|
onSelect={() => {}}
|
||||||
|
/>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
expect(wrapper.find('ExecutionEnvironmentListItem').length).toBe(1);
|
expect(wrapper.find('ExecutionEnvironmentListItem').length).toBe(1);
|
||||||
@@ -31,22 +37,38 @@ describe('<ExecutionEnvironmentListItem/>', () => {
|
|||||||
test('should render the proper data', async () => {
|
test('should render the proper data', async () => {
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
wrapper = mountWithContexts(
|
wrapper = mountWithContexts(
|
||||||
<ExecutionEnvironmentListItem
|
<table>
|
||||||
executionEnvironment={executionEnvironment}
|
<tbody>
|
||||||
detailUrl="execution_environments/1/details"
|
<ExecutionEnvironmentListItem
|
||||||
isSelected={false}
|
executionEnvironment={executionEnvironment}
|
||||||
onSelect={() => {}}
|
detailUrl="execution_environments/1/details"
|
||||||
/>
|
isSelected={false}
|
||||||
|
onSelect={() => {}}
|
||||||
|
/>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
expect(
|
expect(
|
||||||
wrapper
|
wrapper
|
||||||
.find('DataListCell[aria-label="execution environment image"]')
|
.find('Td')
|
||||||
|
.at(1)
|
||||||
|
.text()
|
||||||
|
).toBe(executionEnvironment.name);
|
||||||
|
expect(
|
||||||
|
wrapper
|
||||||
|
.find('Td')
|
||||||
|
.at(2)
|
||||||
.text()
|
.text()
|
||||||
).toBe(executionEnvironment.image);
|
).toBe(executionEnvironment.image);
|
||||||
expect(wrapper.find('PencilAltIcon').length).toBe(1);
|
|
||||||
expect(
|
expect(
|
||||||
wrapper.find('input#select-execution-environment-1').prop('checked')
|
wrapper
|
||||||
).toBe(false);
|
.find('Td')
|
||||||
|
.at(3)
|
||||||
|
.text()
|
||||||
|
).toBe('Globally Available');
|
||||||
|
|
||||||
|
expect(wrapper.find('PencilAltIcon').exists()).toBeTruthy();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user