foreman-tasks 1.1.0 → 1.1.1
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/controllers/foreman_tasks/api/tasks_controller.rb +12 -5
- data/app/lib/foreman_tasks/concerns/polling_action_extensions.rb +12 -0
- data/app/models/setting/foreman_tasks.rb +6 -1
- data/app/services/ui_notifications/tasks/task_bulk_cancel.rb +36 -0
- data/app/services/ui_notifications/tasks/task_bulk_resume.rb +38 -0
- data/db/seeds.d/30-notification_blueprints.rb +14 -0
- data/foreman-tasks.gemspec +1 -0
- data/gemfile.d/foreman-tasks.rb +1 -0
- data/lib/foreman_tasks/engine.rb +1 -0
- data/lib/foreman_tasks/version.rb +1 -1
- data/script/travis_run_js_tests.sh +2 -2
- data/test/lib/concerns/polling_action_extensions_test.rb +34 -0
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/TaskInfo.test.js.snap +1 -3
- data/webpack/ForemanTasks/Components/TasksDashboard/TasksDashboardConstants.js +5 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/TasksDashboardHelper.js +3 -2
- data/webpack/ForemanTasks/Components/TasksTable/Components/SelectAllAlert.js +43 -0
- data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/SelectAllAlert.test.js +29 -0
- data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/__snapshots__/SelectAllAlert.test.js.snap +75 -0
- data/webpack/ForemanTasks/Components/TasksTable/SubTasksPage.js +2 -1
- data/webpack/ForemanTasks/Components/TasksTable/TasksBulkActions.js +164 -0
- data/webpack/ForemanTasks/Components/TasksTable/TasksTable.js +24 -10
- data/webpack/ForemanTasks/Components/TasksTable/TasksTableActionHelpers.js +52 -0
- data/webpack/ForemanTasks/Components/TasksTable/TasksTableActions.js +66 -128
- data/webpack/ForemanTasks/Components/TasksTable/TasksTableConstants.js +11 -1
- data/webpack/ForemanTasks/Components/TasksTable/TasksTableHelpers.js +4 -3
- data/webpack/ForemanTasks/Components/TasksTable/TasksTablePage.js +64 -12
- data/webpack/ForemanTasks/Components/TasksTable/TasksTableReducer.js +21 -2
- data/webpack/ForemanTasks/Components/TasksTable/TasksTableSelectors.js +6 -0
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksBulkActions.test.js +112 -0
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTable.fixtures.js +5 -3
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTableActionHelpers.test.js +46 -0
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTableActions.test.js +19 -41
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTableHelpers.test.js +17 -1
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTablePage.test.js +9 -1
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTableReducer.test.js +22 -1
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/SubTasksPage.test.js.snap +5 -3
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksBulkActions.test.js.snap +229 -0
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksIndexPage.test.js.snap +5 -3
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTableActions.test.js.snap +39 -124
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTablePage.test.js.snap +40 -16
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTableReducer.test.js.snap +34 -0
- data/webpack/ForemanTasks/Components/TasksTable/formatters/__test__/selectionHeaderCellFormatter.test.js +1 -1
- data/webpack/ForemanTasks/Components/TasksTable/formatters/selectionHeaderCellFormatter.js +2 -2
- data/webpack/ForemanTasks/Components/TasksTable/index.js +8 -2
- data/webpack/ForemanTasks/Components/common/ToastTypesConstants.js +11 -0
- metadata +31 -2
@@ -0,0 +1,164 @@
|
|
1
|
+
import API from 'foremanReact/API';
|
2
|
+
import { addToast } from 'foremanReact/redux/actions/toasts';
|
3
|
+
import { translate as __ } from 'foremanReact/common/I18n';
|
4
|
+
import { TOAST_TYPES } from '../common/ToastTypesConstants';
|
5
|
+
import {
|
6
|
+
TASKS_RESUME_REQUEST,
|
7
|
+
TASKS_RESUME_SUCCESS,
|
8
|
+
TASKS_RESUME_FAILURE,
|
9
|
+
TASKS_CANCEL_REQUEST,
|
10
|
+
TASKS_CANCEL_SUCCESS,
|
11
|
+
TASKS_CANCEL_FAILURE,
|
12
|
+
BULK_CANCEL_PATH,
|
13
|
+
BULK_RESUME_PATH,
|
14
|
+
} from './TasksTableConstants';
|
15
|
+
import { reloadPage } from './TasksTableActions';
|
16
|
+
import {
|
17
|
+
convertDashboardQuery,
|
18
|
+
resumeToastInfo,
|
19
|
+
cancelToastInfo,
|
20
|
+
toastDispatch,
|
21
|
+
} from './TasksTableActionHelpers';
|
22
|
+
|
23
|
+
export const bulkByIdRequest = (resumeTasks, path) => {
|
24
|
+
const ids = resumeTasks.map(task => task.id);
|
25
|
+
const url = `/foreman_tasks/api/tasks/${path}`;
|
26
|
+
const data = { task_ids: ids };
|
27
|
+
return API.post(url, data);
|
28
|
+
};
|
29
|
+
|
30
|
+
export const bulkBySearchRequest = ({ query, parentTaskID, path }) => {
|
31
|
+
const url = `/foreman_tasks/api/tasks/${path}`;
|
32
|
+
if (parentTaskID) {
|
33
|
+
query.search = query.search
|
34
|
+
? ` ${query.search} and parent_task_id=${parentTaskID}`
|
35
|
+
: `parent_task_id=${parentTaskID}`;
|
36
|
+
}
|
37
|
+
const searchParam = { search: convertDashboardQuery(query) };
|
38
|
+
return API.post(url, searchParam);
|
39
|
+
};
|
40
|
+
|
41
|
+
const handleErrorResume = (error, dispatch) => {
|
42
|
+
dispatch({ type: TASKS_RESUME_FAILURE, error });
|
43
|
+
dispatch(
|
44
|
+
addToast({
|
45
|
+
type: TOAST_TYPES.ERROR,
|
46
|
+
message: `${__(`Cannot resume tasks at the moment`)} ${error}`,
|
47
|
+
})
|
48
|
+
);
|
49
|
+
};
|
50
|
+
|
51
|
+
export const bulkResumeById = ({
|
52
|
+
selected,
|
53
|
+
url,
|
54
|
+
parentTaskID,
|
55
|
+
}) => async dispatch => {
|
56
|
+
const resumeTasks = selected.filter(task => task.isResumable);
|
57
|
+
if (resumeTasks.length < selected.length)
|
58
|
+
dispatch(
|
59
|
+
addToast({
|
60
|
+
type: TOAST_TYPES.WARNING,
|
61
|
+
message: __('Not all the selected tasks can be resumed'),
|
62
|
+
})
|
63
|
+
);
|
64
|
+
if (resumeTasks.length) {
|
65
|
+
dispatch({ type: TASKS_RESUME_REQUEST });
|
66
|
+
try {
|
67
|
+
const { data } = await bulkByIdRequest(resumeTasks, BULK_RESUME_PATH);
|
68
|
+
dispatch({ type: TASKS_RESUME_SUCCESS });
|
69
|
+
['resumed', 'failed', 'skipped'].forEach(type => {
|
70
|
+
data[type] &&
|
71
|
+
data[type].forEach(task => {
|
72
|
+
toastDispatch({
|
73
|
+
type,
|
74
|
+
name: task.action,
|
75
|
+
toastInfo: resumeToastInfo,
|
76
|
+
dispatch,
|
77
|
+
});
|
78
|
+
});
|
79
|
+
});
|
80
|
+
if (data.resumed) {
|
81
|
+
reloadPage(url, parentTaskID, dispatch);
|
82
|
+
}
|
83
|
+
} catch (error) {
|
84
|
+
handleErrorResume(error, dispatch);
|
85
|
+
}
|
86
|
+
}
|
87
|
+
};
|
88
|
+
|
89
|
+
export const bulkResumeBySearch = ({
|
90
|
+
query,
|
91
|
+
parentTaskID,
|
92
|
+
}) => async dispatch => {
|
93
|
+
dispatch({ type: TASKS_RESUME_REQUEST });
|
94
|
+
dispatch(
|
95
|
+
addToast({
|
96
|
+
type: 'info',
|
97
|
+
message: __('Resuming selected tasks, this might take a while'),
|
98
|
+
})
|
99
|
+
);
|
100
|
+
await bulkBySearchRequest({ query, path: BULK_RESUME_PATH, parentTaskID });
|
101
|
+
};
|
102
|
+
|
103
|
+
const handleErrorCancel = (error, dispatch) => {
|
104
|
+
dispatch({ type: TASKS_CANCEL_FAILURE, error });
|
105
|
+
dispatch(
|
106
|
+
addToast({
|
107
|
+
type: TOAST_TYPES.ERROR,
|
108
|
+
message: `${__(`Cannot cancel tasks at the moment`)} ${error}`,
|
109
|
+
})
|
110
|
+
);
|
111
|
+
};
|
112
|
+
|
113
|
+
export const bulkCancelBySearch = ({
|
114
|
+
query,
|
115
|
+
parentTaskID,
|
116
|
+
}) => async dispatch => {
|
117
|
+
dispatch({ type: TASKS_CANCEL_REQUEST });
|
118
|
+
dispatch(
|
119
|
+
addToast({
|
120
|
+
type: 'info',
|
121
|
+
message: __('Canceling selected tasks, this might take a while'),
|
122
|
+
})
|
123
|
+
);
|
124
|
+
await bulkBySearchRequest({ query, path: BULK_CANCEL_PATH, parentTaskID });
|
125
|
+
};
|
126
|
+
|
127
|
+
export const bulkCancelById = ({
|
128
|
+
selected,
|
129
|
+
url,
|
130
|
+
parentTaskID,
|
131
|
+
}) => async dispatch => {
|
132
|
+
const cancelTasks = selected.filter(task => task.isCancellable);
|
133
|
+
if (cancelTasks.length < selected.length)
|
134
|
+
dispatch(
|
135
|
+
addToast({
|
136
|
+
type: TOAST_TYPES.WARNING,
|
137
|
+
message: __('Not all the selected tasks can be cancelled'),
|
138
|
+
})
|
139
|
+
);
|
140
|
+
if (cancelTasks.length) {
|
141
|
+
dispatch({ type: TASKS_CANCEL_REQUEST });
|
142
|
+
try {
|
143
|
+
const { data } = await bulkByIdRequest(cancelTasks, BULK_CANCEL_PATH);
|
144
|
+
dispatch({ type: TASKS_CANCEL_SUCCESS });
|
145
|
+
|
146
|
+
['cancelled', 'skipped'].forEach(type => {
|
147
|
+
data[type] &&
|
148
|
+
data[type].forEach(task => {
|
149
|
+
toastDispatch({
|
150
|
+
type,
|
151
|
+
name: task.action,
|
152
|
+
toastInfo: cancelToastInfo,
|
153
|
+
dispatch,
|
154
|
+
});
|
155
|
+
});
|
156
|
+
});
|
157
|
+
if (data.cancelled) {
|
158
|
+
reloadPage(url, parentTaskID, dispatch);
|
159
|
+
}
|
160
|
+
} catch (error) {
|
161
|
+
handleErrorCancel(error, dispatch);
|
162
|
+
}
|
163
|
+
}
|
164
|
+
};
|
@@ -18,33 +18,45 @@ const TasksTable = ({
|
|
18
18
|
itemCount,
|
19
19
|
pagination,
|
20
20
|
selectedRows,
|
21
|
-
|
21
|
+
selectPage,
|
22
22
|
unselectAllRows,
|
23
23
|
selectRow,
|
24
24
|
unselectRow,
|
25
25
|
openClickedModal,
|
26
26
|
modalProps,
|
27
|
+
allRowsSelected,
|
27
28
|
}) => {
|
28
|
-
const
|
29
|
+
const { search, pathname } = history.location;
|
30
|
+
const url = pathname + search;
|
29
31
|
const uriQuery = getURIQuery(url);
|
30
32
|
|
31
33
|
useEffect(() => {
|
32
34
|
getTableItems(url);
|
33
35
|
}, [getTableItems, url]);
|
34
36
|
|
37
|
+
useEffect(() => {
|
38
|
+
unselectAllRows();
|
39
|
+
}, [unselectAllRows, search]);
|
40
|
+
|
35
41
|
const getSelectionController = () => {
|
36
|
-
const
|
42
|
+
const checkAllPageSelected = () =>
|
43
|
+
allRowsSelected || results.length === selectedRows.length;
|
37
44
|
return {
|
38
|
-
allRowsSelected
|
39
|
-
|
40
|
-
|
41
|
-
|
45
|
+
allRowsSelected,
|
46
|
+
allPageSelected: () => checkAllPageSelected(),
|
47
|
+
selectPage: () => {
|
48
|
+
if (checkAllPageSelected()) unselectAllRows();
|
49
|
+
else {
|
50
|
+
selectPage(results);
|
51
|
+
}
|
42
52
|
},
|
43
53
|
selectRow: ({ rowData: { id } }) => {
|
44
|
-
if (selectedRows.includes(id)
|
54
|
+
if (selectedRows.includes(id) || allRowsSelected)
|
55
|
+
unselectRow(id, allRowsSelected && results);
|
45
56
|
else selectRow(id);
|
46
57
|
},
|
47
|
-
isSelected: ({ rowData }) =>
|
58
|
+
isSelected: ({ rowData }) =>
|
59
|
+
allRowsSelected || selectedRows.includes(rowData.id),
|
48
60
|
};
|
49
61
|
};
|
50
62
|
|
@@ -135,7 +147,7 @@ TasksTable.propTypes = {
|
|
135
147
|
history: PropTypes.object.isRequired,
|
136
148
|
openClickedModal: PropTypes.func.isRequired,
|
137
149
|
selectedRows: PropTypes.array,
|
138
|
-
|
150
|
+
selectPage: PropTypes.func.isRequired,
|
139
151
|
unselectAllRows: PropTypes.func.isRequired,
|
140
152
|
selectRow: PropTypes.func.isRequired,
|
141
153
|
unselectRow: PropTypes.func.isRequired,
|
@@ -145,6 +157,7 @@ TasksTable.propTypes = {
|
|
145
157
|
cancelModal: PropTypes.object,
|
146
158
|
resumeModal: PropTypes.object,
|
147
159
|
}).isRequired,
|
160
|
+
allRowsSelected: PropTypes.bool,
|
148
161
|
};
|
149
162
|
|
150
163
|
TasksTable.defaultProps = {
|
@@ -155,6 +168,7 @@ TasksTable.defaultProps = {
|
|
155
168
|
perPage: 20,
|
156
169
|
},
|
157
170
|
selectedRows: [],
|
171
|
+
allRowsSelected: false,
|
158
172
|
};
|
159
173
|
|
160
174
|
export default TasksTable;
|
@@ -0,0 +1,52 @@
|
|
1
|
+
import { translate as __, sprintf } from 'foremanReact/common/I18n';
|
2
|
+
import { addToast } from 'foremanReact/redux/actions/toasts';
|
3
|
+
import { TASKS_DASHBOARD_JS_QUERY_MODES } from '../TasksDashboard/TasksDashboardConstants';
|
4
|
+
import { timeToHoursNumber } from '../TasksDashboard/TasksDashboardHelper';
|
5
|
+
|
6
|
+
export const convertDashboardQuery = query => {
|
7
|
+
const {
|
8
|
+
time_mode: timeMode,
|
9
|
+
time_horizon: timeHorizon,
|
10
|
+
state,
|
11
|
+
result,
|
12
|
+
search,
|
13
|
+
} = query;
|
14
|
+
|
15
|
+
const hours = timeToHoursNumber(timeHorizon);
|
16
|
+
const timestamp = new Date(new Date() - hours * 60 * 60 * 1000);
|
17
|
+
let dashboardTime = '';
|
18
|
+
const stateQuery = state ? `state=${state}` : '';
|
19
|
+
const resultQuery = result ? `result=${result}` : '';
|
20
|
+
if (timeMode === TASKS_DASHBOARD_JS_QUERY_MODES.RECENT) {
|
21
|
+
dashboardTime = `(state_updated_at>${timestamp.toISOString()} or state_updated_at = NULL)`;
|
22
|
+
} else if (timeMode === TASKS_DASHBOARD_JS_QUERY_MODES.OLDER) {
|
23
|
+
dashboardTime = `(state_updated_at>${timestamp.toISOString()})`;
|
24
|
+
}
|
25
|
+
const newQuery = [stateQuery, resultQuery, search, dashboardTime]
|
26
|
+
.filter(Boolean)
|
27
|
+
.join(' and ');
|
28
|
+
return newQuery;
|
29
|
+
};
|
30
|
+
|
31
|
+
export const resumeToastInfo = {
|
32
|
+
resumed: { type: 'success', text: __('was resumed') },
|
33
|
+
failed: { type: 'error', text: __('could not be resumed') },
|
34
|
+
skipped: { type: 'warning', text: __('task has to be resumable') },
|
35
|
+
};
|
36
|
+
|
37
|
+
export const cancelToastInfo = {
|
38
|
+
cancelled: { type: 'success', text: __('was cancelled') },
|
39
|
+
skipped: { type: 'warning', text: __('task has to be cancellable') },
|
40
|
+
};
|
41
|
+
|
42
|
+
export const toastDispatch = ({ type, name, toastInfo, dispatch }) => {
|
43
|
+
dispatch(
|
44
|
+
addToast({
|
45
|
+
type: toastInfo[type].type,
|
46
|
+
message: sprintf('%(name)s Task execution %(type)s', {
|
47
|
+
name,
|
48
|
+
type: toastInfo[type].text,
|
49
|
+
}),
|
50
|
+
})
|
51
|
+
);
|
52
|
+
};
|
@@ -2,24 +2,39 @@ import { getURIQuery } from 'foremanReact/common/helpers';
|
|
2
2
|
import { getTableItemsAction } from 'foremanReact/components/common/table';
|
3
3
|
import API from 'foremanReact/API';
|
4
4
|
import { addToast } from 'foremanReact/redux/actions/toasts';
|
5
|
-
import {
|
6
|
-
import URI from 'urijs';
|
5
|
+
import { sprintf } from 'foremanReact/common/I18n';
|
7
6
|
import {
|
8
7
|
TASKS_TABLE_ID,
|
9
8
|
SELECT_ROWS,
|
10
9
|
UNSELECT_ALL_ROWS,
|
10
|
+
SELECT_ALL_ROWS,
|
11
11
|
UNSELECT_ROWS,
|
12
12
|
UPDATE_CLICKED,
|
13
|
+
OPEN_SELECT_ALL,
|
13
14
|
TASKS_RESUME_REQUEST,
|
14
15
|
TASKS_RESUME_SUCCESS,
|
15
16
|
TASKS_RESUME_FAILURE,
|
17
|
+
TASKS_CANCEL_REQUEST,
|
18
|
+
TASKS_CANCEL_SUCCESS,
|
19
|
+
TASKS_CANCEL_FAILURE,
|
16
20
|
} from './TasksTableConstants';
|
21
|
+
import { TOAST_TYPES } from '../common/ToastTypesConstants';
|
17
22
|
import { getApiPathname } from './TasksTableHelpers';
|
18
23
|
import { fetchTasksSummary } from '../TasksDashboard/TasksDashboardActions';
|
24
|
+
import {
|
25
|
+
resumeToastInfo,
|
26
|
+
cancelToastInfo,
|
27
|
+
toastDispatch,
|
28
|
+
} from './TasksTableActionHelpers';
|
19
29
|
|
20
30
|
export const getTableItems = url =>
|
21
31
|
getTableItemsAction(TASKS_TABLE_ID, getURIQuery(url), getApiPathname(url));
|
22
32
|
|
33
|
+
export const reloadPage = (url, parentTaskID, dispatch) => {
|
34
|
+
dispatch(getTableItems(url));
|
35
|
+
dispatch(fetchTasksSummary(getURIQuery(url).time, parentTaskID));
|
36
|
+
};
|
37
|
+
|
23
38
|
export const cancelTask = ({
|
24
39
|
taskId,
|
25
40
|
taskName,
|
@@ -27,32 +42,34 @@ export const cancelTask = ({
|
|
27
42
|
parentTaskID,
|
28
43
|
}) => async dispatch => {
|
29
44
|
await dispatch(cancelTaskRequest(taskId, taskName));
|
30
|
-
|
31
|
-
dispatch(fetchTasksSummary(getURIQuery(url).time, parentTaskID));
|
45
|
+
reloadPage(url, parentTaskID, dispatch);
|
32
46
|
};
|
33
47
|
|
34
48
|
export const cancelTaskRequest = (id, name) => async dispatch => {
|
35
49
|
dispatch(
|
36
50
|
addToast({
|
37
|
-
type:
|
38
|
-
message:
|
51
|
+
type: TOAST_TYPES.INFO,
|
52
|
+
message: sprintf('Trying to cancel %s task', name),
|
39
53
|
})
|
40
54
|
);
|
55
|
+
dispatch({ type: TASKS_CANCEL_REQUEST });
|
41
56
|
try {
|
42
57
|
await API.post(`/foreman_tasks/tasks/${id}/cancel`);
|
43
|
-
dispatch(
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
58
|
+
dispatch({ type: TASKS_CANCEL_SUCCESS });
|
59
|
+
toastDispatch({
|
60
|
+
type: 'cancelled',
|
61
|
+
name,
|
62
|
+
toastInfo: cancelToastInfo,
|
63
|
+
dispatch,
|
64
|
+
});
|
49
65
|
} catch ({ response }) {
|
50
|
-
dispatch(
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
66
|
+
dispatch({ type: TASKS_CANCEL_FAILURE, payload: response });
|
67
|
+
toastDispatch({
|
68
|
+
type: 'skipped',
|
69
|
+
name,
|
70
|
+
toastInfo: cancelToastInfo,
|
71
|
+
dispatch,
|
72
|
+
});
|
56
73
|
}
|
57
74
|
};
|
58
75
|
|
@@ -63,32 +80,44 @@ export const resumeTask = ({
|
|
63
80
|
parentTaskID,
|
64
81
|
}) => async dispatch => {
|
65
82
|
await dispatch(resumeTaskRequest(taskId, taskName));
|
66
|
-
|
67
|
-
dispatch(fetchTasksSummary(getURIQuery(url).time), parentTaskID);
|
83
|
+
reloadPage(url, parentTaskID, dispatch);
|
68
84
|
};
|
69
85
|
|
70
86
|
export const resumeTaskRequest = (id, name) => async dispatch => {
|
87
|
+
dispatch({ type: TASKS_RESUME_REQUEST });
|
71
88
|
try {
|
72
89
|
await API.post(`/foreman_tasks/tasks/${id}/resume`);
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
90
|
+
|
91
|
+
dispatch({ type: TASKS_RESUME_SUCCESS });
|
92
|
+
toastDispatch({
|
93
|
+
type: 'resumed',
|
94
|
+
name,
|
95
|
+
toastInfo: resumeToastInfo,
|
96
|
+
dispatch,
|
97
|
+
});
|
79
98
|
} catch ({ response }) {
|
80
|
-
dispatch(
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
99
|
+
dispatch({ type: TASKS_RESUME_FAILURE, payload: response });
|
100
|
+
toastDispatch({
|
101
|
+
type: 'failed',
|
102
|
+
name,
|
103
|
+
toastInfo: resumeToastInfo,
|
104
|
+
dispatch,
|
105
|
+
});
|
86
106
|
}
|
87
107
|
};
|
88
108
|
|
89
|
-
export const
|
90
|
-
|
91
|
-
|
109
|
+
export const selectPage = results => dispatch => {
|
110
|
+
dispatch({
|
111
|
+
type: SELECT_ROWS,
|
112
|
+
payload: results.map(row => row.id),
|
113
|
+
});
|
114
|
+
dispatch({
|
115
|
+
type: OPEN_SELECT_ALL,
|
116
|
+
});
|
117
|
+
};
|
118
|
+
|
119
|
+
export const selectAllRows = () => ({
|
120
|
+
type: SELECT_ALL_ROWS,
|
92
121
|
});
|
93
122
|
|
94
123
|
export const unselectAllRows = () => ({
|
@@ -100,102 +129,11 @@ export const selectRow = id => ({
|
|
100
129
|
payload: [id],
|
101
130
|
});
|
102
131
|
|
103
|
-
export const unselectRow = id => ({
|
132
|
+
export const unselectRow = (id, results) => ({
|
104
133
|
type: UNSELECT_ROWS,
|
105
|
-
payload: id,
|
134
|
+
payload: { id, results },
|
106
135
|
});
|
107
136
|
|
108
|
-
export const bulkResumeRequest = resumeTasks => {
|
109
|
-
const ids = resumeTasks.map(task => task.id);
|
110
|
-
const url = new URI('/foreman_tasks/api/tasks/bulk_resume');
|
111
|
-
url.setSearch('task_ids[]', ids);
|
112
|
-
return API.post(url);
|
113
|
-
};
|
114
|
-
|
115
|
-
export const bulkResume = ({
|
116
|
-
selected,
|
117
|
-
url,
|
118
|
-
parentTaskID,
|
119
|
-
}) => async dispatch => {
|
120
|
-
const resumeTasks = selected.filter(task => task.isResumable);
|
121
|
-
if (resumeTasks.length < selected.length)
|
122
|
-
dispatch(
|
123
|
-
addToast({
|
124
|
-
type: 'warning',
|
125
|
-
message: __('Not all the selected tasks can be resumed'),
|
126
|
-
})
|
127
|
-
);
|
128
|
-
if (resumeTasks.length) {
|
129
|
-
try {
|
130
|
-
dispatch({ type: TASKS_RESUME_REQUEST });
|
131
|
-
const { data } = await bulkResumeRequest(resumeTasks);
|
132
|
-
dispatch({ type: TASKS_RESUME_SUCCESS });
|
133
|
-
const toastInfo = {
|
134
|
-
resumed: { type: 'success', text: 'was resumed' },
|
135
|
-
failed: { type: 'error', text: 'could not be resumed' },
|
136
|
-
};
|
137
|
-
const toastDispatch = (type, name) =>
|
138
|
-
dispatch(
|
139
|
-
addToast({
|
140
|
-
type: toastInfo[type].type,
|
141
|
-
message: sprintf(__('%(name)s Task execution %(type)s'), {
|
142
|
-
name,
|
143
|
-
type: toastInfo[type].text,
|
144
|
-
}),
|
145
|
-
})
|
146
|
-
);
|
147
|
-
|
148
|
-
['resumed', 'failed'].forEach(type => {
|
149
|
-
data[type].forEach(task => {
|
150
|
-
toastDispatch(type, task.action);
|
151
|
-
});
|
152
|
-
});
|
153
|
-
if (data.resumed.length) {
|
154
|
-
dispatch(getTableItems(url));
|
155
|
-
dispatch(fetchTasksSummary(getURIQuery(url).time, parentTaskID));
|
156
|
-
}
|
157
|
-
} catch (error) {
|
158
|
-
dispatch({ type: TASKS_RESUME_FAILURE, error });
|
159
|
-
dispatch(
|
160
|
-
addToast({
|
161
|
-
type: 'error',
|
162
|
-
message: `${__(`Cannot resume tasks at the moment`)} ${error}`,
|
163
|
-
})
|
164
|
-
);
|
165
|
-
}
|
166
|
-
}
|
167
|
-
};
|
168
|
-
|
169
|
-
export const bulkCancel = ({
|
170
|
-
selected,
|
171
|
-
url,
|
172
|
-
parentTaskID,
|
173
|
-
}) => async dispatch => {
|
174
|
-
let notAllActionable = false;
|
175
|
-
let someActionable = false;
|
176
|
-
const promises = selected.map(task => {
|
177
|
-
if (task.isCancellable) {
|
178
|
-
someActionable = true;
|
179
|
-
return dispatch(cancelTaskRequest(task.id, task.name));
|
180
|
-
}
|
181
|
-
notAllActionable = true;
|
182
|
-
return null;
|
183
|
-
});
|
184
|
-
|
185
|
-
if (notAllActionable)
|
186
|
-
dispatch(
|
187
|
-
addToast({
|
188
|
-
type: 'warning',
|
189
|
-
message: __('Not all the selected tasks can be canceled'),
|
190
|
-
})
|
191
|
-
);
|
192
|
-
if (someActionable) {
|
193
|
-
await Promise.all(promises);
|
194
|
-
dispatch(getTableItems(url));
|
195
|
-
dispatch(fetchTasksSummary(getURIQuery(url).time, parentTaskID));
|
196
|
-
}
|
197
|
-
};
|
198
|
-
|
199
137
|
export const openClickedModal = ({ taskId, taskName, setModalOpen }) => {
|
200
138
|
setModalOpen();
|
201
139
|
return {
|