foreman-tasks 1.2.0 → 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (154) 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/README.md +2 -0
  8. data/app/controllers/foreman_tasks/api/tasks_controller.rb +36 -60
  9. data/app/controllers/foreman_tasks/concerns/parameters/triggering.rb +1 -1
  10. data/app/controllers/foreman_tasks/recurring_logics_controller.rb +7 -0
  11. data/app/controllers/foreman_tasks/tasks_controller.rb +6 -3
  12. data/app/helpers/foreman_tasks/foreman_tasks_helper.rb +3 -3
  13. data/app/lib/actions/proxy_action.rb +1 -1
  14. data/app/models/foreman_tasks/recurring_logic.rb +1 -1
  15. data/app/models/foreman_tasks/task.rb +11 -0
  16. data/app/models/foreman_tasks/task/dynflow_task.rb +29 -33
  17. data/app/models/foreman_tasks/task/status_explicator.rb +1 -1
  18. data/app/models/foreman_tasks/triggering.rb +1 -1
  19. data/app/models/setting/foreman_tasks.rb +9 -9
  20. data/app/services/foreman_tasks/dashboard_table_filter.rb +5 -1
  21. data/app/views/foreman_tasks/api/tasks/index.json.rabl +2 -0
  22. data/app/views/foreman_tasks/api/tasks/show.json.rabl +2 -0
  23. data/app/views/foreman_tasks/recurring_logics/index.html.erb +3 -1
  24. data/config/routes.rb +2 -1
  25. data/db/migrate/20200517215015_rename_bookmarks_controller.rb +2 -2
  26. data/db/migrate/20200611090846_add_task_lock_index_on_resource_type_and_task_id.rb +9 -0
  27. data/db/seeds.d/30-notification_blueprints.rb +7 -7
  28. data/db/seeds.d/61-foreman_tasks_bookmarks.rb +1 -1
  29. data/lib/foreman_tasks/cleaner.rb +4 -6
  30. data/lib/foreman_tasks/dynflow/configuration.rb +1 -1
  31. data/lib/foreman_tasks/dynflow/persistence.rb +4 -6
  32. data/lib/foreman_tasks/engine.rb +2 -7
  33. data/lib/foreman_tasks/tasks/cleanup.rake +2 -2
  34. data/lib/foreman_tasks/tasks/dynflow.rake +6 -0
  35. data/lib/foreman_tasks/tasks/export_tasks.rake +1 -1
  36. data/lib/foreman_tasks/version.rb +1 -1
  37. data/locale/en/LC_MESSAGES/foreman_tasks.mo +0 -0
  38. data/locale/en/foreman_tasks.po +50 -20
  39. data/locale/foreman_tasks.pot +173 -126
  40. data/locale/fr/LC_MESSAGES/foreman_tasks.mo +0 -0
  41. data/locale/fr/foreman_tasks.po +817 -0
  42. data/locale/ja/LC_MESSAGES/foreman_tasks.mo +0 -0
  43. data/locale/ja/foreman_tasks.po +817 -0
  44. data/locale/zh_CN/LC_MESSAGES/foreman_tasks.mo +0 -0
  45. data/locale/zh_CN/foreman_tasks.po +816 -0
  46. data/package.json +1 -1
  47. data/script/npm_link_foreman_js.sh +26 -0
  48. data/test/controllers/api/recurring_logics_controller_test.rb +1 -1
  49. data/test/controllers/api/tasks_controller_test.rb +17 -7
  50. data/test/controllers/tasks_controller_test.rb +6 -6
  51. data/test/core/unit/runner_test.rb +20 -20
  52. data/test/core/unit/task_launcher_test.rb +8 -8
  53. data/test/helpers/foreman_tasks/foreman_tasks_helper_test.rb +7 -7
  54. data/test/helpers/foreman_tasks/tasks_helper_test.rb +3 -3
  55. data/test/lib/actions/middleware/keep_current_request_id_test.rb +3 -3
  56. data/test/support/history_tasks_builder.rb +1 -1
  57. data/test/tasks/generate_task_actions_test.rb +1 -1
  58. data/test/unit/actions/action_with_sub_plans_test.rb +2 -2
  59. data/test/unit/actions/bulk_action_test.rb +6 -6
  60. data/test/unit/actions/proxy_action_test.rb +20 -20
  61. data/test/unit/actions/recurring_action_test.rb +30 -32
  62. data/test/unit/cleaner_test.rb +24 -24
  63. data/test/unit/dashboard_table_filter_test.rb +5 -5
  64. data/test/unit/otp_manager_test.rb +2 -2
  65. data/test/unit/proxy_selector_test.rb +9 -9
  66. data/test/unit/recurring_logic_test.rb +32 -32
  67. data/test/unit/remote_task_test.rb +2 -2
  68. data/test/unit/task_groups_test.rb +4 -4
  69. data/test/unit/task_test.rb +18 -18
  70. data/test/unit/triggering_test.rb +8 -8
  71. data/test/unit/troubleshooting_help_generator_test.rb +6 -6
  72. data/test/unit/ui_notifications_test.rb +11 -11
  73. data/webpack/ForemanTasks/Components/TaskActions/TaskAction.test.js +2 -2
  74. data/webpack/ForemanTasks/Components/TaskActions/index.js +1 -1
  75. data/webpack/ForemanTasks/Components/TaskDetails/Components/RunningSteps.js +17 -3
  76. data/webpack/ForemanTasks/Components/TaskDetails/Components/Task.js +8 -153
  77. data/webpack/ForemanTasks/Components/TaskDetails/Components/TaskButtons.js +168 -0
  78. data/webpack/ForemanTasks/Components/TaskDetails/Components/TaskInfo.js +6 -7
  79. data/webpack/ForemanTasks/Components/TaskDetails/Components/TaskSkeleton.js +48 -0
  80. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/RunningSteps.test.js +8 -1
  81. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/Task.test.js +13 -70
  82. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/TaskButtons.test.js +95 -0
  83. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/RunningSteps.test.js.snap +1 -1
  84. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/Task.test.js.snap +78 -208
  85. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/TaskButtons.test.js.snap +212 -0
  86. data/webpack/ForemanTasks/Components/TaskDetails/Components/__tests__/__snapshots__/TaskInfo.test.js.snap +8 -4
  87. data/webpack/ForemanTasks/Components/TaskDetails/TaskDetails.js +100 -53
  88. data/webpack/ForemanTasks/Components/TaskDetails/TaskDetails.scss +3 -14
  89. data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsActions.js +57 -95
  90. data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsConstants.js +3 -12
  91. data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsSelectors.js +57 -28
  92. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetails.fixtures.js +8 -0
  93. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetails.test.js +8 -1
  94. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetailsActions.test.js +6 -6
  95. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/TaskDetails.test.js.snap +84 -12
  96. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/TaskDetailsActions.test.js.snap +25 -21
  97. data/webpack/ForemanTasks/Components/TaskDetails/index.js +8 -3
  98. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/ScheduledTasksCard/ScheduledTasksCard.scss +4 -0
  99. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/OtherInfo.js +53 -0
  100. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/OtherInfo.test.js +14 -0
  101. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCard.js +27 -19
  102. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCard.scss +14 -0
  103. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCard.test.js +1 -34
  104. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/{StoppedTasksCardHelper.js → StoppedTasksCardTable.js} +28 -1
  105. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/StoppedTasksCardTable.test.js +54 -0
  106. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/__snapshots__/OtherInfo.test.js.snap +48 -0
  107. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/__snapshots__/StoppedTasksCard.test.js.snap +60 -1367
  108. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/Components/StoppedTasksCard/__snapshots__/StoppedTasksCardTable.test.js.snap +960 -0
  109. data/webpack/ForemanTasks/Components/TasksDashboard/Components/TasksCardsGrid/__snapshots__/TasksCardsGrid.test.js.snap +14 -11
  110. data/webpack/ForemanTasks/Components/TasksDashboard/TasksDashboardActions.js +1 -1
  111. data/webpack/ForemanTasks/Components/TasksDashboard/TasksDashboardConstants.js +2 -0
  112. data/webpack/ForemanTasks/Components/TasksDashboard/TasksDashboardSelectors.js +17 -11
  113. data/webpack/ForemanTasks/Components/TasksDashboard/__tests__/TasksDashboardActions.test.js +2 -2
  114. data/webpack/ForemanTasks/Components/TasksDashboard/__tests__/TasksDashboardSelectors.test.js +26 -14
  115. data/webpack/ForemanTasks/Components/TasksDashboard/__tests__/__snapshots__/TasksDashboard.test.js.snap +14 -11
  116. data/webpack/ForemanTasks/Components/TasksDashboard/__tests__/__snapshots__/TasksDashboardSelectors.test.js.snap +38 -22
  117. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/ConfirmModalSelectors.js +1 -0
  118. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/ConfirmModalSelectors.test.js +1 -0
  119. data/webpack/ForemanTasks/Components/TasksTable/Components/ConfirmModal/__test__/__snapshots__/ConfirmModalSelectors.test.js.snap +2 -0
  120. data/webpack/ForemanTasks/Components/TasksTable/TasksBulkActions.js +25 -8
  121. data/webpack/ForemanTasks/Components/TasksTable/TasksTableActions.js +3 -3
  122. data/webpack/ForemanTasks/Components/TasksTable/TasksTablePage.js +6 -2
  123. data/webpack/ForemanTasks/Components/TasksTable/TasksTableSelectors.js +1 -0
  124. data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksBulkActions.test.js +15 -2
  125. data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTable.fixtures.js +1 -0
  126. data/webpack/ForemanTasks/Components/TasksTable/__tests__/TasksTablePage.test.js +2 -1
  127. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/SubTasksPage.test.js.snap +1 -0
  128. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksBulkActions.test.js.snap +48 -0
  129. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksIndexPage.test.js.snap +1 -0
  130. data/webpack/ForemanTasks/Components/TasksTable/__tests__/__snapshots__/TasksTablePage.test.js.snap +39 -5
  131. data/webpack/ForemanTasks/Components/TasksTable/formatters/__test__/__snapshots__/actionCellFormatter.test.js.snap +1 -0
  132. data/webpack/ForemanTasks/Components/TasksTable/formatters/__test__/__snapshots__/selectionCellFormatter.test.js.snap +2 -0
  133. data/webpack/ForemanTasks/Components/TasksTable/formatters/__test__/actionCellFormatter.test.js +1 -1
  134. data/webpack/ForemanTasks/Components/TasksTable/formatters/__test__/selectionCellFormatter.test.js +1 -1
  135. data/webpack/ForemanTasks/Components/TasksTable/formatters/actionCellFormatter.js +10 -7
  136. data/webpack/ForemanTasks/Components/TasksTable/formatters/selectionCellFormatter.js +7 -0
  137. data/webpack/ForemanTasks/Components/common/ActionButtons/ActionButton.js +39 -31
  138. data/webpack/ForemanTasks/Components/common/ActionButtons/ActionButton.test.js +17 -8
  139. data/webpack/ForemanTasks/Components/common/ActionButtons/__snapshots__/ActionButton.test.js.snap +8 -0
  140. data/webpack/ForemanTasks/Components/common/urlHelpers.js +7 -0
  141. data/webpack/ForemanTasks/ForemanTasksReducers.js +0 -2
  142. data/webpack/__mocks__/foremanReact/common/helpers.js +2 -0
  143. data/webpack/__mocks__/foremanReact/redux/API/APISelectors.js +10 -0
  144. data/webpack/__mocks__/foremanReact/redux/API/index.js +10 -0
  145. data/webpack/__mocks__/foremanReact/redux/middlewares/IntervalMiddleware.js +5 -0
  146. metadata +29 -11
  147. data/.travis.yml +0 -5
  148. data/script/travis_run_js_tests.sh +0 -7
  149. data/webpack/ForemanTasks/Components/TaskDetails/TaskDetailsReducer.js +0 -38
  150. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/TaskDetailsReducer.test.js +0 -33
  151. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/TaskDetailsReducer.test.js.snap +0 -26
  152. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/__snapshots__/integration.test.js.snap +0 -122
  153. data/webpack/ForemanTasks/Components/TaskDetails/__tests__/integration.test.js +0 -67
  154. data/webpack/__mocks__/foremanReact/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
 
@@ -1,5 +1,5 @@
1
1
  import { testActionSnapshotWithFixtures } from '@theforeman/test';
2
- import API from 'foremanReact/API';
2
+ import { API } from 'foremanReact/redux/API';
3
3
  import {
4
4
  bulkCancelById,
5
5
  bulkCancelBySearch,
@@ -13,11 +13,12 @@ jest.mock('foremanReact/components/common/table', () => ({
13
13
  getTableItemsAction: jest.fn(controller => controller),
14
14
  }));
15
15
 
16
- jest.mock('foremanReact/API');
16
+ jest.mock('foremanReact/redux/API');
17
17
 
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
  >
@@ -69,12 +69,27 @@ exports[`TasksTablePage rendering render with Breadcrubs 1`] = `
69
69
  toastNotifications="foreman-tasks-cancel"
70
70
  toolbarButtons={
71
71
  <React.Fragment>
72
+ <Button
73
+ active={false}
74
+ block={false}
75
+ bsClass="btn"
76
+ bsStyle="default"
77
+ disabled={false}
78
+ onClick={[Function]}
79
+ >
80
+ <Icon
81
+ name="refresh"
82
+ type="fa"
83
+ />
84
+
85
+ Refresh Data
86
+ </Button>
72
87
  <Spinner
73
88
  className=""
74
89
  inline={false}
75
90
  inverse={false}
76
91
  loading={true}
77
- size="lg"
92
+ size="md"
78
93
  />
79
94
  <ExportButton
80
95
  title="Export All"
@@ -112,10 +127,13 @@ exports[`TasksTablePage rendering render with Breadcrubs 1`] = `
112
127
  }
113
128
  }
114
129
  parentTaskID={null}
130
+ reloadPage={[MockFunction]}
115
131
  results={
116
132
  Array [
117
- "a",
118
- "b",
133
+ Object {
134
+ "action": "a",
135
+ "canEdit": true,
136
+ },
119
137
  ]
120
138
  }
121
139
  selectPage={[MockFunction]}
@@ -187,12 +205,27 @@ exports[`TasksTablePage rendering render with minimal props 1`] = `
187
205
  toastNotifications="foreman-tasks-cancel"
188
206
  toolbarButtons={
189
207
  <React.Fragment>
208
+ <Button
209
+ active={false}
210
+ block={false}
211
+ bsClass="btn"
212
+ bsStyle="default"
213
+ disabled={false}
214
+ onClick={[Function]}
215
+ >
216
+ <Icon
217
+ name="refresh"
218
+ type="fa"
219
+ />
220
+
221
+ Refresh Data
222
+ </Button>
190
223
  <Spinner
191
224
  className=""
192
225
  inline={false}
193
226
  inverse={false}
194
227
  loading={true}
195
- size="lg"
228
+ size="md"
196
229
  />
197
230
  <ExportButton
198
231
  title="Export All"
@@ -230,6 +263,7 @@ exports[`TasksTablePage rendering render with minimal props 1`] = `
230
263
  }
231
264
  }
232
265
  parentTaskID={null}
266
+ reloadPage={[MockFunction]}
233
267
  results={
234
268
  Array [
235
269
  "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 {}}
@@ -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,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
  />