foreman-tasks 2.0.1 → 3.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (147) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/js_tests.yml +31 -0
  3. data/.github/workflows/ruby_tests.yml +74 -0
  4. data/.rubocop.yml +12 -4
  5. data/.rubocop_todo.yml +32 -25
  6. data/Gemfile +5 -0
  7. data/app/controllers/foreman_tasks/api/tasks_controller.rb +54 -63
  8. data/app/controllers/foreman_tasks/concerns/parameters/triggering.rb +1 -1
  9. data/app/controllers/foreman_tasks/recurring_logics_controller.rb +7 -0
  10. data/app/helpers/foreman_tasks/foreman_tasks_helper.rb +3 -3
  11. data/app/lib/actions/proxy_action.rb +1 -1
  12. data/app/models/foreman_tasks/recurring_logic.rb +4 -4
  13. data/app/models/foreman_tasks/task.rb +11 -0
  14. data/app/models/foreman_tasks/task/dynflow_task.rb +29 -34
  15. data/app/models/foreman_tasks/task/status_explicator.rb +1 -1
  16. data/app/models/foreman_tasks/triggering.rb +1 -1
  17. data/app/models/setting/foreman_tasks.rb +9 -9
  18. data/app/services/foreman_tasks/dashboard_table_filter.rb +5 -1
  19. data/app/views/foreman_tasks/api/tasks/index.json.rabl +2 -0
  20. data/app/views/foreman_tasks/api/tasks/show.json.rabl +2 -0
  21. data/app/views/foreman_tasks/layouts/react.html.erb +1 -2
  22. data/app/views/foreman_tasks/recurring_logics/index.html.erb +3 -1
  23. data/app/views/foreman_tasks/tasks/dashboard/_latest_tasks_in_error_warning.html.erb +1 -1
  24. data/app/views/foreman_tasks/tasks/dashboard/_tasks_status.html.erb +1 -1
  25. data/app/views/foreman_tasks/tasks/show.html.erb +1 -6
  26. data/config/routes.rb +2 -1
  27. data/db/migrate/20200517215015_rename_bookmarks_controller.rb +2 -2
  28. data/db/migrate/20200611090846_add_task_lock_index_on_resource_type_and_task_id.rb +3 -3
  29. data/db/seeds.d/30-notification_blueprints.rb +7 -7
  30. data/db/seeds.d/61-foreman_tasks_bookmarks.rb +1 -1
  31. data/foreman-tasks.gemspec +1 -0
  32. data/lib/foreman_tasks/cleaner.rb +4 -6
  33. data/lib/foreman_tasks/dynflow/configuration.rb +1 -1
  34. data/lib/foreman_tasks/dynflow/persistence.rb +4 -6
  35. data/lib/foreman_tasks/engine.rb +2 -2
  36. data/lib/foreman_tasks/tasks/cleanup.rake +2 -2
  37. data/lib/foreman_tasks/tasks/dynflow.rake +6 -0
  38. data/lib/foreman_tasks/tasks/export_tasks.rake +1 -1
  39. data/lib/foreman_tasks/version.rb +1 -1
  40. data/package.json +1 -1
  41. data/script/npm_link_foreman_js.sh +26 -0
  42. data/test/controllers/api/recurring_logics_controller_test.rb +1 -1
  43. data/test/controllers/api/tasks_controller_test.rb +17 -7
  44. data/test/controllers/tasks_controller_test.rb +6 -6
  45. data/test/core/unit/runner_test.rb +20 -20
  46. data/test/core/unit/task_launcher_test.rb +8 -8
  47. data/test/helpers/foreman_tasks/foreman_tasks_helper_test.rb +7 -7
  48. data/test/helpers/foreman_tasks/tasks_helper_test.rb +3 -3
  49. data/test/lib/actions/middleware/keep_current_request_id_test.rb +3 -3
  50. data/test/support/history_tasks_builder.rb +1 -1
  51. data/test/tasks/generate_task_actions_test.rb +1 -1
  52. data/test/unit/actions/action_with_sub_plans_test.rb +2 -2
  53. data/test/unit/actions/bulk_action_test.rb +6 -6
  54. data/test/unit/actions/proxy_action_test.rb +20 -20
  55. data/test/unit/actions/recurring_action_test.rb +30 -32
  56. data/test/unit/cleaner_test.rb +24 -24
  57. data/test/unit/dashboard_table_filter_test.rb +5 -5
  58. data/test/unit/otp_manager_test.rb +2 -2
  59. data/test/unit/proxy_selector_test.rb +9 -9
  60. data/test/unit/recurring_logic_test.rb +38 -32
  61. data/test/unit/remote_task_test.rb +2 -2
  62. data/test/unit/task_groups_test.rb +4 -4
  63. data/test/unit/task_test.rb +18 -18
  64. data/test/unit/triggering_test.rb +8 -8
  65. data/test/unit/troubleshooting_help_generator_test.rb +6 -6
  66. data/test/unit/ui_notifications_test.rb +11 -11
  67. data/webpack/ForemanTasks/Components/TaskDetails/Components/RunningSteps.js +3 -3
  68. data/webpack/ForemanTasks/Components/TaskDetails/Components/Task.js +8 -138
  69. data/webpack/ForemanTasks/Components/TaskDetails/Components/TaskButtons.js +168 -0
  70. data/webpack/ForemanTasks/Components/TaskDetails/Components/TaskInfo.js +6 -7
  71. data/webpack/ForemanTasks/Components/TaskDetails/Components/TaskSkeleton.js +48 -0
  72. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/RunningSteps.test.js +1 -1
  73. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/Task.test.js +13 -70
  74. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/TaskButtons.test.js +95 -0
  75. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/Task.test.js.snap +78 -208
  76. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/TaskButtons.test.js.snap +212 -0
  77. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/TaskInfo.test.js.snap +8 -4
  78. data/webpack/ForemanTasks/Components/TaskDetails/TaskDetails.js +87 -70
  79. data/webpack/ForemanTasks/Components/TaskDetails/TaskDetails.scss +13 -14
  80. data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsActions.js +48 -121
  81. data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsConstants.js +3 -16
  82. data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsSelectors.js +57 -28
  83. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetails.fixtures.js +2 -2
  84. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetails.test.js +6 -0
  85. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetailsActions.test.js +2 -18
  86. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/TaskDetails.test.js.snap +78 -27
  87. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/TaskDetailsActions.test.js.snap +14 -101
  88. data/webpack/ForemanTasks/Components/TaskDetails/index.js +8 -3
  89. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/ScheduledTasksCard/ScheduledTasksCard.scss +4 -0
  90. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/OtherInfo.js +53 -0
  91. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/OtherInfo.test.js +14 -0
  92. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCard.js +27 -19
  93. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCard.scss +14 -0
  94. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCard.test.js +1 -34
  95. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/{StoppedTasksCardHelper.js → StoppedTasksCardTable.js} +28 -1
  96. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCardTable.test.js +54 -0
  97. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/__snapshots__/OtherInfo.test.js.snap +48 -0
  98. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/__snapshots__/StoppedTasksCard.test.js.snap +60 -1367
  99. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/__snapshots__/StoppedTasksCardTable.test.js.snap +960 -0
  100. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/__snapshots__/TasksCardsGrid.test.js.snap +14 -11
  101. data/webpack/ForemanTasks/Components/TasksDashboard/TasksDashboardConstants.js +2 -0
  102. data/webpack/ForemanTasks/Components/TasksDashboard/TasksDashboardSelectors.js +17 -11
  103. data/webpack/ForemanTasks/Components/TasksDashboard/__tests__/TasksDashboardSelectors.test.js +26 -14
  104. data/webpack/ForemanTasks/Components/TasksDashboard/__tests__/__snapshots__/TasksDashboard.test.js.snap +14 -11
  105. data/webpack/ForemanTasks/Components/TasksDashboard/__tests__/__snapshots__/TasksDashboardSelectors.test.js.snap +38 -22
  106. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/ConfirmModalSelectors.js +1 -0
  107. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/ConfirmModalSelectors.test.js +1 -0
  108. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/__snapshots__/ConfirmModalSelectors.test.js.snap +2 -0
  109. data/webpack/ForemanTasks/Components/TasksTable/TasksBulkActions.js +24 -7
  110. data/webpack/ForemanTasks/Components/TasksTable/TasksTableActions.js +3 -3
  111. data/webpack/ForemanTasks/Components/TasksTable/TasksTablePage.js +6 -3
  112. data/webpack/ForemanTasks/Components/TasksTable/TasksTablePage.scss +0 -10
  113. data/webpack/ForemanTasks/Components/TasksTable/TasksTableSelectors.js +1 -0
  114. data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksBulkActions.test.js +13 -0
  115. data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTable.fixtures.js +1 -0
  116. data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTablePage.test.js +2 -1
  117. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/SubTasksPage.test.js.snap +1 -0
  118. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksBulkActions.test.js.snap +48 -0
  119. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksIndexPage.test.js.snap +1 -0
  120. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTablePage.test.js.snap +39 -7
  121. data/webpack/ForemanTasks/Components/TasksTable/formatters/__test__/__snapshots__/actionCellFormatter.test.js.snap +1 -0
  122. data/webpack/ForemanTasks/Components/TasksTable/formatters/__test__/__snapshots__/actionNameCellFormatter.test.js.snap +3 -1
  123. data/webpack/ForemanTasks/Components/TasksTable/formatters/__test__/__snapshots__/selectionCellFormatter.test.js.snap +2 -0
  124. data/webpack/ForemanTasks/Components/TasksTable/formatters/__test__/actionCellFormatter.test.js +1 -1
  125. data/webpack/ForemanTasks/Components/TasksTable/formatters/__test__/selectionCellFormatter.test.js +1 -1
  126. data/webpack/ForemanTasks/Components/TasksTable/formatters/actionCellFormatter.js +10 -7
  127. data/webpack/ForemanTasks/Components/TasksTable/formatters/actionNameCellFormatter.js +6 -1
  128. data/webpack/ForemanTasks/Components/TasksTable/formatters/selectionCellFormatter.js +7 -0
  129. data/webpack/ForemanTasks/Components/common/ActionButtons/ActionButton.js +39 -31
  130. data/webpack/ForemanTasks/Components/common/ActionButtons/ActionButton.test.js +17 -8
  131. data/webpack/ForemanTasks/Components/common/ActionButtons/__snapshots__/ActionButton.test.js.snap +8 -0
  132. data/webpack/ForemanTasks/Components/common/urlHelpers.js +7 -0
  133. data/webpack/ForemanTasks/ForemanTasksReducers.js +0 -2
  134. data/webpack/__mocks__/foremanReact/common/helpers.js +2 -0
  135. data/webpack/__mocks__/foremanReact/redux/API/APISelectors.js +10 -0
  136. data/webpack/__mocks__/foremanReact/redux/API/index.js +10 -0
  137. data/webpack/__mocks__/foremanReact/redux/middlewares/IntervalMiddleware.js +5 -0
  138. metadata +27 -17
  139. data/.travis.yml +0 -5
  140. data/app/assets/stylesheets/foreman_tasks/tasks.scss +0 -9
  141. data/script/travis_run_js_tests.sh +0 -7
  142. data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsReducer.js +0 -38
  143. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetailsReducer.test.js +0 -33
  144. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/TaskDetailsReducer.test.js.snap +0 -26
  145. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/integration.test.js.snap +0 -122
  146. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/integration.test.js +0 -72
  147. data/webpack/__mocks__/foremanReact/redux/API.js +0 -7
@@ -39,6 +39,7 @@ export const selectResults = createSelector(
39
39
  ...result.available_actions,
40
40
  stoppable: result.state !== 'stopped',
41
41
  },
42
+ canEdit: result.can_edit,
42
43
  }))
43
44
  );
44
45
 
@@ -18,6 +18,7 @@ jest.mock('foremanReact/redux/API');
18
18
  const task = {
19
19
  id: 'some-id',
20
20
  name: 'some-name',
21
+ canEdit: true,
21
22
  };
22
23
 
23
24
  const fixtures = {
@@ -140,6 +141,18 @@ const fixtures = {
140
141
  url: 'some-url',
141
142
  parentTaskID: 'parent',
142
143
  }),
144
+ 'handles bulkCancelById requests with canEdit false': () => {
145
+ const selected = [{ ...task, isCancellable: true, canEdit: false }];
146
+ return bulkCancelById({ selected, url: 'some-url' });
147
+ },
148
+ 'handles bulkResumeById requests with canEdit false': () => {
149
+ const selected = [{ ...task, isResumable: false, canEdit: false }];
150
+ return bulkResumeById({ selected, url: 'some-url' });
151
+ },
152
+ 'handles bulkForceCancelById requests with canEdit false': () => {
153
+ const selected = [{ ...task, isResumable: false, canEdit: false }];
154
+ return bulkForceCancelById({ selected, url: 'some-url' });
155
+ },
143
156
  };
144
157
 
145
158
  describe('TasksTable bulk actions', () => {
@@ -9,6 +9,7 @@ export const minProps = {
9
9
  unselectAllRows: jest.fn(),
10
10
  selectRow: jest.fn(),
11
11
  unselectRow: jest.fn(),
12
+ reloadPage: jest.fn(),
12
13
  selectedRows: [],
13
14
  pagination: {
14
15
  page: 1,
@@ -12,9 +12,10 @@ const history = {
12
12
  const fixtures = {
13
13
  'render with minimal props': { ...minProps, history },
14
14
 
15
- 'render with Breadcrubs': {
15
+ 'render with Breadcrubs and edit permissions': {
16
16
  ...minProps,
17
17
  history,
18
+ results: [{ action: 'a', canEdit: true }],
18
19
  getBreadcrumbs: () => ({
19
20
  breadcrumbItems: [
20
21
  { caption: 'Tasks', url: `/foreman_tasks/tasks` },
@@ -30,6 +30,7 @@ exports[`SubTasksPage rendering render with minimal props 1`] = `
30
30
  }
31
31
  }
32
32
  parentTaskID="some-id"
33
+ reloadPage={[MockFunction]}
33
34
  results={
34
35
  Array [
35
36
  "a",
@@ -48,6 +48,22 @@ Array [
48
48
  ]
49
49
  `;
50
50
 
51
+ exports[`TasksTable bulk actions handles bulkCancelById requests with canEdit false 1`] = `
52
+ Array [
53
+ Array [
54
+ Object {
55
+ "payload": Object {
56
+ "message": Object {
57
+ "message": "Not all the selected tasks can be cancelled",
58
+ "type": "warning",
59
+ },
60
+ },
61
+ "type": "TOASTS_ADD",
62
+ },
63
+ ],
64
+ ]
65
+ `;
66
+
51
67
  exports[`TasksTable bulk actions handles bulkCancelBySearch requests 1`] = `
52
68
  Array [
53
69
  Array [
@@ -155,6 +171,22 @@ Array [
155
171
  ]
156
172
  `;
157
173
 
174
+ exports[`TasksTable bulk actions handles bulkForceCancelById requests with canEdit false 1`] = `
175
+ Array [
176
+ Array [
177
+ Object {
178
+ "payload": Object {
179
+ "message": Object {
180
+ "message": "User has no permission for 1 task(s)",
181
+ "type": "warning",
182
+ },
183
+ },
184
+ "type": "TOASTS_ADD",
185
+ },
186
+ ],
187
+ ]
188
+ `;
189
+
158
190
  exports[`TasksTable bulk actions handles bulkForceCancelBySearch requests 1`] = `
159
191
  Array [
160
192
  Array [
@@ -219,6 +251,22 @@ Array [
219
251
  ]
220
252
  `;
221
253
 
254
+ exports[`TasksTable bulk actions handles bulkResumeById requests with canEdit false 1`] = `
255
+ Array [
256
+ Array [
257
+ Object {
258
+ "payload": Object {
259
+ "message": Object {
260
+ "message": "Not all the selected tasks can be resumed",
261
+ "type": "warning",
262
+ },
263
+ },
264
+ "type": "TOASTS_ADD",
265
+ },
266
+ ],
267
+ ]
268
+ `;
269
+
222
270
  exports[`TasksTable bulk actions handles bulkResumeBySearch requests 1`] = `
223
271
  Array [
224
272
  Array [
@@ -21,6 +21,7 @@ exports[`TasksIndexPage rendering render with minimal props 1`] = `
21
21
  "perPage": 10,
22
22
  }
23
23
  }
24
+ reloadPage={[MockFunction]}
24
25
  results={
25
26
  Array [
26
27
  "a",
@@ -1,6 +1,6 @@
1
1
  // Jest Snapshot v1, https://goo.gl/fbAQLP
2
2
 
3
- exports[`TasksTablePage rendering render with Breadcrubs 1`] = `
3
+ exports[`TasksTablePage rendering render with Breadcrubs and edit permissions 1`] = `
4
4
  <div
5
5
  className="tasks-table-wrapper"
6
6
  >
@@ -66,15 +66,29 @@ exports[`TasksTablePage rendering render with Breadcrubs 1`] = `
66
66
  }
67
67
  searchQuery="a=b"
68
68
  searchable={true}
69
- toastNotifications="foreman-tasks-cancel"
70
69
  toolbarButtons={
71
70
  <React.Fragment>
71
+ <Button
72
+ active={false}
73
+ block={false}
74
+ bsClass="btn"
75
+ bsStyle="default"
76
+ disabled={false}
77
+ onClick={[Function]}
78
+ >
79
+ <Icon
80
+ name="refresh"
81
+ type="fa"
82
+ />
83
+
84
+ Refresh Data
85
+ </Button>
72
86
  <Spinner
73
87
  className=""
74
88
  inline={false}
75
89
  inverse={false}
76
90
  loading={true}
77
- size="lg"
91
+ size="md"
78
92
  />
79
93
  <ExportButton
80
94
  title="Export All"
@@ -112,10 +126,13 @@ exports[`TasksTablePage rendering render with Breadcrubs 1`] = `
112
126
  }
113
127
  }
114
128
  parentTaskID={null}
129
+ reloadPage={[MockFunction]}
115
130
  results={
116
131
  Array [
117
- "a",
118
- "b",
132
+ Object {
133
+ "action": "a",
134
+ "canEdit": true,
135
+ },
119
136
  ]
120
137
  }
121
138
  selectPage={[MockFunction]}
@@ -184,15 +201,29 @@ exports[`TasksTablePage rendering render with minimal props 1`] = `
184
201
  }
185
202
  searchQuery="a=b"
186
203
  searchable={true}
187
- toastNotifications="foreman-tasks-cancel"
188
204
  toolbarButtons={
189
205
  <React.Fragment>
206
+ <Button
207
+ active={false}
208
+ block={false}
209
+ bsClass="btn"
210
+ bsStyle="default"
211
+ disabled={false}
212
+ onClick={[Function]}
213
+ >
214
+ <Icon
215
+ name="refresh"
216
+ type="fa"
217
+ />
218
+
219
+ Refresh Data
220
+ </Button>
190
221
  <Spinner
191
222
  className=""
192
223
  inline={false}
193
224
  inverse={false}
194
225
  loading={true}
195
- size="lg"
226
+ size="md"
196
227
  />
197
228
  <ExportButton
198
229
  title="Export All"
@@ -230,6 +261,7 @@ exports[`TasksTablePage rendering render with minimal props 1`] = `
230
261
  }
231
262
  }
232
263
  parentTaskID={null}
264
+ reloadPage={[MockFunction]}
233
265
  results={
234
266
  Array [
235
267
  "a",
@@ -7,6 +7,7 @@ exports[`actionCellFormatter render 1`] = `
7
7
  "cancellable": true,
8
8
  }
9
9
  }
10
+ canEdit={true}
10
11
  id="some-id"
11
12
  name="some-name"
12
13
  taskActions={Object {}}
@@ -4,6 +4,8 @@ exports[`actionNameCellFormatter render 1`] = `
4
4
  <a
5
5
  href="/some-url/some-id"
6
6
  >
7
- action-name
7
+ <EllipisWithTooltip>
8
+ action-name
9
+ </EllipisWithTooltip>
8
10
  </a>
9
11
  `;
@@ -3,8 +3,10 @@
3
3
  exports[`selectionCellFormatter render 1`] = `
4
4
  <TableSelectionCell
5
5
  checked={true}
6
+ disabled={true}
6
7
  id="selectsome-index"
7
8
  label="Select row"
8
9
  onChange={[Function]}
10
+ title="You do not have permission"
9
11
  />
10
12
  `;
@@ -4,7 +4,7 @@ describe('actionCellFormatter', () => {
4
4
  it('render', () => {
5
5
  const data = [
6
6
  { cancellable: true },
7
- { rowData: { action: 'some-name', id: 'some-id' } },
7
+ { rowData: { action: 'some-name', id: 'some-id', canEdit: true } },
8
8
  ];
9
9
  expect(actionCellFormatter({})(...data)).toMatchSnapshot();
10
10
  });
@@ -5,7 +5,7 @@ describe('selectionCellFormatter', () => {
5
5
  expect(
6
6
  selectionCellFormatter(
7
7
  { isSelected: () => true },
8
- { rowIndex: 'some-index' }
8
+ { rowIndex: 'some-index', rowData: {} }
9
9
  )
10
10
  ).toMatchSnapshot();
11
11
  });
@@ -4,13 +4,16 @@ import { ActionButton } from '../../common/ActionButtons/ActionButton';
4
4
 
5
5
  export const actionCellFormatter = taskActions => (
6
6
  value,
7
- { rowData: { action, id } }
7
+ { rowData: { action, id, canEdit } }
8
8
  ) =>
9
9
  cellFormatter(
10
- <ActionButton
11
- id={id}
12
- name={action}
13
- taskActions={taskActions}
14
- availableActions={value}
15
- />
10
+ canEdit && (
11
+ <ActionButton
12
+ canEdit={canEdit}
13
+ id={id}
14
+ name={action}
15
+ taskActions={taskActions}
16
+ availableActions={value}
17
+ />
18
+ )
16
19
  );
@@ -1,5 +1,10 @@
1
1
  import React from 'react';
2
2
  import { cellFormatter } from 'foremanReact/components/common/table';
3
+ import EllipsisWithTooltip from 'react-ellipsis-with-tooltip';
3
4
 
4
5
  export const actionNameCellFormatter = url => (value, { rowData: { id } }) =>
5
- cellFormatter(<a href={`/${url}/${id}`}>{value}</a>);
6
+ cellFormatter(
7
+ <a href={`/${url}/${id}`}>
8
+ <EllipsisWithTooltip>{value}</EllipsisWithTooltip>
9
+ </a>
10
+ );
@@ -1,9 +1,16 @@
1
1
  import React from 'react';
2
+ import { translate as __ } from 'foremanReact/common/I18n';
2
3
  import TableSelectionCell from '../Components/TableSelectionCell';
3
4
 
4
5
  export default (selectionController, additionalData) => (
5
6
  <TableSelectionCell
6
7
  id={`select${additionalData.rowIndex}`}
8
+ disabled={!additionalData.rowData.canEdit}
9
+ title={
10
+ additionalData.rowData.canEdit
11
+ ? undefined
12
+ : __('You do not have permission')
13
+ }
7
14
  checked={selectionController.isSelected(additionalData)}
8
15
  onChange={() => selectionController.selectRow(additionalData)}
9
16
  />
@@ -4,45 +4,48 @@ import { translate as __ } from 'foremanReact/common/I18n';
4
4
  import { ActionButtons } from 'foremanReact/components/common/ActionButtons/ActionButtons';
5
5
 
6
6
  export const ActionButton = ({
7
+ canEdit,
7
8
  id,
8
9
  name,
9
10
  availableActions: { resumable, cancellable, stoppable },
10
11
  taskActions,
11
12
  }) => {
12
13
  const buttons = [];
13
- const isTitle = !(resumable || cancellable || stoppable);
14
+ const isTitle = canEdit && !(resumable || cancellable || stoppable);
14
15
  const title = isTitle ? __('Task cannot be canceled') : undefined;
15
- if (resumable) {
16
- buttons.push({
17
- title: __('Resume'),
18
- action: {
19
- disabled: !resumable,
20
- onClick: () => taskActions.resumeTask(id, name),
21
- id: `task-resume-button-${id}`,
22
- },
23
- });
24
- }
25
- if (cancellable || (!stoppable && !resumable)) {
26
- // Cancel is the default button that should be shown if no task action can be done
27
- buttons.push({
28
- title: __('Cancel'),
29
- action: {
30
- disabled: !cancellable,
31
- onClick: () => taskActions.cancelTask(id, name),
32
- id: `task-cancel-button-${id}`,
33
- },
34
- });
35
- }
16
+ if (canEdit) {
17
+ if (resumable) {
18
+ buttons.push({
19
+ title: __('Resume'),
20
+ action: {
21
+ disabled: !resumable,
22
+ onClick: () => taskActions.resumeTask(id, name),
23
+ id: `task-resume-button-${id}`,
24
+ },
25
+ });
26
+ }
27
+ if (cancellable || (!stoppable && !resumable)) {
28
+ // Cancel is the default button that should be shown if no task action can be done
29
+ buttons.push({
30
+ title: __('Cancel'),
31
+ action: {
32
+ disabled: !cancellable,
33
+ onClick: () => taskActions.cancelTask(id, name),
34
+ id: `task-cancel-button-${id}`,
35
+ },
36
+ });
37
+ }
36
38
 
37
- if (stoppable) {
38
- buttons.push({
39
- title: __('Force Cancel'),
40
- action: {
41
- disabled: !stoppable,
42
- onClick: () => taskActions.forceCancelTask(id, name),
43
- id: `task-force-cancel-button-${id}`,
44
- },
45
- });
39
+ if (stoppable) {
40
+ buttons.push({
41
+ title: __('Force Cancel'),
42
+ action: {
43
+ disabled: !stoppable,
44
+ onClick: () => taskActions.forceCancelTask(id, name),
45
+ id: `task-force-cancel-button-${id}`,
46
+ },
47
+ });
48
+ }
46
49
  }
47
50
  return (
48
51
  <span title={title}>
@@ -52,6 +55,7 @@ export const ActionButton = ({
52
55
  };
53
56
 
54
57
  ActionButton.propTypes = {
58
+ canEdit: PropTypes.bool,
55
59
  id: PropTypes.string.isRequired,
56
60
  name: PropTypes.string.isRequired,
57
61
  availableActions: PropTypes.shape({
@@ -65,3 +69,7 @@ ActionButton.propTypes = {
65
69
  forceCancelTask: PropTypes.func,
66
70
  }).isRequired,
67
71
  };
72
+
73
+ ActionButton.defaultProps = {
74
+ canEdit: false,
75
+ };
@@ -7,6 +7,7 @@ const resumeTask = jest.fn();
7
7
  const cancelTask = jest.fn();
8
8
  const forceCancelTask = jest.fn();
9
9
  const taskActions = { resumeTask, cancelTask, forceCancelTask };
10
+ const minProps = { canEdit: true, id: 'id', name: 'some-name' };
10
11
  const fixtures = {
11
12
  'render with cancellable true props': {
12
13
  availableActions: {
@@ -14,8 +15,7 @@ const fixtures = {
14
15
  resumable: false,
15
16
  },
16
17
  taskActions,
17
- id: 'id',
18
- name: 'some-name',
18
+ ...minProps,
19
19
  },
20
20
  'render with resumable true props': {
21
21
  availableActions: {
@@ -23,8 +23,7 @@ const fixtures = {
23
23
  resumable: true,
24
24
  },
25
25
  taskActions,
26
- id: 'id',
27
- name: 'some-name',
26
+ ...minProps,
28
27
  },
29
28
  'render with stoppable and cancellable true props': {
30
29
  availableActions: {
@@ -32,8 +31,7 @@ const fixtures = {
32
31
  stoppable: true,
33
32
  },
34
33
  taskActions,
35
- id: 'id',
36
- name: 'some-name',
34
+ ...minProps,
37
35
  },
38
36
  'render with cancellable false props': {
39
37
  availableActions: {
@@ -41,8 +39,16 @@ const fixtures = {
41
39
  resumable: false,
42
40
  },
43
41
  taskActions,
44
- id: 'id',
45
- name: 'some-name',
42
+ ...minProps,
43
+ },
44
+ 'render with canEdit false': {
45
+ availableActions: {
46
+ cancellable: false,
47
+ resumable: false,
48
+ },
49
+ taskActions,
50
+ ...minProps,
51
+ canEdit: false,
46
52
  },
47
53
  };
48
54
 
@@ -57,6 +63,7 @@ describe('ActionButton', () => {
57
63
  <ActionButton
58
64
  id={id}
59
65
  name={name}
66
+ canEdit
60
67
  availableActions={{ cancellable: true }}
61
68
  taskActions={taskActions}
62
69
  />
@@ -69,6 +76,7 @@ describe('ActionButton', () => {
69
76
  <ActionButton
70
77
  id={id}
71
78
  name={name}
79
+ canEdit
72
80
  availableActions={{ resumable: true }}
73
81
  taskActions={taskActions}
74
82
  />
@@ -81,6 +89,7 @@ describe('ActionButton', () => {
81
89
  <ActionButton
82
90
  id={id}
83
91
  name={name}
92
+ canEdit
84
93
  availableActions={{ stoppable: true }}
85
94
  taskActions={taskActions}
86
95
  />