foreman-tasks 4.1.6 → 5.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/.github/workflows/ruby_tests.yml +0 -1
- data/app/controllers/foreman_tasks/api/tasks_controller.rb +2 -2
- data/app/controllers/foreman_tasks/tasks_controller.rb +7 -6
- data/app/graphql/types/recurring_logic.rb +18 -0
- data/app/graphql/types/task.rb +25 -0
- data/app/graphql/types/triggering.rb +16 -0
- data/app/lib/actions/helpers/with_continuous_output.rb +1 -1
- data/app/lib/actions/middleware/watch_delegated_proxy_sub_tasks.rb +6 -2
- data/app/models/foreman_tasks/recurring_logic.rb +2 -0
- data/app/models/foreman_tasks/task/dynflow_task.rb +3 -8
- data/app/models/foreman_tasks/task.rb +28 -0
- data/app/models/foreman_tasks/triggering.rb +2 -0
- data/app/services/foreman_tasks/dashboard_table_filter.rb +56 -0
- data/foreman-tasks.gemspec +0 -1
- data/lib/foreman_tasks/continuous_output.rb +50 -0
- data/lib/foreman_tasks/engine.rb +6 -15
- data/lib/foreman_tasks/tasks/export_tasks.rake +46 -90
- data/lib/foreman_tasks/version.rb +1 -1
- data/lib/foreman_tasks.rb +2 -5
- data/test/controllers/api/tasks_controller_test.rb +0 -11
- data/test/graphql/queries/recurring_logic_test.rb +28 -0
- data/test/graphql/queries/recurring_logics_query_test.rb +30 -0
- data/test/graphql/queries/task_query_test.rb +33 -0
- data/test/graphql/queries/tasks_query_test.rb +31 -0
- data/test/unit/dashboard_table_filter_test.rb +77 -0
- data/test/unit/task_test.rb +39 -8
- data/webpack/ForemanTasks/Components/TaskActions/TaskActionHelpers.js +4 -11
- data/webpack/ForemanTasks/Components/TaskActions/TaskActionHelpers.test.js +5 -27
- data/webpack/ForemanTasks/Components/TasksTable/TasksTable.js +0 -8
- data/webpack/ForemanTasks/Components/TasksTable/TasksTableActions.js +1 -6
- data/webpack/ForemanTasks/Components/TasksTable/TasksTableHelpers.js +1 -2
- data/webpack/ForemanTasks/Components/TasksTable/TasksTablePage.js +11 -22
- data/webpack/ForemanTasks/Components/TasksTable/TasksTableReducer.js +16 -17
- data/webpack/ForemanTasks/Components/TasksTable/TasksTableSelectors.js +0 -3
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTableHelpers.test.js +1 -1
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTableReducer.test.js +1 -3
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTablePage.test.js.snap +2 -12
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTableReducer.test.js.snap +0 -5
- data/webpack/ForemanTasks/Components/TasksTable/formatters/__test__/__snapshots__/selectionHeaderCellFormatter.test.js.snap +0 -1
- data/webpack/ForemanTasks/Components/TasksTable/formatters/__test__/selectionHeaderCellFormatter.test.js +1 -1
- data/webpack/ForemanTasks/Components/TasksTable/formatters/selectionHeaderCellFormatter.js +0 -1
- data/webpack/ForemanTasks/Components/TasksTable/index.js +0 -2
- metadata +18 -27
- data/test/core/unit/dispatcher_test.rb +0 -43
- data/test/core/unit/runner_test.rb +0 -116
- data/test/core/unit/task_launcher_test.rb +0 -56
- data/test/foreman_tasks_core_test_helper.rb +0 -4
- data/test/unit/otp_manager_test.rb +0 -77
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'foreman_tasks_test_helper'
|
2
|
+
|
3
|
+
module Queries
|
4
|
+
class RecurringLogicsTest < GraphQLQueryTestCase
|
5
|
+
let(:query) do
|
6
|
+
<<-GRAPHQL
|
7
|
+
query {
|
8
|
+
recurringLogics {
|
9
|
+
nodes {
|
10
|
+
id
|
11
|
+
cronLine
|
12
|
+
}
|
13
|
+
}
|
14
|
+
}
|
15
|
+
GRAPHQL
|
16
|
+
end
|
17
|
+
|
18
|
+
let(:data) { result['data']['recurringLogics'] }
|
19
|
+
|
20
|
+
setup do
|
21
|
+
FactoryBot.create_list(:recurring_logic, 2)
|
22
|
+
end
|
23
|
+
|
24
|
+
test "should fetch recurring logics" do
|
25
|
+
assert_empty result['errors']
|
26
|
+
expected_count = ::ForemanTasks::RecurringLogic.count
|
27
|
+
assert_not_equal 0, expected_count
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'foreman_tasks_test_helper'
|
2
|
+
|
3
|
+
module Queries
|
4
|
+
class TaskQueryTest < GraphQLQueryTestCase
|
5
|
+
let(:query) do
|
6
|
+
<<-GRAPHQL
|
7
|
+
query (
|
8
|
+
$id: String!
|
9
|
+
) {
|
10
|
+
task(id: $id) {
|
11
|
+
id
|
12
|
+
action
|
13
|
+
result
|
14
|
+
}
|
15
|
+
}
|
16
|
+
GRAPHQL
|
17
|
+
end
|
18
|
+
|
19
|
+
let(:res) { 'inconclusive' }
|
20
|
+
let(:task) { FactoryBot.create(:some_task, :result => res) }
|
21
|
+
|
22
|
+
let(:global_id) { Foreman::GlobalId.for(task) }
|
23
|
+
let(:variables) { { id: global_id } }
|
24
|
+
let(:data) { result['data']['task'] }
|
25
|
+
|
26
|
+
test 'should fetch task data' do
|
27
|
+
assert_empty result['errors']
|
28
|
+
|
29
|
+
assert_equal global_id, data['id']
|
30
|
+
assert_equal task.result, data['result']
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'foreman_tasks_test_helper'
|
2
|
+
|
3
|
+
module Queries
|
4
|
+
class TasksQueryTest < GraphQLQueryTestCase
|
5
|
+
let(:query) do
|
6
|
+
<<-GRAPHQL
|
7
|
+
query {
|
8
|
+
tasks {
|
9
|
+
nodes {
|
10
|
+
id
|
11
|
+
action
|
12
|
+
result
|
13
|
+
}
|
14
|
+
}
|
15
|
+
}
|
16
|
+
GRAPHQL
|
17
|
+
end
|
18
|
+
|
19
|
+
let(:data) { result['data']['tasks'] }
|
20
|
+
|
21
|
+
setup do
|
22
|
+
FactoryBot.create_list(:some_task, 2)
|
23
|
+
end
|
24
|
+
|
25
|
+
test "should fetch recurring logics" do
|
26
|
+
assert_empty result['errors']
|
27
|
+
expected_count = ::ForemanTasks::Task.count
|
28
|
+
assert_not_equal 0, expected_count
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
require 'foreman_tasks_test_helper'
|
2
|
+
|
3
|
+
class DashboardTableFilterTest < ActiveSupport::TestCase
|
4
|
+
before do
|
5
|
+
::ForemanTasks::Task.delete_all
|
6
|
+
end
|
7
|
+
|
8
|
+
describe ForemanTasks::DashboardTableFilter do
|
9
|
+
before do
|
10
|
+
@tasks_builder = HistoryTasksBuilder.new
|
11
|
+
@scope = ForemanTasks::Task.all
|
12
|
+
@tasks_builder.build
|
13
|
+
end
|
14
|
+
|
15
|
+
let :subject do
|
16
|
+
ForemanTasks::DashboardTableFilter.new(@scope, params)
|
17
|
+
end
|
18
|
+
|
19
|
+
let :filtered_scope do
|
20
|
+
subject.scope
|
21
|
+
end
|
22
|
+
|
23
|
+
describe 'by result' do
|
24
|
+
let(:params) { { result: 'warning' } }
|
25
|
+
|
26
|
+
it 'filters' do
|
27
|
+
_(filtered_scope.count).must_equal @tasks_builder.distribution['stopped'][:by_result]['warning'][:total]
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe 'by state' do
|
32
|
+
let(:params) { { state: 'running' } }
|
33
|
+
|
34
|
+
it 'filters' do
|
35
|
+
_(filtered_scope.count).must_equal @tasks_builder.distribution['running'][:total]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe 'recent' do
|
40
|
+
let(:params) do
|
41
|
+
{ state: 'running',
|
42
|
+
time_horizon: 'H24',
|
43
|
+
time_mode: 'recent' }
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'filters' do
|
47
|
+
_(filtered_scope.count).must_equal @tasks_builder.distribution['running'][:recent]
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe 'recent week time horizon' do
|
52
|
+
let(:params) do
|
53
|
+
{ state: 'running',
|
54
|
+
time_horizon: 'week',
|
55
|
+
time_mode: 'recent' }
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'filters' do
|
59
|
+
_(filtered_scope.count).must_equal @tasks_builder.distribution['running'][:recent]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe 'older' do
|
64
|
+
let(:params) do
|
65
|
+
{ state: 'running',
|
66
|
+
time_horizon: 'H24',
|
67
|
+
time_mode: 'older' }
|
68
|
+
end
|
69
|
+
|
70
|
+
it 'filters' do
|
71
|
+
old_tasks_count = @tasks_builder.distribution['running'][:total] -
|
72
|
+
@tasks_builder.distribution['running'][:recent]
|
73
|
+
_(filtered_scope.count).must_equal old_tasks_count
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
data/test/unit/task_test.rb
CHANGED
@@ -296,12 +296,12 @@ class TasksTest < ActiveSupport::TestCase
|
|
296
296
|
end
|
297
297
|
|
298
298
|
describe 'search for resource_ids' do
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
resource_type = 'restype1'
|
299
|
+
label = 'label1'
|
300
|
+
resource_ids = [1, 2]
|
301
|
+
resource_type = 'restype1'
|
303
302
|
|
304
|
-
|
303
|
+
let(:task1_old) do
|
304
|
+
FactoryBot.create(
|
305
305
|
:task_with_links,
|
306
306
|
started_at: '2019-10-01 11:15:55',
|
307
307
|
ended_at: '2019-10-01 11:15:57',
|
@@ -309,7 +309,9 @@ class TasksTest < ActiveSupport::TestCase
|
|
309
309
|
label: label,
|
310
310
|
resource_type: resource_type
|
311
311
|
)
|
312
|
-
|
312
|
+
end
|
313
|
+
let(:task1_new) do
|
314
|
+
FactoryBot.create(
|
313
315
|
:task_with_links,
|
314
316
|
started_at: '2019-10-02 11:15:55',
|
315
317
|
ended_at: '2019-10-02 11:15:57',
|
@@ -317,7 +319,9 @@ class TasksTest < ActiveSupport::TestCase
|
|
317
319
|
label: label,
|
318
320
|
resource_type: resource_type
|
319
321
|
)
|
320
|
-
|
322
|
+
end
|
323
|
+
let(:task2) do
|
324
|
+
FactoryBot.create(
|
321
325
|
:task_with_links,
|
322
326
|
started_at: '2019-10-03 11:15:55',
|
323
327
|
ended_at: '2019-10-03 11:15:57',
|
@@ -325,7 +329,9 @@ class TasksTest < ActiveSupport::TestCase
|
|
325
329
|
label: label,
|
326
330
|
resource_type: resource_type
|
327
331
|
)
|
328
|
-
|
332
|
+
end
|
333
|
+
let(:task3) do
|
334
|
+
FactoryBot.create(
|
329
335
|
:task_with_links,
|
330
336
|
started_at: '2019-10-03 11:15:55',
|
331
337
|
ended_at: '2019-10-03 11:15:57',
|
@@ -333,6 +339,13 @@ class TasksTest < ActiveSupport::TestCase
|
|
333
339
|
label: label,
|
334
340
|
resource_type: 'another_type'
|
335
341
|
)
|
342
|
+
end
|
343
|
+
|
344
|
+
it 'finds tasks' do
|
345
|
+
task1_old
|
346
|
+
task1_new
|
347
|
+
task2
|
348
|
+
task3
|
336
349
|
|
337
350
|
result = ForemanTasks::Task.search_for(
|
338
351
|
"resource_id ^ (#{resource_ids.join(',')}) and resource_type = #{resource_type}"
|
@@ -343,5 +356,23 @@ class TasksTest < ActiveSupport::TestCase
|
|
343
356
|
assert_includes result, task2
|
344
357
|
assert_not_includes result, task3
|
345
358
|
end
|
359
|
+
|
360
|
+
it 'finds latest task for each resource_id' do
|
361
|
+
task1_old
|
362
|
+
task1_new
|
363
|
+
task2
|
364
|
+
task3
|
365
|
+
|
366
|
+
result = ForemanTasks::Task.latest_tasks_by_resource_ids(
|
367
|
+
label,
|
368
|
+
resource_type,
|
369
|
+
resource_ids
|
370
|
+
)
|
371
|
+
assert_equal 2, result.length
|
372
|
+
assert_equal resource_ids, result.keys.sort
|
373
|
+
assert_equal task1_new, result[1]
|
374
|
+
assert_equal task2, result[2]
|
375
|
+
assert_not_includes result.values, task3
|
376
|
+
end
|
346
377
|
end
|
347
378
|
end
|
@@ -15,29 +15,22 @@ export const convertDashboardQuery = query => {
|
|
15
15
|
state,
|
16
16
|
result,
|
17
17
|
search,
|
18
|
-
...rest
|
19
18
|
} = query;
|
20
19
|
|
21
20
|
const hours = timeToHoursNumber(timeHorizon);
|
22
21
|
const timestamp = new Date(new Date() - hours * 60 * 60 * 1000);
|
23
22
|
let dashboardTime = '';
|
24
23
|
const stateQuery = state ? `state=${state}` : '';
|
25
|
-
|
26
|
-
if (result === 'other') {
|
27
|
-
resultQuery = 'result ^ (pending, cancelled)';
|
28
|
-
} else {
|
29
|
-
resultQuery = result ? `result=${result}` : '';
|
30
|
-
}
|
24
|
+
const resultQuery = result ? `result=${result}` : '';
|
31
25
|
if (timeMode === TASKS_DASHBOARD_JS_QUERY_MODES.RECENT) {
|
32
|
-
dashboardTime = `state_updated_at>${timestamp.toISOString()} or
|
26
|
+
dashboardTime = `(state_updated_at>${timestamp.toISOString()} or state_updated_at = NULL)`;
|
33
27
|
} else if (timeMode === TASKS_DASHBOARD_JS_QUERY_MODES.OLDER) {
|
34
|
-
dashboardTime = `state_updated_at
|
28
|
+
dashboardTime = `(state_updated_at>${timestamp.toISOString()})`;
|
35
29
|
}
|
36
30
|
const newQuery = [stateQuery, resultQuery, search, dashboardTime]
|
37
31
|
.filter(Boolean)
|
38
|
-
.map(q => `(${q})`)
|
39
32
|
.join(' and ');
|
40
|
-
return newQuery
|
33
|
+
return newQuery;
|
41
34
|
};
|
42
35
|
|
43
36
|
export const resumeToastInfo = {
|
@@ -27,18 +27,9 @@ describe('convertDashboardQuery', () => {
|
|
27
27
|
result: 'error',
|
28
28
|
search: 'action~job',
|
29
29
|
};
|
30
|
-
|
31
|
-
'
|
32
|
-
|
33
|
-
expect(convertDashboardQuery(query)).toEqual({ search: expected });
|
34
|
-
|
35
|
-
const query2 = {
|
36
|
-
...query,
|
37
|
-
time_mode: TASKS_DASHBOARD_JS_QUERY_MODES.OLDER,
|
38
|
-
};
|
39
|
-
const expected2 =
|
40
|
-
'(state=stopped) and (result=error) and (action~job) and (state_updated_at<=2020-05-01T11:01:58.135Z)';
|
41
|
-
expect(convertDashboardQuery(query2)).toEqual({ search: expected2 });
|
30
|
+
expect(convertDashboardQuery(query)).toEqual(
|
31
|
+
'state=stopped and result=error and action~job and (state_updated_at>2020-05-01T11:01:58.135Z or state_updated_at = NULL)'
|
32
|
+
);
|
42
33
|
// Cleanup
|
43
34
|
global.Date = realDate;
|
44
35
|
});
|
@@ -46,23 +37,10 @@ describe('convertDashboardQuery', () => {
|
|
46
37
|
const query = {
|
47
38
|
search: 'action~job',
|
48
39
|
};
|
49
|
-
expect(convertDashboardQuery(query)).toEqual(
|
40
|
+
expect(convertDashboardQuery(query)).toEqual('action~job');
|
50
41
|
});
|
51
42
|
it('convertDashboardQuery should work with no query', () => {
|
52
43
|
const query = {};
|
53
|
-
expect(convertDashboardQuery(query)).toEqual(
|
54
|
-
});
|
55
|
-
it('convertDashboardQuery should not override unknown keys', () => {
|
56
|
-
const query = { weather: 'nice', search: 'okay', number: 7 };
|
57
|
-
expect(convertDashboardQuery(query)).toEqual({
|
58
|
-
...query,
|
59
|
-
search: '(okay)',
|
60
|
-
});
|
61
|
-
});
|
62
|
-
it('convertDashboardQuery should expand other result', () => {
|
63
|
-
const query = { result: 'other' };
|
64
|
-
expect(convertDashboardQuery(query)).toEqual({
|
65
|
-
search: '(result ^ (pending, cancelled))',
|
66
|
-
});
|
44
|
+
expect(convertDashboardQuery(query)).toEqual('');
|
67
45
|
});
|
68
46
|
});
|
@@ -27,7 +27,6 @@ const TasksTable = ({
|
|
27
27
|
openClickedModal,
|
28
28
|
openModal,
|
29
29
|
allRowsSelected,
|
30
|
-
permissions,
|
31
30
|
}) => {
|
32
31
|
const { search, pathname } = history.location;
|
33
32
|
const url = pathname + search;
|
@@ -60,7 +59,6 @@ const TasksTable = ({
|
|
60
59
|
},
|
61
60
|
isSelected: ({ rowData }) =>
|
62
61
|
allRowsSelected || selectedRows.includes(rowData.id),
|
63
|
-
permissions,
|
64
62
|
};
|
65
63
|
};
|
66
64
|
|
@@ -164,9 +162,6 @@ TasksTable.propTypes = {
|
|
164
162
|
unselectRow: PropTypes.func.isRequired,
|
165
163
|
openModal: PropTypes.func.isRequired,
|
166
164
|
allRowsSelected: PropTypes.bool,
|
167
|
-
permissions: PropTypes.shape({
|
168
|
-
edit: PropTypes.bool,
|
169
|
-
}),
|
170
165
|
};
|
171
166
|
|
172
167
|
TasksTable.defaultProps = {
|
@@ -178,9 +173,6 @@ TasksTable.defaultProps = {
|
|
178
173
|
},
|
179
174
|
selectedRows: [],
|
180
175
|
allRowsSelected: false,
|
181
|
-
permissions: {
|
182
|
-
edit: false,
|
183
|
-
},
|
184
176
|
};
|
185
177
|
|
186
178
|
export default TasksTable;
|
@@ -18,14 +18,9 @@ import {
|
|
18
18
|
resumeTaskRequest,
|
19
19
|
forceCancelTaskRequest,
|
20
20
|
} from '../TaskActions';
|
21
|
-
import { convertDashboardQuery } from '../TaskActions/TaskActionHelpers';
|
22
21
|
|
23
22
|
export const getTableItems = url =>
|
24
|
-
getTableItemsAction(
|
25
|
-
TASKS_TABLE_ID,
|
26
|
-
convertDashboardQuery(getURIQuery(url)),
|
27
|
-
getApiPathname(url)
|
28
|
-
);
|
23
|
+
getTableItemsAction(TASKS_TABLE_ID, getURIQuery(url), getApiPathname(url));
|
29
24
|
|
30
25
|
export const reloadPage = (url, parentTaskID) => dispatch => {
|
31
26
|
dispatch(getTableItems(url));
|
@@ -2,7 +2,6 @@ import URI from 'urijs';
|
|
2
2
|
import { translate as __, documentLocale } from 'foremanReact/common/I18n';
|
3
3
|
import humanizeDuration from 'humanize-duration';
|
4
4
|
import { isoCompatibleDate } from 'foremanReact/common/helpers';
|
5
|
-
import { convertDashboardQuery } from '../TaskActions/TaskActionHelpers';
|
6
5
|
|
7
6
|
export const updateURlQuery = (query, history) => {
|
8
7
|
const uri = new URI(history.location.pathname + history.location.search);
|
@@ -18,7 +17,7 @@ export const getApiPathname = url => {
|
|
18
17
|
export const getCSVurl = (path, query) => {
|
19
18
|
let url = new URI(path);
|
20
19
|
url = url.pathname(`${url.pathname()}.csv`);
|
21
|
-
url.addSearch(
|
20
|
+
url.addSearch(query);
|
22
21
|
return url.toString();
|
23
22
|
};
|
24
23
|
|
@@ -77,14 +77,11 @@ const TasksTablePage = ({
|
|
77
77
|
</Button>
|
78
78
|
{props.status === STATUS.PENDING && <Spinner size="md" loading />}
|
79
79
|
<ExportButton
|
80
|
-
url={getCSVurl(
|
80
|
+
url={getCSVurl(url, uriQuery)}
|
81
81
|
title={__('Export All')}
|
82
82
|
/>
|
83
83
|
<ActionSelectButton
|
84
|
-
disabled={
|
85
|
-
!props.permissions.edit ||
|
86
|
-
!(props.selectedRows.length || props.allRowsSelected)
|
87
|
-
}
|
84
|
+
disabled={!(props.selectedRows.length || props.allRowsSelected)}
|
88
85
|
onCancel={() => openModal(CANCEL_SELECTED_MODAL)}
|
89
86
|
onResume={() => openModal(RESUME_SELECTED_MODAL)}
|
90
87
|
onForceCancel={() => openModal(FORCE_UNLOCK_SELECTED_MODAL)}
|
@@ -97,17 +94,15 @@ const TasksTablePage = ({
|
|
97
94
|
}
|
98
95
|
>
|
99
96
|
<React.Fragment>
|
100
|
-
{props.
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
/>
|
110
|
-
)}
|
97
|
+
{showSelectAll && props.itemCount >= props.pagination.perPage && (
|
98
|
+
<SelectAllAlert
|
99
|
+
itemCount={props.itemCount}
|
100
|
+
perPage={props.pagination.perPage}
|
101
|
+
selectAllRows={selectAllRows}
|
102
|
+
unselectAllRows={props.unselectAllRows}
|
103
|
+
allRowsSelected={props.allRowsSelected}
|
104
|
+
/>
|
105
|
+
)}
|
111
106
|
<TasksTable history={history} {...props} openModal={openModal} />
|
112
107
|
</React.Fragment>
|
113
108
|
</PageLayout>
|
@@ -136,9 +131,6 @@ TasksTablePage.propTypes = {
|
|
136
131
|
showSelectAll: PropTypes.bool,
|
137
132
|
unselectAllRows: PropTypes.func.isRequired,
|
138
133
|
reloadPage: PropTypes.func.isRequired,
|
139
|
-
permissions: PropTypes.shape({
|
140
|
-
edit: PropTypes.bool,
|
141
|
-
}),
|
142
134
|
};
|
143
135
|
|
144
136
|
TasksTablePage.defaultProps = {
|
@@ -154,9 +146,6 @@ TasksTablePage.defaultProps = {
|
|
154
146
|
createHeader: () => __('Tasks'),
|
155
147
|
showSelectAll: false,
|
156
148
|
modalID: '',
|
157
|
-
permissions: {
|
158
|
-
edit: false,
|
159
|
-
},
|
160
149
|
};
|
161
150
|
|
162
151
|
export default TasksTablePage;
|
@@ -19,13 +19,8 @@ const initialState = Immutable({
|
|
19
19
|
|
20
20
|
export const TasksTableQueryReducer = (state = initialState, action) => {
|
21
21
|
const { type, payload, response } = action;
|
22
|
-
const {
|
23
|
-
|
24
|
-
page,
|
25
|
-
per_page: perPageString,
|
26
|
-
action_name: actionName,
|
27
|
-
can_edit: canEdit,
|
28
|
-
} = response || {};
|
22
|
+
const { subtotal, page, per_page: perPageString, action_name: actionName } =
|
23
|
+
response || {};
|
29
24
|
const ACTION_TYPES = createTableActionTypes(TASKS_TABLE_ID);
|
30
25
|
switch (type) {
|
31
26
|
case SELECT_ALL_ROWS:
|
@@ -39,22 +34,26 @@ export const TasksTableQueryReducer = (state = initialState, action) => {
|
|
39
34
|
perPage: Number(perPageString),
|
40
35
|
},
|
41
36
|
selectedRows: [],
|
42
|
-
permissions: {
|
43
|
-
edit: canEdit,
|
44
|
-
},
|
45
37
|
});
|
46
38
|
case SELECT_ROWS:
|
47
39
|
return state.set('selectedRows', union(payload, state.selectedRows));
|
48
40
|
case OPEN_SELECT_ALL:
|
49
41
|
return state.set('showSelectAll', true);
|
50
42
|
case UNSELECT_ROWS:
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
43
|
+
if (state.allRowsSelected) {
|
44
|
+
// User can unselect rows if only the page rows are selected
|
45
|
+
return state
|
46
|
+
.set(
|
47
|
+
'selectedRows',
|
48
|
+
payload.results.map(row => row.id).filter(row => row !== payload.id)
|
49
|
+
)
|
50
|
+
.set('allRowsSelected', false)
|
51
|
+
.set('showSelectAll', false);
|
52
|
+
}
|
53
|
+
return state.set(
|
54
|
+
'selectedRows',
|
55
|
+
state.selectedRows.filter(row => row !== payload.id)
|
56
|
+
);
|
58
57
|
case UNSELECT_ALL_ROWS:
|
59
58
|
return state
|
60
59
|
.set('selectedRows', [])
|
@@ -24,9 +24,6 @@ export const selectActionName = state =>
|
|
24
24
|
export const selectSelectedRows = state =>
|
25
25
|
selectTasksTableQuery(state).selectedRows || [];
|
26
26
|
|
27
|
-
export const selectPermissions = state =>
|
28
|
-
selectTasksTableQuery(state).permissions || { edit: false };
|
29
|
-
|
30
27
|
export const selectResults = createSelector(
|
31
28
|
selectTasksTableContent,
|
32
29
|
({ results }) =>
|
@@ -32,7 +32,7 @@ describe('getCSVurl', () => {
|
|
32
32
|
const url = '/foreman_tasks/tasks';
|
33
33
|
const query = { state: 'stopped' };
|
34
34
|
expect(getCSVurl(url, query)).toEqual(
|
35
|
-
'/foreman_tasks/tasks.csv?
|
35
|
+
'/foreman_tasks/tasks.csv?state=stopped'
|
36
36
|
);
|
37
37
|
});
|
38
38
|
it('should return currect url for subtasks', () => {
|
@@ -73,9 +73,7 @@ const fixtures = {
|
|
73
73
|
},
|
74
74
|
},
|
75
75
|
'should handle UNSELECT_ROWS with all rows selected': {
|
76
|
-
state: Immutable({
|
77
|
-
tasksTableQuery: { allRowsSelected: true, selectedRows: [3, 4, 5] },
|
78
|
-
}),
|
76
|
+
state: Immutable({ tasksTableQuery: { allRowsSelected: true } }),
|
79
77
|
action: {
|
80
78
|
type: UNSELECT_ROWS,
|
81
79
|
payload: { id: [4], results: [{ id: 3 }, { id: 4 }, { id: 5 }] },
|
data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTablePage.test.js.snap
CHANGED
@@ -92,7 +92,7 @@ exports[`TasksTablePage rendering render with Breadcrubs and edit permissions 1`
|
|
92
92
|
/>
|
93
93
|
<ExportButton
|
94
94
|
title="Export All"
|
95
|
-
url="/foreman_tasks/tasks.csv?
|
95
|
+
url="/foreman_tasks/tasks.csv?action=%22some-name%22&state=stopped"
|
96
96
|
/>
|
97
97
|
<ActionSelectButton
|
98
98
|
disabled={true}
|
@@ -126,11 +126,6 @@ exports[`TasksTablePage rendering render with Breadcrubs and edit permissions 1`
|
|
126
126
|
}
|
127
127
|
}
|
128
128
|
parentTaskID={null}
|
129
|
-
permissions={
|
130
|
-
Object {
|
131
|
-
"edit": false,
|
132
|
-
}
|
133
|
-
}
|
134
129
|
reloadPage={[MockFunction]}
|
135
130
|
results={
|
136
131
|
Array [
|
@@ -232,7 +227,7 @@ exports[`TasksTablePage rendering render with minimal props 1`] = `
|
|
232
227
|
/>
|
233
228
|
<ExportButton
|
234
229
|
title="Export All"
|
235
|
-
url="/foreman_tasks/tasks.csv?
|
230
|
+
url="/foreman_tasks/tasks.csv?action=%22some-name%22&state=stopped"
|
236
231
|
/>
|
237
232
|
<ActionSelectButton
|
238
233
|
disabled={true}
|
@@ -266,11 +261,6 @@ exports[`TasksTablePage rendering render with minimal props 1`] = `
|
|
266
261
|
}
|
267
262
|
}
|
268
263
|
parentTaskID={null}
|
269
|
-
permissions={
|
270
|
-
Object {
|
271
|
-
"edit": false,
|
272
|
-
}
|
273
|
-
}
|
274
264
|
reloadPage={[MockFunction]}
|
275
265
|
results={
|
276
266
|
Array [
|
@@ -59,9 +59,6 @@ Object {
|
|
59
59
|
"page": 3,
|
60
60
|
"perPage": 12,
|
61
61
|
},
|
62
|
-
"permissions": Object {
|
63
|
-
"edit": undefined,
|
64
|
-
},
|
65
62
|
"selectedRows": Array [],
|
66
63
|
},
|
67
64
|
}
|
@@ -80,9 +77,7 @@ Object {
|
|
80
77
|
exports[`TasksTableReducer reducer should handle UNSELECT_ROWS 1`] = `
|
81
78
|
Object {
|
82
79
|
"tasksTableQuery": Object {
|
83
|
-
"allRowsSelected": false,
|
84
80
|
"selectedRows": Array [],
|
85
|
-
"showSelectAll": false,
|
86
81
|
},
|
87
82
|
}
|
88
83
|
`;
|
@@ -16,7 +16,6 @@ import {
|
|
16
16
|
selectAllRowsSelected,
|
17
17
|
selectShowSelectAll,
|
18
18
|
selectModalID,
|
19
|
-
selectPermissions,
|
20
19
|
} from './TasksTableSelectors';
|
21
20
|
|
22
21
|
const mapStateToProps = state => ({
|
@@ -31,7 +30,6 @@ const mapStateToProps = state => ({
|
|
31
30
|
allRowsSelected: selectAllRowsSelected(state),
|
32
31
|
showSelectAll: selectShowSelectAll(state),
|
33
32
|
modalID: selectModalID(state),
|
34
|
-
permissions: selectPermissions(state),
|
35
33
|
});
|
36
34
|
|
37
35
|
const mapDispatchToProps = dispatch =>
|