foreman-tasks 0.17.0 → 0.17.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/assets/stylesheets/foreman_tasks/tasks.css.scss +3 -3
- data/app/controllers/foreman_tasks/api/tasks_controller.rb +50 -30
- data/app/controllers/foreman_tasks/tasks_controller.rb +8 -17
- data/app/models/foreman_tasks/task.rb +6 -4
- data/app/models/foreman_tasks/task/search.rb +0 -25
- data/app/models/setting/foreman_tasks.rb +19 -23
- data/app/views/foreman_tasks/api/tasks/show.json.rabl +1 -0
- data/app/views/foreman_tasks/layouts/react.html.erb +4 -1
- data/config/routes.rb +17 -3
- data/db/migrate/20180927120509_add_user_id.foreman_tasks.rb +4 -2
- data/lib/foreman_tasks/dynflow.rb +1 -1
- data/lib/foreman_tasks/dynflow/console_authorizer.rb +13 -2
- data/lib/foreman_tasks/engine.rb +1 -1
- data/lib/foreman_tasks/version.rb +1 -1
- data/package.json +1 -0
- data/test/controllers/tasks_controller_test.rb +35 -4
- data/test/unit/dynflow_console_authorizer_test.rb +1 -1
- data/test/unit/otp_manager_test.rb +24 -17
- data/test/unit/task_test.rb +48 -2
- data/webpack/ForemanTasks/Components/TaskDetails/Components/Task.js +29 -16
- data/webpack/ForemanTasks/Components/TaskDetails/Components/TaskHelper.js +3 -17
- data/webpack/ForemanTasks/Components/TaskDetails/Components/TaskInfo.js +18 -5
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/TaskHelper.test.js +1 -56
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/Task.test.js.snap +24 -44
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/TaskInfo.test.js.snap +22 -10
- data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsActions.js +6 -0
- data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsSelectors.js +1 -1
- data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/TaskDetails.test.js.snap +2 -0
- data/webpack/ForemanTasks/Components/TasksDashboard/TasksDashboard.js +6 -3
- data/webpack/ForemanTasks/Components/TasksDashboard/TasksDashboardActions.js +2 -3
- data/webpack/ForemanTasks/Components/TasksDashboard/TasksDashboardHelper.js +10 -41
- data/webpack/ForemanTasks/Components/TasksDashboard/TasksDashboardReducer.js +0 -1
- data/webpack/ForemanTasks/Components/TasksDashboard/__tests__/TasksDashboard.test.js +1 -1
- data/webpack/ForemanTasks/Components/TasksDashboard/__tests__/__snapshots__/TasksDashboardReducer.test.js.snap +1 -6
- data/webpack/ForemanTasks/Components/TasksTable/SubTasksPage.js +30 -0
- data/webpack/ForemanTasks/Components/TasksTable/TaskTableFormmatters.js +53 -0
- data/webpack/ForemanTasks/Components/TasksTable/TasksIndexPage.js +10 -0
- data/webpack/ForemanTasks/Components/TasksTable/TasksTable.js +119 -0
- data/webpack/ForemanTasks/Components/TasksTable/TasksTableActions.js +67 -0
- data/webpack/ForemanTasks/Components/TasksTable/TasksTableConstants.js +5 -0
- data/webpack/ForemanTasks/Components/TasksTable/TasksTableHelpers.js +64 -0
- data/webpack/ForemanTasks/Components/TasksTable/TasksTablePage.js +63 -0
- data/webpack/ForemanTasks/Components/TasksTable/TasksTablePage.scss +29 -0
- data/webpack/ForemanTasks/Components/TasksTable/TasksTableReducer.js +35 -0
- data/webpack/ForemanTasks/Components/TasksTable/TasksTableSchema.js +67 -0
- data/webpack/ForemanTasks/Components/TasksTable/TasksTableSelectors.js +39 -0
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/SubTasksPage.test.js +20 -0
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksIndexPage.test.js +12 -0
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTable.fixtures.js +42 -0
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTable.test.js +9 -0
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTableActions.test.js +48 -0
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTableHelpers.test.js +28 -0
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTablePage.test.js +26 -0
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTableReducer.test.js +37 -0
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/SubTasksPage.test.js.snap +49 -0
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksIndexPage.test.js.snap +42 -0
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTable.test.js.snap +72 -0
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTableActions.test.js.snap +115 -0
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTablePage.test.js.snap +194 -0
- data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTableReducer.test.js.snap +32 -0
- data/webpack/ForemanTasks/Components/TasksTable/index.js +32 -0
- data/webpack/ForemanTasks/Components/common/ActionButtons/ActionButton.js +39 -0
- data/webpack/ForemanTasks/Components/common/ActionButtons/ActionButton.test.js +45 -0
- data/webpack/ForemanTasks/Components/common/ActionButtons/CancelButton.js +23 -0
- data/webpack/ForemanTasks/Components/common/ActionButtons/CancelButton.test.js +27 -0
- data/webpack/ForemanTasks/Components/common/ActionButtons/ResumeButton.js +23 -0
- data/webpack/ForemanTasks/Components/common/ActionButtons/ResumeButton.test.js +27 -0
- data/webpack/ForemanTasks/Components/common/ActionButtons/__snapshots__/ActionButton.test.js.snap +28 -0
- data/webpack/ForemanTasks/Components/common/ActionButtons/__snapshots__/CancelButton.test.js.snap +15 -0
- data/webpack/ForemanTasks/Components/common/ActionButtons/__snapshots__/ResumeButton.test.js.snap +15 -0
- data/webpack/ForemanTasks/ForemanTasks.js +1 -17
- data/webpack/ForemanTasks/ForemanTasksReducers.js +2 -0
- data/webpack/ForemanTasks/Routes/ForemanTasksRouter.test.js +5 -1
- data/webpack/ForemanTasks/Routes/ForemanTasksRoutes.js +9 -3
- data/webpack/ForemanTasks/Routes/ForemanTasksRoutes.test.js +1 -1
- data/webpack/ForemanTasks/Routes/ShowTask/__tests__/ShowTask.test.js +5 -1
- data/webpack/ForemanTasks/Routes/__snapshots__/ForemanTasksRoutes.test.js.snap +18 -2
- data/webpack/ForemanTasks/__snapshots__/ForemanTasks.test.js.snap +1 -54
- data/webpack/__mocks__/foremanReact/common/helpers.js +1 -0
- data/webpack/__mocks__/foremanReact/common/urlHelpers.js +1 -0
- data/webpack/__mocks__/foremanReact/components/Pagination/PaginationWrapper.js +2 -0
- data/webpack/__mocks__/foremanReact/components/common/MessageBox.js +4 -0
- data/webpack/__mocks__/foremanReact/components/common/dates/LongDateTime.js +5 -0
- data/webpack/__mocks__/foremanReact/components/common/dates/RelativeDateTime.js +3 -0
- data/webpack/__mocks__/foremanReact/components/common/table.js +4 -0
- data/webpack/__mocks__/foremanReact/components/common/table/actionsHelpers/actionTypeCreator.js +7 -0
- data/webpack/__mocks__/foremanReact/constants.js +24 -0
- data/webpack/__mocks__/foremanReact/redux/actions/toasts.js +8 -0
- data/webpack/__mocks__/foremanReact/routes/common/PageLayout/PageLayout.js +10 -0
- data/webpack/__mocks__/foremanReact/routes/common/PageLayout/components/ExportButton/ExportButton.js +5 -0
- data/webpack/index.js +5 -0
- metadata +49 -9
- data/app/views/foreman_tasks/tasks/index.html.erb +0 -46
- data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/TaskHelper.test.js.snap +0 -37
- data/webpack/ForemanTasks/Routes/IndexTasks/IndexTasks.js +0 -10
- data/webpack/ForemanTasks/Routes/IndexTasks/__tests__/IndexTasks.test.js +0 -10
- data/webpack/ForemanTasks/Routes/IndexTasks/__tests__/__snapshots__/IndexTasks.test.js.snap +0 -12
- data/webpack/ForemanTasks/Routes/IndexTasks/index.js +0 -1
- data/webpack/ForemanTasks/Routes/IndexTasks/indexTasks.scss +0 -0
@@ -20,7 +20,7 @@ module ForemanTasks
|
|
20
20
|
dynflow_path += task.external_id.to_s if task
|
21
21
|
dynflow_rack_env = { 'rack.session' => { 'user' => user.id, 'expires_at' => Time.zone.now + 100 },
|
22
22
|
'PATH_INFO' => dynflow_path }.with_indifferent_access
|
23
|
-
ForemanTasks::Dynflow::ConsoleAuthorizer.
|
23
|
+
ForemanTasks::Dynflow::ConsoleAuthorizer.from_env(dynflow_rack_env).allow?
|
24
24
|
end
|
25
25
|
|
26
26
|
describe 'admin user' do
|
@@ -9,6 +9,10 @@ module ForemanTasksCore
|
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
|
+
def try_to_authenticate(username, password)
|
13
|
+
TestOtpManager.authenticate(OtpManager.tokenize(username, password))
|
14
|
+
end
|
15
|
+
|
12
16
|
before do
|
13
17
|
TestOtpManager.reset!
|
14
18
|
end
|
@@ -18,7 +22,7 @@ module ForemanTasksCore
|
|
18
22
|
let(:base64) { 'bXl1c2VyOjEyMzQ1Njc4OQ==' }
|
19
23
|
|
20
24
|
it 'it doesn\'t raise when no passwords were generated yet' do
|
21
|
-
|
25
|
+
assert_not try_to_authenticate('missing', 'password')
|
22
26
|
end
|
23
27
|
|
24
28
|
it 'generates OTPs using SecureRandom.hex and converts them to strings' do
|
@@ -27,33 +31,36 @@ module ForemanTasksCore
|
|
27
31
|
TestOtpManager.generate_otp(username).must_equal otp.to_s
|
28
32
|
end
|
29
33
|
|
30
|
-
it 'removes OTP only when correct username and password is provided' do
|
34
|
+
it 'provides #drop_otp method that removes OTP only when correct username and password is provided' do
|
31
35
|
otp = TestOtpManager.generate_otp(username)
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
TestOtpManager.drop_otp(username, otp)
|
36
|
+
assert_not TestOtpManager.drop_otp('wrong_username', 'wrong_password')
|
37
|
+
assert_not TestOtpManager.drop_otp(username, 'wrong_password')
|
38
|
+
assert_not TestOtpManager.drop_otp('wrong_username', otp)
|
39
|
+
assert TestOtpManager.drop_otp(username, otp)
|
36
40
|
end
|
37
41
|
|
38
|
-
it '
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
+
it 'authenticate removes OTP only when correct username and password is provided' do
|
43
|
+
otp = TestOtpManager.generate_otp(username)
|
44
|
+
assert_not try_to_authenticate('wrong_username', 'wrong_password')
|
45
|
+
assert_not try_to_authenticate(username, 'wrong_password')
|
46
|
+
assert_not try_to_authenticate(username, 'wrong_password')
|
47
|
+
assert_not try_to_authenticate('wrong_username', otp)
|
48
|
+
assert try_to_authenticate(username, otp)
|
42
49
|
end
|
43
50
|
|
44
51
|
it 'authenticates correctly' do
|
45
52
|
SecureRandom.stubs(:hex).returns(password)
|
46
|
-
|
53
|
+
TestOtpManager.generate_otp(username)
|
47
54
|
|
48
|
-
TestOtpManager.authenticate(base64)
|
55
|
+
assert TestOtpManager.authenticate(base64)
|
49
56
|
end
|
50
57
|
|
51
58
|
it 'OTPs can be used only once' do
|
52
59
|
SecureRandom.stubs(:hex).returns(password)
|
53
|
-
|
60
|
+
TestOtpManager.generate_otp(username)
|
54
61
|
|
55
|
-
TestOtpManager.authenticate(base64)
|
56
|
-
|
62
|
+
assert TestOtpManager.authenticate(base64)
|
63
|
+
assert_not TestOtpManager.authenticate(base64)
|
57
64
|
end
|
58
65
|
|
59
66
|
it 'creates token from username and password correctly' do
|
@@ -63,8 +70,8 @@ module ForemanTasksCore
|
|
63
70
|
it 'overwrites old OTP when generating a new one for the same username' do
|
64
71
|
old = TestOtpManager.generate_otp(username)
|
65
72
|
new = TestOtpManager.generate_otp(username)
|
66
|
-
|
67
|
-
|
73
|
+
assert_not try_to_authenticate(username, old)
|
74
|
+
assert try_to_authenticate(username, new)
|
68
75
|
end
|
69
76
|
end
|
70
77
|
end
|
data/test/unit/task_test.rb
CHANGED
@@ -30,20 +30,66 @@ class TasksTest < ActiveSupport::TestCase
|
|
30
30
|
assert_equal [@task_one], ForemanTasks::Task.search_for("user = #{@user_one.login}")
|
31
31
|
end
|
32
32
|
|
33
|
+
test 'cannot search by arbitrary key' do
|
34
|
+
proc { ForemanTasks::Task.search_for('user.my_key ~ 5') }.must_raise(ScopedSearch::QueryNotSupported)
|
35
|
+
proc { ForemanTasks::Task.search_for('user. = 5') }.must_raise(ScopedSearch::QueryNotSupported)
|
36
|
+
end
|
37
|
+
|
38
|
+
test 'can search the tasks by negated user' do
|
39
|
+
assert_equal [@task_one], ForemanTasks::Task.search_for("user != #{@user_two.login}")
|
40
|
+
assert_equal [@task_one], ForemanTasks::Task.search_for("user <> #{@user_two.login}")
|
41
|
+
SecureRandom.stubs(:hex).returns('abc')
|
42
|
+
assert_equal ForemanTasks::Task.search_for("user != #{@user_two.login}").to_sql,
|
43
|
+
ForemanTasks::Task.search_for("user <> #{@user_two.login}").to_sql
|
44
|
+
end
|
45
|
+
|
33
46
|
test 'can search the tasks by user\'s id' do
|
34
47
|
assert_equal [@task_one], ForemanTasks::Task.search_for("user.id = #{@user_one.id}")
|
35
48
|
assert_equal [@task_one], ForemanTasks::Task.search_for("owner.id = #{@user_one.id}")
|
49
|
+
assert_equal [@task_one], ForemanTasks::Task.search_for("user.id != #{@user_two.id}")
|
50
|
+
assert_equal [@task_one], ForemanTasks::Task.search_for("owner.id != #{@user_two.id}")
|
51
|
+
end
|
52
|
+
|
53
|
+
test 'can search by array of user ids' do
|
54
|
+
assert_equal [@task_one], ForemanTasks::Task.search_for("user.id ^ (#{@user_one.id})")
|
55
|
+
assert_equal [@task_one], ForemanTasks::Task.search_for("owner.id ^ (#{@user_one.id})")
|
56
|
+
assert_equal [@task_one], ForemanTasks::Task.search_for("user.id !^ (#{@user_two.id})")
|
57
|
+
assert_equal [@task_one], ForemanTasks::Task.search_for("owner.id !^ (#{@user_two.id})")
|
58
|
+
end
|
59
|
+
|
60
|
+
test 'cannot glob on user\'s id' do
|
61
|
+
proc { ForemanTasks::Task.search_for("user.id ~ something") }.must_raise(ScopedSearch::QueryNotSupported)
|
62
|
+
proc { ForemanTasks::Task.search_for("user.id ~ 5") }.must_raise(ScopedSearch::QueryNotSupported)
|
36
63
|
end
|
37
64
|
|
38
65
|
test 'can search the tasks by user with wildcards' do
|
39
|
-
|
40
|
-
|
66
|
+
part = @user_one.login[1..-1] # search for '*ser1' if login is 'user1'
|
67
|
+
# The following two should be equivalent
|
68
|
+
assert_equal [@task_one], ForemanTasks::Task.search_for("user ~ #{part}")
|
69
|
+
assert_equal [@task_one], ForemanTasks::Task.search_for("user ~ *#{part}*")
|
70
|
+
SecureRandom.stubs(:hex).returns('abc')
|
71
|
+
assert_equal ForemanTasks::Task.search_for("user ~ #{part}").to_sql,
|
72
|
+
ForemanTasks::Task.search_for("user ~ *#{part}*").to_sql
|
73
|
+
end
|
74
|
+
|
75
|
+
test 'can search the tasks by user with negated wildcards' do
|
76
|
+
part = @user_two.login[1..-1] # search for '*ser1' if login is 'user1'
|
77
|
+
# The following two should be equivalent
|
78
|
+
assert_equal [@task_one], ForemanTasks::Task.search_for("user !~ #{part}")
|
79
|
+
assert_equal [@task_one], ForemanTasks::Task.search_for("user !~ *#{part}*")
|
80
|
+
SecureRandom.stubs(:hex).returns('abc')
|
81
|
+
assert_equal ForemanTasks::Task.search_for("user !~ #{part}").to_sql,
|
82
|
+
ForemanTasks::Task.search_for("user !~ *#{part}*").to_sql
|
41
83
|
end
|
42
84
|
|
43
85
|
test 'can search the tasks by array' do
|
44
86
|
assert_equal [@task_one], ForemanTasks::Task.search_for("user ^ (this_user, #{@user_one.login}, that_user)")
|
45
87
|
end
|
46
88
|
|
89
|
+
test 'can search the tasks by negated array' do
|
90
|
+
assert_equal [@task_one], ForemanTasks::Task.search_for("user !^ (this_user, #{@user_two.login}, that_user)")
|
91
|
+
end
|
92
|
+
|
47
93
|
test 'properly returns username' do
|
48
94
|
assert_equal @task_one.username, @user_one.login
|
49
95
|
end
|
@@ -4,6 +4,8 @@ import { Grid, Row, Col, Button } from 'patternfly-react';
|
|
4
4
|
import { translate as __ } from 'foremanReact/common/I18n';
|
5
5
|
import TaskInfo from './TaskInfo';
|
6
6
|
import { ClickConfirmation } from '../../common/ClickConfirmation';
|
7
|
+
import { ResumeButton } from '../../common/ActionButtons/ResumeButton';
|
8
|
+
import { CancelButton } from '../../common/ActionButtons/CancelButton';
|
7
9
|
|
8
10
|
class Task extends Component {
|
9
11
|
taskProgressToggle = () => {
|
@@ -37,6 +39,9 @@ class Task extends Component {
|
|
37
39
|
showForceUnlockModal,
|
38
40
|
toggleUnlockModal,
|
39
41
|
toggleForceUnlockModal,
|
42
|
+
cancelTaskRequest,
|
43
|
+
resumeTaskRequest,
|
44
|
+
action,
|
40
45
|
} = this.props;
|
41
46
|
const modalUnlock = (
|
42
47
|
<ClickConfirmation
|
@@ -97,24 +102,28 @@ class Task extends Component {
|
|
97
102
|
>
|
98
103
|
{__('Dynflow console')}
|
99
104
|
</Button>
|
100
|
-
<
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
+
<ResumeButton
|
106
|
+
id={id}
|
107
|
+
onClick={() => {
|
108
|
+
if (!taskReload) {
|
109
|
+
this.taskProgressToggle();
|
110
|
+
}
|
111
|
+
resumeTaskRequest(id, action);
|
112
|
+
}}
|
113
|
+
name={action}
|
105
114
|
disabled={!resumable}
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
bsSize="small"
|
111
|
-
data-method="post"
|
112
|
-
href={`/foreman_tasks/tasks/${id}/cancel`}
|
115
|
+
/>
|
116
|
+
<CancelButton
|
117
|
+
id={id}
|
118
|
+
name={action}
|
113
119
|
disabled={!cancellable}
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
120
|
+
onClick={() => {
|
121
|
+
if (!taskReload) {
|
122
|
+
this.taskProgressToggle();
|
123
|
+
}
|
124
|
+
cancelTaskRequest(id, action);
|
125
|
+
}}
|
126
|
+
/>
|
118
127
|
{parentTask && (
|
119
128
|
<Button
|
120
129
|
bsSize="small"
|
@@ -177,6 +186,8 @@ Task.propTypes = {
|
|
177
186
|
showForceUnlockModal: PropTypes.bool,
|
178
187
|
toggleUnlockModal: PropTypes.func,
|
179
188
|
toggleForceUnlockModal: PropTypes.func,
|
189
|
+
cancelTaskRequest: PropTypes.func,
|
190
|
+
resumeTaskRequest: PropTypes.func,
|
180
191
|
};
|
181
192
|
|
182
193
|
Task.defaultProps = {
|
@@ -197,6 +208,8 @@ Task.defaultProps = {
|
|
197
208
|
showForceUnlockModal: false,
|
198
209
|
toggleUnlockModal: () => null,
|
199
210
|
toggleForceUnlockModal: () => null,
|
211
|
+
cancelTaskRequest: () => null,
|
212
|
+
resumeTaskRequest: () => null,
|
200
213
|
};
|
201
214
|
|
202
215
|
export default Task;
|
@@ -1,29 +1,15 @@
|
|
1
1
|
import { translate as __, documentLocale } from 'foremanReact/common/I18n';
|
2
|
-
import
|
3
|
-
import { FormattedRelative } from 'react-intl';
|
2
|
+
import { isoCompatibleDate } from 'foremanReact/common/helpers';
|
4
3
|
import humanizeDuration from 'humanize-duration';
|
5
4
|
|
6
|
-
const formatDate = date => {
|
7
|
-
// Firefox doesnt format dd-mm-yyyy type strings to date
|
8
|
-
if (typeof date === 'string' || date instanceof String)
|
9
|
-
return new Date(date.replace(/-/, '/').replace(/-/, '/'));
|
10
|
-
return date;
|
11
|
-
};
|
12
|
-
|
13
|
-
export const timeInWords = time => {
|
14
|
-
if (!time) return __('N/A');
|
15
|
-
time = formatDate(time);
|
16
|
-
return <FormattedRelative value={time} />;
|
17
|
-
};
|
18
|
-
|
19
5
|
export const durationInWords = (
|
20
6
|
start,
|
21
7
|
finish,
|
22
8
|
selectedLocale = documentLocale()
|
23
9
|
) => {
|
24
10
|
if (!start) return __('N/A');
|
25
|
-
start =
|
26
|
-
finish =
|
11
|
+
start = new Date(isoCompatibleDate(start)).getTime();
|
12
|
+
finish = new Date(isoCompatibleDate(finish)).getTime();
|
27
13
|
return {
|
28
14
|
text: humanizeDuration(new Date(finish - start).getTime(), {
|
29
15
|
largest: 1,
|
@@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
|
|
3
3
|
import { Grid, Row, Col, ProgressBar } from 'patternfly-react';
|
4
4
|
import { translate as __ } from 'foremanReact/common/I18n';
|
5
5
|
import EllipsisWithTooltip from 'react-ellipsis-with-tooltip';
|
6
|
-
import
|
6
|
+
import RelativeDateTime from 'foremanReact/components/common/dates/RelativeDateTime';
|
7
7
|
|
8
8
|
class TaskInfo extends Component {
|
9
9
|
isDelayed = () => {
|
@@ -73,7 +73,10 @@ class TaskInfo extends Component {
|
|
73
73
|
<EllipsisWithTooltip>{action || __('N/A')}</EllipsisWithTooltip>
|
74
74
|
),
|
75
75
|
},
|
76
|
-
{
|
76
|
+
{
|
77
|
+
title: 'Start at',
|
78
|
+
value: <RelativeDateTime defaultValue={__('N/A')} date={startAt} />,
|
79
|
+
},
|
77
80
|
],
|
78
81
|
[
|
79
82
|
{
|
@@ -85,7 +88,10 @@ class TaskInfo extends Component {
|
|
85
88
|
</React.Fragment>
|
86
89
|
),
|
87
90
|
},
|
88
|
-
{
|
91
|
+
{
|
92
|
+
title: 'Started at',
|
93
|
+
value: <RelativeDateTime defaultValue={__('N/A')} date={startedAt} />,
|
94
|
+
},
|
89
95
|
],
|
90
96
|
[
|
91
97
|
{
|
@@ -96,7 +102,10 @@ class TaskInfo extends Component {
|
|
96
102
|
username || ''
|
97
103
|
),
|
98
104
|
},
|
99
|
-
{
|
105
|
+
{
|
106
|
+
title: 'Ended at',
|
107
|
+
value: <RelativeDateTime defaultValue={__('N/A')} date={endedAt} />,
|
108
|
+
},
|
100
109
|
],
|
101
110
|
[
|
102
111
|
{
|
@@ -105,7 +114,11 @@ class TaskInfo extends Component {
|
|
105
114
|
},
|
106
115
|
{
|
107
116
|
title: 'Start before',
|
108
|
-
value: startBefore ?
|
117
|
+
value: startBefore ? (
|
118
|
+
<RelativeDateTime defaultValue={__('N/A')} date={startBefore} />
|
119
|
+
) : (
|
120
|
+
'-'
|
121
|
+
),
|
109
122
|
},
|
110
123
|
],
|
111
124
|
];
|
@@ -1,59 +1,4 @@
|
|
1
|
-
import
|
2
|
-
import { mount } from 'enzyme';
|
3
|
-
import toJson from 'enzyme-to-json';
|
4
|
-
import { IntlProvider } from 'react-intl';
|
5
|
-
import { timeInWords, durationInWords } from '../TaskHelper';
|
6
|
-
|
7
|
-
describe('timeInWords', () => {
|
8
|
-
it('should work for past minutes', () => {
|
9
|
-
const component = mount(
|
10
|
-
<IntlProvider locale="en">
|
11
|
-
{timeInWords(new Date().getTime() - 1000 * 60 * 5)}
|
12
|
-
</IntlProvider>
|
13
|
-
);
|
14
|
-
expect(toJson(component.render())).toMatchSnapshot();
|
15
|
-
});
|
16
|
-
it('should work for past hours', () => {
|
17
|
-
const component = mount(
|
18
|
-
<IntlProvider locale="en">
|
19
|
-
{timeInWords(new Date().getTime() - 1000 * 60 * 60 * 5)}
|
20
|
-
</IntlProvider>
|
21
|
-
);
|
22
|
-
expect(toJson(component.render())).toMatchSnapshot();
|
23
|
-
});
|
24
|
-
it('should work for past days', () => {
|
25
|
-
const component = mount(
|
26
|
-
<IntlProvider locale="en">
|
27
|
-
{timeInWords(new Date().getTime() - 1000 * 60 * 60 * 24 * 5)}
|
28
|
-
</IntlProvider>
|
29
|
-
);
|
30
|
-
expect(toJson(component.render())).toMatchSnapshot();
|
31
|
-
});
|
32
|
-
it('should work for future minutes', () => {
|
33
|
-
const component = mount(
|
34
|
-
<IntlProvider locale="en">
|
35
|
-
{timeInWords(new Date().getTime() + 1000 * 60 * 5)}
|
36
|
-
</IntlProvider>
|
37
|
-
);
|
38
|
-
expect(toJson(component.render())).toMatchSnapshot();
|
39
|
-
});
|
40
|
-
it('should work for future hours', () => {
|
41
|
-
const component = mount(
|
42
|
-
<IntlProvider locale="en">
|
43
|
-
{timeInWords(new Date().getTime() + 1000 * 60 * 60 * 5)}
|
44
|
-
</IntlProvider>
|
45
|
-
);
|
46
|
-
expect(toJson(component.render())).toMatchSnapshot();
|
47
|
-
});
|
48
|
-
it('should work for future days', () => {
|
49
|
-
const component = mount(
|
50
|
-
<IntlProvider locale="en">
|
51
|
-
{timeInWords(new Date().getTime() + 1000 * 60 * 60 * 24 * 5)}
|
52
|
-
</IntlProvider>
|
53
|
-
);
|
54
|
-
expect(toJson(component.render())).toMatchSnapshot();
|
55
|
-
});
|
56
|
-
});
|
1
|
+
import { durationInWords } from '../TaskHelper';
|
57
2
|
|
58
3
|
describe('durationInWords', () => {
|
59
4
|
it('should work for seconds', () => {
|
@@ -63,30 +63,18 @@ exports[`Task rendering render with some Props 1`] = `
|
|
63
63
|
>
|
64
64
|
Dynflow console
|
65
65
|
</Button>
|
66
|
-
<
|
67
|
-
active={false}
|
68
|
-
block={false}
|
69
|
-
bsClass="btn"
|
70
|
-
bsSize="small"
|
71
|
-
bsStyle="primary"
|
72
|
-
data-method="post"
|
66
|
+
<ResumeButton
|
73
67
|
disabled={true}
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
<
|
79
|
-
active={false}
|
80
|
-
block={false}
|
81
|
-
bsClass="btn"
|
82
|
-
bsSize="small"
|
83
|
-
bsStyle="default"
|
84
|
-
data-method="post"
|
68
|
+
id="test"
|
69
|
+
name=""
|
70
|
+
onClick={[Function]}
|
71
|
+
/>
|
72
|
+
<CancelButton
|
85
73
|
disabled={true}
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
74
|
+
id="test"
|
75
|
+
name=""
|
76
|
+
onClick={[Function]}
|
77
|
+
/>
|
90
78
|
<Button
|
91
79
|
active={false}
|
92
80
|
block={false}
|
@@ -125,6 +113,7 @@ exports[`Task rendering render with some Props 1`] = `
|
|
125
113
|
<TaskInfo
|
126
114
|
action=""
|
127
115
|
allowDangerousActions={true}
|
116
|
+
cancelTaskRequest={[Function]}
|
128
117
|
cancellable={false}
|
129
118
|
endedAt=""
|
130
119
|
error={Array []}
|
@@ -138,6 +127,7 @@ exports[`Task rendering render with some Props 1`] = `
|
|
138
127
|
refetchTaskDetails={[Function]}
|
139
128
|
result="error"
|
140
129
|
resumable={false}
|
130
|
+
resumeTaskRequest={[Function]}
|
141
131
|
showForceUnlockModal={false}
|
142
132
|
showUnlockModal={false}
|
143
133
|
startAt=""
|
@@ -220,35 +210,24 @@ exports[`Task rendering render without Props 1`] = `
|
|
220
210
|
>
|
221
211
|
Dynflow console
|
222
212
|
</Button>
|
223
|
-
<
|
224
|
-
active={false}
|
225
|
-
block={false}
|
226
|
-
bsClass="btn"
|
227
|
-
bsSize="small"
|
228
|
-
bsStyle="primary"
|
229
|
-
data-method="post"
|
213
|
+
<ResumeButton
|
230
214
|
disabled={true}
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
<
|
236
|
-
active={false}
|
237
|
-
block={false}
|
238
|
-
bsClass="btn"
|
239
|
-
bsSize="small"
|
240
|
-
bsStyle="default"
|
241
|
-
data-method="post"
|
215
|
+
id="test"
|
216
|
+
name=""
|
217
|
+
onClick={[Function]}
|
218
|
+
/>
|
219
|
+
<CancelButton
|
242
220
|
disabled={true}
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
221
|
+
id="test"
|
222
|
+
name=""
|
223
|
+
onClick={[Function]}
|
224
|
+
/>
|
247
225
|
</Col>
|
248
226
|
</Row>
|
249
227
|
<TaskInfo
|
250
228
|
action=""
|
251
229
|
allowDangerousActions={false}
|
230
|
+
cancelTaskRequest={[Function]}
|
252
231
|
cancellable={false}
|
253
232
|
endedAt=""
|
254
233
|
error={Array []}
|
@@ -262,6 +241,7 @@ exports[`Task rendering render without Props 1`] = `
|
|
262
241
|
refetchTaskDetails={[Function]}
|
263
242
|
result="error"
|
264
243
|
resumable={false}
|
244
|
+
resumeTaskRequest={[Function]}
|
265
245
|
showForceUnlockModal={false}
|
266
246
|
showUnlockModal={false}
|
267
247
|
startAt=""
|