foreman-tasks 1.1.3 → 1.2.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/controllers/foreman_tasks/api/tasks_controller.rb +29 -1
- data/app/controllers/foreman_tasks/tasks_controller.rb +3 -11
- data/app/models/foreman_tasks/task.rb +4 -0
- data/app/models/setting/foreman_tasks.rb +1 -1
- data/app/services/ui_notifications/tasks/task_bulk_stop.rb +36 -0
- data/app/views/foreman_tasks/api/tasks/details.json.rabl +0 -1
- data/config/routes.rb +1 -0
- data/db/migrate/20200517215015_rename_bookmarks_controller.rb +35 -0
- data/db/migrate/20200519093217_drop_dynflow_allow_dangerous_actions_setting.foreman_tasks.rb +5 -0
- data/db/seeds.d/30-notification_blueprints.rb +7 -0
- data/lib/foreman_tasks/engine.rb +1 -1
- data/lib/foreman_tasks/tasks/cleanup.rake +2 -2
- data/lib/foreman_tasks/tasks/export_tasks.rake +1 -1
- data/lib/foreman_tasks/version.rb +1 -1
- data/locale/action_names.rb +1 -1
- data/locale/en/foreman_tasks.po +227 -41
- data/locale/foreman_tasks.pot +579 -288
- data/webpack/ForemanTasks/Components/TaskActions/TaskAction.test.js +60 -0
- data/webpack/ForemanTasks/Components/{TasksTable/TasksTableActionHelpers.js → TaskActions/TaskActionHelpers.js} +21 -6
- data/webpack/ForemanTasks/Components/{TasksTable/__tests__/TasksTableActionHelpers.test.js → TaskActions/TaskActionHelpers.test.js} +2 -2
- data/webpack/ForemanTasks/Components/TaskActions/TaskActionsConstants.js +16 -0
- data/webpack/ForemanTasks/Components/TaskActions/UnlockModals.js +60 -0
- data/webpack/ForemanTasks/Components/TaskActions/UnlockModals.test.js +14 -0
- data/webpack/ForemanTasks/Components/TaskActions/__snapshots__/TaskAction.test.js.snap +233 -0
- data/webpack/ForemanTasks/Components/TaskActions/__snapshots__/UnlockModals.test.js.snap +25 -0
- data/webpack/ForemanTasks/Components/TaskActions/index.js +115 -0
- data/webpack/ForemanTasks/Components/TaskDetails/Components/Task.js +130 -152
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/Task.test.js +67 -3
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/TaskInfo.test.js +0 -1
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/Task.test.js.snap +101 -70
- data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsActions.js +0 -15
- data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsConstants.js +0 -5
- data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsReducer.js +0 -6
- data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsSelectors.js +0 -9
- data/webpack/ForemanTasks/Components/TaskDetails/TasksDetailsHelper.js +6 -1
- data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetails.test.js +5 -0
- data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/TaskDetails.test.js.snap +2 -7
- data/webpack/ForemanTasks/Components/TaskDetails/__tests__/integration.test.js +4 -0
- data/webpack/ForemanTasks/Components/TaskDetails/index.js +4 -8
- data/webpack/ForemanTasks/Components/TasksTable/Components/ActionSelectButton.js +14 -1
- data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/ConfirmModal.js +83 -0
- data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/ConfirmModalActions.js +106 -0
- data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/ConfirmModalReducer.js +38 -0
- data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/ConfirmModalSelectors.js +45 -0
- data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/ConfirmModal.test.js +36 -0
- data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/ConfirmModalActions.test.js +205 -0
- data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/ConfirmModalReducer.test.js +27 -0
- data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/ConfirmModalSelectors.test.js +54 -0
- data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/__snapshots__/ConfirmModal.test.js.snap +41 -0
- data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/__snapshots__/ConfirmModalReducer.test.js.snap +19 -0
- data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/__snapshots__/ConfirmModalSelectors.test.js.snap +30 -0
- data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/index.js +29 -0
- data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/ActionSelectButton.test.js +1 -0
- data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/__snapshots__/ActionSelectButton.test.js.snap +11 -0
- data/webpack/ForemanTasks/Components/TasksTable/TasksBulkActions.js +113 -30
- data/webpack/ForemanTasks/Components/TasksTable/TasksTable.js +13 -9
- data/webpack/ForemanTasks/Components/TasksTable/TasksTableActions.js +23 -63
- data/webpack/ForemanTasks/Components/TasksTable/TasksTableConstants.js +10 -12
- data/webpack/ForemanTasks/Components/TasksTable/TasksTablePage.js +24 -94
- data/webpack/ForemanTasks/Components/TasksTable/TasksTableSchema.js +2 -2
- data/webpack/ForemanTasks/Components/TasksTable/TasksTableSelectors.js +7 -4
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksBulkActions.test.js +35 -0
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTable.fixtures.js +2 -12
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTableActions.test.js +22 -26
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/SubTasksPage.test.js.snap +2 -14
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksBulkActions.test.js.snap +107 -0
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksIndexPage.test.js.snap +2 -14
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTableActions.test.js.snap +17 -124
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTablePage.test.js.snap +24 -128
- data/webpack/ForemanTasks/Components/TasksTable/index.js +2 -2
- data/webpack/ForemanTasks/Components/common/ActionButtons/ActionButton.js +47 -19
- data/webpack/ForemanTasks/Components/common/ActionButtons/ActionButton.test.js +61 -14
- data/webpack/ForemanTasks/Components/common/ActionButtons/__snapshots__/ActionButton.test.js.snap +80 -21
- data/webpack/ForemanTasks/Components/common/ClickConfirmation/ClickConfirmation.scss +9 -0
- data/webpack/ForemanTasks/Components/common/ClickConfirmation/ClickConfirmation.test.js +44 -0
- data/webpack/ForemanTasks/Components/common/ClickConfirmation/__snapshots__/ClickConfirmation.test.js.snap +52 -0
- data/webpack/ForemanTasks/Components/common/ClickConfirmation/index.js +59 -66
- data/webpack/ForemanTasks/Components/common/{ToastTypesConstants.js → ToastsHelpers/ToastTypesConstants.js} +0 -0
- data/webpack/ForemanTasks/Components/common/ToastsHelpers/index.js +15 -0
- data/webpack/ForemanTasks/ForemanTasksReducers.js +2 -0
- data/webpack/ForemanTasks/Routes/ForemanTasksRoutes.test.js +2 -1
- data/webpack/__mocks__/foremanReact/components/ForemanModal/ForemanModalHooks.js +2 -2
- data/webpack/__mocks__/foremanReact/components/ForemanModal/index.js +17 -3
- data/webpack/__mocks__/foremanReact/components/common/ActionButtons/ActionButtons.js +3 -0
- metadata +32 -22
- data/db/migrate/20200611090846_add_task_lock_index_on_resource_type_and_task_id.rb +0 -9
- data/lib/foreman_tasks/tasks/dynflow.rake +0 -6
- data/webpack/ForemanTasks/Components/TasksTable/Components/CancelConfirm.js +0 -53
- data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmationModals.js +0 -56
- data/webpack/ForemanTasks/Components/TasksTable/Components/ResumeConfirm.js +0 -52
- data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/CancelConfirm.test.js +0 -26
- data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/ConfirmationModals.test.js +0 -24
- data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/ResumeConfirm.test.js +0 -26
- data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/__snapshots__/CancelConfirm.test.js.snap +0 -65
- data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/__snapshots__/ConfirmationModals.test.js.snap +0 -30
- data/webpack/ForemanTasks/Components/TasksTable/Components/__test__/__snapshots__/ResumeConfirm.test.js.snap +0 -63
- data/webpack/ForemanTasks/Components/common/ActionButtons/CancelButton.js +0 -23
- data/webpack/ForemanTasks/Components/common/ActionButtons/CancelButton.test.js +0 -26
- data/webpack/ForemanTasks/Components/common/ActionButtons/ResumeButton.js +0 -23
- data/webpack/ForemanTasks/Components/common/ActionButtons/ResumeButton.test.js +0 -27
- data/webpack/ForemanTasks/Components/common/ActionButtons/__snapshots__/CancelButton.test.js.snap +0 -15
- data/webpack/ForemanTasks/Components/common/ActionButtons/__snapshots__/ResumeButton.test.js.snap +0 -15
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import taskActions from '../ConfirmModalActions';
|
|
2
|
+
import {
|
|
3
|
+
CANCEL_MODAL,
|
|
4
|
+
RESUME_MODAL,
|
|
5
|
+
CANCEL_SELECTED_MODAL,
|
|
6
|
+
RESUME_SELECTED_MODAL,
|
|
7
|
+
FORCE_UNLOCK_SELECTED_MODAL,
|
|
8
|
+
} from '../../../TasksTableConstants';
|
|
9
|
+
|
|
10
|
+
import { FORCE_UNLOCK_MODAL } from '../../../../TaskActions/TaskActionsConstants';
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
resumeTask,
|
|
14
|
+
cancelTask,
|
|
15
|
+
forceCancelTask,
|
|
16
|
+
} from '../../../TasksTableActions';
|
|
17
|
+
import {
|
|
18
|
+
bulkCancelBySearch,
|
|
19
|
+
bulkCancelById,
|
|
20
|
+
bulkResumeBySearch,
|
|
21
|
+
bulkResumeById,
|
|
22
|
+
bulkForceCancelBySearch,
|
|
23
|
+
bulkForceCancelById,
|
|
24
|
+
} from '../../../TasksBulkActions';
|
|
25
|
+
|
|
26
|
+
jest.mock('../../../TasksBulkActions');
|
|
27
|
+
jest.mock('../../../TasksTableActions');
|
|
28
|
+
|
|
29
|
+
const bulkCancelBySearchMock = 'bulkCancelBySearchMock';
|
|
30
|
+
const bulkCancelByIdMock = 'bulkCancelByIdMock';
|
|
31
|
+
const bulkResumeBySearchMock = 'bulkResumeBySearchMock';
|
|
32
|
+
const bulkResumeByIdMock = 'bulkResumeByIdMock';
|
|
33
|
+
const bulkForceCancelBySearchMock = 'bulkForceCancelBySearchMock';
|
|
34
|
+
const bulkForceCancelByIdMock = 'bulkForceCancelByIdMock';
|
|
35
|
+
const resumeTaskMock = 'resumeTaskMock';
|
|
36
|
+
const cancelTaskMock = 'cancelTaskMock';
|
|
37
|
+
const forceCancelTaskMock = 'forceCancelTaskMock';
|
|
38
|
+
|
|
39
|
+
bulkCancelBySearch.mockImplementation(() => bulkCancelBySearchMock);
|
|
40
|
+
bulkCancelById.mockImplementation(() => bulkCancelByIdMock);
|
|
41
|
+
bulkResumeBySearch.mockImplementation(() => bulkResumeBySearchMock);
|
|
42
|
+
bulkResumeById.mockImplementation(() => bulkResumeByIdMock);
|
|
43
|
+
bulkForceCancelBySearch.mockImplementation(() => bulkForceCancelBySearchMock);
|
|
44
|
+
bulkForceCancelById.mockImplementation(() => bulkForceCancelByIdMock);
|
|
45
|
+
resumeTask.mockImplementation(() => resumeTaskMock);
|
|
46
|
+
cancelTask.mockImplementation(() => cancelTaskMock);
|
|
47
|
+
forceCancelTask.mockImplementation(() => forceCancelTaskMock);
|
|
48
|
+
|
|
49
|
+
const url = 'some-url';
|
|
50
|
+
const query = 'some-query';
|
|
51
|
+
const parentTaskID = 'some-parentTaskID';
|
|
52
|
+
|
|
53
|
+
const runWithGetState = (state, action, dispatch, ...params) => {
|
|
54
|
+
const getState = () => state;
|
|
55
|
+
action(...params)(dispatch, getState);
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
const clickedState = {
|
|
59
|
+
foremanTasks: {
|
|
60
|
+
tasksTable: {
|
|
61
|
+
tasksTableQuery: {
|
|
62
|
+
clicked: { taskId: 'some-id', taskName: 'some-name' },
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
|
|
68
|
+
const selectedState = {
|
|
69
|
+
foremanTasks: {
|
|
70
|
+
tasksTable: {
|
|
71
|
+
tasksTableQuery: {
|
|
72
|
+
allRowsSelected: false,
|
|
73
|
+
selectedRows: [1, 2, 3],
|
|
74
|
+
},
|
|
75
|
+
tasksTableContent: {
|
|
76
|
+
results: [
|
|
77
|
+
{
|
|
78
|
+
id: 1,
|
|
79
|
+
action: 'action1',
|
|
80
|
+
available_actions: { cancellable: true },
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
id: 2,
|
|
84
|
+
action: 'action2',
|
|
85
|
+
available_actions: { resumable: true },
|
|
86
|
+
},
|
|
87
|
+
],
|
|
88
|
+
},
|
|
89
|
+
},
|
|
90
|
+
},
|
|
91
|
+
};
|
|
92
|
+
const allRowsState = {
|
|
93
|
+
foremanTasks: {
|
|
94
|
+
tasksTable: {
|
|
95
|
+
tasksTableQuery: {
|
|
96
|
+
allRowsSelected: true,
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
},
|
|
100
|
+
};
|
|
101
|
+
describe('ConfirmModalActions', () => {
|
|
102
|
+
const dispatch = jest.fn();
|
|
103
|
+
|
|
104
|
+
beforeEach(() => dispatch.mockClear());
|
|
105
|
+
it('run CANCEL_MODAL', () => {
|
|
106
|
+
runWithGetState(clickedState, taskActions[CANCEL_MODAL], dispatch, {
|
|
107
|
+
url,
|
|
108
|
+
parentTaskID,
|
|
109
|
+
});
|
|
110
|
+
expect(dispatch).toBeCalledWith(cancelTaskMock);
|
|
111
|
+
});
|
|
112
|
+
it('run RESUME_MODAL', () => {
|
|
113
|
+
runWithGetState(clickedState, taskActions[RESUME_MODAL], dispatch, {
|
|
114
|
+
url,
|
|
115
|
+
parentTaskID,
|
|
116
|
+
});
|
|
117
|
+
expect(dispatch).toBeCalledWith(resumeTaskMock);
|
|
118
|
+
});
|
|
119
|
+
it('run FORCE_UNLOCK_MODAL', () => {
|
|
120
|
+
runWithGetState(clickedState, taskActions[FORCE_UNLOCK_MODAL], dispatch, {
|
|
121
|
+
url,
|
|
122
|
+
parentTaskID,
|
|
123
|
+
});
|
|
124
|
+
expect(dispatch).toBeCalledWith(forceCancelTaskMock);
|
|
125
|
+
});
|
|
126
|
+
it('run CANCEL_SELECTED_MODAL by id', () => {
|
|
127
|
+
runWithGetState(
|
|
128
|
+
selectedState,
|
|
129
|
+
taskActions[CANCEL_SELECTED_MODAL],
|
|
130
|
+
dispatch,
|
|
131
|
+
{
|
|
132
|
+
url,
|
|
133
|
+
query,
|
|
134
|
+
parentTaskID,
|
|
135
|
+
}
|
|
136
|
+
);
|
|
137
|
+
expect(dispatch).toBeCalledWith(bulkCancelByIdMock);
|
|
138
|
+
});
|
|
139
|
+
|
|
140
|
+
it('run CANCEL_SELECTED_MODAL by search', () => {
|
|
141
|
+
runWithGetState(
|
|
142
|
+
allRowsState,
|
|
143
|
+
taskActions[CANCEL_SELECTED_MODAL],
|
|
144
|
+
dispatch,
|
|
145
|
+
{
|
|
146
|
+
url,
|
|
147
|
+
query,
|
|
148
|
+
parentTaskID,
|
|
149
|
+
}
|
|
150
|
+
);
|
|
151
|
+
expect(dispatch).toBeCalledWith(bulkCancelBySearchMock);
|
|
152
|
+
});
|
|
153
|
+
it('run RESUME_SELECTED_MODAL by id', () => {
|
|
154
|
+
runWithGetState(
|
|
155
|
+
selectedState,
|
|
156
|
+
taskActions[RESUME_SELECTED_MODAL],
|
|
157
|
+
dispatch,
|
|
158
|
+
{
|
|
159
|
+
url,
|
|
160
|
+
query,
|
|
161
|
+
parentTaskID,
|
|
162
|
+
}
|
|
163
|
+
);
|
|
164
|
+
expect(dispatch).toBeCalledWith(bulkResumeByIdMock);
|
|
165
|
+
});
|
|
166
|
+
it('run RESUME_SELECTED_MODAL by search', () => {
|
|
167
|
+
runWithGetState(
|
|
168
|
+
allRowsState,
|
|
169
|
+
taskActions[RESUME_SELECTED_MODAL],
|
|
170
|
+
dispatch,
|
|
171
|
+
{
|
|
172
|
+
url,
|
|
173
|
+
query,
|
|
174
|
+
parentTaskID,
|
|
175
|
+
}
|
|
176
|
+
);
|
|
177
|
+
expect(dispatch).toBeCalledWith(bulkResumeBySearchMock);
|
|
178
|
+
});
|
|
179
|
+
it('run FORCE_UNLOCK_SELECTED_MODAL by id', () => {
|
|
180
|
+
runWithGetState(
|
|
181
|
+
selectedState,
|
|
182
|
+
taskActions[FORCE_UNLOCK_SELECTED_MODAL],
|
|
183
|
+
dispatch,
|
|
184
|
+
{
|
|
185
|
+
url,
|
|
186
|
+
query,
|
|
187
|
+
parentTaskID,
|
|
188
|
+
}
|
|
189
|
+
);
|
|
190
|
+
expect(dispatch).toBeCalledWith(bulkForceCancelByIdMock);
|
|
191
|
+
});
|
|
192
|
+
it('run FORCE_UNLOCK_SELECTED_MODAL by search', () => {
|
|
193
|
+
runWithGetState(
|
|
194
|
+
allRowsState,
|
|
195
|
+
taskActions[FORCE_UNLOCK_SELECTED_MODAL],
|
|
196
|
+
dispatch,
|
|
197
|
+
{
|
|
198
|
+
url,
|
|
199
|
+
query,
|
|
200
|
+
parentTaskID,
|
|
201
|
+
}
|
|
202
|
+
);
|
|
203
|
+
expect(dispatch).toBeCalledWith(bulkForceCancelBySearchMock);
|
|
204
|
+
});
|
|
205
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { testReducerSnapshotWithFixtures } from '@theforeman/test';
|
|
2
|
+
import {
|
|
3
|
+
UPDATE_MODAL,
|
|
4
|
+
CANCEL_MODAL,
|
|
5
|
+
RESUME_SELECTED_MODAL,
|
|
6
|
+
} from '../../../TasksTableConstants';
|
|
7
|
+
|
|
8
|
+
import reducer from '../ConfirmModalReducer';
|
|
9
|
+
|
|
10
|
+
const fixtures = {
|
|
11
|
+
'should return the initial state': {},
|
|
12
|
+
'should handle UPDATE_MODAL to cancel': {
|
|
13
|
+
action: {
|
|
14
|
+
type: UPDATE_MODAL,
|
|
15
|
+
payload: { modalID: CANCEL_MODAL },
|
|
16
|
+
},
|
|
17
|
+
},
|
|
18
|
+
'should handle UPDATE_MODAL to resume': {
|
|
19
|
+
action: {
|
|
20
|
+
type: UPDATE_MODAL,
|
|
21
|
+
payload: { modalID: RESUME_SELECTED_MODAL },
|
|
22
|
+
},
|
|
23
|
+
},
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
describe('ConfirmModalReducer reducer', () =>
|
|
27
|
+
testReducerSnapshotWithFixtures(reducer, fixtures));
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { testSelectorsSnapshotWithFixtures } from '@theforeman/test';
|
|
2
|
+
import {
|
|
3
|
+
selectActionText,
|
|
4
|
+
selectActionState,
|
|
5
|
+
selectActionType,
|
|
6
|
+
selectSelectedTasks,
|
|
7
|
+
selectSelectedRowsLen,
|
|
8
|
+
} from '../ConfirmModalSelectors';
|
|
9
|
+
import { CANCEL_MODAL } from '../../../TasksTableConstants';
|
|
10
|
+
|
|
11
|
+
const state = {
|
|
12
|
+
foremanTasks: {
|
|
13
|
+
confirmModal: {
|
|
14
|
+
actionText: 'some-text',
|
|
15
|
+
actionState: 'some-state',
|
|
16
|
+
actionType: 'some-type',
|
|
17
|
+
},
|
|
18
|
+
tasksTable: {
|
|
19
|
+
tasksTableContent: {
|
|
20
|
+
results: [
|
|
21
|
+
{
|
|
22
|
+
id: 1,
|
|
23
|
+
action: 'action1',
|
|
24
|
+
available_actions: { cancellable: true },
|
|
25
|
+
},
|
|
26
|
+
{ id: 2, action: 'action2', available_actions: { resumable: true } },
|
|
27
|
+
],
|
|
28
|
+
itemCount: 10,
|
|
29
|
+
},
|
|
30
|
+
tasksTableQuery: { selectedRows: [1, 2, 3] },
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const fixtures = {
|
|
36
|
+
'should select actionText': () => selectActionText(state),
|
|
37
|
+
'should select actionState': () => selectActionState(state),
|
|
38
|
+
'should select actionType': () => selectActionType(state),
|
|
39
|
+
'should select selectedTasks': () => selectSelectedTasks(state),
|
|
40
|
+
'should select selectedRowsLen 1': () =>
|
|
41
|
+
selectSelectedRowsLen({
|
|
42
|
+
...state,
|
|
43
|
+
foremanTasks: { confirmModal: { actionType: CANCEL_MODAL } },
|
|
44
|
+
}),
|
|
45
|
+
'should select selectedRowsLen all': () => selectSelectedRowsLen(state),
|
|
46
|
+
'should select selectedRowsLen some': () =>
|
|
47
|
+
selectSelectedRowsLen({
|
|
48
|
+
...state,
|
|
49
|
+
tasksTable: { tasksTableQuery: { allRowsSelected: true } },
|
|
50
|
+
}),
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
describe('TasksDashboard - Selectors', () =>
|
|
54
|
+
testSelectorsSnapshotWithFixtures(fixtures));
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`ConfirmModal renders ConfirmModal 1`] = `
|
|
4
|
+
<ForemanModal
|
|
5
|
+
id="modalID"
|
|
6
|
+
title="Some Text Selected Tasks"
|
|
7
|
+
>
|
|
8
|
+
This will some text 1 task(s), putting them in the some state state. Are you sure?
|
|
9
|
+
<Component>
|
|
10
|
+
<Button
|
|
11
|
+
active={false}
|
|
12
|
+
block={false}
|
|
13
|
+
bsClass="btn"
|
|
14
|
+
bsStyle="default"
|
|
15
|
+
disabled={false}
|
|
16
|
+
onClick={[MockFunction]}
|
|
17
|
+
>
|
|
18
|
+
No
|
|
19
|
+
</Button>
|
|
20
|
+
<Button
|
|
21
|
+
active={false}
|
|
22
|
+
block={false}
|
|
23
|
+
bsClass="btn"
|
|
24
|
+
bsStyle="primary"
|
|
25
|
+
className="confirm-button"
|
|
26
|
+
disabled={false}
|
|
27
|
+
onClick={[Function]}
|
|
28
|
+
>
|
|
29
|
+
Yes
|
|
30
|
+
</Button>
|
|
31
|
+
</Component>
|
|
32
|
+
</ForemanModal>
|
|
33
|
+
`;
|
|
34
|
+
|
|
35
|
+
exports[`ConfirmModal renders ConfirmModal for unlock 1`] = `
|
|
36
|
+
<ForceUnlockModal
|
|
37
|
+
id="modalID"
|
|
38
|
+
onClick={[Function]}
|
|
39
|
+
selectedRowsLen={1}
|
|
40
|
+
/>
|
|
41
|
+
`;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`ConfirmModalReducer reducer should handle UPDATE_MODAL to cancel 1`] = `
|
|
4
|
+
Object {
|
|
5
|
+
"actionState": "stopped",
|
|
6
|
+
"actionText": "cancel",
|
|
7
|
+
"actionType": "cancelConfirmModal",
|
|
8
|
+
}
|
|
9
|
+
`;
|
|
10
|
+
|
|
11
|
+
exports[`ConfirmModalReducer reducer should handle UPDATE_MODAL to resume 1`] = `
|
|
12
|
+
Object {
|
|
13
|
+
"actionState": "running",
|
|
14
|
+
"actionText": "resume",
|
|
15
|
+
"actionType": "resumeSelectedConfirmModal",
|
|
16
|
+
}
|
|
17
|
+
`;
|
|
18
|
+
|
|
19
|
+
exports[`ConfirmModalReducer reducer should return the initial state 1`] = `Object {}`;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
|
2
|
+
|
|
3
|
+
exports[`TasksDashboard - Selectors should select actionState 1`] = `"some-state"`;
|
|
4
|
+
|
|
5
|
+
exports[`TasksDashboard - Selectors should select actionText 1`] = `"some-text"`;
|
|
6
|
+
|
|
7
|
+
exports[`TasksDashboard - Selectors should select actionType 1`] = `"some-type"`;
|
|
8
|
+
|
|
9
|
+
exports[`TasksDashboard - Selectors should select selectedRowsLen 1 1`] = `1`;
|
|
10
|
+
|
|
11
|
+
exports[`TasksDashboard - Selectors should select selectedRowsLen all 1`] = `3`;
|
|
12
|
+
|
|
13
|
+
exports[`TasksDashboard - Selectors should select selectedRowsLen some 1`] = `3`;
|
|
14
|
+
|
|
15
|
+
exports[`TasksDashboard - Selectors should select selectedTasks 1`] = `
|
|
16
|
+
Array [
|
|
17
|
+
Object {
|
|
18
|
+
"id": 1,
|
|
19
|
+
"isCancellable": true,
|
|
20
|
+
"isResumable": undefined,
|
|
21
|
+
"name": "action1",
|
|
22
|
+
},
|
|
23
|
+
Object {
|
|
24
|
+
"id": 2,
|
|
25
|
+
"isCancellable": undefined,
|
|
26
|
+
"isResumable": true,
|
|
27
|
+
"name": "action2",
|
|
28
|
+
},
|
|
29
|
+
]
|
|
30
|
+
`;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { connect } from 'react-redux';
|
|
2
|
+
import { bindActionCreators } from 'redux';
|
|
3
|
+
import { ConfirmModal } from './ConfirmModal';
|
|
4
|
+
import reducer from './ConfirmModalReducer';
|
|
5
|
+
import tasksActions from './ConfirmModalActions';
|
|
6
|
+
import {
|
|
7
|
+
selectActionText,
|
|
8
|
+
selectActionState,
|
|
9
|
+
selectActionType,
|
|
10
|
+
selectClicked,
|
|
11
|
+
selectSelectedRowsLen,
|
|
12
|
+
} from './ConfirmModalSelectors';
|
|
13
|
+
import { selectAllRowsSelected } from '../../TasksTableSelectors';
|
|
14
|
+
|
|
15
|
+
const mapStateToProps = state => ({
|
|
16
|
+
actionText: selectActionText(state),
|
|
17
|
+
actionType: selectActionType(state),
|
|
18
|
+
actionState: selectActionState(state),
|
|
19
|
+
allRowsSelected: selectAllRowsSelected(state),
|
|
20
|
+
clicked: selectClicked(state),
|
|
21
|
+
selectedRowsLen: selectSelectedRowsLen(state),
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
const mapDispatchToProps = dispatch =>
|
|
25
|
+
bindActionCreators(tasksActions, dispatch);
|
|
26
|
+
|
|
27
|
+
export const reducers = { confirmModal: reducer };
|
|
28
|
+
|
|
29
|
+
export default connect(mapStateToProps, mapDispatchToProps)(ConfirmModal);
|
|
@@ -28,5 +28,16 @@ exports[`ActionSelectButton renders with minimal props 1`] = `
|
|
|
28
28
|
>
|
|
29
29
|
Resume Selected
|
|
30
30
|
</MenuItem>
|
|
31
|
+
<MenuItem
|
|
32
|
+
bsClass="dropdown"
|
|
33
|
+
disabled={false}
|
|
34
|
+
divider={false}
|
|
35
|
+
eventKey="3"
|
|
36
|
+
header={false}
|
|
37
|
+
onClick={[MockFunction]}
|
|
38
|
+
title="Force Cancel selected tasks"
|
|
39
|
+
>
|
|
40
|
+
Force Cancel Selected
|
|
41
|
+
</MenuItem>
|
|
31
42
|
</DropdownButton>
|
|
32
43
|
`;
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import API from 'foremanReact/API';
|
|
2
2
|
import { addToast } from 'foremanReact/redux/actions/toasts';
|
|
3
|
-
import { translate as __ } from 'foremanReact/common/I18n';
|
|
4
|
-
import {
|
|
3
|
+
import { translate as __, sprintf } from 'foremanReact/common/I18n';
|
|
4
|
+
import {
|
|
5
|
+
BULK_CANCEL_PATH,
|
|
6
|
+
BULK_RESUME_PATH,
|
|
7
|
+
BULK_FORCE_CANCEL_PATH,
|
|
8
|
+
} from './TasksTableConstants';
|
|
5
9
|
import {
|
|
6
10
|
TASKS_RESUME_REQUEST,
|
|
7
11
|
TASKS_RESUME_SUCCESS,
|
|
@@ -9,16 +13,23 @@ import {
|
|
|
9
13
|
TASKS_CANCEL_REQUEST,
|
|
10
14
|
TASKS_CANCEL_SUCCESS,
|
|
11
15
|
TASKS_CANCEL_FAILURE,
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
16
|
+
TASKS_FORCE_CANCEL_REQUEST,
|
|
17
|
+
TASKS_FORCE_CANCEL_SUCCESS,
|
|
18
|
+
TASKS_FORCE_CANCEL_FAILURE,
|
|
19
|
+
} from '../TaskActions/TaskActionsConstants';
|
|
15
20
|
import { reloadPage } from './TasksTableActions';
|
|
16
21
|
import {
|
|
17
22
|
convertDashboardQuery,
|
|
18
23
|
resumeToastInfo,
|
|
19
24
|
cancelToastInfo,
|
|
20
25
|
toastDispatch,
|
|
21
|
-
} from '
|
|
26
|
+
} from '../TaskActions/TaskActionHelpers';
|
|
27
|
+
import {
|
|
28
|
+
successToastData,
|
|
29
|
+
errorToastData,
|
|
30
|
+
warningToastData,
|
|
31
|
+
infoToastData,
|
|
32
|
+
} from '../common/ToastsHelpers';
|
|
22
33
|
|
|
23
34
|
export const bulkByIdRequest = (resumeTasks, path) => {
|
|
24
35
|
const ids = resumeTasks.map(task => task.id);
|
|
@@ -41,10 +52,9 @@ export const bulkBySearchRequest = ({ query, parentTaskID, path }) => {
|
|
|
41
52
|
const handleErrorResume = (error, dispatch) => {
|
|
42
53
|
dispatch({ type: TASKS_RESUME_FAILURE, error });
|
|
43
54
|
dispatch(
|
|
44
|
-
addToast(
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
})
|
|
55
|
+
addToast(
|
|
56
|
+
errorToastData(`${__(`Cannot resume tasks at the moment`)} ${error}`)
|
|
57
|
+
)
|
|
48
58
|
);
|
|
49
59
|
};
|
|
50
60
|
|
|
@@ -56,10 +66,9 @@ export const bulkResumeById = ({
|
|
|
56
66
|
const resumeTasks = selected.filter(task => task.isResumable);
|
|
57
67
|
if (resumeTasks.length < selected.length)
|
|
58
68
|
dispatch(
|
|
59
|
-
addToast(
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
})
|
|
69
|
+
addToast(
|
|
70
|
+
warningToastData(__('Not all the selected tasks can be resumed'))
|
|
71
|
+
)
|
|
63
72
|
);
|
|
64
73
|
if (resumeTasks.length) {
|
|
65
74
|
dispatch({ type: TASKS_RESUME_REQUEST });
|
|
@@ -92,10 +101,9 @@ export const bulkResumeBySearch = ({
|
|
|
92
101
|
}) => async dispatch => {
|
|
93
102
|
dispatch({ type: TASKS_RESUME_REQUEST });
|
|
94
103
|
dispatch(
|
|
95
|
-
addToast(
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
})
|
|
104
|
+
addToast(
|
|
105
|
+
infoToastData(__('Resuming selected tasks, this might take a while'))
|
|
106
|
+
)
|
|
99
107
|
);
|
|
100
108
|
await bulkBySearchRequest({ query, path: BULK_RESUME_PATH, parentTaskID });
|
|
101
109
|
};
|
|
@@ -103,10 +111,9 @@ export const bulkResumeBySearch = ({
|
|
|
103
111
|
const handleErrorCancel = (error, dispatch) => {
|
|
104
112
|
dispatch({ type: TASKS_CANCEL_FAILURE, error });
|
|
105
113
|
dispatch(
|
|
106
|
-
addToast(
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
})
|
|
114
|
+
addToast(
|
|
115
|
+
errorToastData(`${__(`Cannot cancel tasks at the moment`)} ${error}`)
|
|
116
|
+
)
|
|
110
117
|
);
|
|
111
118
|
};
|
|
112
119
|
|
|
@@ -116,10 +123,9 @@ export const bulkCancelBySearch = ({
|
|
|
116
123
|
}) => async dispatch => {
|
|
117
124
|
dispatch({ type: TASKS_CANCEL_REQUEST });
|
|
118
125
|
dispatch(
|
|
119
|
-
addToast(
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
})
|
|
126
|
+
addToast(
|
|
127
|
+
infoToastData(__('Canceling selected tasks, this might take a while'))
|
|
128
|
+
)
|
|
123
129
|
);
|
|
124
130
|
await bulkBySearchRequest({ query, path: BULK_CANCEL_PATH, parentTaskID });
|
|
125
131
|
};
|
|
@@ -132,10 +138,9 @@ export const bulkCancelById = ({
|
|
|
132
138
|
const cancelTasks = selected.filter(task => task.isCancellable);
|
|
133
139
|
if (cancelTasks.length < selected.length)
|
|
134
140
|
dispatch(
|
|
135
|
-
addToast(
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
})
|
|
141
|
+
addToast(
|
|
142
|
+
warningToastData(__('Not all the selected tasks can be cancelled'))
|
|
143
|
+
)
|
|
139
144
|
);
|
|
140
145
|
if (cancelTasks.length) {
|
|
141
146
|
dispatch({ type: TASKS_CANCEL_REQUEST });
|
|
@@ -162,3 +167,81 @@ export const bulkCancelById = ({
|
|
|
162
167
|
}
|
|
163
168
|
}
|
|
164
169
|
};
|
|
170
|
+
|
|
171
|
+
const handleErrorForceCancel = (error, dispatch) => {
|
|
172
|
+
dispatch({ type: TASKS_FORCE_CANCEL_FAILURE, error });
|
|
173
|
+
dispatch(
|
|
174
|
+
addToast(
|
|
175
|
+
errorToastData(
|
|
176
|
+
`${__(`Cannot force cancel tasks at the moment`)} ${error}`
|
|
177
|
+
)
|
|
178
|
+
)
|
|
179
|
+
);
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
export const bulkForceCancelById = ({
|
|
183
|
+
selected,
|
|
184
|
+
url,
|
|
185
|
+
parentTaskID,
|
|
186
|
+
}) => async dispatch => {
|
|
187
|
+
const stopTasks = selected.filter(task => task.state !== 'stopped');
|
|
188
|
+
if (stopTasks.length < selected.length)
|
|
189
|
+
dispatch(
|
|
190
|
+
addToast(
|
|
191
|
+
warningToastData(
|
|
192
|
+
sprintf(
|
|
193
|
+
'%s task(s) are already stopped',
|
|
194
|
+
selected.length - stopTasks.length
|
|
195
|
+
)
|
|
196
|
+
)
|
|
197
|
+
)
|
|
198
|
+
);
|
|
199
|
+
if (stopTasks.length > 0) {
|
|
200
|
+
dispatch({ type: TASKS_FORCE_CANCEL_REQUEST });
|
|
201
|
+
try {
|
|
202
|
+
const { data } = await bulkByIdRequest(stopTasks, BULK_FORCE_CANCEL_PATH);
|
|
203
|
+
dispatch({ type: TASKS_FORCE_CANCEL_SUCCESS });
|
|
204
|
+
if (data.stopped_length) {
|
|
205
|
+
dispatch(
|
|
206
|
+
addToast(
|
|
207
|
+
successToastData(
|
|
208
|
+
sprintf('%s task(s) cancelled with force', data.stopped_length)
|
|
209
|
+
)
|
|
210
|
+
)
|
|
211
|
+
);
|
|
212
|
+
}
|
|
213
|
+
if (data.skipped_length > 0)
|
|
214
|
+
dispatch(
|
|
215
|
+
addToast(
|
|
216
|
+
warningToastData(
|
|
217
|
+
sprintf('%s task(s) are already stopped', data.skipped_length)
|
|
218
|
+
)
|
|
219
|
+
)
|
|
220
|
+
);
|
|
221
|
+
if (data.stopped_length > 0) {
|
|
222
|
+
reloadPage(url, parentTaskID, dispatch);
|
|
223
|
+
}
|
|
224
|
+
} catch (error) {
|
|
225
|
+
handleErrorForceCancel(error, dispatch);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
};
|
|
229
|
+
|
|
230
|
+
export const bulkForceCancelBySearch = ({
|
|
231
|
+
query,
|
|
232
|
+
parentTaskID,
|
|
233
|
+
}) => async dispatch => {
|
|
234
|
+
dispatch({ type: TASKS_FORCE_CANCEL_REQUEST });
|
|
235
|
+
dispatch(
|
|
236
|
+
addToast(
|
|
237
|
+
infoToastData(
|
|
238
|
+
__('Canceling with force selected tasks, this might take a while')
|
|
239
|
+
)
|
|
240
|
+
)
|
|
241
|
+
);
|
|
242
|
+
await bulkBySearchRequest({
|
|
243
|
+
query,
|
|
244
|
+
path: BULK_FORCE_CANCEL_PATH,
|
|
245
|
+
parentTaskID,
|
|
246
|
+
});
|
|
247
|
+
};
|