foreman-tasks 4.1.2 → 4.1.3
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 +1 -1
- data/app/controllers/foreman_tasks/tasks_controller.rb +3 -2
- data/app/lib/actions/middleware/watch_delegated_proxy_sub_tasks.rb +2 -6
- data/app/models/foreman_tasks/task/dynflow_task.rb +8 -3
- data/lib/foreman_tasks/tasks/export_tasks.rake +90 -46
- data/lib/foreman_tasks/version.rb +1 -1
- data/webpack/ForemanTasks/Components/TaskActions/TaskActionHelpers.js +11 -4
- data/webpack/ForemanTasks/Components/TaskActions/TaskActionHelpers.test.js +27 -5
- data/webpack/ForemanTasks/Components/TasksTable/TasksTableActions.js +6 -1
- data/webpack/ForemanTasks/Components/TasksTable/TasksTableHelpers.js +2 -1
- data/webpack/ForemanTasks/Components/TasksTable/TasksTablePage.js +1 -1
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTableHelpers.test.js +1 -1
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTablePage.test.js.snap +2 -2
- metadata +2 -5
- data/app/services/foreman_tasks/dashboard_table_filter.rb +0 -56
- data/test/unit/dashboard_table_filter_test.rb +0 -77
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ba89e76b07357c27678169c5350b13a80ea346896e681e7061da8c9ff5c6d2ce
|
4
|
+
data.tar.gz: c0a597c5a7db439fcd6627460b0fa91ed9e5bf0ef2d5308f356d35582c141b9d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3f873f26387eb89860543bca5f888b017c2ac692c986873b97b48506f30429172d49e926450937262a9dcb06c26c45d7eefabdb7f3cce0b8c70ce6786ea7e4ad
|
7
|
+
data.tar.gz: b021241e11f9db347960eb55e2497112cf996f1e77e48d92f593fa47b735c0268532ec61e2779bd35fc01768178037eaedf8248b59dfc178031dd56fb1340b6f
|
@@ -192,7 +192,7 @@ module ForemanTasks
|
|
192
192
|
params[:order] = "#{ordering_params[:sort_by]} #{ordering_params[:sort_order]}"
|
193
193
|
end
|
194
194
|
params[:order] ||= 'started_at DESC'
|
195
|
-
@tasks =
|
195
|
+
@tasks = resource_scope_for_index.order(params[:order].to_s)
|
196
196
|
end
|
197
197
|
|
198
198
|
def search_options
|
@@ -127,8 +127,9 @@ module ForemanTasks
|
|
127
127
|
end
|
128
128
|
|
129
129
|
def filter(scope, paginate: true)
|
130
|
-
|
131
|
-
|
130
|
+
search = current_taxonomy_search
|
131
|
+
search = [search, params[:search]].select(&:present?).join(' AND ')
|
132
|
+
scope = scope.search_for(search, order: params[:order])
|
132
133
|
scope = scope.paginate(page: params[:page], per_page: params[:per_page]) if paginate
|
133
134
|
scope.distinct
|
134
135
|
end
|
@@ -20,9 +20,7 @@ module Actions
|
|
20
20
|
private
|
21
21
|
|
22
22
|
def set_clock
|
23
|
-
action.
|
24
|
-
POLL_INTERVAL,
|
25
|
-
CheckOnProxyActions
|
23
|
+
action.plan_event(CheckOnProxyActions, POLL_INTERVAL, optional: true)
|
26
24
|
end
|
27
25
|
|
28
26
|
def check_triggered
|
@@ -44,9 +42,7 @@ module Actions
|
|
44
42
|
|
45
43
|
def notify(event, tasks)
|
46
44
|
tasks.each do |task|
|
47
|
-
action.
|
48
|
-
task.step_id,
|
49
|
-
event
|
45
|
+
action.plan_event(event, execution_plan_id: task.execution_plan_id, step_id: task.step_id)
|
50
46
|
end
|
51
47
|
end
|
52
48
|
|
@@ -140,12 +140,17 @@ module ForemanTasks
|
|
140
140
|
|
141
141
|
def main_action
|
142
142
|
return @main_action if defined?(@main_action)
|
143
|
+
|
144
|
+
@main_action = execution_plan && execution_plan.root_plan_step.try(:action, execution_plan)
|
143
145
|
if active_job?
|
144
146
|
job_data = active_job_data
|
145
|
-
|
146
|
-
|
147
|
-
|
147
|
+
begin
|
148
|
+
@main_action = active_job_action(job_data['job_class'], job_data['arguments'])
|
149
|
+
rescue => e
|
150
|
+
Foreman::Logging.exception("Failed to load ActiveJob for task #{id}", e, :logger => 'foreman-tasks')
|
151
|
+
end
|
148
152
|
end
|
153
|
+
@main_action
|
149
154
|
end
|
150
155
|
|
151
156
|
# The class for ActiveJob jobs in Dynflow, JobWrapper is not expected to
|
@@ -12,7 +12,7 @@ namespace :foreman_tasks do
|
|
12
12
|
|
13
13
|
* TASK_SEARCH : scoped search filter (example: 'label = "Actions::Foreman::Host::ImportFacts"')
|
14
14
|
* TASK_FILE : file to export to
|
15
|
-
* TASK_FORMAT : format to use for the export (either html or csv)
|
15
|
+
* TASK_FORMAT : format to use for the export (either html, html-dir or csv)
|
16
16
|
* TASK_DAYS : number of days to go back
|
17
17
|
|
18
18
|
If TASK_SEARCH is not defined, it defaults to all tasks in the past 7 days and
|
@@ -185,23 +185,27 @@ namespace :foreman_tasks do
|
|
185
185
|
end
|
186
186
|
|
187
187
|
class PageHelper
|
188
|
-
def self.pagify(template)
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
#{template}
|
202
|
-
<body>
|
203
|
-
</html>
|
188
|
+
def self.pagify(io, template = nil)
|
189
|
+
io.write <<~HTML
|
190
|
+
<html>
|
191
|
+
<head>
|
192
|
+
<title>Dynflow Console</title>
|
193
|
+
<script src="jquery.js"></script>
|
194
|
+
<link rel="stylesheet" type="text/css" href="bootstrap.css">
|
195
|
+
<link rel="stylesheet" type="text/css" href="application.css">
|
196
|
+
<script src="bootstrap.js"></script>
|
197
|
+
<script src="run_prettify.js"></script>
|
198
|
+
<script src="application.js"></script>
|
199
|
+
</head>
|
200
|
+
<body>
|
204
201
|
HTML
|
202
|
+
if block_given?
|
203
|
+
yield io
|
204
|
+
else
|
205
|
+
io.write template
|
206
|
+
end
|
207
|
+
ensure
|
208
|
+
io.write '</body></html>'
|
205
209
|
end
|
206
210
|
|
207
211
|
def self.copy_assets(tmp_dir)
|
@@ -216,13 +220,64 @@ namespace :foreman_tasks do
|
|
216
220
|
end
|
217
221
|
end
|
218
222
|
|
219
|
-
def self.
|
220
|
-
|
221
|
-
|
222
|
-
|
223
|
-
|
223
|
+
def self.generate_with_index(io)
|
224
|
+
io.write '<div><table class="table">'
|
225
|
+
yield io
|
226
|
+
ensure
|
227
|
+
io.write '</table></div>'
|
228
|
+
end
|
229
|
+
|
230
|
+
def self.generate_index_entry(io, task)
|
231
|
+
io << <<~HTML
|
232
|
+
<tr>
|
233
|
+
<td><a href=\"#{task.id}.html\">#{task.label}</a></td>
|
234
|
+
<td>#{task.started_at}</td>
|
235
|
+
<td>#{task.state}</td>
|
236
|
+
<td>#{task.result}</td>
|
237
|
+
</tr>
|
238
|
+
HTML
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
def csv_export(export_filename, tasks)
|
243
|
+
CSV.open(export_filename, 'wb') do |csv|
|
244
|
+
csv << %w[id state type label result parent_task_id started_at ended_at]
|
245
|
+
tasks.find_each do |task|
|
246
|
+
csv << [task.id, task.state, task.type, task.label, task.result,
|
247
|
+
task.parent_task_id, task.started_at, task.ended_at]
|
224
248
|
end
|
225
|
-
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
def html_export(workdir, tasks)
|
253
|
+
PageHelper.copy_assets(workdir)
|
254
|
+
|
255
|
+
renderer = TaskRender.new
|
256
|
+
total = tasks.count
|
257
|
+
index = File.open(File.join(workdir, 'index.html'), 'w')
|
258
|
+
|
259
|
+
File.open(File.join(workdir, 'index.html'), 'w') do |index|
|
260
|
+
PageHelper.pagify(index) do |io|
|
261
|
+
PageHelper.generate_with_index(io) do |index|
|
262
|
+
tasks.find_each.each_with_index do |task, count|
|
263
|
+
File.open(File.join(workdir, "#{task.id}.html"), 'w') { |file| PageHelper.pagify(file, renderer.render_task(task)) }
|
264
|
+
PageHelper.generate_index_entry(index, task)
|
265
|
+
puts "#{count + 1}/#{total}"
|
266
|
+
end
|
267
|
+
end
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
271
|
+
|
272
|
+
def generate_filename(format)
|
273
|
+
base = "/tmp/task-export-#{Time.now.to_i}"
|
274
|
+
case format
|
275
|
+
when 'html'
|
276
|
+
base + '.tar.gz'
|
277
|
+
when 'csv'
|
278
|
+
base + '.csv'
|
279
|
+
when 'html-dir'
|
280
|
+
base
|
226
281
|
end
|
227
282
|
end
|
228
283
|
|
@@ -239,36 +294,25 @@ namespace :foreman_tasks do
|
|
239
294
|
end
|
240
295
|
|
241
296
|
format = ENV['TASK_FORMAT'] || 'html'
|
242
|
-
export_filename = ENV['TASK_FILE'] ||
|
297
|
+
export_filename = ENV['TASK_FILE'] || generate_filename(format)
|
243
298
|
|
244
|
-
tasks = ForemanTasks::Task.search_for(filter)
|
299
|
+
tasks = ForemanTasks::Task.search_for(filter).order(:started_at => :desc)
|
245
300
|
|
246
301
|
puts _("Exporting all tasks matching filter #{filter}")
|
247
302
|
puts _("Gathering #{tasks.count} tasks.")
|
248
|
-
|
303
|
+
case format
|
304
|
+
when 'html'
|
249
305
|
Dir.mktmpdir('task-export') do |tmp_dir|
|
250
|
-
|
251
|
-
|
252
|
-
renderer = TaskRender.new
|
253
|
-
total = tasks.count
|
254
|
-
|
255
|
-
tasks.find_each.with_index do |task, count|
|
256
|
-
File.open(File.join(tmp_dir, "#{task.id}.html"), 'w') { |file| file.write(PageHelper.pagify(renderer.render_task(task))) }
|
257
|
-
puts "#{count + 1}/#{total}"
|
258
|
-
end
|
259
|
-
|
260
|
-
File.open(File.join(tmp_dir, 'index.html'), 'w') { |file| file.write(PageHelper.pagify(PageHelper.generate_index(tasks))) }
|
261
|
-
|
306
|
+
html_export(tmp_dir, tasks)
|
262
307
|
system("tar", "czf", export_filename, tmp_dir)
|
263
308
|
end
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
end
|
309
|
+
when 'html-dir'
|
310
|
+
FileUtils.mkdir_p(export_filename)
|
311
|
+
html_export(export_filename, tasks)
|
312
|
+
when 'csv'
|
313
|
+
csv_export(export_filename, tasks)
|
314
|
+
else
|
315
|
+
raise "Unkonwn export format '#{format}'"
|
272
316
|
end
|
273
317
|
|
274
318
|
puts "Created #{export_filename}"
|
@@ -15,22 +15,29 @@ export const convertDashboardQuery = query => {
|
|
15
15
|
state,
|
16
16
|
result,
|
17
17
|
search,
|
18
|
+
...rest
|
18
19
|
} = query;
|
19
20
|
|
20
21
|
const hours = timeToHoursNumber(timeHorizon);
|
21
22
|
const timestamp = new Date(new Date() - hours * 60 * 60 * 1000);
|
22
23
|
let dashboardTime = '';
|
23
24
|
const stateQuery = state ? `state=${state}` : '';
|
24
|
-
|
25
|
+
let resultQuery = '';
|
26
|
+
if (result === 'other') {
|
27
|
+
resultQuery = 'result ^ (pending, cancelled)';
|
28
|
+
} else {
|
29
|
+
resultQuery = result ? `result=${result}` : '';
|
30
|
+
}
|
25
31
|
if (timeMode === TASKS_DASHBOARD_JS_QUERY_MODES.RECENT) {
|
26
|
-
dashboardTime = `
|
32
|
+
dashboardTime = `state_updated_at>${timestamp.toISOString()} or null? state_updated_at`;
|
27
33
|
} else if (timeMode === TASKS_DASHBOARD_JS_QUERY_MODES.OLDER) {
|
28
|
-
dashboardTime = `
|
34
|
+
dashboardTime = `state_updated_at<=${timestamp.toISOString()}`;
|
29
35
|
}
|
30
36
|
const newQuery = [stateQuery, resultQuery, search, dashboardTime]
|
31
37
|
.filter(Boolean)
|
38
|
+
.map(q => `(${q})`)
|
32
39
|
.join(' and ');
|
33
|
-
return newQuery;
|
40
|
+
return newQuery ? { search: newQuery, ...rest } : rest;
|
34
41
|
};
|
35
42
|
|
36
43
|
export const resumeToastInfo = {
|
@@ -27,9 +27,18 @@ describe('convertDashboardQuery', () => {
|
|
27
27
|
result: 'error',
|
28
28
|
search: 'action~job',
|
29
29
|
};
|
30
|
-
|
31
|
-
'state=stopped and result=error and action~job and (state_updated_at>2020-05-01T11:01:58.135Z or state_updated_at
|
32
|
-
|
30
|
+
const expected =
|
31
|
+
'(state=stopped) and (result=error) and (action~job) and (state_updated_at>2020-05-01T11:01:58.135Z or null? state_updated_at)';
|
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 });
|
33
42
|
// Cleanup
|
34
43
|
global.Date = realDate;
|
35
44
|
});
|
@@ -37,10 +46,23 @@ describe('convertDashboardQuery', () => {
|
|
37
46
|
const query = {
|
38
47
|
search: 'action~job',
|
39
48
|
};
|
40
|
-
expect(convertDashboardQuery(query)).toEqual('action~job');
|
49
|
+
expect(convertDashboardQuery(query)).toEqual({ search: '(action~job)' });
|
41
50
|
});
|
42
51
|
it('convertDashboardQuery should work with no query', () => {
|
43
52
|
const query = {};
|
44
|
-
expect(convertDashboardQuery(query)).toEqual(
|
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
|
+
});
|
45
67
|
});
|
46
68
|
});
|
@@ -18,9 +18,14 @@ import {
|
|
18
18
|
resumeTaskRequest,
|
19
19
|
forceCancelTaskRequest,
|
20
20
|
} from '../TaskActions';
|
21
|
+
import { convertDashboardQuery } from '../TaskActions/TaskActionHelpers';
|
21
22
|
|
22
23
|
export const getTableItems = url =>
|
23
|
-
getTableItemsAction(
|
24
|
+
getTableItemsAction(
|
25
|
+
TASKS_TABLE_ID,
|
26
|
+
convertDashboardQuery(getURIQuery(url)),
|
27
|
+
getApiPathname(url)
|
28
|
+
);
|
24
29
|
|
25
30
|
export const reloadPage = (url, parentTaskID) => dispatch => {
|
26
31
|
dispatch(getTableItems(url));
|
@@ -2,6 +2,7 @@ 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';
|
5
6
|
|
6
7
|
export const updateURlQuery = (query, history) => {
|
7
8
|
const uri = new URI(history.location.pathname + history.location.search);
|
@@ -17,7 +18,7 @@ export const getApiPathname = url => {
|
|
17
18
|
export const getCSVurl = (path, query) => {
|
18
19
|
let url = new URI(path);
|
19
20
|
url = url.pathname(`${url.pathname()}.csv`);
|
20
|
-
url.addSearch(query);
|
21
|
+
url.addSearch(convertDashboardQuery(query));
|
21
22
|
return url.toString();
|
22
23
|
};
|
23
24
|
|
@@ -77,7 +77,7 @@ const TasksTablePage = ({
|
|
77
77
|
</Button>
|
78
78
|
{props.status === STATUS.PENDING && <Spinner size="md" loading />}
|
79
79
|
<ExportButton
|
80
|
-
url={getCSVurl(
|
80
|
+
url={getCSVurl(history.location.pathname, uriQuery)}
|
81
81
|
title={__('Export All')}
|
82
82
|
/>
|
83
83
|
<ActionSelectButton
|
@@ -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?search=%28state%3Dstopped%29'
|
36
36
|
);
|
37
37
|
});
|
38
38
|
it('should return currect url for subtasks', () => {
|
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?search=%28state%3Dstopped%29"
|
96
96
|
/>
|
97
97
|
<ActionSelectButton
|
98
98
|
disabled={true}
|
@@ -227,7 +227,7 @@ exports[`TasksTablePage rendering render with minimal props 1`] = `
|
|
227
227
|
/>
|
228
228
|
<ExportButton
|
229
229
|
title="Export All"
|
230
|
-
url="/foreman_tasks/tasks.csv?
|
230
|
+
url="/foreman_tasks/tasks.csv?search=%28state%3Dstopped%29"
|
231
231
|
/>
|
232
232
|
<ActionSelectButton
|
233
233
|
disabled={true}
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: foreman-tasks
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.1.
|
4
|
+
version: 4.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ivan Nečas
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-08-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: dynflow
|
@@ -198,7 +198,6 @@ files:
|
|
198
198
|
- app/models/foreman_tasks/task_groups/recurring_logic_task_group.rb
|
199
199
|
- app/models/foreman_tasks/triggering.rb
|
200
200
|
- app/models/setting/foreman_tasks.rb
|
201
|
-
- app/services/foreman_tasks/dashboard_table_filter.rb
|
202
201
|
- app/services/foreman_tasks/proxy_selector.rb
|
203
202
|
- app/services/foreman_tasks/troubleshooting_help_generator.rb
|
204
203
|
- app/services/ui_notifications/tasks.rb
|
@@ -335,7 +334,6 @@ files:
|
|
335
334
|
- test/unit/actions/recurring_action_test.rb
|
336
335
|
- test/unit/cleaner_test.rb
|
337
336
|
- test/unit/config/environment.rb
|
338
|
-
- test/unit/dashboard_table_filter_test.rb
|
339
337
|
- test/unit/dynflow_console_authorizer_test.rb
|
340
338
|
- test/unit/locking_test.rb
|
341
339
|
- test/unit/otp_manager_test.rb
|
@@ -650,7 +648,6 @@ test_files:
|
|
650
648
|
- test/unit/actions/recurring_action_test.rb
|
651
649
|
- test/unit/cleaner_test.rb
|
652
650
|
- test/unit/config/environment.rb
|
653
|
-
- test/unit/dashboard_table_filter_test.rb
|
654
651
|
- test/unit/dynflow_console_authorizer_test.rb
|
655
652
|
- test/unit/locking_test.rb
|
656
653
|
- test/unit/otp_manager_test.rb
|
@@ -1,56 +0,0 @@
|
|
1
|
-
module ForemanTasks
|
2
|
-
# narrows the scope for the tasks table based on params coming from tasks dashboard
|
3
|
-
#
|
4
|
-
# Supported filters:
|
5
|
-
#
|
6
|
-
# * :result
|
7
|
-
# * :state
|
8
|
-
# * :time_horizon - expected format of Hxy, where the xy is the time horizon in hours we're interested in
|
9
|
-
# :time_mode can be set to 'recent' to filter the recent tasks, or 'older' (default) to filter earlier ones
|
10
|
-
class DashboardTableFilter
|
11
|
-
def initialize(scope, params)
|
12
|
-
@scope = scope
|
13
|
-
@params = params
|
14
|
-
end
|
15
|
-
|
16
|
-
def scope
|
17
|
-
@new_scope = @scope
|
18
|
-
scope_by(:result)
|
19
|
-
scope_by(:state)
|
20
|
-
scope_by_time
|
21
|
-
@new_scope
|
22
|
-
end
|
23
|
-
|
24
|
-
private
|
25
|
-
|
26
|
-
def scope_by(field)
|
27
|
-
if (field == :result) && (@params[field] == 'other')
|
28
|
-
@new_scope = @new_scope.where(:result => ['cancelled', 'pending'])
|
29
|
-
elsif @params[field].present?
|
30
|
-
@new_scope = @new_scope.where(field => @params[field])
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def scope_by_time
|
35
|
-
return if @params[:time_horizon].blank?
|
36
|
-
hours = if @params[:time_horizon].casecmp('week') == 0
|
37
|
-
24 * 7
|
38
|
-
else
|
39
|
-
@params[:time_horizon][/\AH(\d{1,2})$/i, 1]
|
40
|
-
end
|
41
|
-
|
42
|
-
unless hours
|
43
|
-
raise Foreman::Exception, 'Unexpected format of time: should be in form of "H24" or equal to "week"'
|
44
|
-
end
|
45
|
-
timestamp = Time.now.utc - hours.to_i.hours
|
46
|
-
case @params[:time_mode]
|
47
|
-
when 'recent'
|
48
|
-
operator = '>'
|
49
|
-
else
|
50
|
-
operator = '<'
|
51
|
-
search_suffix = 'OR state_updated_at IS NULL'
|
52
|
-
end
|
53
|
-
@new_scope = @new_scope.where("state_updated_at #{operator} ? #{search_suffix}", timestamp)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
@@ -1,77 +0,0 @@
|
|
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
|