foreman-tasks 11.0.7 → 12.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/views/foreman_tasks/api/tasks/dependency_summary.json.rabl +4 -0
- data/app/views/foreman_tasks/api/tasks/details.json.rabl +20 -0
- data/lib/foreman_tasks/engine.rb +6 -1
- data/lib/foreman_tasks/triggers.rb +4 -0
- data/lib/foreman_tasks/version.rb +1 -1
- data/lib/foreman_tasks.rb +24 -0
- data/test/unit/chaining_test.rb +62 -0
- data/webpack/ForemanTasks/Components/TaskDetails/Components/Dependencies.js +93 -0
- data/webpack/ForemanTasks/Components/TaskDetails/Components/Task.js +7 -12
- data/webpack/ForemanTasks/Components/TaskDetails/Components/TaskButtons.js +40 -20
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/Dependencies.test.js +92 -0
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/TaskButtons.test.js +2 -3
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/Task.test.js.snap +90 -112
- data/webpack/ForemanTasks/Components/TaskDetails/TaskDetails.js +13 -1
- data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsSelectors.js +6 -0
- data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/TaskDetails.test.js.snap +19 -0
- data/webpack/ForemanTasks/Components/TaskDetails/index.js +4 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/OtherInfo.js +5 -3
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/OtherInfo.test.js +58 -9
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCard.scss +0 -30
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCard.test.js +190 -9
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCardTable.js +70 -35
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksLabelsRow/TasksLabelsRow.js +9 -14
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksLabelsRow/TasksLabelsRow.scss +3 -23
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksLabelsRow/TasksLabelsRow.test.js +33 -26
- data/webpack/ForemanTasks/Components/TasksTable/Components/ActionSelectButton.js +31 -30
- data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/ActionSelectButton.test.js +78 -11
- data/webpack/ForemanTasks/Components/TasksTable/TasksTablePage.js +40 -21
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTablePage.test.js.snap +64 -62
- metadata +6 -7
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCardTable.test.js +0 -54
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/__snapshots__/OtherInfo.test.js.snap +0 -30
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/__snapshots__/StoppedTasksCard.test.js.snap +0 -107
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/__snapshots__/StoppedTasksCardTable.test.js.snap +0 -960
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksLabelsRow/__snapshots__/TasksLabelsRow.test.js.snap +0 -47
- data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/__snapshots__/ActionSelectButton.test.js.snap +0 -43
|
@@ -2,7 +2,13 @@ import React from 'react';
|
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import { capitalize } from 'lodash';
|
|
4
4
|
import classNames from 'classnames';
|
|
5
|
-
import { Icon, Button } from 'patternfly-
|
|
5
|
+
import { Icon, Button } from '@patternfly/react-core';
|
|
6
|
+
import {
|
|
7
|
+
ExclamationCircleIcon,
|
|
8
|
+
ExclamationTriangleIcon,
|
|
9
|
+
CheckIcon,
|
|
10
|
+
} from '@patternfly/react-icons';
|
|
11
|
+
import { Table, Thead, Tbody, Tr, Th, Td } from '@patternfly/react-table';
|
|
6
12
|
import { translate as __ } from 'foremanReact/common/I18n';
|
|
7
13
|
import {
|
|
8
14
|
TASKS_DASHBOARD_AVAILABLE_QUERY_STATES,
|
|
@@ -15,9 +21,21 @@ import {
|
|
|
15
21
|
} from '../../../../TasksDashboardPropTypes';
|
|
16
22
|
|
|
17
23
|
const resultIcons = {
|
|
18
|
-
error:
|
|
19
|
-
|
|
20
|
-
|
|
24
|
+
error: (
|
|
25
|
+
<Icon status="danger" size="sm">
|
|
26
|
+
<ExclamationCircleIcon />
|
|
27
|
+
</Icon>
|
|
28
|
+
),
|
|
29
|
+
warning: (
|
|
30
|
+
<Icon status="warning" size="sm">
|
|
31
|
+
<ExclamationTriangleIcon />
|
|
32
|
+
</Icon>
|
|
33
|
+
),
|
|
34
|
+
success: (
|
|
35
|
+
<Icon status="success" size="sm">
|
|
36
|
+
<CheckIcon />
|
|
37
|
+
</Icon>
|
|
38
|
+
),
|
|
21
39
|
};
|
|
22
40
|
|
|
23
41
|
const StoppedTableCells = (data, query, time, updateQuery) =>
|
|
@@ -35,51 +53,68 @@ const StoppedTableCells = (data, query, time, updateQuery) =>
|
|
|
35
53
|
state && !(state === STOPPED && !query.result) && !activeLast;
|
|
36
54
|
|
|
37
55
|
return (
|
|
38
|
-
<
|
|
39
|
-
<
|
|
40
|
-
{resultIcons[result]}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
56
|
+
<Tr key={result} ouiaId={`stopped-table-row-${result}`}>
|
|
57
|
+
<Td dataLabel={__('Result')}>
|
|
58
|
+
{resultIcons[result]} {capitalize(result)}
|
|
59
|
+
</Td>
|
|
60
|
+
<Td
|
|
61
|
+
dataLabel={__('Total')}
|
|
44
62
|
className={classNames('data-col', {
|
|
45
63
|
active: active && mode !== LAST,
|
|
46
64
|
'not-focused': notFocusedTotal,
|
|
47
65
|
})}
|
|
48
|
-
onClick={() => updateQuery({ state: STOPPED, result })}
|
|
49
66
|
>
|
|
50
|
-
<Button
|
|
51
|
-
|
|
52
|
-
|
|
67
|
+
<Button
|
|
68
|
+
ouiaId={`stopped-table-button-${result}-total`}
|
|
69
|
+
variant="link"
|
|
70
|
+
onClick={() => updateQuery({ state: STOPPED, result })}
|
|
71
|
+
>
|
|
72
|
+
{total}
|
|
73
|
+
</Button>
|
|
74
|
+
</Td>
|
|
75
|
+
<Td
|
|
76
|
+
dataLabel={getQueryValueText(time)}
|
|
53
77
|
className={classNames('data-col', {
|
|
54
78
|
active: activeLast,
|
|
55
79
|
'not-focused': notFocusedLast,
|
|
56
80
|
})}
|
|
57
|
-
onClick={() =>
|
|
58
|
-
updateQuery({
|
|
59
|
-
state: STOPPED,
|
|
60
|
-
result,
|
|
61
|
-
mode: LAST,
|
|
62
|
-
time,
|
|
63
|
-
})
|
|
64
|
-
}
|
|
65
81
|
>
|
|
66
|
-
<Button
|
|
67
|
-
|
|
68
|
-
|
|
82
|
+
<Button
|
|
83
|
+
ouiaId={`stopped-table-button-${result}-${time}`}
|
|
84
|
+
onClick={() =>
|
|
85
|
+
updateQuery({
|
|
86
|
+
state: STOPPED,
|
|
87
|
+
result,
|
|
88
|
+
mode: LAST,
|
|
89
|
+
time,
|
|
90
|
+
})
|
|
91
|
+
}
|
|
92
|
+
variant="link"
|
|
93
|
+
>
|
|
94
|
+
{last}
|
|
95
|
+
</Button>
|
|
96
|
+
</Td>
|
|
97
|
+
</Tr>
|
|
69
98
|
);
|
|
70
99
|
});
|
|
71
100
|
|
|
72
101
|
export const StoppedTable = ({ data, query, time, updateQuery }) => (
|
|
73
|
-
<
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
102
|
+
<Table
|
|
103
|
+
ouiaId="stopped-table"
|
|
104
|
+
className="stopped-table"
|
|
105
|
+
variant="compact"
|
|
106
|
+
isStriped
|
|
107
|
+
aria-label={__('Stopped tasks by result')}
|
|
108
|
+
>
|
|
109
|
+
<Thead>
|
|
110
|
+
<Tr ouiaId="stopped-table-header">
|
|
111
|
+
<Th aria-label={__('Result')} />
|
|
112
|
+
<Th aria-label={__('Total')}>{__('Total')}</Th>
|
|
113
|
+
<Th aria-label={getQueryValueText(time)}>{getQueryValueText(time)}</Th>
|
|
114
|
+
</Tr>
|
|
115
|
+
</Thead>
|
|
116
|
+
<Tbody>{StoppedTableCells(data, query, time, updateQuery)}</Tbody>
|
|
117
|
+
</Table>
|
|
83
118
|
);
|
|
84
119
|
|
|
85
120
|
StoppedTable.propTypes = {
|
data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksLabelsRow/TasksLabelsRow.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
|
-
import {
|
|
3
|
+
import { Label, LabelGroup } from '@patternfly/react-core';
|
|
4
4
|
import { noop } from 'foremanReact/common/helpers';
|
|
5
5
|
import { translate as __ } from 'foremanReact/common/I18n';
|
|
6
6
|
|
|
@@ -24,23 +24,18 @@ const TasksLabelsRow = ({ query, updateQuery }) => {
|
|
|
24
24
|
const queryEntries = Object.entries(query);
|
|
25
25
|
|
|
26
26
|
return (
|
|
27
|
-
<
|
|
28
|
-
|
|
27
|
+
<LabelGroup
|
|
28
|
+
className="tasks-labels-row"
|
|
29
|
+
categoryName={__('Active Filters')}
|
|
30
|
+
isClosable
|
|
31
|
+
onClick={() => updateQuery({})}
|
|
32
|
+
>
|
|
29
33
|
{queryEntries.map(([key, value]) => (
|
|
30
|
-
<Label
|
|
31
|
-
bsStyle="info"
|
|
32
|
-
key={key}
|
|
33
|
-
onRemoveClick={() => onDeleteClick(key)}
|
|
34
|
-
>
|
|
34
|
+
<Label color="blue" key={key} onClose={() => onDeleteClick(key)}>
|
|
35
35
|
{getLabelText(key, value)}
|
|
36
36
|
</Label>
|
|
37
37
|
))}
|
|
38
|
-
|
|
39
|
-
<Button bsStyle="link" onClick={() => updateQuery({})}>
|
|
40
|
-
{__('Clear All Filters')}
|
|
41
|
-
</Button>
|
|
42
|
-
)}
|
|
43
|
-
</Row>
|
|
38
|
+
</LabelGroup>
|
|
44
39
|
);
|
|
45
40
|
};
|
|
46
41
|
|
data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksLabelsRow/TasksLabelsRow.scss
CHANGED
|
@@ -1,26 +1,6 @@
|
|
|
1
|
-
@import 'foremanReact/common/variables';
|
|
2
|
-
|
|
3
1
|
.tasks-labels-row {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
font-weight: 600;
|
|
8
|
-
font-size: 13px;
|
|
9
|
-
}
|
|
10
|
-
.label {
|
|
11
|
-
font-size: 100%;
|
|
12
|
-
|
|
13
|
-
margin-left: 5px;
|
|
14
|
-
margin-right: 5px;
|
|
15
|
-
a {
|
|
16
|
-
padding-left: 10px;
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
.pficon-close {
|
|
20
|
-
color: $color-pf-white;
|
|
21
|
-
}
|
|
22
|
-
.compound-label-pf {
|
|
23
|
-
margin-left: 0;
|
|
24
|
-
margin: 10px;
|
|
2
|
+
align-items: center;
|
|
3
|
+
ul {
|
|
4
|
+
margin: 0;
|
|
25
5
|
}
|
|
26
6
|
}
|
data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksLabelsRow/TasksLabelsRow.test.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import {
|
|
2
|
+
import { render, screen, fireEvent } from '@testing-library/react';
|
|
3
|
+
import '@testing-library/jest-dom';
|
|
3
4
|
|
|
4
5
|
import { getQueryKeyText, getQueryValueText } from '../../TasksDashboardHelper';
|
|
5
6
|
import TasksLabelsRow from './TasksLabelsRow';
|
|
@@ -9,46 +10,52 @@ jest.mock('../../TasksDashboardHelper');
|
|
|
9
10
|
getQueryKeyText.mockImplementation(val => val);
|
|
10
11
|
getQueryValueText.mockImplementation(val => val);
|
|
11
12
|
|
|
12
|
-
const fixtures = {
|
|
13
|
-
'render with minimal props': {},
|
|
14
|
-
'render with props': {
|
|
15
|
-
query: { some: 'query' },
|
|
16
|
-
updateQuery: jest.fn(),
|
|
17
|
-
},
|
|
18
|
-
};
|
|
19
|
-
|
|
20
13
|
describe('TasksLabelsRow', () => {
|
|
21
|
-
describe('rendering', () =>
|
|
22
|
-
|
|
14
|
+
describe('rendering', () => {
|
|
15
|
+
it('renders nothing when query is empty', () => {
|
|
16
|
+
render(<TasksLabelsRow />);
|
|
17
|
+
expect(screen.queryByText('Active Filters')).not.toBeInTheDocument();
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it('renders Active Filters category and label when query has entries', () => {
|
|
21
|
+
render(
|
|
22
|
+
<TasksLabelsRow query={{ some: 'query' }} updateQuery={jest.fn()} />
|
|
23
|
+
);
|
|
24
|
+
expect(screen.getByText('Active Filters')).toBeInTheDocument();
|
|
25
|
+
expect(screen.getByText('some = query')).toBeInTheDocument();
|
|
26
|
+
});
|
|
27
|
+
});
|
|
23
28
|
|
|
24
29
|
describe('triggering', () => {
|
|
25
|
-
it('
|
|
30
|
+
it('calls updateQuery with remaining query when a label close button is clicked', () => {
|
|
26
31
|
const updateQuery = jest.fn();
|
|
27
32
|
const query = { some: 'query', someOther: 'some-query' };
|
|
28
33
|
|
|
29
|
-
|
|
30
|
-
<TasksLabelsRow query={query} updateQuery={updateQuery} />
|
|
31
|
-
);
|
|
32
|
-
const labels = component.find('Label');
|
|
33
|
-
|
|
34
|
-
const firstLabel = labels.first();
|
|
35
|
-
const secondLabel = labels.at(1);
|
|
34
|
+
render(<TasksLabelsRow query={query} updateQuery={updateQuery} />);
|
|
36
35
|
|
|
37
|
-
|
|
36
|
+
const firstLabelCloseButton = screen.getByRole('button', {
|
|
37
|
+
name: /close some = query/i,
|
|
38
|
+
});
|
|
39
|
+
fireEvent.click(firstLabelCloseButton);
|
|
38
40
|
expect(updateQuery).toHaveBeenCalledWith({ someOther: 'some-query' });
|
|
39
41
|
|
|
40
|
-
|
|
42
|
+
const secondLabelCloseButton = screen.getByRole('button', {
|
|
43
|
+
name: /close someOther = some-query/i,
|
|
44
|
+
});
|
|
45
|
+
fireEvent.click(secondLabelCloseButton);
|
|
41
46
|
expect(updateQuery).toHaveBeenCalledWith({ some: 'query' });
|
|
42
47
|
});
|
|
43
48
|
|
|
44
|
-
it('
|
|
49
|
+
it('calls updateQuery with empty object when close label group button is clicked', () => {
|
|
45
50
|
const updateQuery = jest.fn();
|
|
46
51
|
const query = { some: 'query', someOther: 'some-query' };
|
|
47
52
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
53
|
+
render(<TasksLabelsRow query={query} updateQuery={updateQuery} />);
|
|
54
|
+
|
|
55
|
+
const closeGroupButton = screen.getByRole('button', {
|
|
56
|
+
name: /close label group/i,
|
|
57
|
+
});
|
|
58
|
+
fireEvent.click(closeGroupButton);
|
|
52
59
|
|
|
53
60
|
expect(updateQuery).toHaveBeenCalledWith({});
|
|
54
61
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { DropdownButton, MenuItem } from 'patternfly-react';
|
|
3
2
|
import PropTypes from 'prop-types';
|
|
3
|
+
import { SimpleDropdown } from '@patternfly/react-templates';
|
|
4
|
+
import { EllipsisVIcon } from '@patternfly/react-icons';
|
|
4
5
|
import { translate as __ } from 'foremanReact/common/I18n';
|
|
5
6
|
|
|
6
7
|
export const ActionSelectButton = ({
|
|
@@ -8,35 +9,35 @@ export const ActionSelectButton = ({
|
|
|
8
9
|
onResume,
|
|
9
10
|
onForceCancel,
|
|
10
11
|
disabled,
|
|
11
|
-
}) =>
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
{
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
12
|
+
}) => {
|
|
13
|
+
const buttons = [
|
|
14
|
+
{
|
|
15
|
+
content: __('Cancel Selected'),
|
|
16
|
+
onClick: onCancel,
|
|
17
|
+
value: 1,
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
content: __('Resume Selected'),
|
|
21
|
+
onClick: onResume,
|
|
22
|
+
value: 2,
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
content: __('Force Cancel Selected'),
|
|
26
|
+
onClick: onForceCancel,
|
|
27
|
+
value: 3,
|
|
28
|
+
},
|
|
29
|
+
];
|
|
30
|
+
return (
|
|
31
|
+
<SimpleDropdown
|
|
32
|
+
isDisabled={disabled}
|
|
33
|
+
ouiaId="tasks-table-action-select-dropdown"
|
|
34
|
+
toggleVariant="plain"
|
|
35
|
+
popperProps={{ position: 'right' }}
|
|
36
|
+
initialItems={buttons}
|
|
37
|
+
toggleContent={<EllipsisVIcon aria-hidden="true" />}
|
|
38
|
+
/>
|
|
39
|
+
);
|
|
40
|
+
};
|
|
40
41
|
|
|
41
42
|
ActionSelectButton.propTypes = {
|
|
42
43
|
disabled: PropTypes.bool,
|
data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/ActionSelectButton.test.js
CHANGED
|
@@ -1,14 +1,81 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
|
|
3
|
+
import '@testing-library/jest-dom';
|
|
3
4
|
import { ActionSelectButton } from '../ActionSelectButton';
|
|
4
5
|
|
|
5
|
-
const
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
}
|
|
11
|
-
|
|
6
|
+
const mockOnCancel = jest.fn();
|
|
7
|
+
const mockOnResume = jest.fn();
|
|
8
|
+
const mockOnForceCancel = jest.fn();
|
|
9
|
+
|
|
10
|
+
describe('ActionSelectButton', () => {
|
|
11
|
+
const renderComponent = (props = {}) => {
|
|
12
|
+
const defaultProps = {
|
|
13
|
+
onCancel: mockOnCancel,
|
|
14
|
+
onResume: mockOnResume,
|
|
15
|
+
onForceCancel: mockOnForceCancel,
|
|
16
|
+
disabled: false,
|
|
17
|
+
};
|
|
18
|
+
return render(<ActionSelectButton {...defaultProps} {...props} />);
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
beforeEach(() => {
|
|
22
|
+
jest.clearAllMocks();
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it('renders with minimal props', () => {
|
|
26
|
+
renderComponent();
|
|
27
|
+
|
|
28
|
+
const toggle = screen.getByRole('button');
|
|
29
|
+
expect(toggle).toBeInTheDocument();
|
|
30
|
+
expect(toggle).not.toBeDisabled();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('renders disabled when disabled prop is true', () => {
|
|
34
|
+
renderComponent({ disabled: true });
|
|
35
|
+
|
|
36
|
+
const toggle = screen.getByRole('button');
|
|
37
|
+
expect(toggle).toBeDisabled();
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('opens dropdown and shows action options when toggle is clicked', async () => {
|
|
41
|
+
renderComponent();
|
|
42
|
+
const toggle = screen.getByRole('button');
|
|
43
|
+
fireEvent.click(toggle);
|
|
44
|
+
|
|
45
|
+
await waitFor(() => {
|
|
46
|
+
expect(screen.getByText('Cancel Selected')).toBeInTheDocument();
|
|
47
|
+
expect(screen.getByText('Resume Selected')).toBeInTheDocument();
|
|
48
|
+
expect(screen.getByText('Force Cancel Selected')).toBeInTheDocument();
|
|
49
|
+
});
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
it('calls onCancel when Cancel Selected is clicked', async () => {
|
|
53
|
+
renderComponent();
|
|
54
|
+
fireEvent.click(screen.getByRole('button'));
|
|
55
|
+
await waitFor(() => {
|
|
56
|
+
expect(screen.getByText('Cancel Selected')).toBeInTheDocument();
|
|
57
|
+
});
|
|
58
|
+
fireEvent.click(screen.getByText('Cancel Selected'));
|
|
59
|
+
expect(mockOnCancel).toHaveBeenCalledTimes(1);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('calls onResume when Resume Selected is clicked', async () => {
|
|
63
|
+
renderComponent();
|
|
64
|
+
fireEvent.click(screen.getByRole('button'));
|
|
65
|
+
await waitFor(() => {
|
|
66
|
+
expect(screen.getByText('Resume Selected')).toBeInTheDocument();
|
|
67
|
+
});
|
|
68
|
+
fireEvent.click(screen.getByText('Resume Selected'));
|
|
69
|
+
expect(mockOnResume).toHaveBeenCalledTimes(1);
|
|
70
|
+
});
|
|
12
71
|
|
|
13
|
-
|
|
14
|
-
|
|
72
|
+
it('calls onForceCancel when Force Cancel Selected is clicked', async () => {
|
|
73
|
+
renderComponent();
|
|
74
|
+
fireEvent.click(screen.getByRole('button'));
|
|
75
|
+
await waitFor(() => {
|
|
76
|
+
expect(screen.getByText('Force Cancel Selected')).toBeInTheDocument();
|
|
77
|
+
});
|
|
78
|
+
fireEvent.click(screen.getByText('Force Cancel Selected'));
|
|
79
|
+
expect(mockOnForceCancel).toHaveBeenCalledTimes(1);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
@@ -2,11 +2,11 @@ import React, { useState } from 'react';
|
|
|
2
2
|
import PropTypes from 'prop-types';
|
|
3
3
|
import URI from 'urijs';
|
|
4
4
|
import { getURIsearch } from 'foremanReact/common/urlHelpers';
|
|
5
|
-
import {
|
|
5
|
+
import { Button, ToolbarItem, Spinner } from '@patternfly/react-core';
|
|
6
|
+
import { RedoIcon } from '@patternfly/react-icons';
|
|
6
7
|
import PageLayout from 'foremanReact/routes/common/PageLayout/PageLayout';
|
|
7
8
|
import { translate as __ } from 'foremanReact/common/I18n';
|
|
8
9
|
import { getURIQuery } from 'foremanReact/common/helpers';
|
|
9
|
-
import ExportButton from 'foremanReact/routes/common/PageLayout/components/ExportButton/ExportButton';
|
|
10
10
|
import { STATUS } from 'foremanReact/constants';
|
|
11
11
|
import TasksDashboard from '../TasksDashboard';
|
|
12
12
|
import TasksTable from './TasksTable';
|
|
@@ -127,25 +127,44 @@ const TasksTablePage = ({
|
|
|
127
127
|
header={createHeader(props.actionName)}
|
|
128
128
|
breadcrumbOptions={getBreadcrumbs(props.actionName)}
|
|
129
129
|
toolbarButtons={
|
|
130
|
-
|
|
131
|
-
<
|
|
132
|
-
<
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
130
|
+
<>
|
|
131
|
+
<ToolbarItem>
|
|
132
|
+
<Button
|
|
133
|
+
ouiaId="tasks-table-refresh-data"
|
|
134
|
+
variant="primary"
|
|
135
|
+
onClick={() => props.reloadPage(url, props.parentTaskID)}
|
|
136
|
+
icon={<RedoIcon />}
|
|
137
|
+
>
|
|
138
|
+
{__('Refresh Data')}
|
|
139
|
+
</Button>
|
|
140
|
+
</ToolbarItem>
|
|
141
|
+
{props.status === STATUS.PENDING && (
|
|
142
|
+
<ToolbarItem>
|
|
143
|
+
<Spinner size="lg" />
|
|
144
|
+
</ToolbarItem>
|
|
145
|
+
)}
|
|
146
|
+
<ToolbarItem>
|
|
147
|
+
<Button
|
|
148
|
+
ouiaId="tasks-table-export-all"
|
|
149
|
+
variant="secondary"
|
|
150
|
+
component="a"
|
|
151
|
+
href={getCSVurl(history.location.pathname, uriQuery)}
|
|
152
|
+
>
|
|
153
|
+
{__('Export All')}
|
|
154
|
+
</Button>
|
|
155
|
+
</ToolbarItem>
|
|
156
|
+
<ToolbarItem>
|
|
157
|
+
<ActionSelectButton
|
|
158
|
+
disabled={
|
|
159
|
+
!props.permissions.edit ||
|
|
160
|
+
!(props.selectedRows.length || props.allRowsSelected)
|
|
161
|
+
}
|
|
162
|
+
onCancel={() => openModal(CANCEL_SELECTED_MODAL)}
|
|
163
|
+
onResume={() => openModal(RESUME_SELECTED_MODAL)}
|
|
164
|
+
onForceCancel={() => openModal(FORCE_UNLOCK_SELECTED_MODAL)}
|
|
165
|
+
/>
|
|
166
|
+
</ToolbarItem>
|
|
167
|
+
</>
|
|
149
168
|
}
|
|
150
169
|
searchQuery={getURIsearch()}
|
|
151
170
|
beforeToolbarComponent={
|