foreman-tasks 2.0.3 → 3.0.4
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/js_tests.yml +31 -0
- data/.github/workflows/ruby_tests.yml +74 -0
- data/.rubocop.yml +12 -4
- data/.rubocop_todo.yml +32 -25
- data/Gemfile +5 -0
- data/app/controllers/foreman_tasks/api/tasks_controller.rb +50 -63
- data/app/controllers/foreman_tasks/concerns/parameters/triggering.rb +1 -1
- data/app/controllers/foreman_tasks/recurring_logics_controller.rb +7 -0
- data/app/helpers/foreman_tasks/foreman_tasks_helper.rb +3 -3
- data/app/models/foreman_tasks/recurring_logic.rb +1 -1
- data/app/models/foreman_tasks/task.rb +11 -0
- data/app/models/foreman_tasks/task/dynflow_task.rb +27 -33
- data/app/models/foreman_tasks/task/search.rb +1 -1
- data/app/models/foreman_tasks/task/status_explicator.rb +1 -1
- data/app/models/foreman_tasks/triggering.rb +1 -1
- data/app/models/setting/foreman_tasks.rb +9 -9
- data/app/services/foreman_tasks/dashboard_table_filter.rb +5 -1
- data/app/views/foreman_tasks/api/tasks/index.json.rabl +2 -0
- data/app/views/foreman_tasks/layouts/react.html.erb +1 -2
- data/app/views/foreman_tasks/recurring_logics/index.html.erb +3 -1
- data/app/views/foreman_tasks/tasks/dashboard/_latest_tasks_in_error_warning.html.erb +1 -1
- data/app/views/foreman_tasks/tasks/dashboard/_tasks_status.html.erb +1 -1
- data/app/views/foreman_tasks/tasks/show.html.erb +1 -6
- data/config/routes.rb +2 -1
- data/db/migrate/20200517215015_rename_bookmarks_controller.rb +2 -2
- data/db/seeds.d/30-notification_blueprints.rb +7 -7
- data/db/seeds.d/61-foreman_tasks_bookmarks.rb +1 -1
- data/foreman-tasks.gemspec +1 -0
- data/lib/foreman_tasks/cleaner.rb +4 -6
- data/lib/foreman_tasks/dynflow/configuration.rb +1 -1
- data/lib/foreman_tasks/dynflow/persistence.rb +4 -6
- data/lib/foreman_tasks/engine.rb +2 -2
- data/lib/foreman_tasks/version.rb +1 -1
- data/package.json +0 -1
- data/test/controllers/api/recurring_logics_controller_test.rb +1 -1
- data/test/controllers/api/tasks_controller_test.rb +17 -7
- data/test/controllers/tasks_controller_test.rb +6 -6
- data/test/core/unit/runner_test.rb +20 -20
- data/test/core/unit/task_launcher_test.rb +8 -8
- data/test/helpers/foreman_tasks/foreman_tasks_helper_test.rb +7 -7
- data/test/helpers/foreman_tasks/tasks_helper_test.rb +3 -3
- data/test/lib/actions/middleware/keep_current_request_id_test.rb +3 -3
- data/test/support/history_tasks_builder.rb +1 -1
- data/test/tasks/generate_task_actions_test.rb +1 -1
- data/test/unit/actions/action_with_sub_plans_test.rb +2 -2
- data/test/unit/actions/bulk_action_test.rb +6 -6
- data/test/unit/actions/proxy_action_test.rb +20 -20
- data/test/unit/actions/recurring_action_test.rb +30 -32
- data/test/unit/cleaner_test.rb +24 -24
- data/test/unit/dashboard_table_filter_test.rb +5 -5
- data/test/unit/otp_manager_test.rb +2 -2
- data/test/unit/proxy_selector_test.rb +9 -9
- data/test/unit/recurring_logic_test.rb +32 -32
- data/test/unit/remote_task_test.rb +2 -2
- data/test/unit/task_groups_test.rb +4 -4
- data/test/unit/task_test.rb +26 -18
- data/test/unit/triggering_test.rb +8 -8
- data/test/unit/troubleshooting_help_generator_test.rb +6 -6
- data/test/unit/ui_notifications_test.rb +11 -11
- data/webpack/ForemanTasks/Components/TaskDetails/Components/RunningSteps.js +3 -3
- data/webpack/ForemanTasks/Components/TaskDetails/Components/Task.js +8 -157
- data/webpack/ForemanTasks/Components/TaskDetails/Components/TaskButtons.js +168 -0
- data/webpack/ForemanTasks/Components/TaskDetails/Components/TaskInfo.js +6 -7
- data/webpack/ForemanTasks/Components/TaskDetails/Components/TaskSkeleton.js +48 -0
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/RunningSteps.test.js +1 -1
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/Task.test.js +12 -70
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/TaskButtons.test.js +95 -0
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/Task.test.js.snap +78 -225
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/TaskButtons.test.js.snap +212 -0
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/TaskInfo.test.js.snap +8 -4
- data/webpack/ForemanTasks/Components/TaskDetails/TaskDetails.js +87 -70
- data/webpack/ForemanTasks/Components/TaskDetails/TaskDetails.scss +10 -0
- data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsActions.js +48 -125
- data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsConstants.js +3 -16
- data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsSelectors.js +55 -29
- data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetails.fixtures.js +2 -2
- data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetails.test.js +6 -0
- data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetailsActions.test.js +2 -18
- data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/TaskDetails.test.js.snap +77 -27
- data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/TaskDetailsActions.test.js.snap +14 -101
- data/webpack/ForemanTasks/Components/TaskDetails/index.js +6 -3
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/ScheduledTasksCard/ScheduledTasksCard.scss +4 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/OtherInfo.js +53 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/OtherInfo.test.js +14 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCard.js +27 -19
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCard.scss +14 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCard.test.js +1 -34
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/{StoppedTasksCardHelper.js → StoppedTasksCardTable.js} +28 -1
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCardTable.test.js +54 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/__snapshots__/OtherInfo.test.js.snap +48 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/__snapshots__/StoppedTasksCard.test.js.snap +60 -1367
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/__snapshots__/StoppedTasksCardTable.test.js.snap +960 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/__snapshots__/TasksCardsGrid.test.js.snap +14 -11
- data/webpack/ForemanTasks/Components/TasksDashboard/TasksDashboardConstants.js +2 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/TasksDashboardSelectors.js +17 -11
- data/webpack/ForemanTasks/Components/TasksDashboard/__tests__/TasksDashboardSelectors.test.js +26 -14
- data/webpack/ForemanTasks/Components/TasksDashboard/__tests__/__snapshots__/TasksDashboard.test.js.snap +14 -11
- data/webpack/ForemanTasks/Components/TasksDashboard/__tests__/__snapshots__/TasksDashboardSelectors.test.js.snap +38 -22
- data/webpack/ForemanTasks/Components/TasksTable/TasksTableHelpers.js +0 -8
- data/webpack/ForemanTasks/Components/TasksTable/TasksTablePage.js +13 -4
- data/webpack/ForemanTasks/Components/TasksTable/TasksTablePage.scss +0 -10
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTablePage.test.js.snap +0 -2
- data/webpack/ForemanTasks/Components/TasksTable/formatters/__test__/__snapshots__/actionNameCellFormatter.test.js.snap +3 -1
- data/webpack/ForemanTasks/Components/TasksTable/formatters/actionNameCellFormatter.js +6 -1
- data/webpack/ForemanTasks/Components/common/urlHelpers.js +7 -0
- data/webpack/ForemanTasks/ForemanTasksReducers.js +0 -2
- data/webpack/__mocks__/foremanReact/common/helpers.js +2 -0
- data/webpack/__mocks__/foremanReact/redux/API/APISelectors.js +10 -0
- data/webpack/__mocks__/foremanReact/redux/API/index.js +10 -0
- data/webpack/__mocks__/foremanReact/redux/middlewares/IntervalMiddleware.js +5 -0
- metadata +21 -13
- data/.travis.yml +0 -7
- data/app/assets/stylesheets/foreman_tasks/tasks.scss +0 -9
- data/script/travis_run_js_tests.sh +0 -7
- data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsReducer.js +0 -38
- data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetailsReducer.test.js +0 -33
- data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/TaskDetailsReducer.test.js.snap +0 -26
- data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/integration.test.js.snap +0 -122
- data/webpack/ForemanTasks/Components/TaskDetails/__tests__/integration.test.js +0 -72
- data/webpack/__mocks__/foremanReact/redux/API.js +0 -7
|
@@ -24,8 +24,8 @@ module ForemanTasks
|
|
|
24
24
|
RemoteTask.batch_trigger('a_operation', remote_tasks)
|
|
25
25
|
remote_tasks.each do |remote_task|
|
|
26
26
|
remote_task.reload
|
|
27
|
-
remote_task.state.must_equal 'triggered'
|
|
28
|
-
remote_task.remote_task_id.must_equal((remote_task.id + 5).to_s)
|
|
27
|
+
_(remote_task.state).must_equal 'triggered'
|
|
28
|
+
_(remote_task.remote_task_id).must_equal((remote_task.id + 5).to_s)
|
|
29
29
|
end
|
|
30
30
|
end
|
|
31
31
|
|
|
@@ -55,18 +55,18 @@ module ForemanTasks
|
|
|
55
55
|
|
|
56
56
|
it 'has the task group assigned' do
|
|
57
57
|
task = spawn_task.call ChildAction
|
|
58
|
-
task.task_groups.map(&:id).must_equal [1]
|
|
58
|
+
_(task.task_groups.map(&:id)).must_equal [1]
|
|
59
59
|
end
|
|
60
60
|
|
|
61
61
|
it 'tasks inherit task groups correctly' do
|
|
62
62
|
children_count = 3
|
|
63
63
|
task = spawn_task.call ParentAction, children_count
|
|
64
64
|
# Parent task has task groups of its children
|
|
65
|
-
task.task_groups.map(&:id).sort.must_equal [1, 2, 3, 4]
|
|
65
|
+
_(task.task_groups.map(&:id).sort).must_equal [1, 2, 3, 4]
|
|
66
66
|
# Children have the parent's and their own, they don't have their siblings' task groups
|
|
67
|
-
task.sub_tasks.count.must_equal children_count
|
|
67
|
+
_(task.sub_tasks.count).must_equal children_count
|
|
68
68
|
task.sub_tasks.each do |sub_task|
|
|
69
|
-
sub_task.task_groups.map(&:id).sort.must_equal [1, sub_task.input[:id]].sort
|
|
69
|
+
_(sub_task.task_groups.map(&:id).sort).must_equal [1, sub_task.input[:id]].sort
|
|
70
70
|
end
|
|
71
71
|
end
|
|
72
72
|
end
|
data/test/unit/task_test.rb
CHANGED
|
@@ -32,8 +32,8 @@ class TasksTest < ActiveSupport::TestCase
|
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
test 'cannot search by arbitrary key' do
|
|
35
|
-
proc { ForemanTasks::Task.search_for('user.my_key ~ 5') }.must_raise(ScopedSearch::QueryNotSupported)
|
|
36
|
-
proc { ForemanTasks::Task.search_for('user. = 5') }.must_raise(ScopedSearch::QueryNotSupported)
|
|
35
|
+
_ { proc { ForemanTasks::Task.search_for('user.my_key ~ 5') } }.must_raise(ScopedSearch::QueryNotSupported)
|
|
36
|
+
_ { proc { ForemanTasks::Task.search_for('user. = 5') } }.must_raise(ScopedSearch::QueryNotSupported)
|
|
37
37
|
end
|
|
38
38
|
|
|
39
39
|
test 'can search the tasks by negated user' do
|
|
@@ -59,8 +59,8 @@ class TasksTest < ActiveSupport::TestCase
|
|
|
59
59
|
end
|
|
60
60
|
|
|
61
61
|
test 'cannot glob on user\'s id' do
|
|
62
|
-
proc { ForemanTasks::Task.search_for("user.id ~ something") }.must_raise(ScopedSearch::QueryNotSupported)
|
|
63
|
-
proc { ForemanTasks::Task.search_for("user.id ~ 5") }.must_raise(ScopedSearch::QueryNotSupported)
|
|
62
|
+
_ { proc { ForemanTasks::Task.search_for("user.id ~ something") } }.must_raise(ScopedSearch::QueryNotSupported)
|
|
63
|
+
_ { proc { ForemanTasks::Task.search_for("user.id ~ 5") } }.must_raise(ScopedSearch::QueryNotSupported)
|
|
64
64
|
end
|
|
65
65
|
|
|
66
66
|
test 'can search the tasks by user with wildcards' do
|
|
@@ -126,7 +126,15 @@ class TasksTest < ActiveSupport::TestCase
|
|
|
126
126
|
end
|
|
127
127
|
|
|
128
128
|
it 'raises an exception if duration is unknown' do
|
|
129
|
-
proc { ForemanTasks::Task.search_for('duration = "25 potatoes"') }.must_raise ScopedSearch::QueryNotSupported
|
|
129
|
+
_ { proc { ForemanTasks::Task.search_for('duration = "25 potatoes"') } }.must_raise ScopedSearch::QueryNotSupported
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
context 'by taxonomies' do
|
|
134
|
+
test 'can search by taxonomies using IN' do
|
|
135
|
+
assert_nothing_raised(PG::SyntaxError) { ForemanTasks::Task.search_for('location_id ^ (1)').first }
|
|
136
|
+
assert_nothing_raised(PG::SyntaxError) { ForemanTasks::Task.search_for('organization_id ^ (1)').first }
|
|
137
|
+
assert_nothing_raised(PG::SyntaxError) { ForemanTasks::Task.search_for('organization_id = 1').first }
|
|
130
138
|
end
|
|
131
139
|
end
|
|
132
140
|
end
|
|
@@ -176,13 +184,13 @@ class TasksTest < ActiveSupport::TestCase
|
|
|
176
184
|
let(:inconsistent_task) { FactoryBot.create(:dynflow_task, :inconsistent_dynflow_task) }
|
|
177
185
|
|
|
178
186
|
it 'ensures the tasks marked as running are really running in Dynflow' do
|
|
179
|
-
consistent_task.state.must_equal 'planned'
|
|
180
|
-
inconsistent_task.state.must_equal 'running'
|
|
187
|
+
_(consistent_task.state).must_equal 'planned'
|
|
188
|
+
_(inconsistent_task.state).must_equal 'running'
|
|
181
189
|
|
|
182
190
|
ForemanTasks::Task::DynflowTask.consistency_check
|
|
183
191
|
|
|
184
|
-
consistent_task.reload.state.must_equal 'planned'
|
|
185
|
-
inconsistent_task.reload.state.must_equal 'planned'
|
|
192
|
+
_(consistent_task.reload.state).must_equal 'planned'
|
|
193
|
+
_(inconsistent_task.reload.state).must_equal 'planned'
|
|
186
194
|
end
|
|
187
195
|
end
|
|
188
196
|
|
|
@@ -190,8 +198,8 @@ class TasksTest < ActiveSupport::TestCase
|
|
|
190
198
|
it 'when scheduled to the future, the label and action is set properly' do
|
|
191
199
|
job = Support::DummyActiveJob.set(:wait => 12.hours).perform_later
|
|
192
200
|
task = ForemanTasks::Task.find_by!(:external_id => job.provider_job_id)
|
|
193
|
-
task.action.must_equal "Dummy action"
|
|
194
|
-
task.label.must_equal "Support::DummyActiveJob"
|
|
201
|
+
_(task.action).must_equal "Dummy action"
|
|
202
|
+
_(task.label).must_equal "Support::DummyActiveJob"
|
|
195
203
|
end
|
|
196
204
|
end
|
|
197
205
|
|
|
@@ -224,14 +232,14 @@ class TasksTest < ActiveSupport::TestCase
|
|
|
224
232
|
:total => 0,
|
|
225
233
|
:success => 0,
|
|
226
234
|
:cancelled => 0,
|
|
227
|
-
:pending => 0
|
|
235
|
+
:pending => 0,
|
|
228
236
|
}
|
|
229
237
|
end
|
|
230
238
|
let(:task) { FactoryBot.create(:dynflow_task) }
|
|
231
239
|
|
|
232
240
|
describe 'without sub tasks' do
|
|
233
241
|
it 'calculates the progress report correctly' do
|
|
234
|
-
task.sub_tasks_counts.must_equal result_base
|
|
242
|
+
_(task.sub_tasks_counts).must_equal result_base
|
|
235
243
|
end
|
|
236
244
|
end
|
|
237
245
|
|
|
@@ -242,7 +250,7 @@ class TasksTest < ActiveSupport::TestCase
|
|
|
242
250
|
|
|
243
251
|
it 'calculate the progress report correctly' do
|
|
244
252
|
expected_result = result_base.merge(:success => 1, :error => 1, :total => 2)
|
|
245
|
-
task.sub_tasks_counts.must_equal expected_result
|
|
253
|
+
_(task.sub_tasks_counts).must_equal expected_result
|
|
246
254
|
end
|
|
247
255
|
|
|
248
256
|
it 'calculates the progress report correctly when using batch planning' do
|
|
@@ -252,11 +260,11 @@ class TasksTest < ActiveSupport::TestCase
|
|
|
252
260
|
|
|
253
261
|
task.state = 'stopped'
|
|
254
262
|
expected_result = result_base.merge(:cancelled => 23)
|
|
255
|
-
task.sub_tasks_counts.must_equal expected_result
|
|
263
|
+
_(task.sub_tasks_counts).must_equal expected_result
|
|
256
264
|
|
|
257
265
|
task.state = 'pending'
|
|
258
266
|
expected_result = result_base.merge(:pending => 23)
|
|
259
|
-
task.sub_tasks_counts.must_equal expected_result
|
|
267
|
+
_(task.sub_tasks_counts).must_equal expected_result
|
|
260
268
|
end
|
|
261
269
|
end
|
|
262
270
|
end
|
|
@@ -278,10 +286,10 @@ class TasksTest < ActiveSupport::TestCase
|
|
|
278
286
|
|
|
279
287
|
it 'can indicate it is delayed' do
|
|
280
288
|
assert_not task.delayed?
|
|
281
|
-
task.execution_type.must_equal 'Immediate'
|
|
289
|
+
_(task.execution_type).must_equal 'Immediate'
|
|
282
290
|
task.start_at = Time.now.utc + 100
|
|
283
291
|
assert task.delayed?
|
|
284
|
-
task.execution_type.must_equal 'Delayed'
|
|
292
|
+
_(task.execution_type).must_equal 'Delayed'
|
|
285
293
|
end
|
|
286
294
|
end
|
|
287
295
|
|
|
@@ -3,28 +3,28 @@ require 'foreman_tasks_test_helper'
|
|
|
3
3
|
class TriggeringTest < ActiveSupport::TestCase
|
|
4
4
|
describe 'validation' do
|
|
5
5
|
it 'is valid when immediate' do
|
|
6
|
-
FactoryBot.build(:triggering).must_be :valid?
|
|
6
|
+
_(FactoryBot.build(:triggering)).must_be :valid?
|
|
7
7
|
end
|
|
8
8
|
|
|
9
9
|
it 'is validates future execution' do
|
|
10
10
|
triggering = FactoryBot.build(:triggering, :future)
|
|
11
|
-
triggering.must_be :valid?
|
|
11
|
+
_(triggering).must_be :valid?
|
|
12
12
|
triggering.start_before = triggering.start_at - 120
|
|
13
|
-
triggering.wont_be :valid?
|
|
13
|
+
_(triggering).wont_be :valid?
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
it 'is invalid when recurring logic is invalid' do
|
|
17
17
|
triggering = FactoryBot.build(:triggering, :recurring)
|
|
18
|
-
triggering.must_be :valid?
|
|
18
|
+
_(triggering).must_be :valid?
|
|
19
19
|
triggering.recurring_logic.stubs(:valid?).returns(false)
|
|
20
|
-
triggering.wont_be :valid?
|
|
20
|
+
_(triggering).wont_be :valid?
|
|
21
21
|
end
|
|
22
22
|
end
|
|
23
23
|
|
|
24
24
|
it 'cannot have mode set to arbitrary value' do
|
|
25
25
|
triggering = FactoryBot.build(:triggering)
|
|
26
|
-
triggering.must_be :valid?
|
|
27
|
-
proc { triggering.mode = 'bogus' }.must_raise ArgumentError
|
|
28
|
-
proc { triggering.mode = 27 }.must_raise ArgumentError
|
|
26
|
+
_(triggering).must_be :valid?
|
|
27
|
+
_ { proc { triggering.mode = 'bogus' } }.must_raise ArgumentError
|
|
28
|
+
_ { proc { triggering.mode = 27 } }.must_raise ArgumentError
|
|
29
29
|
end
|
|
30
30
|
end
|
|
@@ -29,8 +29,8 @@ module ForemanTasks
|
|
|
29
29
|
|
|
30
30
|
it 'generates html from the main action troubleshooting_info' do
|
|
31
31
|
generated_html = subject.generate_html
|
|
32
|
-
generated_html.must_include "A paused task represents a process that has not finished properly"
|
|
33
|
-
generated_html.must_include %(See <a href="#{expected_troubleshooting_url}">troubleshooting documentation</a> for more details on how to resolve the issue)
|
|
32
|
+
_(generated_html).must_include "A paused task represents a process that has not finished properly"
|
|
33
|
+
_(generated_html).must_include %(See <a href="#{expected_troubleshooting_url}">troubleshooting documentation</a> for more details on how to resolve the issue)
|
|
34
34
|
end
|
|
35
35
|
|
|
36
36
|
it 'exposes link details' do
|
|
@@ -48,10 +48,10 @@ module ForemanTasks
|
|
|
48
48
|
|
|
49
49
|
it 'includes additional description in generated html' do
|
|
50
50
|
generated_html = subject.generate_html
|
|
51
|
-
generated_html.must_include 'A paused task represents a process that has not finished properly'
|
|
52
|
-
generated_html.must_match %r{See <a href=".*">troubleshooting documentation</a> for more details on how to resolve the issue}
|
|
53
|
-
generated_html.must_include 'This task requires special handling'
|
|
54
|
-
generated_html.must_include 'Investigate <a href="/additional_troubleshooting_page">custom link</a> on more details for this custom error'
|
|
51
|
+
_(generated_html).must_include 'A paused task represents a process that has not finished properly'
|
|
52
|
+
_(generated_html).must_match %r{See <a href=".*">troubleshooting documentation</a> for more details on how to resolve the issue}
|
|
53
|
+
_(generated_html).must_include 'This task requires special handling'
|
|
54
|
+
_(generated_html).must_include 'Investigate <a href="/additional_troubleshooting_page">custom link</a> on more details for this custom error'
|
|
55
55
|
end
|
|
56
56
|
|
|
57
57
|
it 'includes additional links' do
|
|
@@ -23,11 +23,11 @@ module ForemanTasks
|
|
|
23
23
|
it 'notifies all admins about current amount of paused tasks when some paused task occurs' do
|
|
24
24
|
trigger_task
|
|
25
25
|
notification = user_notifications(admin_user).first
|
|
26
|
-
notification.message.must_equal "There is 1 paused task in the system that need attention"
|
|
26
|
+
_(notification.message).must_equal "There is 1 paused task in the system that need attention"
|
|
27
27
|
links = notification.actions['links']
|
|
28
|
-
links.must_include('href' => '/foreman_tasks/tasks?search=state%3Dpaused',
|
|
28
|
+
_(links).must_include('href' => '/foreman_tasks/tasks?search=state%3Dpaused',
|
|
29
29
|
'title' => 'List of tasks')
|
|
30
|
-
links.must_include('name' => 'troubleshooting',
|
|
30
|
+
_(links).must_include('name' => 'troubleshooting',
|
|
31
31
|
'title' => 'Troubleshooting Documentation',
|
|
32
32
|
'description' => 'See %{link} for more details on how to resolve the issue',
|
|
33
33
|
'href' => "https://theforeman.org/manuals/#{SETTINGS[:version].short}/tasks_troubleshooting.html#",
|
|
@@ -37,19 +37,19 @@ module ForemanTasks
|
|
|
37
37
|
it 'aggregates the notification when multiple tasks get paused' do
|
|
38
38
|
trigger_task
|
|
39
39
|
recipient1 = NotificationRecipient.find_by(user_id: admin_user)
|
|
40
|
-
recipient1.notification.message.must_match(/1 paused task/)
|
|
40
|
+
_(recipient1.notification.message).must_match(/1 paused task/)
|
|
41
41
|
|
|
42
42
|
new_admin_user = FactoryBot.create(:user, :admin)
|
|
43
43
|
|
|
44
44
|
trigger_task
|
|
45
45
|
|
|
46
|
-
NotificationRecipient.find_by(id: recipient1.id).must_be_nil
|
|
47
|
-
Notification.find_by(id: recipient1.notification.id).must_be_nil
|
|
46
|
+
_(NotificationRecipient.find_by(id: recipient1.id)).must_be_nil
|
|
47
|
+
_(Notification.find_by(id: recipient1.notification.id)).must_be_nil
|
|
48
48
|
recipient2 = NotificationRecipient.find_by(user_id: admin_user)
|
|
49
|
-
recipient2.notification.message.must_match(/2 paused tasks/)
|
|
49
|
+
_(recipient2.notification.message).must_match(/2 paused tasks/)
|
|
50
50
|
|
|
51
51
|
new_recipient = NotificationRecipient.find_by(user_id: new_admin_user)
|
|
52
|
-
new_recipient.notification.must_equal recipient2.notification
|
|
52
|
+
_(new_recipient.notification).must_equal recipient2.notification
|
|
53
53
|
end
|
|
54
54
|
end
|
|
55
55
|
|
|
@@ -59,11 +59,11 @@ module ForemanTasks
|
|
|
59
59
|
notifications = user_notifications(task_owner)
|
|
60
60
|
assert_equal 1, notifications.size, 'Only notification for the main action should be triggered'
|
|
61
61
|
notification = notifications.first
|
|
62
|
-
notification.message.must_equal "The task 'Dummy pause action' got paused"
|
|
62
|
+
_(notification.message).must_equal "The task 'Dummy pause action' got paused"
|
|
63
63
|
links = notification.actions['links']
|
|
64
|
-
links.must_include("href" => "/foreman_tasks/tasks/#{task.id}",
|
|
64
|
+
_(links).must_include("href" => "/foreman_tasks/tasks/#{task.id}",
|
|
65
65
|
"title" => "Task Details")
|
|
66
|
-
links.must_include('name' => 'troubleshooting',
|
|
66
|
+
_(links).must_include('name' => 'troubleshooting',
|
|
67
67
|
'title' => 'Troubleshooting Documentation',
|
|
68
68
|
'description' => 'See %{link} for more details on how to resolve the issue',
|
|
69
69
|
'href' => "https://theforeman.org/manuals/#{SETTINGS[:version].short}/tasks_troubleshooting.html#Support::DummyPauseAction",
|
|
@@ -8,7 +8,7 @@ const RunningSteps = ({
|
|
|
8
8
|
id,
|
|
9
9
|
cancelStep,
|
|
10
10
|
taskReload,
|
|
11
|
-
|
|
11
|
+
taskReloadStart,
|
|
12
12
|
}) => {
|
|
13
13
|
if (!runningSteps.length) return <span>{__('No running steps')}</span>;
|
|
14
14
|
return (
|
|
@@ -21,7 +21,7 @@ const RunningSteps = ({
|
|
|
21
21
|
bsSize="small"
|
|
22
22
|
onClick={() => {
|
|
23
23
|
if (!taskReload) {
|
|
24
|
-
|
|
24
|
+
taskReloadStart(id);
|
|
25
25
|
}
|
|
26
26
|
cancelStep(id, step.id);
|
|
27
27
|
}}
|
|
@@ -59,7 +59,7 @@ RunningSteps.propTypes = {
|
|
|
59
59
|
id: PropTypes.string.isRequired,
|
|
60
60
|
cancelStep: PropTypes.func.isRequired,
|
|
61
61
|
taskReload: PropTypes.bool.isRequired,
|
|
62
|
-
|
|
62
|
+
taskReloadStart: PropTypes.func.isRequired,
|
|
63
63
|
};
|
|
64
64
|
|
|
65
65
|
RunningSteps.defaultProps = {
|
|
@@ -1,159 +1,37 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import
|
|
3
|
-
import { Grid, Row, Col, Button } from 'patternfly-react';
|
|
4
|
-
import { translate as __ } from 'foremanReact/common/I18n';
|
|
5
|
-
import { useForemanModal } from 'foremanReact/components/ForemanModal/ForemanModalHooks';
|
|
2
|
+
import { Grid, Row } from 'patternfly-react';
|
|
6
3
|
import TaskInfo from './TaskInfo';
|
|
7
|
-
import {
|
|
8
|
-
UNLOCK_MODAL,
|
|
9
|
-
FORCE_UNLOCK_MODAL,
|
|
10
|
-
} from '../../TaskActions/TaskActionsConstants';
|
|
11
4
|
import { ForceUnlockModal, UnlockModal } from '../../TaskActions/UnlockModals';
|
|
5
|
+
import { TaskButtons } from './TaskButtons';
|
|
12
6
|
|
|
13
7
|
const Task = props => {
|
|
14
|
-
const unlockModalActions = useForemanModal({
|
|
15
|
-
id: UNLOCK_MODAL,
|
|
16
|
-
});
|
|
17
|
-
const forceUnlockModalActions = useForemanModal({
|
|
18
|
-
id: FORCE_UNLOCK_MODAL,
|
|
19
|
-
});
|
|
20
|
-
|
|
21
8
|
const {
|
|
22
9
|
taskReload,
|
|
23
|
-
externalId,
|
|
24
10
|
id,
|
|
25
|
-
state,
|
|
26
|
-
resumable,
|
|
27
|
-
cancellable,
|
|
28
|
-
hasSubTasks,
|
|
29
|
-
parentTask,
|
|
30
|
-
cancelTaskRequest,
|
|
31
|
-
resumeTaskRequest,
|
|
32
11
|
forceCancelTaskRequest,
|
|
33
12
|
unlockTaskRequest,
|
|
34
13
|
action,
|
|
35
|
-
|
|
36
|
-
taskProgressToggle,
|
|
37
|
-
canEdit,
|
|
14
|
+
taskReloadStart,
|
|
38
15
|
} = props;
|
|
39
16
|
const forceUnlock = () => {
|
|
40
17
|
if (!taskReload) {
|
|
41
|
-
|
|
18
|
+
taskReloadStart(id);
|
|
42
19
|
}
|
|
43
20
|
forceCancelTaskRequest(id, action);
|
|
44
21
|
};
|
|
45
22
|
const unlock = () => {
|
|
46
23
|
if (!taskReload) {
|
|
47
|
-
|
|
24
|
+
taskReloadStart(id);
|
|
48
25
|
}
|
|
49
26
|
unlockTaskRequest(id, action);
|
|
50
27
|
};
|
|
51
|
-
const editActionsTitle = canEdit
|
|
52
|
-
? undefined
|
|
53
|
-
: __('You do not have permission');
|
|
54
|
-
const dynflowTitle = dynflowEnableConsole
|
|
55
|
-
? undefined
|
|
56
|
-
: `dynflow_enable_console ${__('Setting is off')}`;
|
|
57
28
|
return (
|
|
58
29
|
<React.Fragment>
|
|
59
30
|
<UnlockModal onClick={unlock} />
|
|
60
31
|
<ForceUnlockModal onClick={forceUnlock} />
|
|
61
32
|
<Grid>
|
|
62
33
|
<Row>
|
|
63
|
-
<
|
|
64
|
-
<Button
|
|
65
|
-
className="reload-button"
|
|
66
|
-
bsSize="small"
|
|
67
|
-
onClick={taskProgressToggle}
|
|
68
|
-
>
|
|
69
|
-
<span
|
|
70
|
-
className={`glyphicon glyphicon-refresh ${
|
|
71
|
-
taskReload ? 'spin' : ''
|
|
72
|
-
}`}
|
|
73
|
-
/>
|
|
74
|
-
{__(`${taskReload ? 'Stop' : 'Start'} auto-reloading`)}
|
|
75
|
-
</Button>
|
|
76
|
-
<Button
|
|
77
|
-
className="dynflow-button"
|
|
78
|
-
bsSize="small"
|
|
79
|
-
href={`/foreman_tasks/dynflow/${externalId}`}
|
|
80
|
-
disabled={!dynflowEnableConsole}
|
|
81
|
-
rel="noopener noreferrer"
|
|
82
|
-
target="_blank"
|
|
83
|
-
>
|
|
84
|
-
<span title={dynflowTitle} data-original-title={dynflowTitle}>
|
|
85
|
-
{__('Dynflow console')}
|
|
86
|
-
</span>
|
|
87
|
-
</Button>
|
|
88
|
-
<Button
|
|
89
|
-
className="resume-button"
|
|
90
|
-
bsSize="small"
|
|
91
|
-
title={editActionsTitle}
|
|
92
|
-
data-original-title={editActionsTitle}
|
|
93
|
-
disabled={!canEdit || !resumable}
|
|
94
|
-
onClick={() => {
|
|
95
|
-
if (!taskReload) {
|
|
96
|
-
taskProgressToggle();
|
|
97
|
-
}
|
|
98
|
-
resumeTaskRequest(id, action);
|
|
99
|
-
}}
|
|
100
|
-
>
|
|
101
|
-
{__('Resume')}
|
|
102
|
-
</Button>
|
|
103
|
-
<Button
|
|
104
|
-
className="cancel-button"
|
|
105
|
-
bsSize="small"
|
|
106
|
-
title={editActionsTitle}
|
|
107
|
-
data-original-title={editActionsTitle}
|
|
108
|
-
disabled={!canEdit || !cancellable}
|
|
109
|
-
onClick={() => {
|
|
110
|
-
if (!taskReload) {
|
|
111
|
-
taskProgressToggle();
|
|
112
|
-
}
|
|
113
|
-
cancelTaskRequest(id, action);
|
|
114
|
-
}}
|
|
115
|
-
>
|
|
116
|
-
{__('Cancel')}
|
|
117
|
-
</Button>
|
|
118
|
-
{parentTask && (
|
|
119
|
-
<Button
|
|
120
|
-
className="parent-button"
|
|
121
|
-
bsSize="small"
|
|
122
|
-
href={`/foreman_tasks/tasks/${parentTask}`}
|
|
123
|
-
>
|
|
124
|
-
{__('Parent task')}
|
|
125
|
-
</Button>
|
|
126
|
-
)}
|
|
127
|
-
{hasSubTasks && (
|
|
128
|
-
<Button
|
|
129
|
-
className="subtask-button"
|
|
130
|
-
bsSize="small"
|
|
131
|
-
href={`/foreman_tasks/tasks/${id}/sub_tasks`}
|
|
132
|
-
>
|
|
133
|
-
{__('Sub tasks')}
|
|
134
|
-
</Button>
|
|
135
|
-
)}
|
|
136
|
-
<Button
|
|
137
|
-
className="unlock-button"
|
|
138
|
-
bsSize="small"
|
|
139
|
-
disabled={!canEdit || state !== 'paused'}
|
|
140
|
-
onClick={unlockModalActions.setModalOpen}
|
|
141
|
-
title={editActionsTitle}
|
|
142
|
-
data-original-title={editActionsTitle}
|
|
143
|
-
>
|
|
144
|
-
{__('Unlock')}
|
|
145
|
-
</Button>
|
|
146
|
-
<Button
|
|
147
|
-
className="force-unlock-button"
|
|
148
|
-
bsSize="small"
|
|
149
|
-
disabled={!canEdit || state === 'stopped'}
|
|
150
|
-
onClick={forceUnlockModalActions.setModalOpen}
|
|
151
|
-
title={editActionsTitle}
|
|
152
|
-
data-original-title={editActionsTitle}
|
|
153
|
-
>
|
|
154
|
-
{__('Force Unlock')}
|
|
155
|
-
</Button>
|
|
156
|
-
</Col>
|
|
34
|
+
<TaskButtons taskReloadStart={taskReloadStart} {...props} />
|
|
157
35
|
</Row>
|
|
158
36
|
<TaskInfo {...props} />
|
|
159
37
|
</Grid>
|
|
@@ -163,39 +41,12 @@ const Task = props => {
|
|
|
163
41
|
|
|
164
42
|
Task.propTypes = {
|
|
165
43
|
...TaskInfo.PropTypes,
|
|
166
|
-
|
|
167
|
-
resumable: PropTypes.bool,
|
|
168
|
-
cancellable: PropTypes.bool,
|
|
169
|
-
refetchTaskDetails: PropTypes.func,
|
|
170
|
-
hasSubTasks: PropTypes.bool,
|
|
171
|
-
parentTask: PropTypes.string,
|
|
172
|
-
taskReload: PropTypes.bool,
|
|
173
|
-
taskReloadStop: PropTypes.func,
|
|
174
|
-
timeoutId: PropTypes.number,
|
|
175
|
-
externalId: PropTypes.string,
|
|
176
|
-
id: PropTypes.string.isRequired,
|
|
177
|
-
cancelTaskRequest: PropTypes.func,
|
|
178
|
-
resumeTaskRequest: PropTypes.func,
|
|
179
|
-
dynflowEnableConsole: PropTypes.bool,
|
|
180
|
-
canEdit: PropTypes.bool,
|
|
44
|
+
...TaskButtons.PropTypes,
|
|
181
45
|
};
|
|
182
46
|
|
|
183
47
|
Task.defaultProps = {
|
|
184
48
|
...TaskInfo.defaultProps,
|
|
185
|
-
|
|
186
|
-
resumable: false,
|
|
187
|
-
cancellable: false,
|
|
188
|
-
refetchTaskDetails: () => null,
|
|
189
|
-
hasSubTasks: false,
|
|
190
|
-
parentTask: '',
|
|
191
|
-
taskReload: false,
|
|
192
|
-
taskReloadStop: () => null,
|
|
193
|
-
timeoutId: null,
|
|
194
|
-
externalId: '',
|
|
195
|
-
cancelTaskRequest: () => null,
|
|
196
|
-
resumeTaskRequest: () => null,
|
|
197
|
-
dynflowEnableConsole: false,
|
|
198
|
-
canEdit: false,
|
|
49
|
+
...TaskButtons.defaultProps,
|
|
199
50
|
};
|
|
200
51
|
|
|
201
52
|
export default Task;
|